libimager-perl-1.004+dfsg.orig/0000755000175000017500000000000012617670351015571 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/io.c0000644000175000017500000002146312263740601016343 0ustar gregoagregoa#include "imager.h" #include "imageri.h" #include #ifndef _MSC_VER #include #endif /* FIXME: make allocation dynamic */ #ifdef IMAGER_DEBUG_MALLOC #define MAXMAL 102400 #define MAXDESC 65 #define UNDRRNVAL 10 #define OVERRNVAL 10 #define PADBYTE 0xaa static int malloc_need_init = 1; typedef struct { void* ptr; size_t size; const char *file; int line; } malloc_entry; malloc_entry malloc_pointers[MAXMAL]; /* Utility functions */ static void malloc_init(void) { int i; for(i=0; i %ld bytes allocated at %p for %s (%d)\n", i, (long)size, buf, file, line)); return buf; } void * (mymalloc)(size_t size) { return mymalloc_file_line(size, "unknown", 0); } void* myrealloc_file_line(void *ptr, size_t newsize, char* file, int line) { char *buf; int i; if (malloc_need_init) malloc_init(); /* bndcheck_all(); ACTIVATE FOR LOTS OF THRASHING */ if (!ptr) { mm_log((1, "realloc called with ptr = NULL, sending request to malloc\n")); return mymalloc_file_line(newsize, file, line); } if (!newsize) { mm_log((1, "newsize = 0, sending request to free\n")); myfree_file_line(ptr, file, line); return NULL; } if ( (i = find_ptr(ptr)) == -1) { mm_log((0, "Unable to find %p in realloc for %s (%i)\n", ptr, file, line)); exit(3); } if ( (buf = realloc(((char *)ptr)-UNDRRNVAL, UNDRRNVAL+OVERRNVAL+newsize)) == NULL ) { mm_log((1,"Unable to reallocate %ld bytes at %p for %s (%i)\n", (long) newsize, ptr, file, line)); exit(3); } buf = set_entry(i, buf, newsize, file, line); mm_log((1,"realloc_file_line: slot <%d> %ld bytes allocated at %p for %s (%d)\n", i, (long)newsize, buf, file, line)); return buf; } void * (myrealloc)(void *ptr, size_t newsize) { return myrealloc_file_line(ptr, newsize, "unknown", 0); } static void bndcheck(int idx) { int i; size_t s = malloc_pointers[idx].size; unsigned char *pp = malloc_pointers[idx].ptr; if (!pp) { mm_log((1, "bndcheck: No pointer in slot %d\n", idx)); return; } for(i=0;i %p\n", (long)size, buf)); return buf; } void * mymalloc_file_line(size_t size, char *file, int line) { return mymalloc(size); } void myfree(void *p) { mm_log((1, "myfree(p %p)\n", p)); free(p); } void myfree_file_line(void *p, char *file, int line) { myfree(p); } void * myrealloc(void *block, size_t size) { void *result; mm_log((1, "myrealloc(block %p, size %ld)\n", block, (long)size)); if ((result = realloc(block, size)) == NULL) { mm_log((1, "myrealloc: out of memory\n")); fprintf(stderr, "Out of memory.\n"); exit(3); } return result; } void * myrealloc_file_line(void *block, size_t newsize, char *file, int size) { return myrealloc(block, newsize); } #endif /* IMAGER_MALLOC_DEBUG */ /* memory pool implementation */ void i_mempool_init(i_mempool *mp) { mp->alloc = 10; mp->used = 0; mp->p = mymalloc(sizeof(void*)*mp->alloc); } void i_mempool_extend(i_mempool *mp) { mp->p = myrealloc(mp->p, mp->alloc * 2); mp->alloc *=2; } void * i_mempool_alloc(i_mempool *mp, size_t size) { if (mp->used == mp->alloc) i_mempool_extend(mp); mp->p[mp->used] = mymalloc(size); mp->used++; return mp->p[mp->used-1]; } void i_mempool_destroy(i_mempool *mp) { unsigned int i; for(i=0; iused; i++) myfree(mp->p[i]); myfree(mp->p); } /* Should these really be here? */ #undef min #undef max i_img_dim i_minx(i_img_dim a, i_img_dim b) { if (ab) return a; else return b; } struct utf8_size { int mask, expect; int size; }; struct utf8_size utf8_sizes[] = { { 0x80, 0x00, 1 }, { 0xE0, 0xC0, 2 }, { 0xF0, 0xE0, 3 }, { 0xF8, 0xF0, 4 }, }; /* =item i_utf8_advance(char **p, size_t *len) Retrieve a C character from the stream. Modifies *p and *len to indicate the consumed characters. This doesn't support the extended C encoding used by later versions of Perl. Since this is typically used to implement text output by font drivers, the strings supplied shouldn't have such out of range characters. This doesn't check that the C character is using the shortest possible representation. Returns ~0UL on failure. =cut */ unsigned long i_utf8_advance(char const **p, size_t *len) { unsigned char c; int i, ci, clen = 0; unsigned char codes[3]; if (*len == 0) return ~0UL; c = *(*p)++; --*len; for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) { if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) { clen = utf8_sizes[i].size; break; } } if (clen == 0 || *len < clen-1) { --*p; ++*len; return ~0UL; } /* check that each character is well formed */ i = 1; ci = 0; while (i < clen) { if (((*p)[ci] & 0xC0) != 0x80) { --*p; ++*len; return ~0UL; } codes[ci] = (*p)[ci]; ++ci; ++i; } *p += clen-1; *len -= clen-1; if (c & 0x80) { if ((c & 0xE0) == 0xC0) { return ((c & 0x1F) << 6) + (codes[0] & 0x3F); } else if ((c & 0xF0) == 0xE0) { return ((c & 0x0F) << 12) | ((codes[0] & 0x3F) << 6) | (codes[1] & 0x3f); } else if ((c & 0xF8) == 0xF0) { return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12) | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F); } else { *p -= clen; *len += clen; return ~0UL; } } else { return c; } } libimager-perl-1.004+dfsg.orig/conv.im0000644000175000017500000000502712263740600017061 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" /* General convolution for 2d decoupled filters end effects are acounted for by increasing scaling the result with the sum of used coefficients coeff: (double array) coefficients for filter len: length of filter.. number of coefficients note that this has to be an odd number (since the filter is even); */ int i_conv(i_img *im, const double *coeff,int len) { i_img_dim xo, yo; /* output pixel co-ordinate */ int c, ch, center; double pc; double res[MAXCHANNELS]; i_img *timg; dIMCTXim(im); im_log((aIMCTX,1,"i_conv(im %p, coeff %p, len %d)\n",im,coeff,len)); im_clear_error(aIMCTX); if (len < 1) { im_push_error(aIMCTX, 0, "there must be at least one coefficient"); return 0; } center=(len-1)/2; pc = 0; for (c = 0; c < len; ++c) pc += coeff[c]; if (pc == 0) { i_push_error(0, "sum of coefficients is zero"); return 0; } timg = i_sametype(im, im->xsize, im->ysize); #code im->bits <= 8 IM_COLOR rcolor; /* don't move the calculation of pc up here, it depends on which pixels are readable */ for(yo = 0; yo < im->ysize; yo++) { for(xo = 0; xo < im->xsize; xo++) { for(ch = 0;ch < im->channels; ch++) res[ch] = 0; for(c = 0;c < len; c++) { i_img_dim xi = xo + c - center; if (xi < 0) xi = 0; else if (xi >= im->xsize) xi = im->xsize - 1; if (IM_GPIX(im, xi, yo, &rcolor)!=-1) { for(ch = 0; ch < im->channels; ch++) res[ch] += (rcolor.channel[ch]) *coeff[c]; } } im_assert(pc != 0); for(ch = 0; ch < im->channels; ch++) { double temp = res[ch] / pc; rcolor.channel[ch] = temp < 0 ? 0 : temp > IM_SAMPLE_MAX ? IM_SAMPLE_MAX : (IM_SAMPLE_T)temp; } IM_PPIX(timg, xo, yo, &rcolor); } } for(xo = 0; xo < im->xsize; xo++) { for(yo = 0;yo < im->ysize; yo++) { for(ch = 0; ch < im->channels; ch++) res[ch] = 0; for(c = 0; c < len; c++) { i_img_dim yi = yo + c - center; if (yi < 0) yi = 0; else if (yi >= im->ysize) yi = im->ysize - 1; if (IM_GPIX(timg, xo, yi, &rcolor) != -1) { for(ch = 0;ch < im->channels; ch++) res[ch] += (rcolor.channel[ch]) * coeff[c]; } } im_assert(pc != 0); for(ch = 0;ch < im->channels; ch++) { double temp = res[ch] / pc; rcolor.channel[ch] = temp < 0 ? 0 : temp > IM_SAMPLE_MAX ? IM_SAMPLE_MAX : (IM_SAMPLE_T)temp; } IM_PPIX(im, xo, yo,&rcolor); } } #/code i_img_destroy(timg); return 1; } libimager-perl-1.004+dfsg.orig/img8.c0000644000175000017500000004522412614520110016570 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" static int i_ppix_d(i_img *im, i_img_dim x, i_img_dim y, const i_color *val); static int i_gpix_d(i_img *im, i_img_dim x, i_img_dim y, i_color *val); static i_img_dim i_glin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals); static i_img_dim i_plin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals); static int i_ppixf_d(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val); static int i_gpixf_d(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val); static i_img_dim i_glinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals); static i_img_dim i_plinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals); static i_img_dim i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, const int *chans, int chan_count); static i_img_dim i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, const int *chans, int chan_count); static i_img_dim i_psamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count); static i_img_dim i_psampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count); /* =item IIM_base_8bit_direct (static) A static i_img object used to initialize direct 8-bit per sample images. =cut */ static i_img IIM_base_8bit_direct = { 0, /* channels set */ 0, 0, 0, /* xsize, ysize, bytes */ ~0U, /* ch_mask */ i_8_bits, /* bits */ i_direct_type, /* type */ 0, /* virtual */ NULL, /* idata */ { 0, 0, NULL }, /* tags */ NULL, /* ext_data */ i_ppix_d, /* i_f_ppix */ i_ppixf_d, /* i_f_ppixf */ i_plin_d, /* i_f_plin */ i_plinf_d, /* i_f_plinf */ i_gpix_d, /* i_f_gpix */ i_gpixf_d, /* i_f_gpixf */ i_glin_d, /* i_f_glin */ i_glinf_d, /* i_f_glinf */ i_gsamp_d, /* i_f_gsamp */ i_gsampf_d, /* i_f_gsampf */ NULL, /* i_f_gpal */ NULL, /* i_f_ppal */ NULL, /* i_f_addcolors */ NULL, /* i_f_getcolors */ NULL, /* i_f_colorcount */ NULL, /* i_f_maxcolors */ NULL, /* i_f_findcolor */ NULL, /* i_f_setcolors */ NULL, /* i_f_destroy */ i_gsamp_bits_fb, NULL, /* i_f_psamp_bits */ i_psamp_d, i_psampf_d }; /*static void set_8bit_direct(i_img *im) { im->i_f_ppix = i_ppix_d; im->i_f_ppixf = i_ppixf_d; im->i_f_plin = i_plin_d; im->i_f_plinf = i_plinf_d; im->i_f_gpix = i_gpix_d; im->i_f_gpixf = i_gpixf_d; im->i_f_glin = i_glin_d; im->i_f_glinf = i_glinf_d; im->i_f_gpal = NULL; im->i_f_ppal = NULL; im->i_f_addcolor = NULL; im->i_f_getcolor = NULL; im->i_f_colorcount = NULL; im->i_f_findcolor = NULL; }*/ /* =item im_img_8_new(ctx, x, y, ch) XX =category Image creation/destruction =synopsis i_img *img = im_img_8_new(aIMCTX, width, height, channels); =synopsis i_img *img = i_img_8_new(width, height, channels); Creates a new image object I pixels wide, and I pixels high with I channels. =cut */ i_img * im_img_8_new(pIMCTX, i_img_dim x,i_img_dim y,int ch) { i_img *im; im_log((aIMCTX, 1,"im_img_8_new(x %" i_DF ", y %" i_DF ", ch %d)\n", i_DFc(x), i_DFc(y), ch)); im = im_img_empty_ch(aIMCTX, NULL,x,y,ch); im_log((aIMCTX, 1,"(%p) <- IIM_new\n",im)); return im; } /* =item i_img_empty(im, x, y) Re-new image reference (assumes 3 channels) im - Image pointer x - xsize of destination image y - ysize of destination image **FIXME** what happens if a live image is passed in here? Should this just call i_img_empty_ch()? =cut */ i_img * im_img_empty(pIMCTX, i_img *im,i_img_dim x,i_img_dim y) { im_log((aIMCTX, 1,"i_img_empty(*im %p, x %" i_DF ", y %" i_DF ")\n", im, i_DFc(x), i_DFc(y))); return im_img_empty_ch(aIMCTX, im, x, y, 3); } /* =item i_img_empty_ch(im, x, y, ch) Re-new image reference im - Image pointer x - xsize of destination image y - ysize of destination image ch - number of channels =cut */ i_img * im_img_empty_ch(pIMCTX, i_img *im,i_img_dim x,i_img_dim y,int ch) { size_t bytes; im_log((aIMCTX, 1,"i_img_empty_ch(*im %p, x %" i_DF ", y %" i_DF ", ch %d)\n", im, i_DFc(x), i_DFc(y), ch)); if (x < 1 || y < 1) { im_push_error(aIMCTX, 0, "Image sizes must be positive"); return NULL; } if (ch < 1 || ch > MAXCHANNELS) { im_push_errorf(aIMCTX, 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) { im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation"); return NULL; } if (im == NULL) im = im_img_alloc(aIMCTX); memcpy(im, &IIM_base_8bit_direct, sizeof(i_img)); i_tags_new(&im->tags); im->xsize = x; im->ysize = y; im->channels = ch; im->ch_mask = ~0U; im->bytes=bytes; if ( (im->idata=mymalloc(im->bytes)) == NULL) im_fatal(aIMCTX, 2,"malloc() error\n"); memset(im->idata,0,(size_t)im->bytes); im->ext_data = NULL; im_img_init(aIMCTX, im); im_log((aIMCTX, 1,"(%p) <- i_img_empty_ch\n",im)); return im; } /* =head2 8-bit per sample image internal functions These are the functions installed in an 8-bit per sample image. =over =item i_ppix_d(im, x, y, col) Internal function. This is the function kept in the i_f_ppix member of an i_img object. It does a normal store of a pixel into the image with range checking. Returns 0 if the pixel could be set, -1 otherwise. =cut */ static int i_ppix_d(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) { int ch; if ( x>-1 && xxsize && y>-1 && yysize ) { for(ch=0;chchannels;ch++) if (im->ch_mask&(1<idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch]; return 0; } return -1; /* error was clipped */ } /* =item i_gpix_d(im, x, y, &col) Internal function. This is the function kept in the i_f_gpix member of an i_img object. It does normal retrieval of a pixel from the image with range checking. Returns 0 if the pixel could be set, -1 otherwise. =cut */ static int i_gpix_d(i_img *im, i_img_dim x, i_img_dim y, i_color *val) { int ch; if (x>-1 && xxsize && y>-1 && yysize) { for(ch=0;chchannels;ch++) val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch]; return 0; } for(ch=0;chchannels;ch++) val->channel[ch] = 0; return -1; /* error was cliped */ } /* =item i_glin_d(im, l, r, y, vals) Reads a line of data from the image, storing the pixels at vals. The line runs from (l,y) inclusive to (r,y) non-inclusive vals should point at space for (r-l) pixels. l should never be less than zero (to avoid confusion about where to put the pixels in vals). Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ static i_img_dim i_glin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) { int ch; i_img_dim count, i; unsigned char *data; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) vals[i].channel[ch] = *data++; } return count; } else { return 0; } } /* =item i_plin_d(im, l, r, y, vals) Writes a line of data into the image, using the pixels at vals. The line runs from (l,y) inclusive to (r,y) non-inclusive vals should point at (r-l) pixels. l should never be less than zero (to avoid confusion about where to get the pixels in vals). Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ static i_img_dim i_plin_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) { int ch; i_img_dim count, i; unsigned char *data; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { if (im->ch_mask & (1 << ch)) *data = vals[i].channel[ch]; ++data; } } return count; } else { return 0; } } /* =item i_ppixf_d(im, x, y, val) =cut */ static int i_ppixf_d(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) { int ch; if ( x>-1 && xxsize && y>-1 && yysize ) { for(ch=0;chchannels;ch++) if (im->ch_mask&(1<idata[(x+y*im->xsize)*im->channels+ch] = SampleFTo8(val->channel[ch]); } return 0; } return -1; /* error was clipped */ } /* =item i_gpixf_d(im, x, y, val) =cut */ static int i_gpixf_d(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) { int ch; if (x>-1 && xxsize && y>-1 && yysize) { for(ch=0;chchannels;ch++) { val->channel[ch] = Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]); } return 0; } return -1; /* error was cliped */ } /* =item i_glinf_d(im, l, r, y, vals) Reads a line of data from the image, storing the pixels at vals. The line runs from (l,y) inclusive to (r,y) non-inclusive vals should point at space for (r-l) pixels. l should never be less than zero (to avoid confusion about where to put the pixels in vals). Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ static i_img_dim i_glinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) { int ch; i_img_dim count, i; unsigned char *data; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) vals[i].channel[ch] = Sample8ToF(*data++); } return count; } else { return 0; } } /* =item i_plinf_d(im, l, r, y, vals) Writes a line of data into the image, using the pixels at vals. The line runs from (l,y) inclusive to (r,y) non-inclusive vals should point at (r-l) pixels. l should never be less than zero (to avoid confusion about where to get the pixels in vals). Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ static i_img_dim i_plinf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) { int ch; i_img_dim count, i; unsigned char *data; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { if (im->ch_mask & (1 << ch)) *data = SampleFTo8(vals[i].channel[ch]); ++data; } } return count; } else { return 0; } } /* =item i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int *chans, int chan_count) Reads sample values from im for the horizontal line (l, y) to (r-1,y) for the channels specified by chans, an array of int with chan_count elements. Returns the number of samples read (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_gsamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; unsigned char *data; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return 0; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = data[chans[ch]]; ++count; } data += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return 0; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = data[ch]; ++count; } data += im->channels; } } return count; } else { return 0; } } /* =item i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, int *chans, int chan_count) Reads sample values from im for the horizontal line (l, y) to (r-1,y) for the channels specified by chan_mask, where bit 0 is the first channel. Returns the number of samples read (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_gsampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; unsigned char *data; for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); } } if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return 0; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = Sample8ToF(data[chans[ch]]); ++count; } data += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return 0; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = Sample8ToF(data[ch]); ++count; } data += im->channels; } } return count; } else { return 0; } } /* =item i_psamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int *chans, int chan_count) Writes sample values to im for the horizontal line (l, y) to (r-1,y) for the channels specified by chans, an array of int with chan_count elements. Returns the number of samples written (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_psamp_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; unsigned char *data; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ /* and test if all channels specified are in the mask */ int all_in_mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } if (!((1 << chans[ch]) & im->ch_mask)) all_in_mask = 0; } if (all_in_mask) { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { data[chans[ch]] = *samps++; ++count; } data += im->channels; } } else { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << (chans[ch]))) data[chans[ch]] = *samps; ++samps; ++count; } data += im->channels; } } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } for (i = 0; i < w; ++i) { unsigned mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & mask) data[ch] = *samps; ++samps; ++count; mask <<= 1; } data += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =item i_psampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, int *chans, int chan_count) Writes sample values to im for the horizontal line (l, y) to (r-1,y) for the channels specified by chans, an array of int with chan_count elements. Returns the number of samples written (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_psampf_d(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; unsigned char *data; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = im->idata + (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ /* and test if all channels specified are in the mask */ int all_in_mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } if (!((1 << chans[ch]) & im->ch_mask)) all_in_mask = 0; } if (all_in_mask) { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { data[chans[ch]] = SampleFTo8(*samps); ++samps; ++count; } data += im->channels; } } else { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << (chans[ch]))) data[chans[ch]] = SampleFTo8(*samps); ++samps; ++count; } data += im->channels; } } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } for (i = 0; i < w; ++i) { unsigned mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & mask) data[ch] = SampleFTo8(*samps); ++samps; ++count; mask <<= 1; } data += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson Tony Cook =head1 SEE ALSO L =cut */ libimager-perl-1.004+dfsg.orig/imperl.h0000644000175000017500000000130712031434615017222 0ustar gregoagregoa/* This header file defines types that Imager's typemap uses to convert to perl types. This is meant for use in XS code, not in normal C source. */ #ifndef IMAGER_IMPERL_H #define IMAGER_IMPERL_H #include "imdatatypes.h" typedef i_color* Imager__Color; typedef i_fcolor* Imager__Color__Float; typedef i_img* Imager__ImgRaw; typedef int undef_neg_int; typedef i_img * Imager; #ifdef HAVE_LIBTT typedef TT_Fonthandle* Imager__Font__TT; #endif /* for the fill objects Since a fill object may later have dependent images, (or fills!) we need perl wrappers - oh well */ #define IFILL_DESTROY(fill) i_fill_destroy(fill); typedef i_fill_t* Imager__FillHandle; typedef io_glue *Imager__IO; #endif libimager-perl-1.004+dfsg.orig/trans2.c0000644000175000017500000000407212263740601017142 0ustar gregoagregoa#include "imager.h" #include "regmach.h" /* =head1 NAME trans2.c - entry point for the general transformation engine =head1 SYNOPSIS int width, height, channels; struct rm_ops *ops; int op_count; double *n_regs; int n_regs_count; i_color *c_regs; int c_regs_count; i_img **in_imgs; int in_imgs_count; i_img *result = transform2(width, height, channels, ops, ops_count, n_regs, n_regs_count, c_regs, c_regs_count, in_imgs, in_imgs_count); =head1 DESCRIPTION This (short) file implements the transform2() function, just iterating over the image - most of the work is done in L =cut */ i_img* i_transform2(i_img_dim width, i_img_dim height, int channels, struct rm_op *ops, int ops_count, double *n_regs, int n_regs_count, i_color *c_regs, int c_regs_count, i_img **in_imgs, int in_imgs_count) { i_img *new_img; i_img_dim x, y; i_color val; int i; int need_images; i_clear_error(); /* since the number of images is variable and the image numbers for getp? are fixed, we can check them here instead of in the register machine - this will help performance */ need_images = 0; for (i = 0; i < ops_count; ++i) { switch (ops[i].code) { case rbc_getp1: case rbc_getp2: case rbc_getp3: if (ops[i].code - rbc_getp1 + 1 > need_images) { need_images = ops[i].code - rbc_getp1 + 1; } } } if (need_images > in_imgs_count) { i_push_errorf(0, "not enough images, code requires %d, %d supplied", need_images, in_imgs_count); return NULL; } new_img = i_img_empty_ch(NULL, width, height, channels); for (x = 0; x < width; ++x) { for (y = 0; y < height; ++y) { n_regs[0] = x; n_regs[1] = y; val = i_rm_run(ops, ops_count, n_regs, n_regs_count, c_regs, c_regs_count, in_imgs, in_imgs_count); i_ppix(new_img, x, y, &val); } } return new_img; } /* =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3), regmach.c =cut */ libimager-perl-1.004+dfsg.orig/spot.perl0000644000175000017500000000153312031434615017433 0ustar gregoagregoa#!perl -w # takes spot function and builds an ordered dither 8x8 matrix use strict; my $func = shift or die "Usage: $0 function [width height expandx expandy]\n"; my $width = shift || 8; my $height = shift || 8; my @spot; use vars qw($x $y); for $y (0..$height-1) { for $x (0..$width-1) { my $res = eval $func; $spot[$x+$y*$width] = $res * $res; } } my @sp; @sp[sort { $spot[$a] <=> $spot[$b] } (0.. $#spot)] = 0..$#spot; while (@sp) { print " ",map(sprintf("%4d,", 4*$_), splice(@sp, 0, $width)),"\n"; } sub min { my (@data) = @_; my $min = shift @data; for (@data) { $min = $_ if $_ < $min; } $min; } sub dist { my ($x1, $y1) = @_; return ($x1-$x)*($x1-$x) + ($y1-$y)*($y1-$y); } sub theta { my ($x1, $y1) = @_; return atan2($y1-$y, $x1-$x); } sub dt { my ($x1, $y1) = @_; dist($x1, $y1)+theta($x1,$y1)/20; } libimager-perl-1.004+dfsg.orig/Imager.xs0000644000175000017500000027445512616363730017371 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define NEED_newRV_noinc #define NEED_sv_2pv_nolen #define NEED_sv_2pvbyte #include "ppport.h" #ifdef __cplusplus } #endif #define i_int_hlines_testing() 1 #include "imager.h" #include "feat.h" #include "dynaload.h" #include "regmach.h" #include "imextdef.h" #include "imextpltypes.h" #include "imperlio.h" #include #if i_int_hlines_testing() #include "imageri.h" #endif #include "imperl.h" #define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array)) /* Context object management */ typedef im_context_t Imager__Context; #define im_context_DESTROY(ctx) im_context_refdec((ctx), "DESTROY") #ifdef PERL_IMPLICIT_CONTEXT #define MY_CXT_KEY "Imager::_context" XS_VERSION typedef struct { im_context_t ctx; } my_cxt_t; START_MY_CXT im_context_t fallback_context; static void start_context(pTHX) { dMY_CXT; MY_CXT.ctx = im_context_new(); sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx); /* Ideally we'd free this reference, but the error message memory was never released on exit, so the associated memory here is reasonable to keep. With logging enabled we always need at least one context, since objects may be released fairly late and attempt to get the log file. */ im_context_refinc(MY_CXT.ctx, "start_context"); fallback_context = MY_CXT.ctx; } static im_context_t perl_get_context(void) { dTHX; dMY_CXT; return MY_CXT.ctx ? MY_CXT.ctx : fallback_context; } #else static im_context_t perl_context; static void start_context(pTHX) { perl_context = im_context_new(); im_context_refinc(perl_context, "start_context"); } static im_context_t perl_get_context(void) { return perl_context; } #endif /* used to represent channel lists parameters */ typedef struct i_channel_list_tag { int *channels; int count; } i_channel_list; typedef struct { size_t count; const i_sample_t *samples; } i_sample_list; typedef struct { size_t count; const i_fsample_t *samples; } i_fsample_list; typedef struct { size_t count; const i_polygon_t *polygons; } i_polygon_list; /* Allocate memory that will be discarded when mortals are discarded. */ static void * malloc_temp(pTHX_ size_t size) { SV *sv = sv_2mortal(newSV(size)); return SvPVX(sv); } static void * calloc_temp(pTHX_ size_t size) { void *result = malloc_temp(aTHX_ size); memset(result, 0, size); return result; } /* for use with the T_AVARRAY typemap */ #define doublePtr(size) ((double *)calloc_temp(aTHX_ sizeof(double) * (size))) #define SvDouble(sv, pname) (SvNV(sv)) #define intPtr(size) ((int *)calloc_temp(aTHX_ sizeof(int) * (size))) #define SvInt(sv, pname) (SvIV(sv)) #define i_img_dimPtr(size) ((i_img_dim *)calloc_temp(aTHX_ sizeof(i_img_dim) * (size))) #define SvI_img_dim(sv, pname) (SvIV(sv)) #define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color *) * (size))) #define SvI_color(sv, pname) S_sv_to_i_color(aTHX_ sv, pname) static i_color S_sv_to_i_color(pTHX_ SV *sv, const char *pname) { if (!sv_derived_from(sv, "Imager::Color")) { croak("%s: not a color object", pname); } return *INT2PTR(i_color *, SvIV((SV *)SvRV(sv))); } /* These functions are all shared - then comes platform dependant code */ static int getstr(void *hv_t,char *key,char **store) { dTHX; SV** svpp; HV* hv=(HV*)hv_t; mm_log((1,"getstr(hv_t %p, key %s, store %p)\n",hv_t,key,store)); if ( !hv_exists(hv,key,strlen(key)) ) return 0; svpp=hv_fetch(hv, key, strlen(key), 0); *store=SvPV(*svpp, PL_na ); return 1; } static int getint(void *hv_t,char *key,int *store) { dTHX; SV** svpp; HV* hv=(HV*)hv_t; mm_log((1,"getint(hv_t %p, key %s, store %p)\n",hv_t,key,store)); if ( !hv_exists(hv,key,strlen(key)) ) return 0; svpp=hv_fetch(hv, key, strlen(key), 0); *store=(int)SvIV(*svpp); return 1; } static int getdouble(void *hv_t,char* key,double *store) { dTHX; SV** svpp; HV* hv=(HV*)hv_t; mm_log((1,"getdouble(hv_t %p, key %s, store %p)\n",hv_t,key,store)); if ( !hv_exists(hv,key,strlen(key)) ) return 0; svpp=hv_fetch(hv, key, strlen(key), 0); *store=(double)SvNV(*svpp); return 1; } static int getvoid(void *hv_t,char* key,void **store) { dTHX; SV** svpp; HV* hv=(HV*)hv_t; mm_log((1,"getvoid(hv_t %p, key %s, store %p)\n",hv_t,key,store)); if ( !hv_exists(hv,key,strlen(key)) ) return 0; svpp=hv_fetch(hv, key, strlen(key), 0); *store = INT2PTR(void*, SvIV(*svpp)); return 1; } static int getobj(void *hv_t,char *key,char *type,void **store) { dTHX; SV** svpp; HV* hv=(HV*)hv_t; mm_log((1,"getobj(hv_t %p, key %s,type %s, store %p)\n",hv_t,key,type,store)); if ( !hv_exists(hv,key,strlen(key)) ) return 0; svpp=hv_fetch(hv, key, strlen(key), 0); if (sv_derived_from(*svpp,type)) { IV tmp = SvIV((SV*)SvRV(*svpp)); *store = INT2PTR(void*, tmp); } else { mm_log((1,"getobj: key exists in hash but is not of correct type")); return 0; } return 1; } UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj}; static void free_buffer(void *p) { myfree(p); } static void i_log_entry(char *string, int level) { mm_log((level, "%s", string)); } static SV * make_i_color_sv(pTHX_ const i_color *c) { SV *sv; i_color *col = mymalloc(sizeof(i_color)); *col = *c; sv = sv_newmortal(); sv_setref_pv(sv, "Imager::Color", (void *)col); return sv; } #define CBDATA_BUFSIZE 8192 struct cbdata { /* the SVs we use to call back to Perl */ SV *writecb; SV *readcb; SV *seekcb; SV *closecb; }; static ssize_t call_reader(struct cbdata *cbd, void *buf, size_t size, size_t maxread) { dTHX; int count; int result; SV *data; dSP; if (!SvOK(cbd->readcb)) { mm_log((1, "read callback called but no readcb supplied\n")); i_push_error(0, "read callback called but no readcb supplied"); return -1; } ENTER; SAVETMPS; EXTEND(SP, 2); PUSHMARK(SP); PUSHs(sv_2mortal(newSViv(size))); PUSHs(sv_2mortal(newSViv(maxread))); PUTBACK; count = perl_call_sv(cbd->readcb, G_SCALAR); SPAGAIN; if (count != 1) croak("Result of perl_call_sv(..., G_SCALAR) != 1"); data = POPs; if (SvOK(data)) { STRLEN len; char *ptr = SvPVbyte(data, len); if (len > maxread) croak("Too much data returned in reader callback (wanted %d, got %d, expected %d)", (int)size, (int)len, (int)maxread); memcpy(buf, ptr, len); result = len; } else { result = -1; } PUTBACK; FREETMPS; LEAVE; return result; } static off_t io_seeker(void *p, off_t offset, int whence) { dTHX; struct cbdata *cbd = p; int count; off_t result; dSP; if (!SvOK(cbd->seekcb)) { mm_log((1, "seek callback called but no seekcb supplied\n")); i_push_error(0, "seek callback called but no seekcb supplied"); return -1; } ENTER; SAVETMPS; EXTEND(SP, 2); PUSHMARK(SP); PUSHs(sv_2mortal(newSViv(offset))); PUSHs(sv_2mortal(newSViv(whence))); PUTBACK; count = perl_call_sv(cbd->seekcb, G_SCALAR); SPAGAIN; if (count != 1) croak("Result of perl_call_sv(..., G_SCALAR) != 1"); result = POPi; PUTBACK; FREETMPS; LEAVE; return result; } static ssize_t io_writer(void *p, void const *data, size_t size) { dTHX; struct cbdata *cbd = p; I32 count; SV *sv; dSP; bool success; if (!SvOK(cbd->writecb)) { mm_log((1, "write callback called but no writecb supplied\n")); i_push_error(0, "write callback called but no writecb supplied"); return -1; } ENTER; SAVETMPS; EXTEND(SP, 1); PUSHMARK(SP); PUSHs(sv_2mortal(newSVpv((char *)data, size))); PUTBACK; count = perl_call_sv(cbd->writecb, G_SCALAR); SPAGAIN; if (count != 1) croak("Result of perl_call_sv(..., G_SCALAR) != 1"); sv = POPs; success = SvTRUE(sv); PUTBACK; FREETMPS; LEAVE; return success ? size : -1; } static ssize_t io_reader(void *p, void *data, size_t size) { struct cbdata *cbd = p; return call_reader(cbd, data, size, size); } static int io_closer(void *p) { dTHX; struct cbdata *cbd = p; int success = 1; if (SvOK(cbd->closecb)) { dSP; I32 count; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; count = perl_call_sv(cbd->closecb, G_SCALAR); SPAGAIN; if (count) { SV *sv = POPs; success = SvTRUE(sv); } else success = 0; PUTBACK; FREETMPS; LEAVE; } return success ? 0 : -1; } static void io_destroyer(void *p) { dTHX; struct cbdata *cbd = p; SvREFCNT_dec(cbd->writecb); SvREFCNT_dec(cbd->readcb); SvREFCNT_dec(cbd->seekcb); SvREFCNT_dec(cbd->closecb); myfree(cbd); } static bool im_SvREFSCALAR(SV *sv) { svtype type = SvTYPE(sv); switch (type) { case SVt_PV: case SVt_PVIV: case SVt_PVNV: case SVt_PVMG: case SVt_IV: case SVt_NV: case SVt_PVLV: #if PERL_VERSION > 10 case SVt_REGEXP: #endif return 1; default: return 0; } } static const char * describe_sv(SV *sv) { if (SvOK(sv)) { if (SvROK(sv)) { svtype type = SvTYPE(SvRV(sv)); switch (type) { case SVt_PVCV: return "CV"; case SVt_PVGV: return "GV"; case SVt_PVLV: return "LV"; default: return "some reference"; } } else { return "non-reference scalar"; } } else { return "undef"; } } static i_io_glue_t * do_io_new_buffer(pTHX_ SV *data_sv) { const char *data; char *data_copy; STRLEN length; SV *sv; SvGETMAGIC(data_sv); if (SvROK(data_sv)) { if (im_SvREFSCALAR(SvRV(data_sv))) { sv = SvRV(data_sv); } else { i_push_errorf(0, "data is not a scalar or a reference to scalar"); return NULL; } } else { sv = data_sv; } /* previously this would keep the SV around, but this is unsafe in many ways, so always copy the bytes */ data = SvPVbyte(sv, length); data_copy = mymalloc(length); memcpy(data_copy, data, length); return io_new_buffer(data_copy, length, free_buffer, data_copy); } static i_io_glue_t * do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) { struct cbdata *cbd; cbd = mymalloc(sizeof(struct cbdata)); cbd->writecb = newSVsv(writecb); cbd->readcb = newSVsv(readcb); cbd->seekcb = newSVsv(seekcb); cbd->closecb = newSVsv(closecb); mm_log((1, "do_io_new_cb(writecb %p (%s), readcb %p (%s), seekcb %p (%s), closecb %p (%s))\n", writecb, describe_sv(writecb), readcb, describe_sv(readcb), seekcb, describe_sv(seekcb), closecb, describe_sv(closecb))); return io_new_cb(cbd, io_reader, io_writer, io_seeker, io_closer, io_destroyer); } struct value_name { char *name; int value; }; static int lookup_name(const struct value_name *names, int count, char *name, int def_value) { int i; for (i = 0; i < count; ++i) if (strEQ(names[i].name, name)) return names[i].value; return def_value; } static struct value_name transp_names[] = { { "none", tr_none }, { "threshold", tr_threshold }, { "errdiff", tr_errdiff }, { "ordered", tr_ordered, }, }; static struct value_name make_color_names[] = { { "none", mc_none, }, { "webmap", mc_web_map, }, { "addi", mc_addi, }, { "mediancut", mc_median_cut, }, { "mono", mc_mono, }, { "monochrome", mc_mono, }, { "gray", mc_gray, }, { "gray4", mc_gray4, }, { "gray16", mc_gray16, }, }; static struct value_name translate_names[] = { { "giflib", pt_giflib, }, { "closest", pt_closest, }, { "perturb", pt_perturb, }, { "errdiff", pt_errdiff, }, }; static struct value_name errdiff_names[] = { { "floyd", ed_floyd, }, { "jarvis", ed_jarvis, }, { "stucki", ed_stucki, }, { "custom", ed_custom, }, }; static struct value_name orddith_names[] = { { "random", od_random, }, { "dot8", od_dot8, }, { "dot4", od_dot4, }, { "hline", od_hline, }, { "vline", od_vline, }, { "/line", od_slashline, }, { "slashline", od_slashline, }, { "\\line", od_backline, }, { "backline", od_backline, }, { "tiny", od_tiny, }, { "custom", od_custom, }, }; /* look through the hash for quantization options */ static void ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) { /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/ SV **sv; int i; STRLEN len; char *str; quant->mc_colors = mymalloc(quant->mc_size * sizeof(i_color)); sv = hv_fetch(hv, "transp", 6, 0); if (sv && *sv && (str = SvPV(*sv, len))) { quant->transp = lookup_name(transp_names, sizeof(transp_names)/sizeof(*transp_names), str, tr_none); if (quant->transp != tr_none) { quant->tr_threshold = 127; sv = hv_fetch(hv, "tr_threshold", 12, 0); if (sv && *sv) quant->tr_threshold = SvIV(*sv); } if (quant->transp == tr_errdiff) { sv = hv_fetch(hv, "tr_errdiff", 10, 0); if (sv && *sv && (str = SvPV(*sv, len))) quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd); } if (quant->transp == tr_ordered) { quant->tr_orddith = od_tiny; sv = hv_fetch(hv, "tr_orddith", 10, 0); if (sv && *sv && (str = SvPV(*sv, len))) quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random); if (quant->tr_orddith == od_custom) { sv = hv_fetch(hv, "tr_map", 6, 0); if (sv && *sv && SvTYPE(SvRV(*sv)) == SVt_PVAV) { AV *av = (AV*)SvRV(*sv); len = av_len(av) + 1; if (len > sizeof(quant->tr_custom)) len = sizeof(quant->tr_custom); for (i = 0; i < len; ++i) { SV **sv2 = av_fetch(av, i, 0); if (sv2 && *sv2) { quant->tr_custom[i] = SvIV(*sv2); } } while (i < sizeof(quant->tr_custom)) quant->tr_custom[i++] = 0; } } } } quant->make_colors = mc_median_cut; sv = hv_fetch(hv, "make_colors", 11, 0); if (sv && *sv && (str = SvPV(*sv, len))) { quant->make_colors = lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut); } sv = hv_fetch(hv, "colors", 6, 0); if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { /* needs to be an array of Imager::Color note that the caller allocates the mc_color array and sets mc_size to it's size */ AV *av = (AV *)SvRV(*sv); quant->mc_count = av_len(av)+1; if (quant->mc_count > quant->mc_size) quant->mc_count = quant->mc_size; for (i = 0; i < quant->mc_count; ++i) { SV **sv1 = av_fetch(av, i, 0); if (sv1 && *sv1 && SvROK(*sv1) && sv_derived_from(*sv1, "Imager::Color")) { i_color *col = INT2PTR(i_color *, SvIV((SV*)SvRV(*sv1))); quant->mc_colors[i] = *col; } } } sv = hv_fetch(hv, "max_colors", 10, 0); if (sv && *sv) { i = SvIV(*sv); if (i <= quant->mc_size && i >= quant->mc_count) quant->mc_size = i; } quant->translate = pt_closest; sv = hv_fetch(hv, "translate", 9, 0); if (sv && *sv && (str = SvPV(*sv, len))) { quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest); } sv = hv_fetch(hv, "errdiff", 7, 0); if (sv && *sv && (str = SvPV(*sv, len))) { quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd); } if (quant->translate == pt_errdiff && quant->errdiff == ed_custom) { /* get the error diffusion map */ sv = hv_fetch(hv, "errdiff_width", 13, 0); if (sv && *sv) quant->ed_width = SvIV(*sv); sv = hv_fetch(hv, "errdiff_height", 14, 0); if (sv && *sv) quant->ed_height = SvIV(*sv); sv = hv_fetch(hv, "errdiff_orig", 12, 0); if (sv && *sv) quant->ed_orig = SvIV(*sv); if (quant->ed_width > 0 && quant->ed_height > 0) { int sum = 0; quant->ed_map = mymalloc(sizeof(int)*quant->ed_width*quant->ed_height); sv = hv_fetch(hv, "errdiff_map", 11, 0); if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { AV *av = (AV*)SvRV(*sv); len = av_len(av) + 1; if (len > quant->ed_width * quant->ed_height) len = quant->ed_width * quant->ed_height; for (i = 0; i < len; ++i) { SV **sv2 = av_fetch(av, i, 0); if (sv2 && *sv2) { quant->ed_map[i] = SvIV(*sv2); sum += quant->ed_map[i]; } } } if (!sum) { /* broken map */ myfree(quant->ed_map); quant->ed_map = 0; quant->errdiff = ed_floyd; } } } sv = hv_fetch(hv, "perturb", 7, 0); if (sv && *sv) quant->perturb = SvIV(*sv); } static void ip_cleanup_quant_opts(pTHX_ i_quantize *quant) { myfree(quant->mc_colors); if (quant->ed_map) myfree(quant->ed_map); } /* copies the color map from the hv into the colors member of the HV */ static void ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) { SV **sv; AV *av; int i; SV *work; sv = hv_fetch(hv, "colors", 6, 0); if (!sv || !*sv || !SvROK(*sv) || SvTYPE(SvRV(*sv)) != SVt_PVAV) { /* nothing to do */ return; } av = (AV *)SvRV(*sv); av_clear(av); av_extend(av, quant->mc_count+1); for (i = 0; i < quant->mc_count; ++i) { i_color *in = quant->mc_colors+i; Imager__Color c = ICL_new_internal(in->rgb.r, in->rgb.g, in->rgb.b, 255); work = sv_newmortal(); sv_setref_pv(work, "Imager::Color", (void *)c); SvREFCNT_inc(work); av_push(av, work); } } static struct value_name poly_fill_mode_names[] = { { "evenodd", i_pfm_evenodd }, { "nonzero", i_pfm_nonzero } }; static i_poly_fill_mode_t S_get_poly_fill_mode(pTHX_ SV *sv) { if (looks_like_number(sv)) { IV work = SvIV(sv); if (work < (IV)i_pfm_evenodd || work > (IV)i_pfm_nonzero) work = (IV)i_pfm_evenodd; return (i_poly_fill_mode_t)work; } else { return (i_poly_fill_mode_t)lookup_name (poly_fill_mode_names, ARRAY_COUNT(poly_fill_mode_names), SvPV_nolen(sv), i_pfm_evenodd); } } static void S_get_polygon_list(pTHX_ i_polygon_list *polys, SV *sv) { AV *av; int i; i_polygon_t *s; SvGETMAGIC(sv); if (!SvOK(sv) || !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV) croak("polys must be an arrayref"); av = (AV*)SvRV(sv); polys->count = av_len(av) + 1; if (polys->count < 1) croak("polypolygon: no polygons provided"); s = malloc_temp(aTHX_ sizeof(i_polygon_t) * polys->count); for (i = 0; i < polys->count; ++i) { SV **poly_sv = av_fetch(av, i, 0); AV *poly_av; SV **x_sv, **y_sv; AV *x_av, *y_av; double *x_data, *y_data; ssize_t j; ssize_t point_count; if (!poly_sv) croak("poly_polygon: nothing found for polygon %d", i); /* needs to be another av */ SvGETMAGIC(*poly_sv); if (!SvOK(*poly_sv) || !SvROK(*poly_sv) || SvTYPE(SvRV(*poly_sv)) != SVt_PVAV) croak("poly_polygon: polygon %d isn't an arrayref", i); poly_av = (AV*)SvRV(*poly_sv); /* with two elements */ if (av_len(poly_av) != 1) croak("poly_polygon: polygon %d should contain two arrays", i); x_sv = av_fetch(poly_av, 0, 0); y_sv = av_fetch(poly_av, 1, 0); if (!x_sv) croak("poly_polygon: polygon %d has no x elements", i); if (!y_sv) croak("poly_polygon: polygon %d has no y elements", i); SvGETMAGIC(*x_sv); SvGETMAGIC(*y_sv); if (!SvOK(*x_sv) || !SvROK(*x_sv) || SvTYPE(SvRV(*x_sv)) != SVt_PVAV) croak("poly_polygon: polygon %d x elements isn't an array", i); if (!SvOK(*y_sv) || !SvROK(*y_sv) || SvTYPE(SvRV(*y_sv)) != SVt_PVAV) croak("poly_polygon: polygon %d y elements isn't an array", i); x_av = (AV*)SvRV(*x_sv); y_av = (AV*)SvRV(*y_sv); if (av_len(x_av) != av_len(y_av)) croak("poly_polygon: polygon %d x and y arrays different lengths", i+1); point_count = av_len(x_av)+1; x_data = malloc_temp(aTHX_ sizeof(double) * point_count * 2); y_data = x_data + point_count; for (j = 0; j < point_count; ++j) { SV **x_item_sv = av_fetch(x_av, j, 0); SV **y_item_sv = av_fetch(y_av, j, 0); x_data[j] = x_item_sv ? SvNV(*x_item_sv) : 0; y_data[j] = y_item_sv ? SvNV(*y_item_sv) : 0; } s[i].x = x_data; s[i].y = y_data; s[i].count = point_count; } polys->polygons = s; } /* loads the segments of a fountain fill into an array */ static i_fountain_seg * load_fount_segs(pTHX_ AV *asegs, int *count) { /* Each element of segs must contain: [ start, middle, end, c0, c1, segtype, colortrans ] start, middle, end are doubles from 0 to 1 c0, c1 are Imager::Color::Float or Imager::Color objects segtype, colortrans are ints */ int i, j; AV *aseg; i_fountain_seg *segs; double work[3]; int worki[2]; *count = av_len(asegs)+1; if (*count < 1) croak("i_fountain must have at least one segment"); segs = mymalloc(sizeof(i_fountain_seg) * *count); for(i = 0; i < *count; i++) { SV **sv1 = av_fetch(asegs, i, 0); if (!sv1 || !*sv1 || !SvROK(*sv1) || SvTYPE(SvRV(*sv1)) != SVt_PVAV) { myfree(segs); croak("i_fountain: segs must be an arrayref of arrayrefs"); } aseg = (AV *)SvRV(*sv1); if (av_len(aseg) != 7-1) { myfree(segs); croak("i_fountain: a segment must have 7 members"); } for (j = 0; j < 3; ++j) { SV **sv2 = av_fetch(aseg, j, 0); if (!sv2 || !*sv2) { myfree(segs); croak("i_fountain: XS error"); } work[j] = SvNV(*sv2); } segs[i].start = work[0]; segs[i].middle = work[1]; segs[i].end = work[2]; for (j = 0; j < 2; ++j) { SV **sv3 = av_fetch(aseg, 3+j, 0); if (!sv3 || !*sv3 || !SvROK(*sv3) || (!sv_derived_from(*sv3, "Imager::Color") && !sv_derived_from(*sv3, "Imager::Color::Float"))) { myfree(segs); croak("i_fountain: segs must contain colors in elements 3 and 4"); } if (sv_derived_from(*sv3, "Imager::Color::Float")) { segs[i].c[j] = *INT2PTR(i_fcolor *, SvIV((SV *)SvRV(*sv3))); } else { i_color c = *INT2PTR(i_color *, SvIV((SV *)SvRV(*sv3))); int ch; for (ch = 0; ch < MAXCHANNELS; ++ch) { segs[i].c[j].channel[ch] = c.channel[ch] / 255.0; } } } for (j = 0; j < 2; ++j) { SV **sv2 = av_fetch(aseg, j+5, 0); if (!sv2 || !*sv2) { myfree(segs); croak("i_fountain: XS error"); } worki[j] = SvIV(*sv2); } segs[i].type = worki[0]; segs[i].color = worki[1]; } return segs; } /* validates the indexes supplied to i_ppal i_ppal() doesn't do that for speed, but I'm not comfortable doing that for calls from perl. */ static void validate_i_ppal(i_img *im, i_palidx const *indexes, int count) { int color_count = i_colorcount(im); int i; if (color_count == -1) croak("i_plin() called on direct color image"); for (i = 0; i < count; ++i) { if (indexes[i] >= color_count) { croak("i_plin() called with out of range color index %d (max %d)", indexes[i], color_count-1); } } } /* I don't think ICLF_* names belong at the C interface this makes the XS code think we have them, to let us avoid putting function bodies in the XS code */ #define ICLF_new_internal(r, g, b, a) i_fcolor_new((r), (g), (b), (a)) #define ICLF_DESTROY(cl) i_fcolor_destroy(cl) #ifdef IMAGER_LOG #define i_log_enabled() 1 #else #define i_log_enabled() 0 #endif #if i_int_hlines_testing() typedef i_int_hlines *Imager__Internal__Hlines; static i_int_hlines * i_int_hlines_new(i_img_dim start_y, i_img_dim count_y, i_img_dim start_x, i_img_dim count_x) { i_int_hlines *result = mymalloc(sizeof(i_int_hlines)); i_int_init_hlines(result, start_y, count_y, start_x, count_x); return result; } static i_int_hlines * i_int_hlines_new_img(i_img *im) { i_int_hlines *result = mymalloc(sizeof(i_int_hlines)); i_int_init_hlines_img(result, im); return result; } static void i_int_hlines_DESTROY(i_int_hlines *hlines) { i_int_hlines_destroy(hlines); myfree(hlines); } #define i_int_hlines_CLONE_SKIP(cls) 1 static int seg_compare(const void *vleft, const void *vright) { const i_int_hline_seg *left = vleft; const i_int_hline_seg *right = vright; return left->minx - right->minx; } static SV * i_int_hlines_dump(i_int_hlines *hlines) { dTHX; SV *dump = newSVpvf("start_y: %" i_DF " limit_y: %" i_DF " start_x: %" i_DF " limit_x: %" i_DF"\n", i_DFc(hlines->start_y), i_DFc(hlines->limit_y), i_DFc(hlines->start_x), i_DFc(hlines->limit_x)); i_img_dim y; for (y = hlines->start_y; y < hlines->limit_y; ++y) { i_int_hline_entry *entry = hlines->entries[y-hlines->start_y]; if (entry) { int i; /* sort the segments, if any */ if (entry->count) qsort(entry->segs, entry->count, sizeof(i_int_hline_seg), seg_compare); sv_catpvf(dump, " %" i_DF " (%" i_DF "):", i_DFc(y), i_DFc(entry->count)); for (i = 0; i < entry->count; ++i) { sv_catpvf(dump, " [%" i_DF ", %" i_DF ")", i_DFc(entry->segs[i].minx), i_DFc(entry->segs[i].x_limit)); } sv_catpv(dump, "\n"); } } return dump; } #endif static off_t i_sv_off_t(pTHX_ SV *sv) { #if LSEEKSIZE > IVSIZE return (off_t)SvNV(sv); #else return (off_t)SvIV(sv); #endif } static SV * i_new_sv_off_t(pTHX_ off_t off) { #if LSEEKSIZE > IVSIZE return newSVnv(off); #else return newSViv(off); #endif } static im_pl_ext_funcs im_perl_funcs = { IMAGER_PL_API_VERSION, IMAGER_PL_API_LEVEL, ip_handle_quant_opts, ip_cleanup_quant_opts, ip_copy_colors_back }; #define PERL_PL_SET_GLOBAL_CALLBACKS \ sv_setiv(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1), PTR2IV(&im_perl_funcs)); #define IIM_new i_img_8_new #define IIM_DESTROY i_img_destroy typedef int SysRet; #ifdef IMEXIF_ENABLE #define i_exif_enabled() 1 #else #define i_exif_enabled() 0 #endif /* trying to use more C style names, map them here */ #define i_io_DESTROY(ig) io_glue_destroy(ig) #define i_img_get_width(im) ((im)->xsize) #define i_img_get_height(im) ((im)->ysize) #define i_img_epsilonf() (DBL_EPSILON * 4) /* avoid some xsubpp strangeness */ #define NEWLINE '\n' MODULE = Imager PACKAGE = Imager::Color PREFIX = ICL_ Imager::Color ICL_new_internal(r,g,b,a) unsigned char r unsigned char g unsigned char b unsigned char a void ICL_DESTROY(cl) Imager::Color cl void ICL_set_internal(cl,r,g,b,a) Imager::Color cl unsigned char r unsigned char g unsigned char b unsigned char a PPCODE: ICL_set_internal(cl, r, g, b, a); EXTEND(SP, 1); PUSHs(ST(0)); void ICL_info(cl) Imager::Color cl void ICL_rgba(cl) Imager::Color cl PPCODE: EXTEND(SP, 4); PUSHs(sv_2mortal(newSViv(cl->rgba.r))); PUSHs(sv_2mortal(newSViv(cl->rgba.g))); PUSHs(sv_2mortal(newSViv(cl->rgba.b))); PUSHs(sv_2mortal(newSViv(cl->rgba.a))); Imager::Color i_hsv_to_rgb(c) Imager::Color c CODE: RETVAL = mymalloc(sizeof(i_color)); *RETVAL = *c; i_hsv_to_rgb(RETVAL); OUTPUT: RETVAL Imager::Color i_rgb_to_hsv(c) Imager::Color c CODE: RETVAL = mymalloc(sizeof(i_color)); *RETVAL = *c; i_rgb_to_hsv(RETVAL); OUTPUT: RETVAL MODULE = Imager PACKAGE = Imager::Color::Float PREFIX=ICLF_ Imager::Color::Float ICLF_new_internal(r, g, b, a) double r double g double b double a void ICLF_DESTROY(cl) Imager::Color::Float cl void ICLF_rgba(cl) Imager::Color::Float cl PREINIT: int ch; PPCODE: EXTEND(SP, MAXCHANNELS); for (ch = 0; ch < MAXCHANNELS; ++ch) { /* printf("%d: %g\n", ch, cl->channel[ch]); */ PUSHs(sv_2mortal(newSVnv(cl->channel[ch]))); } void ICLF_set_internal(cl,r,g,b,a) Imager::Color::Float cl double r double g double b double a PPCODE: cl->rgba.r = r; cl->rgba.g = g; cl->rgba.b = b; cl->rgba.a = a; EXTEND(SP, 1); PUSHs(ST(0)); Imager::Color::Float i_hsv_to_rgb(c) Imager::Color::Float c CODE: RETVAL = mymalloc(sizeof(i_fcolor)); *RETVAL = *c; i_hsv_to_rgbf(RETVAL); OUTPUT: RETVAL Imager::Color::Float i_rgb_to_hsv(c) Imager::Color::Float c CODE: RETVAL = mymalloc(sizeof(i_fcolor)); *RETVAL = *c; i_rgb_to_hsvf(RETVAL); OUTPUT: RETVAL MODULE = Imager PACKAGE = Imager::ImgRaw PREFIX = IIM_ Imager::ImgRaw IIM_new(x,y,ch) i_img_dim x i_img_dim y int ch void IIM_DESTROY(im) Imager::ImgRaw im MODULE = Imager PACKAGE = Imager PROTOTYPES: ENABLE Imager::IO io_new_fd(fd) int fd Imager::IO io_new_bufchain() Imager::IO io_new_buffer(data_sv) SV *data_sv CODE: i_clear_error(); RETVAL = do_io_new_buffer(aTHX_ data_sv); if (!RETVAL) XSRETURN(0); OUTPUT: RETVAL Imager::IO io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE) SV *writecb; SV *readcb; SV *seekcb; SV *closecb; CODE: RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb); OUTPUT: RETVAL SV * io_slurp(ig) Imager::IO ig PREINIT: unsigned char* data; size_t tlength; CODE: data = NULL; tlength = io_slurp(ig, &data); RETVAL = newSVpv((char *)data,tlength); myfree(data); OUTPUT: RETVAL undef_int i_set_image_file_limits(width, height, bytes) i_img_dim width i_img_dim height size_t bytes void i_get_image_file_limits() PREINIT: i_img_dim width, height; size_t bytes; PPCODE: if (i_get_image_file_limits(&width, &height, &bytes)) { EXTEND(SP, 3); PUSHs(sv_2mortal(newSViv(width))); PUSHs(sv_2mortal(newSViv(height))); PUSHs(sv_2mortal(newSVuv(bytes))); } bool i_int_check_image_file_limits(width, height, channels, sample_size) i_img_dim width i_img_dim height int channels size_t sample_size PROTOTYPE: DISABLE MODULE = Imager PACKAGE = Imager::IO PREFIX = io_ Imager::IO io_new_fd(class, fd) int fd CODE: RETVAL = io_new_fd(fd); OUTPUT: RETVAL Imager::IO io_new_buffer(class, data_sv) SV *data_sv CODE: i_clear_error(); RETVAL = do_io_new_buffer(aTHX_ data_sv); if (!RETVAL) XSRETURN(0); OUTPUT: RETVAL Imager::IO io_new_cb(class, writecb, readcb, seekcb, closecb) SV *writecb; SV *readcb; SV *seekcb; SV *closecb; CODE: RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb); OUTPUT: RETVAL Imager::IO io_new_bufchain(class) CODE: RETVAL = io_new_bufchain(); OUTPUT: RETVAL Imager::IO io__new_perlio(class, io) PerlIO *io CODE: RETVAL = im_io_new_perlio(aTHX_ io); OUTPUT: RETVAL SV * io_slurp(class, ig) Imager::IO ig PREINIT: unsigned char* data; size_t tlength; CODE: data = NULL; tlength = io_slurp(ig, &data); RETVAL = newSVpv((char *)data,tlength); myfree(data); OUTPUT: RETVAL MODULE = Imager PACKAGE = Imager::IO PREFIX = i_io_ IV i_io_raw_write(ig, data_sv) Imager::IO ig SV *data_sv PREINIT: void *data; STRLEN size; CODE: data = SvPVbyte(data_sv, size); RETVAL = i_io_raw_write(ig, data, size); OUTPUT: RETVAL void i_io_raw_read(ig, buffer_sv, size) Imager::IO ig SV *buffer_sv IV size PREINIT: void *buffer; ssize_t result; PPCODE: if (size <= 0) croak("size negative in call to i_io_raw_read()"); /* prevent an undefined value warning if they supplied an undef buffer. Orginally conditional on !SvOK(), but this will prevent the downgrade from croaking */ sv_setpvn(buffer_sv, "", 0); #ifdef SvUTF8 if (SvUTF8(buffer_sv)) sv_utf8_downgrade(buffer_sv, FALSE); #endif buffer = SvGROW(buffer_sv, size+1); result = i_io_raw_read(ig, buffer, size); if (result >= 0) { SvCUR_set(buffer_sv, result); *SvEND(buffer_sv) = '\0'; SvPOK_only(buffer_sv); EXTEND(SP, 1); PUSHs(sv_2mortal(newSViv(result))); } ST(1) = buffer_sv; SvSETMAGIC(ST(1)); void i_io_raw_read2(ig, size) Imager::IO ig IV size PREINIT: SV *buffer_sv; void *buffer; ssize_t result; PPCODE: if (size <= 0) croak("size negative in call to i_io_read2()"); buffer_sv = newSV(size); buffer = SvGROW(buffer_sv, size+1); result = i_io_raw_read(ig, buffer, size); if (result >= 0) { SvCUR_set(buffer_sv, result); *SvEND(buffer_sv) = '\0'; SvPOK_only(buffer_sv); EXTEND(SP, 1); PUSHs(sv_2mortal(buffer_sv)); } else { /* discard it */ SvREFCNT_dec(buffer_sv); } off_t i_io_raw_seek(ig, position, whence) Imager::IO ig off_t position int whence int i_io_raw_close(ig) Imager::IO ig void i_io_DESTROY(ig) Imager::IO ig int i_io_CLONE_SKIP(...) CODE: (void)items; /* avoid unused warning for XS variable */ RETVAL = 1; OUTPUT: RETVAL int i_io_getc(ig) Imager::IO ig int i_io_putc(ig, c) Imager::IO ig int c int i_io_close(ig) Imager::IO ig int i_io_flush(ig) Imager::IO ig int i_io_peekc(ig) Imager::IO ig int i_io_seek(ig, off, whence) Imager::IO ig off_t off int whence void i_io_peekn(ig, size) Imager::IO ig STRLEN size PREINIT: SV *buffer_sv; void *buffer; ssize_t result; PPCODE: buffer_sv = newSV(size+1); buffer = SvGROW(buffer_sv, size+1); result = i_io_peekn(ig, buffer, size); if (result >= 0) { SvCUR_set(buffer_sv, result); *SvEND(buffer_sv) = '\0'; SvPOK_only(buffer_sv); EXTEND(SP, 1); PUSHs(sv_2mortal(buffer_sv)); } else { /* discard it */ SvREFCNT_dec(buffer_sv); } void i_io_read(ig, buffer_sv, size) Imager::IO ig SV *buffer_sv IV size PREINIT: void *buffer; ssize_t result; PPCODE: if (size <= 0) croak("size negative in call to i_io_read()"); /* prevent an undefined value warning if they supplied an undef buffer. Orginally conditional on !SvOK(), but this will prevent the downgrade from croaking */ sv_setpvn(buffer_sv, "", 0); #ifdef SvUTF8 if (SvUTF8(buffer_sv)) sv_utf8_downgrade(buffer_sv, FALSE); #endif buffer = SvGROW(buffer_sv, size+1); result = i_io_read(ig, buffer, size); if (result >= 0) { SvCUR_set(buffer_sv, result); *SvEND(buffer_sv) = '\0'; SvPOK_only(buffer_sv); EXTEND(SP, 1); PUSHs(sv_2mortal(newSViv(result))); } ST(1) = buffer_sv; SvSETMAGIC(ST(1)); void i_io_read2(ig, size) Imager::IO ig STRLEN size PREINIT: SV *buffer_sv; void *buffer; ssize_t result; PPCODE: if (size == 0) croak("size zero in call to read2()"); buffer_sv = newSV(size); buffer = SvGROW(buffer_sv, size+1); result = i_io_read(ig, buffer, size); if (result > 0) { SvCUR_set(buffer_sv, result); *SvEND(buffer_sv) = '\0'; SvPOK_only(buffer_sv); EXTEND(SP, 1); PUSHs(sv_2mortal(buffer_sv)); } else { /* discard it */ SvREFCNT_dec(buffer_sv); } void i_io_gets(ig, size = 8192, eol = NEWLINE) Imager::IO ig STRLEN size int eol PREINIT: SV *buffer_sv; void *buffer; ssize_t result; PPCODE: if (size < 2) croak("size too small in call to gets()"); buffer_sv = sv_2mortal(newSV(size+1)); buffer = SvPVX(buffer_sv); result = i_io_gets(ig, buffer, size+1, eol); if (result > 0) { SvCUR_set(buffer_sv, result); *SvEND(buffer_sv) = '\0'; SvPOK_only(buffer_sv); EXTEND(SP, 1); PUSHs(buffer_sv); } IV i_io_write(ig, data_sv) Imager::IO ig SV *data_sv PREINIT: void *data; STRLEN size; CODE: data = SvPVbyte(data_sv, size); RETVAL = i_io_write(ig, data, size); OUTPUT: RETVAL void i_io_dump(ig, flags = I_IO_DUMP_DEFAULT) Imager::IO ig int flags bool i_io_set_buffered(ig, flag = 1) Imager::IO ig int flag bool i_io_is_buffered(ig) Imager::IO ig bool i_io_eof(ig) Imager::IO ig bool i_io_error(ig) Imager::IO ig MODULE = Imager PACKAGE = Imager PROTOTYPES: ENABLE void i_list_formats() PREINIT: char* item; int i; PPCODE: i=0; while( (item=i_format_list[i++]) != NULL ) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(item,0))); } Imager::ImgRaw i_sametype(im, x, y) Imager::ImgRaw im i_img_dim x i_img_dim y Imager::ImgRaw i_sametype_chans(im, x, y, channels) Imager::ImgRaw im i_img_dim x i_img_dim y int channels int i_init_log(name_sv,level) SV* name_sv int level PREINIT: const char *name = SvOK(name_sv) ? SvPV_nolen(name_sv) : NULL; CODE: RETVAL = i_init_log(name, level); OUTPUT: RETVAL void i_log_entry(string,level) char* string int level int i_log_enabled() void i_img_info(im) Imager::ImgRaw im PREINIT: i_img_dim info[4]; PPCODE: i_img_info(im,info); EXTEND(SP, 4); PUSHs(sv_2mortal(newSViv(info[0]))); PUSHs(sv_2mortal(newSViv(info[1]))); PUSHs(sv_2mortal(newSViv(info[2]))); PUSHs(sv_2mortal(newSViv(info[3]))); void i_img_setmask(im,ch_mask) Imager::ImgRaw im int ch_mask int i_img_getmask(im) Imager::ImgRaw im int i_img_getchannels(im) Imager::ImgRaw im void i_img_getdata(im) Imager::ImgRaw im PPCODE: EXTEND(SP, 1); PUSHs(im->idata ? sv_2mortal(newSVpv((char *)im->idata, im->bytes)) : &PL_sv_undef); IV i_img_get_width(im) Imager::ImgRaw im IV i_img_get_height(im) Imager::ImgRaw im int i_img_color_model(im) Imager::ImgRaw im int i_img_color_channels(im) Imager::ImgRaw im int i_img_alpha_channel(im) Imager::ImgRaw im CODE: if (!i_img_alpha_channel(im, &RETVAL)) XSRETURN(0); OUTPUT: RETVAL void i_img_is_monochrome(im) Imager::ImgRaw im PREINIT: int zero_is_white; int result; PPCODE: result = i_img_is_monochrome(im, &zero_is_white); if (result) { if (GIMME_V == G_ARRAY) { EXTEND(SP, 2); PUSHs(&PL_sv_yes); PUSHs(sv_2mortal(newSViv(zero_is_white))); } else { EXTEND(SP, 1); PUSHs(&PL_sv_yes); } } void i_line(im,x1,y1,x2,y2,val,endp) Imager::ImgRaw im i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 Imager::Color val int endp void i_line_aa(im,x1,y1,x2,y2,val,endp) Imager::ImgRaw im i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 Imager::Color val int endp void i_box(im,x1,y1,x2,y2,val) Imager::ImgRaw im i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 Imager::Color val void i_box_filled(im,x1,y1,x2,y2,val) Imager::ImgRaw im i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 Imager::Color val int i_box_filledf(im,x1,y1,x2,y2,val) Imager::ImgRaw im i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 Imager::Color::Float val void i_box_cfill(im,x1,y1,x2,y2,fill) Imager::ImgRaw im i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 Imager::FillHandle fill void i_arc(im,x,y,rad,d1,d2,val) Imager::ImgRaw im i_img_dim x i_img_dim y double rad double d1 double d2 Imager::Color val void i_arc_aa(im,x,y,rad,d1,d2,val) Imager::ImgRaw im double x double y double rad double d1 double d2 Imager::Color val void i_arc_cfill(im,x,y,rad,d1,d2,fill) Imager::ImgRaw im i_img_dim x i_img_dim y double rad double d1 double d2 Imager::FillHandle fill void i_arc_aa_cfill(im,x,y,rad,d1,d2,fill) Imager::ImgRaw im double x double y double rad double d1 double d2 Imager::FillHandle fill void i_circle_aa(im,x,y,rad,val) Imager::ImgRaw im double x double y double rad Imager::Color val void i_circle_aa_fill(im,x,y,rad,fill) Imager::ImgRaw im double x double y double rad Imager::FillHandle fill int i_circle_out(im,x,y,rad,val) Imager::ImgRaw im i_img_dim x i_img_dim y i_img_dim rad Imager::Color val int i_circle_out_aa(im,x,y,rad,val) Imager::ImgRaw im i_img_dim x i_img_dim y i_img_dim rad Imager::Color val int i_arc_out(im,x,y,rad,d1,d2,val) Imager::ImgRaw im i_img_dim x i_img_dim y i_img_dim rad double d1 double d2 Imager::Color val int i_arc_out_aa(im,x,y,rad,d1,d2,val) Imager::ImgRaw im i_img_dim x i_img_dim y i_img_dim rad double d1 double d2 Imager::Color val void i_bezier_multi(im,x,y,val) Imager::ImgRaw im double *x double *y Imager::Color val PREINIT: STRLEN size_x; STRLEN size_y; PPCODE: if (size_x != size_y) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n"); i_bezier_multi(im,size_x,x,y,val); int i_poly_aa_m(im,x,y,mode,val) Imager::ImgRaw im double *x double *y i_poly_fill_mode_t mode Imager::Color val PREINIT: STRLEN size_x; STRLEN size_y; CODE: if (size_x != size_y) croak("Imager: x and y arrays to i_poly_aa must be equal length\n"); RETVAL = i_poly_aa_m(im, size_x, x, y, mode, val); OUTPUT: RETVAL int i_poly_aa_cfill_m(im, x, y, mode, fill) Imager::ImgRaw im double *x double *y i_poly_fill_mode_t mode Imager::FillHandle fill PREINIT: STRLEN size_x; STRLEN size_y; CODE: if (size_x != size_y) croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n"); RETVAL = i_poly_aa_cfill_m(im, size_x, x, y, mode, fill); OUTPUT: RETVAL int i_poly_poly_aa(im, polys, mode, color) Imager::ImgRaw im i_polygon_list polys i_poly_fill_mode_t mode Imager::Color color CODE: RETVAL = i_poly_poly_aa(im, polys.count, polys.polygons, mode, color); OUTPUT: RETVAL int i_poly_poly_aa_cfill(im, polys, mode, fill) Imager::ImgRaw im i_polygon_list polys i_poly_fill_mode_t mode Imager::FillHandle fill CODE: RETVAL = i_poly_poly_aa_cfill(im, polys.count, polys.polygons, mode, fill); OUTPUT: RETVAL undef_int i_flood_fill(im,seedx,seedy,dcol) Imager::ImgRaw im i_img_dim seedx i_img_dim seedy Imager::Color dcol undef_int i_flood_cfill(im,seedx,seedy,fill) Imager::ImgRaw im i_img_dim seedx i_img_dim seedy Imager::FillHandle fill undef_int i_flood_fill_border(im,seedx,seedy,dcol, border) Imager::ImgRaw im i_img_dim seedx i_img_dim seedy Imager::Color dcol Imager::Color border undef_int i_flood_cfill_border(im,seedx,seedy,fill, border) Imager::ImgRaw im i_img_dim seedx i_img_dim seedy Imager::FillHandle fill Imager::Color border void i_copyto(im,src,x1,y1,x2,y2,tx,ty) Imager::ImgRaw im Imager::ImgRaw src i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 i_img_dim tx i_img_dim ty void i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans) Imager::ImgRaw im Imager::ImgRaw src i_img_dim x1 i_img_dim y1 i_img_dim x2 i_img_dim y2 i_img_dim tx i_img_dim ty Imager::Color trans Imager::ImgRaw i_copy(src) Imager::ImgRaw src undef_int i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy) Imager::ImgRaw im Imager::ImgRaw src i_img_dim tx i_img_dim ty i_img_dim src_minx i_img_dim src_miny i_img_dim src_maxx i_img_dim src_maxy undef_int i_compose(out, src, out_left, out_top, src_left, src_top, width, height, combine = ic_normal, opacity = 0.0) Imager::ImgRaw out Imager::ImgRaw src i_img_dim out_left i_img_dim out_top i_img_dim src_left i_img_dim src_top i_img_dim width i_img_dim height int combine double opacity undef_int i_compose_mask(out, src, mask, out_left, out_top, src_left, src_top, mask_left, mask_top, width, height, combine = ic_normal, opacity = 0.0) Imager::ImgRaw out Imager::ImgRaw src Imager::ImgRaw mask i_img_dim out_left i_img_dim out_top i_img_dim src_left i_img_dim src_top i_img_dim mask_left i_img_dim mask_top i_img_dim width i_img_dim height int combine double opacity Imager::ImgRaw i_combine(src_av, channels_av = NULL) AV *src_av AV *channels_av PREINIT: i_img **imgs = NULL; STRLEN in_count; int *channels = NULL; int i; SV **psv; IV tmp; CODE: in_count = av_len(src_av) + 1; if (in_count > 0) { imgs = mymalloc(sizeof(i_img*) * in_count); channels = mymalloc(sizeof(int) * in_count); for (i = 0; i < in_count; ++i) { psv = av_fetch(src_av, i, 0); if (!psv || !*psv || !sv_derived_from(*psv, "Imager::ImgRaw")) { myfree(imgs); myfree(channels); croak("imgs must contain only images"); } tmp = SvIV((SV*)SvRV(*psv)); imgs[i] = INT2PTR(i_img*, tmp); if (channels_av && (psv = av_fetch(channels_av, i, 0)) != NULL && *psv) { channels[i] = SvIV(*psv); } else { channels[i] = 0; } } } RETVAL = i_combine(imgs, channels, in_count); myfree(imgs); myfree(channels); OUTPUT: RETVAL undef_int i_flipxy(im, direction) Imager::ImgRaw im int direction Imager::ImgRaw i_rotate90(im, degrees) Imager::ImgRaw im int degrees Imager::ImgRaw i_rotate_exact(im, amount, ...) Imager::ImgRaw im double amount PREINIT: i_color *backp = NULL; i_fcolor *fbackp = NULL; int i; SV * sv1; CODE: /* extract the bg colors if any */ /* yes, this is kind of strange */ for (i = 2; i < items; ++i) { sv1 = ST(i); if (sv_derived_from(sv1, "Imager::Color")) { IV tmp = SvIV((SV*)SvRV(sv1)); backp = INT2PTR(i_color *, tmp); } else if (sv_derived_from(sv1, "Imager::Color::Float")) { IV tmp = SvIV((SV*)SvRV(sv1)); fbackp = INT2PTR(i_fcolor *, tmp); } } RETVAL = i_rotate_exact_bg(im, amount, backp, fbackp); OUTPUT: RETVAL Imager::ImgRaw i_matrix_transform(im, xsize, ysize, matrix_av, ...) Imager::ImgRaw im i_img_dim xsize i_img_dim ysize AV *matrix_av PREINIT: double matrix[9]; STRLEN len; SV *sv1; int i; i_color *backp = NULL; i_fcolor *fbackp = NULL; CODE: len=av_len(matrix_av)+1; if (len > 9) len = 9; for (i = 0; i < len; ++i) { sv1=(*(av_fetch(matrix_av,i,0))); matrix[i] = SvNV(sv1); } for (; i < 9; ++i) matrix[i] = 0; /* extract the bg colors if any */ /* yes, this is kind of strange */ for (i = 4; i < items; ++i) { sv1 = ST(i); if (sv_derived_from(sv1, "Imager::Color")) { IV tmp = SvIV((SV*)SvRV(sv1)); backp = INT2PTR(i_color *, tmp); } else if (sv_derived_from(sv1, "Imager::Color::Float")) { IV tmp = SvIV((SV*)SvRV(sv1)); fbackp = INT2PTR(i_fcolor *, tmp); } } RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp); OUTPUT: RETVAL undef_int i_gaussian(im,stdev) Imager::ImgRaw im double stdev void i_unsharp_mask(im,stdev,scale) Imager::ImgRaw im double stdev double scale int i_conv(im,coef) Imager::ImgRaw im AV *coef PREINIT: double* c_coef; int len; SV* sv1; int i; CODE: len = av_len(coef) + 1; c_coef=mymalloc( len * sizeof(double) ); for(i = 0; i < len; i++) { sv1 = (*(av_fetch(coef, i, 0))); c_coef[i] = (double)SvNV(sv1); } RETVAL = i_conv(im, c_coef, len); myfree(c_coef); OUTPUT: RETVAL Imager::ImgRaw i_convert(src, avmain) Imager::ImgRaw src AV *avmain PREINIT: double *coeff; int outchan; int inchan; SV **temp; AV *avsub; int len; int i, j; CODE: outchan = av_len(avmain)+1; /* find the biggest */ inchan = 0; for (j=0; j < outchan; ++j) { temp = av_fetch(avmain, j, 0); if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) { avsub = (AV*)SvRV(*temp); len = av_len(avsub)+1; if (len > inchan) inchan = len; } else { i_push_errorf(0, "invalid matrix: element %d is not an array ref", j); XSRETURN(0); } } coeff = mymalloc(sizeof(double) * outchan * inchan); for (j = 0; j < outchan; ++j) { avsub = (AV*)SvRV(*av_fetch(avmain, j, 0)); len = av_len(avsub)+1; for (i = 0; i < len; ++i) { temp = av_fetch(avsub, i, 0); if (temp) coeff[i+j*inchan] = SvNV(*temp); else coeff[i+j*inchan] = 0; } while (i < inchan) coeff[i++ + j*inchan] = 0; } RETVAL = i_convert(src, coeff, outchan, inchan); myfree(coeff); OUTPUT: RETVAL undef_int i_map(im, pmaps_av) Imager::ImgRaw im AV *pmaps_av PREINIT: unsigned int mask = 0; AV *avsub; SV **temp; int len; int i, j; unsigned char (*maps)[256]; CODE: len = av_len(pmaps_av)+1; if (im->channels < len) len = im->channels; maps = mymalloc( len * sizeof(unsigned char [256]) ); for (j=0; j255) val = 255; maps[j][i] = val; } } } i_map(im, maps, mask); myfree(maps); RETVAL = 1; OUTPUT: RETVAL float i_img_diff(im1,im2) Imager::ImgRaw im1 Imager::ImgRaw im2 double i_img_diffd(im1,im2) Imager::ImgRaw im1 Imager::ImgRaw im2 int i_img_samef(im1, im2, epsilon = i_img_epsilonf(), what=NULL) Imager::ImgRaw im1 Imager::ImgRaw im2 double epsilon const char *what double i_img_epsilonf() bool _is_color_object(sv) SV* sv CODE: SvGETMAGIC(sv); RETVAL = SvOK(sv) && SvROK(sv) && (sv_derived_from(sv, "Imager::Color") || sv_derived_from(sv, "Imager::Color::Float")); OUTPUT: RETVAL #ifdef HAVE_LIBTT Imager::Font::TT i_tt_new(fontname) char* fontname MODULE = Imager PACKAGE = Imager::Font::TT PREFIX=TT_ #define TT_DESTROY(handle) i_tt_destroy(handle) void TT_DESTROY(handle) Imager::Font::TT handle int TT_CLONE_SKIP(...) CODE: (void)items; /* avoid unused warning */ RETVAL = 1; OUTPUT: RETVAL MODULE = Imager PACKAGE = Imager undef_int i_tt_text(handle,im,xb,yb,cl,points,str_sv,smooth,utf8,align=1) Imager::Font::TT handle Imager::ImgRaw im i_img_dim xb i_img_dim yb Imager::Color cl double points SV * str_sv int smooth int utf8 int align PREINIT: char *str; STRLEN len; CODE: str = SvPV(str_sv, len); #ifdef SvUTF8 if (SvUTF8(str_sv)) utf8 = 1; #endif RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, len, smooth, utf8, align); OUTPUT: RETVAL undef_int i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1) Imager::Font::TT handle Imager::ImgRaw im i_img_dim xb i_img_dim yb int channel double points SV * str_sv int smooth int utf8 int align PREINIT: char *str; STRLEN len; CODE: str = SvPV(str_sv, len); #ifdef SvUTF8 if (SvUTF8(str_sv)) utf8 = 1; #endif RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len, smooth, utf8, align); OUTPUT: RETVAL void i_tt_bbox(handle,point,str_sv,utf8) Imager::Font::TT handle double point SV* str_sv int utf8 PREINIT: i_img_dim cords[BOUNDING_BOX_COUNT]; int rc; char * str; STRLEN len; int i; PPCODE: str = SvPV(str_sv, len); #ifdef SvUTF8 if (SvUTF8(ST(2))) utf8 = 1; #endif if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) { EXTEND(SP, rc); for (i = 0; i < rc; ++i) { PUSHs(sv_2mortal(newSViv(cords[i]))); } } void i_tt_has_chars(handle, text_sv, utf8) Imager::Font::TT handle SV *text_sv int utf8 PREINIT: char const *text; STRLEN len; char *work; size_t count; size_t i; PPCODE: i_clear_error(); text = SvPV(text_sv, len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif work = mymalloc(len); count = i_tt_has_chars(handle, text, len, utf8, work); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) { PUSHs(boolSV(work[i])); } } else { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(work, count))); } myfree(work); void i_tt_dump_names(handle) Imager::Font::TT handle void i_tt_face_name(handle) Imager::Font::TT handle PREINIT: char name[255]; size_t len; PPCODE: len = i_tt_face_name(handle, name, sizeof(name)); if (len) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(name, len-1))); } void i_tt_glyph_name(handle, text_sv, utf8 = 0) Imager::Font::TT handle SV *text_sv int utf8 PREINIT: char const *text; STRLEN work_len; size_t len; size_t outsize; char name[255]; SSize_t count = 0; PPCODE: i_clear_error(); text = SvPV(text_sv, work_len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif len = work_len; while (len) { unsigned long ch; if (utf8) { ch = i_utf8_advance(&text, &len); if (ch == ~0UL) { i_push_error(0, "invalid UTF8 character"); XSRETURN_EMPTY; } } else { ch = *text++; --len; } EXTEND(SP, count+1); if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) { ST(count) = sv_2mortal(newSVpv(name, 0)); } else { ST(count) = &PL_sv_undef; } ++count; } XSRETURN(count); #endif const char * i_test_format_probe(ig, length) Imager::IO ig int length Imager::ImgRaw i_readpnm_wiol(ig, allow_incomplete) Imager::IO ig int allow_incomplete void i_readpnm_multi_wiol(ig, allow_incomplete) Imager::IO ig int allow_incomplete PREINIT: i_img **imgs; int count=0; int i; PPCODE: imgs = i_readpnm_multi_wiol(ig, &count, allow_incomplete); if (imgs) { EXTEND(SP, count); for (i = 0; i < count; ++i) { SV *sv = sv_newmortal(); sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]); PUSHs(sv); } myfree(imgs); } undef_int i_writeppm_wiol(im, ig) Imager::ImgRaw im Imager::IO ig Imager::ImgRaw i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl) Imager::IO ig i_img_dim x i_img_dim y int datachannels int storechannels int intrl undef_int i_writeraw_wiol(im,ig) Imager::ImgRaw im Imager::IO ig undef_int i_writebmp_wiol(im,ig) Imager::ImgRaw im Imager::IO ig Imager::ImgRaw i_readbmp_wiol(ig, allow_incomplete=0) Imager::IO ig int allow_incomplete undef_int i_writetga_wiol(im,ig, wierdpack, compress, idstring) Imager::ImgRaw im Imager::IO ig int wierdpack int compress char* idstring PREINIT: int idlen; CODE: idlen = SvCUR(ST(4)); RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen); OUTPUT: RETVAL Imager::ImgRaw i_readtga_wiol(ig, length) Imager::IO ig int length Imager::ImgRaw i_scaleaxis(im,Value,Axis) Imager::ImgRaw im double Value int Axis Imager::ImgRaw i_scale_nn(im,scx,scy) Imager::ImgRaw im double scx double scy Imager::ImgRaw i_scale_mixing(im, width, height) Imager::ImgRaw im i_img_dim width i_img_dim height Imager::ImgRaw i_haar(im) Imager::ImgRaw im int i_count_colors(im,maxc) Imager::ImgRaw im int maxc void i_get_anonymous_color_histo(im, maxc = 0x40000000) Imager::ImgRaw im int maxc PREINIT: int i; unsigned int * col_usage = NULL; int col_cnt; PPCODE: col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc); if (col_cnt > 0) { EXTEND(SP, col_cnt); for (i = 0; i < col_cnt; i++) { PUSHs(sv_2mortal(newSViv( col_usage[i]))); } myfree(col_usage); XSRETURN(col_cnt); } else { XSRETURN_EMPTY; } void i_transform(im, opx, opy, parm) Imager::ImgRaw im int *opx int *opy double *parm PREINIT: STRLEN size_opx, size_opy, size_parm; i_img *result; PPCODE: result=i_transform(im,opx,size_opx,opy,size_opy,parm,size_parm); if (result) { SV *result_sv = sv_newmortal(); EXTEND(SP, 1); sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result); PUSHs(result_sv); } void i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs) SV *sv_width SV *sv_height SV *sv_ops AV *av_n_regs AV *av_c_regs AV *av_in_imgs int channels PREINIT: i_img_dim width; i_img_dim height; struct rm_op *ops; STRLEN ops_len; int ops_count; double *n_regs; int n_regs_count; i_color *c_regs; int c_regs_count; int in_imgs_count; i_img **in_imgs; SV *sv1; IV tmp; int i; i_img *result; PPCODE: in_imgs_count = av_len(av_in_imgs)+1; for (i = 0; i < in_imgs_count; ++i) { sv1 = *av_fetch(av_in_imgs, i, 0); if (!sv_derived_from(sv1, "Imager::ImgRaw")) { croak("sv_in_img must contain only images"); } } if (in_imgs_count > 0) { in_imgs = mymalloc(in_imgs_count*sizeof(i_img*)); for (i = 0; i < in_imgs_count; ++i) { sv1 = *av_fetch(av_in_imgs,i,0); if (!sv_derived_from(sv1, "Imager::ImgRaw")) { croak("Parameter 5 must contain only images"); } tmp = SvIV((SV*)SvRV(sv1)); in_imgs[i] = INT2PTR(i_img*, tmp); } } else { /* no input images */ in_imgs = NULL; } /* default the output size from the first input if possible */ if (SvOK(sv_width)) width = SvIV(sv_width); else if (in_imgs_count) width = in_imgs[0]->xsize; else croak("No output image width supplied"); if (SvOK(sv_height)) height = SvIV(sv_height); else if (in_imgs_count) height = in_imgs[0]->ysize; else croak("No output image height supplied"); ops = (struct rm_op *)SvPV(sv_ops, ops_len); if (ops_len % sizeof(struct rm_op)) croak("Imager: Parameter 3 must be a bitmap of regops\n"); ops_count = ops_len / sizeof(struct rm_op); n_regs_count = av_len(av_n_regs)+1; n_regs = mymalloc(n_regs_count * sizeof(double)); for (i = 0; i < n_regs_count; ++i) { sv1 = *av_fetch(av_n_regs,i,0); if (SvOK(sv1)) n_regs[i] = SvNV(sv1); } c_regs_count = av_len(av_c_regs)+1; c_regs = mymalloc(c_regs_count * sizeof(i_color)); /* I don't bother initializing the colou?r registers */ result=i_transform2(width, height, channels, ops, ops_count, n_regs, n_regs_count, c_regs, c_regs_count, in_imgs, in_imgs_count); if (in_imgs) myfree(in_imgs); myfree(n_regs); myfree(c_regs); if (result) { SV *result_sv = sv_newmortal(); EXTEND(SP, 1); sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result); PUSHs(result_sv); } void i_contrast(im,intensity) Imager::ImgRaw im float intensity void i_hardinvert(im) Imager::ImgRaw im void i_hardinvertall(im) Imager::ImgRaw im void i_noise(im,amount,type) Imager::ImgRaw im float amount unsigned char type void i_bumpmap(im,bump,channel,light_x,light_y,strength) Imager::ImgRaw im Imager::ImgRaw bump int channel i_img_dim light_x i_img_dim light_y i_img_dim strength void i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is) Imager::ImgRaw im Imager::ImgRaw bump int channel i_img_dim tx i_img_dim ty double Lx double Ly double Lz float cd float cs float n Imager::Color Ia Imager::Color Il Imager::Color Is void i_postlevels(im,levels) Imager::ImgRaw im int levels void i_mosaic(im,size) Imager::ImgRaw im i_img_dim size void i_watermark(im,wmark,tx,ty,pixdiff) Imager::ImgRaw im Imager::ImgRaw wmark i_img_dim tx i_img_dim ty int pixdiff void i_autolevels(im,lsat,usat,skew) Imager::ImgRaw im float lsat float usat float skew void i_autolevels_mono(im,lsat,usat) Imager::ImgRaw im float lsat float usat void i_radnoise(im,xo,yo,rscale,ascale) Imager::ImgRaw im float xo float yo float rscale float ascale void i_turbnoise(im, xo, yo, scale) Imager::ImgRaw im float xo float yo float scale void i_gradgen(im, xo, yo, ac, dmeasure) Imager::ImgRaw im i_img_dim *xo i_img_dim *yo i_color *ac int dmeasure PREINIT: STRLEN size_xo; STRLEN size_yo; STRLEN size_ac; CODE: if (size_xo != size_yo || size_xo != size_ac) croak("i_gradgen: x, y and color arrays must be the same size"); if (size_xo < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each"); i_gradgen(im, size_xo, xo, yo, ac, dmeasure); Imager::ImgRaw i_diff_image(im, im2, mindist=0) Imager::ImgRaw im Imager::ImgRaw im2 double mindist undef_int i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs) Imager::ImgRaw im double xa double ya double xb double yb int type int repeat int combine int super_sample double ssample_param PREINIT: AV *asegs; int count; i_fountain_seg *segs; CODE: if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10)))) croak("i_fountain: argument 11 must be an array ref"); asegs = (AV *)SvRV(ST(10)); segs = load_fount_segs(aTHX_ asegs, &count); RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs); myfree(segs); OUTPUT: RETVAL Imager::FillHandle i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs) double xa double ya double xb double yb int type int repeat int combine int super_sample double ssample_param PREINIT: AV *asegs; int count; i_fountain_seg *segs; CODE: if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9)))) croak("i_fountain: argument 11 must be an array ref"); asegs = (AV *)SvRV(ST(9)); segs = load_fount_segs(aTHX_ asegs, &count); RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs); myfree(segs); OUTPUT: RETVAL Imager::FillHandle i_new_fill_opacity(other_fill, alpha_mult) Imager::FillHandle other_fill double alpha_mult void i_errors() PREINIT: i_errmsg *errors; int i; AV *av; SV *sv; PPCODE: errors = i_errors(); i = 0; while (errors[i].msg) { av = newAV(); sv = newSVpv(errors[i].msg, strlen(errors[i].msg)); if (!av_store(av, 0, sv)) { SvREFCNT_dec(sv); } sv = newSViv(errors[i].code); if (!av_store(av, 1, sv)) { SvREFCNT_dec(sv); } PUSHs(sv_2mortal(newRV_noinc((SV*)av))); ++i; } void i_clear_error() void i_push_error(code, msg) int code const char *msg undef_int i_nearest_color(im, ...) Imager::ImgRaw im PREINIT: int num; i_img_dim *xo; i_img_dim *yo; i_color *ival; int dmeasure; int i; SV *sv; AV *axx; AV *ayy; AV *ac; CODE: if (items != 5) croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)"); if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1)))) croak("i_nearest_color: Second argument must be an array ref"); if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2)))) croak("i_nearest_color: Third argument must be an array ref"); if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3)))) croak("i_nearest_color: Fourth argument must be an array ref"); axx = (AV *)SvRV(ST(1)); ayy = (AV *)SvRV(ST(2)); ac = (AV *)SvRV(ST(3)); dmeasure = (int)SvIV(ST(4)); num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy); num = num <= av_len(ac) ? num : av_len(ac); num++; if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each"); xo = mymalloc( sizeof(i_img_dim) * num ); yo = mymalloc( sizeof(i_img_dim) * num ); ival = mymalloc( sizeof(i_color) * num ); for(i = 0; i 3) { work = malloc_temp(aTHX_ sizeof(i_palidx) * (items-3)); for (i=0; i < items-3; ++i) { work[i] = SvIV(ST(i+3)); } validate_i_ppal(im, work, items - 3); RETVAL = i_ppal(im, l, l+items-3, y, work); } else { RETVAL = 0; } OUTPUT: RETVAL int i_ppal_p(im, l, y, data) Imager::ImgRaw im i_img_dim l i_img_dim y SV *data PREINIT: i_palidx const *work; STRLEN len; CODE: work = (i_palidx const *)SvPV(data, len); len /= sizeof(i_palidx); if (len > 0) { validate_i_ppal(im, work, len); RETVAL = i_ppal(im, l, l+len, y, work); } else { RETVAL = 0; } OUTPUT: RETVAL SysRet i_addcolors(im, ...) Imager::ImgRaw im PREINIT: i_color *colors; int i; CODE: if (items < 2) croak("i_addcolors: no colors to add"); colors = mymalloc((items-1) * sizeof(i_color)); for (i=0; i < items-1; ++i) { if (sv_isobject(ST(i+1)) && sv_derived_from(ST(i+1), "Imager::Color")) { IV tmp = SvIV((SV *)SvRV(ST(i+1))); colors[i] = *INT2PTR(i_color *, tmp); } else { myfree(colors); croak("i_addcolor: pixels must be Imager::Color objects"); } } RETVAL = i_addcolors(im, colors, items-1); OUTPUT: RETVAL undef_int i_setcolors(im, index, ...) Imager::ImgRaw im int index PREINIT: i_color *colors; int i; CODE: if (items < 3) croak("i_setcolors: no colors to add"); colors = mymalloc((items-2) * sizeof(i_color)); for (i=0; i < items-2; ++i) { if (sv_isobject(ST(i+2)) && sv_derived_from(ST(i+2), "Imager::Color")) { IV tmp = SvIV((SV *)SvRV(ST(i+2))); colors[i] = *INT2PTR(i_color *, tmp); } else { myfree(colors); croak("i_setcolors: pixels must be Imager::Color objects"); } } RETVAL = i_setcolors(im, index, colors, items-2); myfree(colors); OUTPUT: RETVAL void i_getcolors(im, index, count=1) Imager::ImgRaw im int index int count PREINIT: i_color *colors; int i; PPCODE: if (count < 1) croak("i_getcolors: count must be positive"); colors = malloc_temp(aTHX_ sizeof(i_color) * count); if (i_getcolors(im, index, colors, count)) { EXTEND(SP, count); for (i = 0; i < count; ++i) { SV *sv = make_i_color_sv(aTHX_ colors+i); PUSHs(sv); } } undef_neg_int i_colorcount(im) Imager::ImgRaw im undef_neg_int i_maxcolors(im) Imager::ImgRaw im i_palidx i_findcolor(im, color) Imager::ImgRaw im Imager::Color color CODE: if (!i_findcolor(im, color, &RETVAL)) { XSRETURN_UNDEF; } OUTPUT: RETVAL int i_img_bits(im) Imager::ImgRaw im int i_img_type(im) Imager::ImgRaw im int i_img_virtual(im) Imager::ImgRaw im void i_gsamp(im, l, r, y, channels) Imager::ImgRaw im i_img_dim l i_img_dim r i_img_dim y i_channel_list channels PREINIT: i_sample_t *data; i_img_dim count, i; PPCODE: if (l < r) { data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count); count = i_gsamp(im, l, r, y, data, channels.channels, channels.count); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) PUSHs(sv_2mortal(newSViv(data[i]))); } else { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t)))); } myfree(data); } else { if (GIMME_V != G_ARRAY) { XSRETURN_UNDEF; } } undef_neg_int i_gsamp_bits(im, l, r, y, bits, target, offset, channels) Imager::ImgRaw im i_img_dim l i_img_dim r i_img_dim y int bits AV *target STRLEN offset i_channel_list channels PREINIT: unsigned *data; i_img_dim count, i; CODE: i_clear_error(); if (items < 8) croak("No channel numbers supplied to g_samp()"); if (l < r) { data = mymalloc(sizeof(unsigned) * (r-l) * channels.count); count = i_gsamp_bits(im, l, r, y, data, channels.channels, channels.count, bits); for (i = 0; i < count; ++i) { av_store(target, i+offset, newSVuv(data[i])); } myfree(data); RETVAL = count; } else { RETVAL = 0; } OUTPUT: RETVAL undef_neg_int i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -1) Imager::ImgRaw im i_img_dim l i_img_dim y int bits i_channel_list channels AV *data_av i_img_dim data_offset i_img_dim pixel_count PREINIT: STRLEN data_count; size_t data_used; unsigned *data; ptrdiff_t i; CODE: i_clear_error(); data_count = av_len(data_av) + 1; if (data_offset < 0) { croak("data_offset must be non-negative"); } if (data_offset > data_count) { croak("data_offset greater than number of samples supplied"); } if (pixel_count == -1 || data_offset + pixel_count * channels.count > data_count) { pixel_count = (data_count - data_offset) / channels.count; } data_used = pixel_count * channels.count; data = mymalloc(sizeof(unsigned) * data_count); for (i = 0; i < data_used; ++i) data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0)); RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels.channels, channels.count, bits); if (data) myfree(data); OUTPUT: RETVAL undef_neg_int i_psamp(im, x, y, channels, data, offset = 0, width = -1) Imager::ImgRaw im i_img_dim x i_img_dim y i_channel_list channels i_sample_list data i_img_dim offset i_img_dim width PREINIT: i_img_dim r; CODE: i_clear_error(); if (offset < 0) { i_push_error(0, "offset must be non-negative"); XSRETURN_UNDEF; } if (offset > 0) { if (offset > data.count) { i_push_error(0, "offset greater than number of samples supplied"); XSRETURN_UNDEF; } data.samples += offset; data.count -= offset; } if (width == -1 || width * channels.count > data.count) { width = data.count / channels.count; } r = x + width; RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count); OUTPUT: RETVAL undef_neg_int i_psampf(im, x, y, channels, data, offset = 0, width = -1) Imager::ImgRaw im i_img_dim x i_img_dim y i_channel_list channels i_fsample_list data i_img_dim offset i_img_dim width PREINIT: i_img_dim r; CODE: i_clear_error(); if (offset < 0) { i_push_error(0, "offset must be non-negative"); XSRETURN_UNDEF; } if (offset > 0) { if (offset > data.count) { i_push_error(0, "offset greater than number of samples supplied"); XSRETURN_UNDEF; } data.samples += offset; data.count -= offset; } if (width == -1 || width * channels.count > data.count) { width = data.count / channels.count; } r = x + width; RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count); OUTPUT: RETVAL Imager::ImgRaw i_img_masked_new(targ, mask, x, y, w, h) Imager::ImgRaw targ i_img_dim x i_img_dim y i_img_dim w i_img_dim h PREINIT: i_img *mask; CODE: if (SvOK(ST(1))) { if (!sv_isobject(ST(1)) || !sv_derived_from(ST(1), "Imager::ImgRaw")) { croak("i_img_masked_new: parameter 2 must undef or an image"); } mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1)))); } else mask = NULL; RETVAL = i_img_masked_new(targ, mask, x, y, w, h); OUTPUT: RETVAL int i_plin(im, l, y, ...) Imager::ImgRaw im i_img_dim l i_img_dim y PREINIT: i_color *work; STRLEN i; STRLEN len; size_t count; CODE: if (items > 3) { if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) { /* supplied as a byte string */ work = (i_color *)SvPV(ST(3), len); count = len / sizeof(i_color); if (count * sizeof(i_color) != len) { croak("i_plin: length of scalar argument must be multiple of sizeof i_color"); } RETVAL = i_plin(im, l, l+count, y, work); } else { work = mymalloc(sizeof(i_color) * (items-3)); for (i=0; i < items-3; ++i) { if (sv_isobject(ST(i+3)) && sv_derived_from(ST(i+3), "Imager::Color")) { IV tmp = SvIV((SV *)SvRV(ST(i+3))); work[i] = *INT2PTR(i_color *, tmp); } else { myfree(work); croak("i_plin: pixels must be Imager::Color objects"); } } RETVAL = i_plin(im, l, l+items-3, y, work); myfree(work); } } else { RETVAL = 0; } OUTPUT: RETVAL int i_ppixf(im, x, y, cl) Imager::ImgRaw im i_img_dim x i_img_dim y Imager::Color::Float cl void i_gsampf(im, l, r, y, channels) Imager::ImgRaw im i_img_dim l i_img_dim r i_img_dim y i_channel_list channels PREINIT: i_fsample_t *data; i_img_dim count, i; PPCODE: if (l < r) { data = mymalloc(sizeof(i_fsample_t) * (r-l) * channels.count); count = i_gsampf(im, l, r, y, data, channels.channels, channels.count); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) PUSHs(sv_2mortal(newSVnv(data[i]))); } else { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t)))); } myfree(data); } else { if (GIMME_V != G_ARRAY) { XSRETURN_UNDEF; } } int i_plinf(im, l, y, ...) Imager::ImgRaw im i_img_dim l i_img_dim y PREINIT: i_fcolor *work; i_img_dim i; STRLEN len; size_t count; CODE: if (items > 3) { if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) { /* supplied as a byte string */ work = (i_fcolor *)SvPV(ST(3), len); count = len / sizeof(i_fcolor); if (count * sizeof(i_fcolor) != len) { croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor"); } RETVAL = i_plinf(im, l, l+count, y, work); } else { work = mymalloc(sizeof(i_fcolor) * (items-3)); for (i=0; i < items-3; ++i) { if (sv_isobject(ST(i+3)) && sv_derived_from(ST(i+3), "Imager::Color::Float")) { IV tmp = SvIV((SV *)SvRV(ST(i+3))); work[i] = *INT2PTR(i_fcolor *, tmp); } else { myfree(work); croak("i_plinf: pixels must be Imager::Color::Float objects"); } } /**(char *)0 = 1;*/ RETVAL = i_plinf(im, l, l+items-3, y, work); myfree(work); } } else { RETVAL = 0; } OUTPUT: RETVAL Imager::Color::Float i_gpixf(im, x, y) Imager::ImgRaw im i_img_dim x i_img_dim y; CODE: RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor)); memset(RETVAL, 0, sizeof(*RETVAL)); if (i_gpixf(im, x, y, RETVAL) != 0) { myfree(RETVAL); XSRETURN_UNDEF; } OUTPUT: RETVAL void i_glin(im, l, r, y) Imager::ImgRaw im i_img_dim l i_img_dim r i_img_dim y PREINIT: i_color *vals; i_img_dim count, i; PPCODE: if (l < r) { vals = mymalloc((r-l) * sizeof(i_color)); memset(vals, 0, (r-l) * sizeof(i_color)); count = i_glin(im, l, r, y, vals); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) { SV *sv = make_i_color_sv(aTHX_ vals+i); PUSHs(sv); } } else if (count) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color)))); } myfree(vals); } void i_glinf(im, l, r, y) Imager::ImgRaw im i_img_dim l i_img_dim r i_img_dim y PREINIT: i_fcolor *vals; i_img_dim count, i; i_fcolor zero; PPCODE: for (i = 0; i < MAXCHANNELS; ++i) zero.channel[i] = 0; if (l < r) { vals = mymalloc((r-l) * sizeof(i_fcolor)); for (i = 0; i < r-l; ++i) vals[i] = zero; count = i_glinf(im, l, r, y, vals); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) { SV *sv; i_fcolor *col = mymalloc(sizeof(i_fcolor)); *col = vals[i]; sv = sv_newmortal(); sv_setref_pv(sv, "Imager::Color::Float", (void *)col); PUSHs(sv); } } else if (count) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor)))); } myfree(vals); } Imager::ImgRaw i_img_8_new(x, y, ch) i_img_dim x i_img_dim y int ch Imager::ImgRaw i_img_16_new(x, y, ch) i_img_dim x i_img_dim y int ch Imager::ImgRaw i_img_to_rgb16(im) Imager::ImgRaw im Imager::ImgRaw i_img_double_new(x, y, ch) i_img_dim x i_img_dim y int ch Imager::ImgRaw i_img_to_drgb(im) Imager::ImgRaw im undef_int i_tags_addn(im, name_sv, code, idata) Imager::ImgRaw im SV *name_sv int code int idata PREINIT: char *name; STRLEN len; CODE: SvGETMAGIC(name_sv); if (SvOK(name_sv)) name = SvPV_nomg(name_sv, len); else name = NULL; RETVAL = i_tags_addn(&im->tags, name, code, idata); OUTPUT: RETVAL undef_int i_tags_add(im, name_sv, code, data_sv, idata) Imager::ImgRaw im SV *name_sv int code SV *data_sv int idata PREINIT: char *name; char *data; STRLEN len; CODE: SvGETMAGIC(name_sv); if (SvOK(name_sv)) name = SvPV_nomg(name_sv, len); else name = NULL; SvGETMAGIC(data_sv); if (SvOK(data_sv)) data = SvPV(data_sv, len); else { data = NULL; len = 0; } RETVAL = i_tags_add(&im->tags, name, code, data, len, idata); OUTPUT: RETVAL SysRet i_tags_find(im, name, start) Imager::ImgRaw im char *name int start PREINIT: int entry; CODE: if (i_tags_find(&im->tags, name, start, &entry)) { RETVAL = entry; } else { XSRETURN_UNDEF; } OUTPUT: RETVAL SysRet i_tags_findn(im, code, start) Imager::ImgRaw im int code int start PREINIT: int entry; CODE: if (i_tags_findn(&im->tags, code, start, &entry)) { RETVAL = entry; } else { XSRETURN_UNDEF; } OUTPUT: RETVAL int i_tags_delete(im, entry) Imager::ImgRaw im int entry CODE: RETVAL = i_tags_delete(&im->tags, entry); OUTPUT: RETVAL int i_tags_delbyname(im, name) Imager::ImgRaw im char * name CODE: RETVAL = i_tags_delbyname(&im->tags, name); OUTPUT: RETVAL int i_tags_delbycode(im, code) Imager::ImgRaw im int code CODE: RETVAL = i_tags_delbycode(&im->tags, code); OUTPUT: RETVAL void i_tags_get(im, index) Imager::ImgRaw im int index PPCODE: if (index >= 0 && index < im->tags.count) { i_img_tag *entry = im->tags.tags + index; EXTEND(SP, 5); if (entry->name) { PUSHs(sv_2mortal(newSVpv(entry->name, 0))); } else { PUSHs(sv_2mortal(newSViv(entry->code))); } if (entry->data) { PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size))); } else { PUSHs(sv_2mortal(newSViv(entry->idata))); } } void i_tags_get_string(im, what_sv) Imager::ImgRaw im SV *what_sv PREINIT: char const *name = NULL; int code; char buffer[200]; PPCODE: if (SvIOK(what_sv)) { code = SvIV(what_sv); name = NULL; } else { name = SvPV_nolen(what_sv); code = 0; } if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(buffer, 0))); } int i_tags_count(im) Imager::ImgRaw im CODE: RETVAL = im->tags.count; OUTPUT: RETVAL MODULE = Imager PACKAGE = Imager::FillHandle PREFIX=IFILL_ void IFILL_DESTROY(fill) Imager::FillHandle fill int IFILL_CLONE_SKIP(...) CODE: (void)items; /* avoid unused warning for XS variable */ RETVAL = 1; OUTPUT: RETVAL MODULE = Imager PACKAGE = Imager Imager::FillHandle i_new_fill_solid(cl, combine) Imager::Color cl int combine Imager::FillHandle i_new_fill_solidf(cl, combine) Imager::Color::Float cl int combine Imager::FillHandle i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy) Imager::Color fg Imager::Color bg int combine int hatch SV *cust_hatch_sv i_img_dim dx i_img_dim dy PREINIT: unsigned char *cust_hatch; STRLEN len; CODE: SvGETMAGIC(cust_hatch_sv); if (SvOK(cust_hatch_sv)) { cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len); } else cust_hatch = NULL; RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy); OUTPUT: RETVAL Imager::FillHandle i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy) Imager::Color::Float fg Imager::Color::Float bg int combine int hatch SV *cust_hatch_sv i_img_dim dx i_img_dim dy PREINIT: unsigned char *cust_hatch; STRLEN len; CODE: SvGETMAGIC(cust_hatch_sv); if (SvOK(cust_hatch_sv)) { cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len); } else cust_hatch = NULL; RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy); OUTPUT: RETVAL Imager::FillHandle i_new_fill_image(src, matrix_sv, xoff, yoff, combine) Imager::ImgRaw src SV *matrix_sv i_img_dim xoff i_img_dim yoff int combine PREINIT: double matrix[9]; double *matrixp; AV *av; IV len; SV *sv1; int i; CODE: SvGETMAGIC(matrix_sv); if (!SvOK(matrix_sv)) { matrixp = NULL; } else { if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV) croak("i_new_fill_image: matrix parameter must be an arrayref or undef"); av=(AV*)SvRV(matrix_sv); len=av_len(av)+1; if (len > 9) len = 9; for (i = 0; i < len; ++i) { sv1=(*(av_fetch(av,i,0))); matrix[i] = SvNV(sv1); } for (; i < 9; ++i) matrix[i] = 0; matrixp = matrix; } RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine); OUTPUT: RETVAL MODULE = Imager PACKAGE = Imager::Internal::Hlines PREFIX=i_int_hlines_ # this class is only exposed for testing int i_int_hlines_testing() #if i_int_hlines_testing() Imager::Internal::Hlines i_int_hlines_new(start_y, count_y, start_x, count_x) i_img_dim start_y int count_y i_img_dim start_x int count_x Imager::Internal::Hlines i_int_hlines_new_img(im) Imager::ImgRaw im void i_int_hlines_add(hlines, y, minx, width) Imager::Internal::Hlines hlines i_img_dim y i_img_dim minx i_img_dim width void i_int_hlines_DESTROY(hlines) Imager::Internal::Hlines hlines SV * i_int_hlines_dump(hlines) Imager::Internal::Hlines hlines int i_int_hlines_CLONE_SKIP(cls) #endif MODULE = Imager PACKAGE = Imager::Context PREFIX=im_context_ void im_context_DESTROY(ctx) Imager::Context ctx #ifdef PERL_IMPLICIT_CONTEXT void im_context_CLONE(...) CODE: MY_CXT_CLONE; (void)items; /* the following sv_setref_pv() will free this inc */ im_context_refinc(MY_CXT.ctx, "CLONE"); MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE"); sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx); #endif BOOT: PERL_SET_GLOBAL_CALLBACKS; PERL_PL_SET_GLOBAL_CALLBACKS; #ifdef PERL_IMPLICIT_CONTEXT { MY_CXT_INIT; (void)MY_CXT; } #endif start_context(aTHX); im_get_context = perl_get_context; #ifdef HAVE_LIBTT i_tt_start(); #endif libimager-perl-1.004+dfsg.orig/Mandelbrot/0000755000175000017500000000000012617614576017667 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/Mandelbrot/mandel.c0000644000175000017500000000254312370401736021263 0ustar gregoagregoa#include "imext.h" #include char evalstr[]="Mandlebrot renderer"; /* Example Mandlebrot generator */ /* input parameters image is the image object. */ static int mandel(double x, double y, int max_iter) { double xn, yn; double xo, yo; int iter = 1; /* Z(n+1) = Z(n) ^2 + c */ /* printf("(%.2f, %.2f) -> \n", x,y); */ xo = x; yo = y; while( xo*xo+yo*yo <= 10 && iter < max_iter) { xn = xo*xo-yo*yo + x; yn = 2*xo*yo + y; xo=xn; yo=yn; iter++; } return (iter == max_iter)?0:iter; } void mandelbrot(i_img *im, double minx, double miny, double maxx, double maxy, int max_iter) { int i; i_img_dim x,y; int idx; double divx, divy; i_color icl[256]; srand(12235); for(i=1;i<256; i++) { icl[i].rgb.r = 100+(int) (156.0*rand()/(RAND_MAX+1.0)); icl[i].rgb.g = 100+(int) (156.0*rand()/(RAND_MAX+1.0)); icl[i].rgb.b = 100+(int) (156.0*rand()/(RAND_MAX+1.0)); } icl[0].rgb.r = 0; icl[0].rgb.g = 0; icl[0].rgb.b = 0; if (maxx <= minx) maxx = minx + 1.0; if (maxy <= miny) maxy = miny + 1.0; divx = (maxx - minx) / im->xsize; divy = (maxy - miny) / im->ysize; for(y = 0; y < im->ysize; y ++) { for(x = 0; x < im->xsize; x ++ ) { idx = mandel(minx + x*divx , miny + y*divy, max_iter); idx = idx % 256; i_ppix(im,x,y,&icl[idx]); } } } libimager-perl-1.004+dfsg.orig/Mandelbrot/t/0000755000175000017500000000000012617614576020132 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/Mandelbrot/t/t00mandel.t0000644000175000017500000000055112031434614022063 0ustar gregoagregoa#!perl -w use strict; use blib; use lib '../t'; use Imager; use Test::More tests => 3; BEGIN { use_ok('Imager::Filter::Mandelbrot') } my $im = Imager->new(xsize=>100, ysize=>100); SKIP: { ok($im->filter(type=>'mandelbrot'), "try filter") or print "# ", $im->errstr, "\n"; ok($im->write(file => '../testout/t00mandel.ppm'), "save result"); } libimager-perl-1.004+dfsg.orig/Mandelbrot/Makefile.PL0000644000175000017500000000062512567572530021641 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; my %opts = ( NAME => 'Imager::Filter::Mandelbrot', VERSION_FROM => 'Mandelbrot.pm', OBJECT => 'Mandelbrot.o mandel.o', INC => '-I..' ); my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'Mandelbrot Imager filter extension'; } WriteMakefile(%opts); libimager-perl-1.004+dfsg.orig/Mandelbrot/Mandelbrot.xs0000644000175000017500000000125412031434614022313 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #ifdef __cplusplus } #endif #include "imext.h" #include "imperl.h" void mandelbrot(i_img *im, double minx, double miny, double maxx, double maxy, int max_iter); DEFINE_IMAGER_CALLBACKS; MODULE = Imager::Filter::Mandelbrot PACKAGE = Imager::Filter::Mandelbrot PROTOTYPES: ENABLE void mandelbrot(im, minx=-2.5, miny=-2.0, maxx=2.5, maxy=-2.0, max_iter=256) Imager::ImgRaw im double minx double miny double maxx double maxy int max_iter BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/Mandelbrot/Mandelbrot.pm0000644000175000017500000000275312370401736022307 0ustar gregoagregoapackage Imager::Filter::Mandelbrot; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.04"; require XSLoader; XSLoader::load('Imager::Filter::Mandelbrot', $VERSION); } sub _mandelbrot { my %hsh = @_; mandelbrot($hsh{image}, $hsh{minx}, $hsh{miny}, $hsh{maxx}, $hsh{maxy}, $hsh{maxiter}); } my %defaults = ( minx => -2.5, maxx => 1.5, miny => -1.5, maxy => 1.5, maxiter => 256, ); my @callseq = qw/image minx miny maxx maxy maxiter/; Imager->register_filter(type=>'mandelbrot', callsub => \&_mandelbrot, defaults => \%defaults, callseq => \@callseq); 1; __END__ =head1 NAME Imager::Filter::Mandelbrot - filter that renders the Mandelbrot set. =head1 SYNOPSIS use Imager; use Imager::Filter::Mandelbrot; $img->filter(type=>'mandelbrot', ...); =head1 DESCRIPTION This is a expansion of the C dynamically loadable filter provided in C in previous releases of Imager. Valid filter parameters are: =over =item * C, C - the range of x values to render. Defaults: -2.5, 1.5. =item * C, C - the range of y values to render. Defaults: -1.5, 1.5 =item * C - the maximum number of iterations to perform when checking if the sequence tend towards infinity. =back =head1 AUTHOR Original by Arnar M. Hrafnkelsson. Adapted and expanded by Tony Cook =head1 SEE ALSO Imager, Imager::Filters. =cut libimager-perl-1.004+dfsg.orig/render.im0000644000175000017500000010136112504440416017371 0ustar gregoagregoa/* Render utilities */ #include "imager.h" #define RENDER_MAGIC 0x765AE typedef void (*render_color_f)(i_render *, i_img_dim, i_img_dim, i_img_dim, unsigned char const *src, i_color const *color); #define i_has_alpha(channels) ((channels) == 2 || (channels) == 4) #define i_color_channels(channels) (i_has_alpha(channels) ? (channels)-1 : (channels)) #code static void IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color); static void IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color); static render_color_f IM_SUFFIX(render_color_tab)[] = { NULL, IM_SUFFIX(render_color_13), IM_SUFFIX(render_color_alpha), IM_SUFFIX(render_color_13), IM_SUFFIX(render_color_alpha), }; static void IM_SUFFIX(combine_line_noalpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count); static void IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count); /* the copy variant copies the source alpha to the the output alpha channel */ static void IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count); static void IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count); static void IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count); #/code /* =item i_render_new(im, width) =category Blit tools Allocate a new C object and initialize it. =cut */ i_render * i_render_new(i_img *im, i_img_dim width) { i_render *r = mymalloc(sizeof(i_render)); i_render_init(r, im, width); return r; } /* =item i_render_delete(r) =category Blit tools Release an C object. =cut */ void i_render_delete(i_render *r) { i_render_done(r); myfree(r); } void i_render_init(i_render *r, i_img *im, i_img_dim width) { r->magic = RENDER_MAGIC; r->im = im; r->line_width = width; r->line_8 = NULL; r->line_double = NULL; r->fill_width = width; r->fill_line_8 = NULL; r->fill_line_double = NULL; } void i_render_done(i_render *r) { if (r->line_8) myfree(r->line_8); if (r->line_double) myfree(r->line_double); if (r->fill_line_8) myfree(r->fill_line_8); if (r->fill_line_double) myfree(r->fill_line_double); r->magic = 0; } static void alloc_line(i_render *r, i_img_dim width, i_img_dim eight_bit) { if (width > r->line_width) { i_img_dim new_width = r->line_width * 2; if (new_width < width) new_width = width; if (eight_bit) { if (r->line_8) r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width); else r->line_8 = mymalloc(sizeof(i_color) * new_width); if (r->line_double) { myfree(r->line_double); r->line_double = NULL; } } else { if (r->line_double) r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width); else r->line_double = mymalloc(sizeof(i_fcolor) * new_width); if (r->line_8) { myfree(r->line_8); r->line_double = NULL; } } r->line_width = new_width; } else { if (eight_bit) { if (!r->line_8) r->line_8 = mymalloc(sizeof(i_color) * r->line_width); if (r->line_double) { myfree(r->line_double); r->line_double = NULL; } } else { if (!r->line_double) r->line_double = mymalloc(sizeof(i_fcolor) * r->line_width); if (r->line_8) { myfree(r->line_8); r->line_8 = NULL; } } } } static void alloc_fill_line(i_render *r, i_img_dim width, int eight_bit) { if (width > r->fill_width) { i_img_dim new_width = r->fill_width * 2; if (new_width < width) new_width = width; if (eight_bit) { if (r->line_8) r->fill_line_8 = myrealloc(r->fill_line_8, sizeof(i_color) * new_width); else r->fill_line_8 = mymalloc(sizeof(i_color) * new_width); if (r->fill_line_double) { myfree(r->fill_line_double); r->fill_line_double = NULL; } } else { if (r->fill_line_double) r->fill_line_double = myrealloc(r->fill_line_double, sizeof(i_fcolor) * new_width); else r->fill_line_double = mymalloc(sizeof(i_fcolor) * new_width); if (r->fill_line_8) { myfree(r->fill_line_8); r->fill_line_double = NULL; } } r->fill_width = new_width; } else { if (eight_bit) { if (!r->fill_line_8) r->fill_line_8 = mymalloc(sizeof(i_color) * r->fill_width); if (r->fill_line_double) { myfree(r->fill_line_double); r->fill_line_double = NULL; } } else { if (!r->fill_line_double) r->fill_line_double = mymalloc(sizeof(i_fcolor) * r->fill_width); if (r->fill_line_8) { myfree(r->fill_line_8); r->fill_line_8 = NULL; } } } } /* =item i_render_color(r, x, y, width, source, color) =category Blit tools Render the given color with the coverage specified by C to C. Renders in normal combine mode. =cut */ void i_render_color(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color) { i_img *im = r->im; if (y < 0 || y >= im->ysize) return; if (x < 0) { width += x; src -= x; x = 0; } if (x + width > im->xsize) { width = im->xsize - x; } if (x >= im->xsize || x + width <= 0 || width <= 0) return; /* avoid as much work as we can */ while (width > 0 && *src == 0) { --width; ++src; ++x; } while (width > 0 && src[width-1] == 0) { --width; } if (!width) return; alloc_line(r, width, r->im->bits <= 8); #code r->im->bits <= 8 /*if (r->IM_SUFFIX(line) == NULL) r->IM_SUFFIX(line) = mymalloc(sizeof(IM_COLOR) * r->width);*/ (IM_SUFFIX(render_color_tab)[im->channels])(r, x, y, width, src, color); #/code } /* =item i_render_fill(r, x, y, width, source, fill) =category Blit tools Render the given fill with the coverage in C through C. =cut */ void i_render_fill(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_fill_t *fill) { i_img *im = r->im; int fill_channels = im->channels; if (fill_channels == 1 || fill_channels == 3) ++fill_channels; if (y < 0 || y >= im->ysize) return; if (x < 0) { width += x; src -= x; x = 0; } if (x + width > im->xsize) { width = im->xsize - x; } if (x >= im->xsize || x + width <= 0 || width <= 0) return; if (src) { /* avoid as much work as we can */ while (width > 0 && *src == 0) { --width; ++src; ++x; } while (width > 0 && src[width-1] == 0) { --width; } } if (!width) return; alloc_line(r, width, r->im->bits <= 8 && fill->f_fill_with_color != NULL); alloc_fill_line(r, width, r->im->bits <= 8 && fill->f_fill_with_color != NULL); #code r->im->bits <= 8 && fill->f_fill_with_color if (IM_FILL_COMBINE(fill)) { IM_COLOR *srcc = r->IM_SUFFIX(fill_line); IM_COLOR *destc = r->IM_SUFFIX(line); IM_FILL_FILLER(fill)(fill, x, y, width, fill_channels, r->IM_SUFFIX(fill_line)); if (src) { unsigned char const *srcc = src; IM_COLOR *fillc = r->IM_SUFFIX(fill_line); i_img_dim work_width = width; while (work_width) { if (*srcc == 0) { fillc->channel[fill_channels-1] = 0; } else if (*srcc != 255) { fillc->channel[fill_channels-1] = fillc->channel[fill_channels-1] * *srcc / 255; } --work_width; ++srcc; ++fillc; } } IM_GLIN(r->im, x, x+width, y, r->IM_SUFFIX(line)); IM_FILL_COMBINE(fill)(destc, srcc, r->im->channels, width); } else { if (src) { i_img_dim work_width = width; IM_COLOR *srcc = r->IM_SUFFIX(fill_line); IM_COLOR *destc = r->IM_SUFFIX(line); int ch; IM_FILL_FILLER(fill)(fill, x, y, width, fill_channels, r->IM_SUFFIX(fill_line)); IM_GLIN(r->im, x, x+width, y, r->IM_SUFFIX(line)); while (work_width) { if (*src == 255) { /* just replace it */ *destc = *srcc; } else if (*src) { for (ch = 0; ch < im->channels; ++ch) { IM_WORK_T work = (destc->channel[ch] * (255 - *src) + srcc->channel[ch] * *src) / 255.0; destc->channel[ch] = IM_LIMIT(work); } } ++srcc; ++destc; ++src; --work_width; } } else { /* if (src) */ IM_FILL_FILLER(fill)(fill, x, y, width, fill_channels, r->IM_SUFFIX(line)); } } IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line)); #/code } #if 0 /* for debuggin */ static void dump_src(const char *note, unsigned char const *src, i_img_dim width) { i_img_dim i; printf("%s - %p/%" i_DF "\n", note, src, i_DFc(width)); for (i = 0; i < width; ++i) { printf("%02x ", src[i]); } putchar('\n'); } #endif #code /* =item i_render_line(r, x, y, width, source, fill) =category Blit tools Render the given fill with the coverage in C through C. =cut =item i_render_linef(r, x, y, width, source, fill) =category Blit tools Render the given fill with the coverage in C through C. =cut */ void IM_RENDER_LINE(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, const IM_SAMPLE_T *src, IM_COLOR *line, IM_FILL_COMBINE_F combine) { i_img *im = r->im; int src_chans = im->channels; /* src must always have an alpha channel */ if (src_chans == 1 || src_chans == 3) ++src_chans; if (y < 0 || y >= im->ysize) return; if (x < 0) { src -= x; line -= x; width += x; x = 0; } if (x + width > im->xsize) width = r->im->xsize - x; #ifdef IM_EIGHT_BIT alloc_line(r, width, 1); #else alloc_line(r, width, 0); #endif if (combine) { if (src) { i_img_dim work_width = width; IM_COLOR *linep = line; const IM_SAMPLE_T *srcp = src; int alpha_chan = src_chans - 1; while (work_width) { if (*srcp) { if (*srcp != IM_SAMPLE_MAX) linep->channel[alpha_chan] = linep->channel[alpha_chan] * *srcp / IM_SAMPLE_MAX; } else { linep->channel[alpha_chan] = 0; } --work_width; ++srcp; ++linep; } } IM_GLIN(im, x, x+width, y, r->IM_SUFFIX(line)); combine(r->IM_SUFFIX(line), line, im->channels, width); IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line)); } else { if (src) { i_img_dim work_width = width; IM_COLOR *srcc = line; IM_COLOR *destc = r->IM_SUFFIX(line); IM_GLIN(im, x, x+width, y, r->IM_SUFFIX(line)); while (work_width) { if (*src == 255) { /* just replace it */ *destc = *srcc; } else if (*src) { int ch; for (ch = 0; ch < im->channels; ++ch) { IM_WORK_T work = (destc->channel[ch] * (IM_SAMPLE_MAX - *src) + srcc->channel[ch] * *src) / IM_SAMPLE_MAX; destc->channel[ch] = IM_LIMIT(work); } } ++srcc; ++destc; ++src; --work_width; } IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line)); } else { IM_PLIN(im, x, x+width, y, line); } } } static void IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color) { i_img *im = r->im; IM_COLOR *linep = r->IM_SUFFIX(line); int ch, channels = im->channels; i_img_dim fetch_offset; int color_alpha = color->channel[im->channels]; #undef STORE_COLOR #ifdef IM_EIGHT_BIT #define STORE_COLOR (*color) #else i_fcolor fcolor; for (ch = 0; ch < channels; ++ch) { fcolor.channel[ch] = color->channel[ch] / 255.0; } #define STORE_COLOR fcolor #endif fetch_offset = 0; if (color_alpha == 0xFF) { while (fetch_offset < width && *src == 0xFF) { *linep++ = STORE_COLOR; ++src; ++fetch_offset; } } IM_GLIN(im, x+fetch_offset, x+width, y, linep); while (fetch_offset < width) { #ifdef IM_EIGHT_BIT IM_WORK_T alpha = *src++ * color_alpha / 255; #else IM_WORK_T alpha = *src++ * color_alpha / (255.0 * 255.0); #endif if (alpha == IM_SAMPLE_MAX) *linep = STORE_COLOR; else if (alpha) { for (ch = 0; ch < channels; ++ch) { linep->channel[ch] = (linep->channel[ch] * (IM_SAMPLE_MAX - alpha) + STORE_COLOR.channel[ch] * alpha) / IM_SAMPLE_MAX; } } ++linep; ++fetch_offset; } IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line)); } static void IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color) { IM_COLOR *linep = r->IM_SUFFIX(line); int ch; int alpha_channel = r->im->channels - 1; i_img_dim fetch_offset; int color_alpha = color->channel[alpha_channel]; #undef STORE_COLOR #ifdef IM_EIGHT_BIT #define STORE_COLOR (*color) #else i_fcolor fcolor; for (ch = 0; ch < r->im->channels; ++ch) { fcolor.channel[ch] = color->channel[ch] / 255.0; } #define STORE_COLOR fcolor #endif fetch_offset = 0; if (color->channel[alpha_channel] == 0xFF) { while (fetch_offset < width && *src == 0xFF) { *linep++ = STORE_COLOR; ++src; ++fetch_offset; } } IM_GLIN(r->im, x+fetch_offset, x+width, y, linep); while (fetch_offset < width) { #ifdef IM_EIGHT_BIT IM_WORK_T src_alpha = *src++ * color_alpha / 255; #else IM_WORK_T src_alpha = *src++ * color_alpha / (255.0 * 255.0); #endif if (src_alpha == IM_SAMPLE_MAX) *linep = STORE_COLOR; else if (src_alpha) { IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha; IM_WORK_T orig_alpha = linep->channel[alpha_channel]; IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX; for (ch = 0; ch < alpha_channel; ++ch) { linep->channel[ch] = ( src_alpha * STORE_COLOR.channel[ch] + remains * linep->channel[ch] * orig_alpha / IM_SAMPLE_MAX ) / dest_alpha; } linep->channel[alpha_channel] = dest_alpha; } ++linep; ++fetch_offset; } IM_PLIN(r->im, x, x+width, y, r->IM_SUFFIX(line)); #undef STORE_COLOR } /* combine a line of image data with an output line, both the input and output lines include an alpha channel. Both input and output lines have I of data, channels should be either 2 or 4. */ static void IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) { int ch; int alpha_channel = channels - 1; while (count) { IM_WORK_T src_alpha = in->channel[alpha_channel]; if (src_alpha == IM_SAMPLE_MAX) *out = *in; else if (src_alpha) { IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha; IM_WORK_T orig_alpha = out->channel[alpha_channel]; IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX; for (ch = 0; ch < alpha_channel; ++ch) { out->channel[ch] = ( src_alpha * in->channel[ch] + remains * out->channel[ch] * orig_alpha / IM_SAMPLE_MAX ) / dest_alpha; } out->channel[alpha_channel] = dest_alpha; } ++out; ++in; --count; } } /* combine a line of image data with an output line. The input line includes an alpha channel, the output line has no alpha channel. The input line has I+1 of color data. The output line has I of color data. */ static void IM_SUFFIX(combine_line_noalpha) (IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) { int ch; while (count) { IM_WORK_T src_alpha = in->channel[channels]; if (src_alpha == IM_SAMPLE_MAX) *out = *in; else if (src_alpha) { IM_WORK_T remains; remains = IM_SAMPLE_MAX - src_alpha; for (ch = 0; ch < channels; ++ch) { out->channel[ch] = ( in->channel[ch] * src_alpha + out->channel[ch] * remains) / IM_SAMPLE_MAX; } } ++out; ++in; --count; } } /* combine a line of image data with an output line, both the input and output lines include an alpha channel. Both input and output lines have I of data, channels should be either 2 or 4. This variant does not modify the output alpha channel. */ static void IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) { int ch; int alpha_channel = channels - 1; while (count) { IM_WORK_T src_alpha = in->channel[alpha_channel]; if (src_alpha == IM_SAMPLE_MAX) *out = *in; else if (src_alpha) { IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha; IM_WORK_T orig_alpha = out->channel[alpha_channel]; IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX; for (ch = 0; ch < alpha_channel; ++ch) { out->channel[ch] = ( src_alpha * in->channel[ch] + remains * out->channel[ch] * orig_alpha / IM_SAMPLE_MAX ) / dest_alpha; } } ++out; ++in; --count; } } static void IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) { if (channels == 2 || channels == 4) IM_SUFFIX(combine_line_alpha)(out, in, channels, count); else IM_SUFFIX(combine_line_noalpha)(out, in, channels, count); } static void IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) { if (channels == 2 || channels == 4) IM_SUFFIX(combine_line_alpha_na)(out, in, channels, count); else IM_SUFFIX(combine_line_noalpha)(out, in, channels, count); } static void IM_SUFFIX(combine_alphablend)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_mult)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_dissolve)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_add)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_subtract)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_diff)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_darken)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_lighten)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_hue)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_sat)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_value)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static void IM_SUFFIX(combine_color)(IM_COLOR *, IM_COLOR *, int, i_img_dim); static const IM_FILL_COMBINE_F IM_SUFFIX(combines)[] = { NULL, IM_SUFFIX(combine_alphablend), IM_SUFFIX(combine_mult), IM_SUFFIX(combine_dissolve), IM_SUFFIX(combine_add), IM_SUFFIX(combine_subtract), IM_SUFFIX(combine_diff), IM_SUFFIX(combine_lighten), IM_SUFFIX(combine_darken), IM_SUFFIX(combine_hue), IM_SUFFIX(combine_sat), IM_SUFFIX(combine_value), IM_SUFFIX(combine_color) }; #/code /* =item i_get_combine(combine, color_func, fcolor_func) =cut */ void i_get_combine(int combine, i_fill_combine_f *color_func, i_fill_combinef_f *fcolor_func) { if (combine < 0 || combine > sizeof(combines_8) / sizeof(*combines_8)) combine = 0; *color_func = combines_8[combine]; *fcolor_func = combines_double[combine]; } #code /* Three good references for implementing combining modes: http://www.w3.org/TR/2004/WD-SVG12-20041027/rendering.html referenced as [svg1.2] http://gimp-savvy.com/BOOK/index.html?node55.html ("The Blending Modes", if it changes) referenced as [savvy] http://www.pegtop.net/delphi/articles/blendmodes/ referenced as [pegtop] Where differences exist, I follow the SVG practice, the gimp practice, and lastly pegtop. */ static void IM_SUFFIX(combine_alphablend)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { IM_SUFFIX(combine_line)(out, in, channels, count); } /* Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) Da' = Sa.Da + Sa.(1 - Da) + Da.(1 - Sa) = Sa + Da - Sa.Da When Da=1 Dc' = Sc.Sa.Dc + Dc.(1 - Sa) */ static void IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { int ch; IM_COLOR *inp = in; IM_COLOR *outp = out; i_img_dim work_count = count; int color_channels = i_color_channels(channels); if (i_has_alpha(channels)) { while (work_count--) { IM_WORK_T orig_alpha = outp->channel[color_channels]; IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { IM_WORK_T dest_alpha = src_alpha + orig_alpha - (src_alpha * orig_alpha) / IM_SAMPLE_MAX; for (ch = 0; ch < color_channels; ++ch) { outp->channel[ch] = (inp->channel[ch] * src_alpha * outp->channel[ch] / IM_SAMPLE_MAX * orig_alpha + inp->channel[ch] * src_alpha * (IM_SAMPLE_MAX - orig_alpha) + outp->channel[ch] * orig_alpha * (IM_SAMPLE_MAX - src_alpha)) / IM_SAMPLE_MAX / dest_alpha; } outp->channel[color_channels] = dest_alpha; } ++outp; ++inp; } } else { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha; if (src_alpha) { for (ch = 0; ch < color_channels; ++ch) { outp->channel[ch] = (src_alpha * inp->channel[ch] * outp->channel[ch] / IM_SAMPLE_MAX + outp->channel[ch] * remains) / IM_SAMPLE_MAX; } } ++outp; ++inp; } } } static void IM_SUFFIX(combine_dissolve)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { int color_channels = i_color_channels(channels); int ch; if (i_has_alpha(channels)) { while (count--) { if (in->channel[channels-1] > rand() * ((double)IM_SAMPLE_MAX / RAND_MAX)) { for (ch = 0; ch < color_channels; ++ch) { out->channel[ch] = in->channel[ch]; } out->channel[color_channels] = IM_SAMPLE_MAX; } ++out; ++in; } } else { while (count--) { if (in->channel[channels] > rand() * ((double)IM_SAMPLE_MAX / RAND_MAX)) { for (ch = 0; ch < color_channels; ++ch) { out->channel[ch] = in->channel[ch]; } } ++out; ++in; } } } /* Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) = Sca + Dca Da' = Sa.Da + Da.Sa + Sa.(1 - Da) + Da.(1 - Sa) = Sa + Da */ static void IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { int ch; int color_channels = i_color_channels(channels); i_img_dim work_count = count; IM_COLOR *inp = in; IM_COLOR *outp = out; if (i_has_alpha(channels)) { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { IM_WORK_T orig_alpha = outp->channel[color_channels]; IM_WORK_T dest_alpha = src_alpha + orig_alpha; if (dest_alpha > IM_SAMPLE_MAX) dest_alpha = IM_SAMPLE_MAX; for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T total = (outp->channel[ch] * orig_alpha + inp->channel[ch] * src_alpha) / dest_alpha; if (total > IM_SAMPLE_MAX) total = IM_SAMPLE_MAX; outp->channel[ch] = total; } outp->channel[color_channels] = dest_alpha; } ++outp; ++inp; } } else { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T total = outp->channel[ch] + inp->channel[ch] * src_alpha / IM_SAMPLE_MAX; if (total > IM_SAMPLE_MAX) total = IM_SAMPLE_MAX; outp->channel[ch] = total; } } ++outp; ++inp; } } } /* [pegtop] documents this as max(A+B-256, 0) while [savvy] documents it as max(A-B, 0). [svg1.2] doesn't cover it. [savvy] doesn't document how it works with an alpha channel. GIMP actually seems to calculate the final value then use the alpha channel to apply that to the target. */ static void IM_SUFFIX(combine_subtract)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { int ch; IM_COLOR const *inp = in; IM_COLOR *outp = out; i_img_dim work_count = count; int color_channels = i_color_channels(channels); if (i_has_alpha(channels)) { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { IM_WORK_T orig_alpha = outp->channel[color_channels]; IM_WORK_T dest_alpha = src_alpha + orig_alpha; if (dest_alpha > IM_SAMPLE_MAX) dest_alpha = IM_SAMPLE_MAX; for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T total = (outp->channel[ch] * orig_alpha - inp->channel[ch] * src_alpha) / dest_alpha; if (total < 0) total = 0; outp->channel[ch] = total; } outp->channel[color_channels] = dest_alpha; } ++outp; ++inp; } } else { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T total = outp->channel[ch] - inp->channel[ch] * src_alpha / IM_SAMPLE_MAX; if (total < 0) total = 0; outp->channel[ch] = total; } } ++outp; ++inp; } } } #ifdef IM_EIGHT_BIT #define IM_abs(x) abs(x) #else #define IM_abs(x) fabs(x) #endif /* Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) = Sca + Dca - 2.min(Sca.Da, Dca.Sa) Da' = Sa + Da - Sa.Da */ static void IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { int ch; IM_COLOR const *inp = in; IM_COLOR *outp = out; i_img_dim work_count = count; int color_channels = i_color_channels(channels); if (i_has_alpha(channels)) { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { IM_WORK_T orig_alpha = outp->channel[color_channels]; IM_WORK_T dest_alpha = src_alpha + orig_alpha - src_alpha * orig_alpha / IM_SAMPLE_MAX; for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T src = inp->channel[ch] * src_alpha; IM_WORK_T orig = outp->channel[ch] * orig_alpha; IM_WORK_T src_da = src * orig_alpha; IM_WORK_T dest_sa = orig * src_alpha; IM_WORK_T diff = src_da < dest_sa ? src_da : dest_sa; outp->channel[ch] = (src + orig - 2 * diff / IM_SAMPLE_MAX) / dest_alpha; } outp->channel[color_channels] = dest_alpha; } ++inp; ++outp; } } else { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T src = inp->channel[ch] * src_alpha; IM_WORK_T orig = outp->channel[ch] * IM_SAMPLE_MAX; IM_WORK_T src_da = src * IM_SAMPLE_MAX; IM_WORK_T dest_sa = orig * src_alpha; IM_WORK_T diff = src_da < dest_sa ? src_da : dest_sa; outp->channel[ch] = (src + orig - 2 * diff / IM_SAMPLE_MAX) / IM_SAMPLE_MAX; } } ++inp; ++outp; } } } #undef IM_abs /* Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca(1 - Sa) Da' = Sa + Da - Sa.Da To hoist some code: Dca' = min(Sc.Sa.Da, Dc.Da.Sa) + Sca - Sca.Da + Dca - Dca.Sa = Sa.Da.min(Sc, Dc) + Sca - Sca.Da + Dca - Dca.Sa When Da=1: Dca' = min(Sca.1, Dc.1.Sa) + Sca.(1 - 1) + Dc.1(1 - Sa) = min(Sca, Dc.Sa) + Dc(1-Sa) = Sa.min(Sc, Dc) + Dc - Dc.Sa Da' = Sa + 1 - Sa.1 = 1 */ static void IM_SUFFIX(combine_darken)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { int ch; IM_COLOR const *inp = in; IM_COLOR *outp = out; i_img_dim work_count = count; int color_channels = i_color_channels(channels); if (i_has_alpha(channels)) { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { IM_WORK_T orig_alpha = outp->channel[color_channels]; IM_WORK_T dest_alpha = src_alpha + orig_alpha - src_alpha * orig_alpha / IM_SAMPLE_MAX; for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T Sca = inp->channel[ch] * src_alpha; IM_WORK_T Dca = outp->channel[ch] * orig_alpha; IM_WORK_T ScaDa = Sca * orig_alpha; IM_WORK_T DcaSa = Dca * src_alpha; IM_WORK_T minc = ScaDa < DcaSa ? ScaDa : DcaSa; outp->channel[ch] = ( minc + (Sca + Dca) * IM_SAMPLE_MAX - ScaDa - DcaSa ) / (IM_SAMPLE_MAX * dest_alpha); } outp->channel[color_channels] = dest_alpha; } ++outp; ++inp; } } else { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T minc = outp->channel[ch] < inp->channel[ch] ? outp->channel[ch] : inp->channel[ch]; outp->channel[ch] = ( src_alpha * minc + outp->channel[ch] * ( IM_SAMPLE_MAX - src_alpha ) ) / IM_SAMPLE_MAX; } } ++outp; ++inp; } } } static void IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { int ch; IM_COLOR const *inp = in; IM_COLOR *outp = out; i_img_dim work_count = count; int color_channels = i_color_channels(channels); if (i_has_alpha(channels)) { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { IM_WORK_T orig_alpha = outp->channel[color_channels]; IM_WORK_T dest_alpha = src_alpha + orig_alpha - src_alpha * orig_alpha / IM_SAMPLE_MAX; for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T Sca = inp->channel[ch] * src_alpha; IM_WORK_T Dca = outp->channel[ch] * orig_alpha; IM_WORK_T ScaDa = Sca * orig_alpha; IM_WORK_T DcaSa = Dca * src_alpha; IM_WORK_T maxc = ScaDa > DcaSa ? ScaDa : DcaSa; outp->channel[ch] = ( maxc + (Sca + Dca) * IM_SAMPLE_MAX - ScaDa - DcaSa ) / (IM_SAMPLE_MAX * dest_alpha); } outp->channel[color_channels] = dest_alpha; } ++outp; ++inp; } } else { while (work_count--) { IM_WORK_T src_alpha = inp->channel[color_channels]; if (src_alpha) { for (ch = 0; ch < color_channels; ++ch) { IM_WORK_T maxc = outp->channel[ch] > inp->channel[ch] ? outp->channel[ch] : inp->channel[ch]; outp->channel[ch] = ( src_alpha * maxc + outp->channel[ch] * ( IM_SAMPLE_MAX - src_alpha ) ) / IM_SAMPLE_MAX; } } ++outp; ++inp; } } } #if IM_EIGHT_BIT #define IM_RGB_TO_HSV i_rgb_to_hsv #define IM_HSV_TO_RGB i_hsv_to_rgb #else #define IM_RGB_TO_HSV i_rgb_to_hsvf #define IM_HSV_TO_RGB i_hsv_to_rgbf #endif static void IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { if (channels > 2) { IM_COLOR *inp = in; IM_COLOR const *outp = out; i_img_dim work_count = count; if (i_has_alpha(channels)) { while (work_count--) { IM_COLOR c = *inp; IM_RGB_TO_HSV(&c); /* only transfer hue if there's saturation */ if (c.channel[1] && inp->channel[3] && outp->channel[3]) { *inp = *outp; IM_RGB_TO_HSV(inp); /* and no point in setting the target hue if the target has no sat */ if (inp->channel[1]) { inp->channel[0] = c.channel[0]; IM_HSV_TO_RGB(inp); inp->channel[3] = c.channel[3]; } else { inp->channel[3] = 0; } } else { inp->channel[3] = 0; } ++outp; ++inp; } } else { while (work_count--) { IM_COLOR c = *inp; IM_RGB_TO_HSV(&c); /* only transfer hue if there's saturation */ if (c.channel[1] && inp->channel[3]) { *inp = *outp; IM_RGB_TO_HSV(inp); /* and no point in setting the target hue if the target has no sat */ if (inp->channel[1]) { inp->channel[0] = c.channel[0]; IM_HSV_TO_RGB(inp); inp->channel[3] = c.channel[3]; } } else { inp->channel[3] = 0; } ++outp; ++inp; } } IM_SUFFIX(combine_line_na)(out, in, channels, count); } } static void IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { if (channels > 2) { IM_COLOR *inp = in; IM_COLOR const *outp = out; i_img_dim work_count = count; while (work_count--) { IM_COLOR c = *inp; *inp = *outp; IM_RGB_TO_HSV(&c); IM_RGB_TO_HSV(inp); inp->channel[1] = c.channel[1]; IM_HSV_TO_RGB(inp); inp->channel[3] = c.channel[3]; ++outp; ++inp; } IM_SUFFIX(combine_line_na)(out, in, channels, count); } } static void IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { if (channels > 2) { IM_COLOR *inp = in; IM_COLOR const *outp = out; i_img_dim work_count = count; while (work_count--) { IM_COLOR c = *inp; *inp = *outp; IM_RGB_TO_HSV(&c); IM_RGB_TO_HSV(inp); inp->channel[2] = c.channel[2]; IM_HSV_TO_RGB(inp); inp->channel[3] = c.channel[3]; ++outp; ++inp; } } /* all images have a "value channel" - for greyscale it's the only colour channel */ IM_SUFFIX(combine_line_na)(out, in, channels, count); } static void IM_SUFFIX(combine_color)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) { if (channels > 2) { IM_COLOR *inp = in; IM_COLOR const *outp = out; i_img_dim work_count = count; while (work_count--) { IM_COLOR c = *inp; *inp = *outp; IM_RGB_TO_HSV(&c); IM_RGB_TO_HSV(inp); inp->channel[0] = c.channel[0]; inp->channel[1] = c.channel[1]; IM_HSV_TO_RGB(inp); inp->channel[3] = c.channel[3]; ++outp; ++inp; } IM_SUFFIX(combine_line_na)(out, in, channels, count); } } #undef IM_RGB_TO_HSV #undef IM_HSV_TO_RGB #/code libimager-perl-1.004+dfsg.orig/MANIFEST0000644000175000017500000004154612617670351016734 0ustar gregoagregoaapidocs.perl Build lib/Imager/APIRef.pm bigtest.perl Library selection tester bmp.c Reading and writing Windows BMP files Changes Changes.old Old changes color.c Color translation and handling combine.im Channel combine compose.im context.c conv.im convert.im CountColor/CountColor.pm sample XS access to API CountColor/CountColor.xs CountColor/Makefile.PL CountColor/t/t00countcolor.t datatypes.c doco.perl draw.c draw.h dynaload.c dynaload.h dynfilt/compile.txt dynfilt/dt2.c dynfilt/dt2.exp dynfilt/dyntest.c dynfilt/dyntest.exp dynfilt/flines.c dynfilt/flines.exp dynfilt/Makefile.PL dynfilt/mandelbrot.c dynfilt/mandelbrot.exp dynfilt/pluginst.h dynfilt/t/t60dyntest.t Simple test script DynTest/DynTest.pm simple conversion of the dyntest sample from dynfilt/ DynTest/DynTest.xs DynTest/linstretch.c DynTest/Makefile.PL DynTest/t/t00dyntest.t errep.perl error.c ext.h feat.c feat.h fills.c Generic fills filterlist.perl filters.im Flines/Flines.pm Flines/Flines.xs Flines/Makefile.PL Flines/t/t00flines.t flip.im fontfiles/dodge.ttf fontfiles/ExistenceTest.ttf generated using pfaedit fontfiles/ImUgly.ttf fontfiles/NameTest.ttf test glyph_names() - see FT2/t/t10ft2.t fontft1.c FT2/fontfiles/dodge.ttf FT2/fontfiles/ExistenceTest.afm FT2/fontfiles/ExistenceTest.pfb FT2/fontfiles/ExistenceTest.ttf FT2/fontfiles/ImUgly.ttf FT2/fontfiles/NameTest.ttf FT2/freetyp2.c Implements freetype2 font support FT2/FT2.pm FT2/FT2.xs FT2/imft2.h FT2/Makefile.PL FT2/README FT2/t/t10ft2.t FT2/t/t20thread.t FT2/t/t90std.t Standard font tests for FT2 FT2/typemap gaussian.im GIF/GIF.pm GIF/GIF.xs GIF/imgif.c GIF/imgif.h GIF/Makefile.PL GIF/README GIF/t/t10gif.t GIF/t/t20new.t GIF/t/t30fixed.t GIF/t/t40limit.t GIF/t/t50header.t GIF/testimg/badindex.gif GIF with a bad color index GIF/testimg/bandw.gif GIF/testimg/expected.gif GIF/testimg/loccmap.gif GIF/testimg/nocmap.gif GIF/testimg/scale.gif GIF/testimg/scalei.gif GIF/testimg/screen2.gif GIF/testimg/screen3.gif GIF/testimg/trimgdesc.gif GIF/testimg/trmiddesc.gif GIF/testimg/zerocomm.gif Image with a zero-length comment extension hlines.c Manage sets of horizontal line segments ICO/ICO.pm Windows Icon file support ICO/ICO.xs ICO/imicon.c ICO/imicon.h ICO/lib/Imager/File/CUR.pm ICO/Makefile.PL ICO/msicon.c ICO/msicon.h ICO/t/t10icon.t ICO/t/t20readone.t ICO/t/t21readmult.t ICO/t/t30cursor.t ICO/t/t40readcurone.t ICO/t/t41curmultread.t ICO/t/t50readfail.t ICO/t/t60writefail.t ICO/t/t70icosing.t ICO/t/t71icomult.t ICO/t/t72cursing.t ICO/t/t73curmult.t ICO/testimg/combo.ico ICO/testimg/pal13232.ico ICO/testimg/pal256.ico ICO/testimg/pal43232.cur ICO/testimg/pal43232.ico ICO/testimg/pal43232.ppm ICO/testimg/pal83232.ico ICO/testimg/pal83232.ppm ICO/testimg/rgb1616.ico ICO/testimg/rgba3232.ico ICO/testimg/rgba3232.ppm image.c imager.h Imager.pm Imager.xs imageri.h imdatatypes.h imerror.h Error handling functions imext.c Defines the function table imext.h Included by external modules for API access imextdef.h imextpl.h Included by external modules for Perl API access imextpltypes.h Define Perl API function table type imexttypes.h Define API function table type img16.c Implements 16-bit/sample images img8.c Implements 8-bit/sample images imgdouble.c Implements double/sample images imio.h immacros.h imperl.h imperlio.h imrender.h Buffer rending engine function declarations inc/Devel/CheckLib.pm David Cantrell's Devel::CheckLib io.c iolayer.c iolayer.h iolayert.h IO layer types JPEG/imexif.c Experimental JPEG EXIF decoding JPEG/imexif.h JPEG/imjpeg.c JPEG/imjpeg.h JPEG/JPEG.pm JPEG/JPEG.xs JPEG/Makefile.PL JPEG/README JPEG/t/t00load.t JPEG/t/t10jpeg.t Test jpeg support JPEG/t/t20limit.t JPEG/testimg/209_yonge.jpg Regression test: #17981 JPEG/testimg/exiftest.jpg Test image for EXIF parsing JPEG/testimg/scmyk.jpg Simple CMYK JPEG image JPEG/testimg/zerotype.jpg Image with a zero type entry in the EXIF data lib/Imager/API.pod lib/Imager/APIRef.pod API function reference lib/Imager/Color.pm lib/Imager/Color/Float.pm lib/Imager/Color/Table.pm lib/Imager/Cookbook.pod lib/Imager/Draw.pod lib/Imager/Engines.pod lib/Imager/Expr.pm lib/Imager/Expr/Assem.pm lib/Imager/ExtUtils.pm lib/Imager/Files.pod lib/Imager/Fill.pm lib/Imager/Filters.pod lib/Imager/Font.pm lib/Imager/Font/BBox.pm lib/Imager/Font/FreeType2.pm lib/Imager/Font/Image.pm lib/Imager/Font/Test.pm Font for testing (outputs boxes only) lib/Imager/Font/Truetype.pm lib/Imager/Font/Type1.pm Compatibility wrapper for Imager::Font::T1 lib/Imager/Font/Wrap.pm lib/Imager/Fountain.pm lib/Imager/Handy.pod lib/Imager/ImageTypes.pod lib/Imager/Inline.pod Using Imager with Inline::C lib/Imager/Install.pod Installation notes lib/Imager/interface.pod lib/Imager/IO.pod Document Imager::IO objects lib/Imager/LargeSamples.pod Track large sample support lib/Imager/Matrix2d.pm lib/Imager/Preprocess.pm lib/Imager/Probe.pm Library probes lib/Imager/regmach.pod lib/Imager/Regops.pm lib/Imager/Security.pod lib/Imager/Test.pm lib/Imager/Threads.pod lib/Imager/Transform.pm lib/Imager/Transformations.pod lib/Imager/Tutorial.pod limits.c log.c log.h Makefile.PL Mandelbrot/Makefile.PL more complex filter Mandelbrot/mandel.c Mandelbrot/Mandelbrot.pm Mandelbrot/Mandelbrot.xs Mandelbrot/t/t00mandel.t MANIFEST MANIFEST.SKIP map.c maskimg.c mutexnull.c mutexpthr.c mutexwin.c palimg.c paste.im perlio.c plug.h PNG/impng.c PNG/impng.h PNG/Makefile.PL PNG/PNG.pm PNG/PNG.xs PNG/README PNG/t/00load.t PNG/t/10png.t Test png support PNG/testimg/badcrc.png PNG/testimg/bilevel.png PNG/testimg/bipalette.png bi-level but with a palette PNG/testimg/comment.png PNG/testimg/cover.png PNG/testimg/cover16.png PNG/testimg/cover16i.png PNG/testimg/coveri.png PNG/testimg/coverpal.png PNG/testimg/coverpali.png PNG/testimg/gray.png PNG/testimg/graya.png PNG/testimg/pal.png PNG/testimg/palette.png PNG/testimg/palette_out.png PNG/testimg/paltrans.png PNG/testimg/rgb16.png PNG/testimg/rgb8.png PNG/testimg/rgb8i.png pnm.c polygon.c ppport.h quant.c raw.c README regmach.c regmach.h regops.perl render.im rendert.h Buffer rendering engine types rotate.im rubthru.im samples/align-string.pl Demonstrate align_string method. samples/anaglyph.pl samples/border.pl Demonstrate adding a border samples/drop_shadow.pl Draw a drop shadow or glow samples/flasher.pl Animate an source image fading to a color and back samples/gifscale.pl Scale an animated GIF, preserving animation info samples/inline_capture2image.pl convert captured BGR data to an image samples/inline_replace_color.pl replace colors using Inline::C samples/interleave.pl samples/quad_to_square.pl Transform a quadrilateral into a square samples/README samples/replace_color.pl replace colors using transform2() samples/samp-form.cgi samples/samp-image.cgi samples/samp-scale.cgi Demonstrate image upload via a HTML form samples/samp-scale.html Form for samp-scale.cgi samples/samp-tags.cgi Demonstrate image upload via a HTML form samples/samp-tags.html Form for samp-tags.cgi samples/slant_text.pl Using $font->transform() to slant text samples/tk-photo.pl samples/wiggle.pl "Wiggle" stereoscopy scale.im Newer scaling code SGI/imsgi.c SGI/imsgi.h SGI/Makefile.PL SGI/SGI.pm SGI/SGI.xs SGI/t/00load.t SGI/t/10read.t SGI/t/20write.t SGI/t/30limit.t Test size limit checking SGI/testimg/rle.rgb SGI/testimg/rle12.rgb SGI/testimg/rle16.rgb SGI/testimg/rle6.rgb SGI/testimg/rleagr.rgb SGI/testimg/verb.rgb SGI/testimg/verb12.rgb SGI/testimg/verb16.rgb SGI/testimg/verb6.rgb spot.perl For making an ordered dither matrix from a spot function stackmach.c stackmach.h t/000-load.t Test Imager modules can be loaded t/100-base/010-introvert.t Test image inspection t/100-base/020-color.t Test Imager::Color t/100-base/030-countc.t Test getcolorcount() etc t/100-base/800-tr18561.t Regression test for RT #18561 t/100-base/801-tr18561b.t Regression test for RT #18561 t/150-type/020-sixteen.t Test 16-bit/sample images t/150-type/030-double.t Test double/sample images t/150-type/040-palette.t Test paletted images t/150-type/100-masked.t Test masked images t/200-file/010-iolayer.t Test Imager I/O layer objects t/200-file/100-files.t Format independent file tests t/200-file/200-nojpeg.t Test handling when jpeg not available t/200-file/210-nopng.t Test handling when png not available t/200-file/220-nogif.t Test handling when gif not available t/200-file/230-notiff.t Test handling when tiff not available t/200-file/300-raw.t Test raw file handling t/200-file/310-pnm.t Test PNM file handling t/200-file/320-bmp.t Test BMP file handling t/200-file/330-tga.t Test TGA file handling t/200-file/400-basic.t Test basic operations across file formats t/200-file/450-preload.t Test the preload class method t/250-draw/010-draw.t Basic drawing tests t/250-draw/020-flood.t Flood fill tests t/250-draw/030-paste.t Test the paste() method t/250-draw/040-rubthru.t Test the rubthrough() method t/250-draw/050-polyaa.t polygon() t/250-draw/060-polypoly.t polypolygon() t/250-draw/100-fill.t fills t/250-draw/200-compose.t compose() t/300-transform/010-scale.t scale(), scaleX() and scaleY() t/300-transform/020-combine.t Test combine() method t/300-transform/030-copyflip.t Test copy, flip, rotate, matrix_transform t/300-transform/040-crop.t t/300-transform/050-convert.t t/300-transform/060-map.t t/300-transform/500-trans.t transform() t/300-transform/600-trans2.t transform2() using RPN t/300-transform/610-postfix.t more transform2() using RPN t/300-transform/620-infix.t transform2() using infix t/300-transform/630-assem.t transform2() using assembler t/350-font/010-font.t General font interface tests t/350-font/020-tt.t low level FT1 tests t/350-font/030-ttoo.t OO level FT1 tests t/350-font/040-ttstd.t Standard font tests for TT t/350-font/100-texttools.t Test text wrapping t/400-filter/010-filters.t Consolidated filter tests (needs to split) t/450-api/100-inline.t Inline::C integration and API t/450-api/110-inlinectx.t context APIs t/850-thread/010-base.t Test wrt to perl threads t/850-thread/100-error.t error stack handling with threads t/850-thread/110-log.t log handling with threads t/900-util/010-test.t Test Imager::Test t/900-util/020-error.t Error stack t/900-util/030-log.t log t/900-util/040-limit.t file size limits t/900-util/050-matrix.t Imager::Matrix2d t/900-util/060-extutil.t Imager::ExtUtils t/900-util/060-hlines.t hlines.c internal API t/950-kwalitee/010-pod.t Test POD with Test::Pod t/950-kwalitee/020-samples.t Check samples are in samples/README t/950-kwalitee/030-podcover.t POD Coverage tests t/950-kwalitee/040-strict.t Check use strict is usede t/950-kwalitee/050-meta.t Check META.yml is valid t/950-kwalitee/060-podstruct.t t/GoodTestFont.pm A dummy (hardly implemented) font driver. t/Pod/Coverage/Imager.pm t/t1000lib/Imager/File/BAD.pm Test failing to load a file handler T1/fontfiles/ExistenceTest.afm please edit ExistenceTest.sfd in CVS T1/fontfiles/ExistenceTest.pfb to change these files, edited and T1/fontfiles/SpaceTest.afm test bounding box with spaces in t10type1.t T1/fontfiles/SpaceTest.pfb T1/imt1.c T1/imt1.h T1/Makefile.PL T1/README T1/t/t10type1.t T1/t/t20oo.t T1/t/t30thread.t T1/t/t90std.t Standard font tests for T1 T1/T1.pm T1/T1.xs T1/typemap tags.c testimg/alpha16.tga 16-bit/pixel TGA with alpha "channel" RT 32926 testimg/bad1oflow.bmp 1-bit/pixel, overflow integer on 32-bit machines testimg/bad1wid0.bmp 1-bit/pixel, zero width testimg/bad24comp.bmp 24-bit/pixel, bad compression testimg/bad24oflow.bmp 24-bit/pixel, overflow integer on 32-bit machines testimg/bad24wid0.bmp 24-bit/pixel, 0 width testimg/bad4oflow.bmp 4-bit/pixel, overflow integer on 32-bit machines testimg/bad4wid0.bmp 4-bit/pixel, 0 width testimg/bad4widbig.bmp 4-bit/pixel, large width testimg/bad8comp.bmp 8-bit/pixel, bad compression testimg/bad8oflow.bmp 8-bit/pixel, overflow integer on 32-bit machines testimg/bad8useda.bmp 8-bit/pixel, bad colors used value testimg/bad8wid0.bmp 8-bit/pixel, width 0 testimg/bad_asc.pbm ASCII PBM with invalid image data testimg/bad_asc.pgm ASCII PGM with invalid image data testimg/bad_asc.ppm ASCII PPM with invalid image data testimg/badbits.bmp bad bits value in header testimg/badcomp1.bmp bad compression for 1-bit/pixel testimg/badcomp4.bmp bad compression for 4-bit/pixel testimg/badplanes.bmp bad planes value in header testimg/badused1.bmp 1-bit/pixel, out of range colors used value testimg/badused4a.bmp 4-bit/pixel, badly out of range used value (SEGV test) testimg/badused4b.bmp 4-bit/pixel, just out of range used value (SEGV test) testimg/base.jpg Base JPEG test image testimg/comp4.bmp Compressed 4-bit/pixel BMP testimg/comp8.bmp Compressed 8-bit/pixel BMP testimg/filltest.ppm Test for flood fills testimg/gimpgrad A GIMP gradient file testimg/gradbad.ggr A bad GIMP gradient file (bad seg count) testimg/gradbad2.ggr A bad GIMP gradient file (bad segment) testimg/imager.pbm Test bi-level testimg/junk.ppm testimg/longid.tga Test TGA with a long id string testimg/maxval.ppm For ppm file maxval handling testimg/maxval_0.ppm testimg/maxval_256.ppm testimg/maxval_4095_asc.ppm testimg/maxval_65536.ppm testimg/maxval_asc.ppm testimg/multiple.ppm Test multiple PPM reading testimg/newgimpgrad.ggr Test GIMP Gradient file (newer type) testimg/penguin-base.ppm testimg/pgm.pgm Simple pgm for testing the right sample is in the right place testimg/scale.ppm testimg/short1.bmp 1-bit/pixel, data missing from EOF testimg/short24.bmp 24-bit/pixel, data missing from EOF testimg/short4.bmp truncated 4bit/pixel uncompressed BMP testimg/short4rle.bmp truncated 4bit/pixel compressed BMP testimg/short8.bmp 8-bit/pixel, data missing from EOF testimg/short8rle.bmp 8-bit/pixel compressed, data missing from EOF testimg/short_asc.pbm ASCII PBM with short image section testimg/short_asc.pgm ASCII PGM with short image section testimg/short_asc.ppm ASCII PPM with short image section testimg/short_bin.pbm Bin PBM with short image section testimg/short_bin.pgm Bin PGM with short image section testimg/short_bin.ppm Bin PPM with short image section testimg/short_bin16.pgm 16-bit Bin PGM with short image section testimg/short_bin16.ppm 16-bit Bin PPM with short image section testimg/simple.pbm testimg/test.png Standard test image as PNG testimg/test.raw Standard test image as RAW testimg/test.tga Standard test image as TGA testimg/test_gimp_pal A simple GIMP palette file testimg/tootall.ppm testimg/toowide.ppm testimg/winrgb2.bmp 1-bit bmp base testimg/winrgb24.bmp 24-bit bmp base testimg/winrgb24off.bmp 24-bit bmp with image data offset from header testimg/winrgb2off.bmp 1-bit bmp with image data offset from header testimg/winrgb4.bmp 4-bit bmp base testimg/winrgb4off.bmp 4-bit bmp with image data offset from header testimg/winrgb8.bmp 8-bit bmp base testimg/winrgb8off.bmp 8-bit bmp with image data offset from header tga.c Reading and writing Targa files TIFF/imtiff.c TIFF/imtiff.h TIFF/Makefile.PL TIFF/README TIFF/t/t10tiff.t Test tiff support TIFF/testimg/alpha.tif Alpha scaling test image TIFF/testimg/comp4.bmp Compressed 4-bit/pixel BMP TIFF/testimg/comp4.tif 4-bit/pixel paletted TIFF TIFF/testimg/comp4bad.tif corrupted 4-bit/pixel paletted TIFF TIFF/testimg/comp4t.tif 4-bit/pixel paletted TIFF (tiled) TIFF/testimg/comp8.bmp Compressed 8-bit/pixel BMP TIFF/testimg/comp8.tif 8-bit/pixel paletted TIFF TIFF/testimg/gralpha.tif Grey alpha test image TIFF/testimg/grey16.tif 16-bit/sample greyscale TIFF TIFF/testimg/grey16sg.tif signed 16-bit/sample greyscale TIFF TIFF/testimg/grey32.tif 32-bit/sample greyscale+alpha TIFF TIFF/testimg/imager.pbm Test bi-level TIFF/testimg/imager.tif Test bi-level TIFF/testimg/pengtile.tif Tiled tiff image, same as penguin-base.ppm TIFF/testimg/penguin-base.ppm TIFF/testimg/rgb16.tif 16-bit/sample RGB image - strips TIFF/testimg/rgb16t.tif 16-bit/sample RGB image - tiled TIFF/testimg/rgbatsep.tif Tiled/separated for testing RGBA codepath TIFF/testimg/scmyk.tif Simple CMYK TIFF image TIFF/testimg/scmyka.tif CMYK with one alpha channel TIFF/testimg/scmyka16.tif CMYK with one alpha channel (16-bit) TIFF/testimg/scmykaa.tif CMYK with 2 alpha channels TIFF/testimg/slab.tif Lab color image TIFF/testimg/srgb.tif Simple RGB image TIFF/testimg/srgba.tif RGB with one alpha TIFF/testimg/srgba16.tif TIFF/testimg/srgba32.tif TIFF/testimg/srgba32f.tif floating point sample RGBA TIFF/testimg/srgbaa.tif RGB with 2 alpha TIFF/testimg/tiffwarn.tif Generates a warning while being read TIFF/TIFF.pm TIFF/TIFF.xs trans2.c transform.perl Shell interface to Imager::Transform typemap typemap.local typemap for Imager.xs specific definitions typemap.oldperl typemap for older versions of perl W32/fontfiles/ExistenceTest.ttf W32/imw32.h W32/lib/Imager/Font/Win32.pm W32/Makefile.PL W32/README W32/t/t10win32.t Tests Win32 GDI font support W32/t/t90std.t Standard font tests for W32 W32/W32.pm W32/W32.xs W32/win32.c Implements font support through Win32 GDI META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) libimager-perl-1.004+dfsg.orig/regmach.h0000644000175000017500000000530512031434615017342 0ustar gregoagregoa#ifndef _REGMACH_H_ #define _REGMACH_H_ #include #include #include "imager.h" enum rm_byte_codes { rbc_add, /* ra + rb -> r*/ rbc_subtract, /* ra - rb -> r */ rbc_mult, /* ra * rb -> r */ rbc_div, /* ra / rb -> r */ rbc_mod, /* ra % rb -> r */ rbc_pow, /* ra ** rb -> r */ rbc_uminus, /* -ra -> r */ rbc_multp, /* pa ** rb -> p */ rbc_addp, /* pa + pb -> p */ rbc_subtractp, /* pa - pb -> p */ /* rbcParm, we just preload a register */ rbc_sin, /* sin(ra) -> r */ rbc_cos, /* cos(ra) -> r */ rbc_atan2, /* atan2(ra,rb) -> r */ rbc_sqrt, /* sqrt(ra) -> r */ rbc_distance, /* distance(rx, ry, rx, ry) -> r */ /* getp? codes must be in order */ rbc_getp1, /* getp1(ra, rb) -> p */ rbc_getp2, /* getp2(ra, rb) -> p */ rbc_getp3, /* getp3(ra, rb) -> p */ rbc_value, /* value(pa) -> r */ rbc_hue, /* hue(pa) -> r */ rbc_sat, /* sat(pa) -> r */ rbc_hsv, /* hsv(rh, rs, rv) -> p */ rbc_red, /* red(pa) -> r */ rbc_green, /* green(pa) -> r */ rbc_blue, /* blue(pa) -> r */ rbc_rgb, /* rgb(rr, rg, rb) -> p */ rbc_int, /* int(ra) -> r */ rbc_if, /* if(rc, rt, rf) -> r */ rbc_ifp, /* if(rc, pt, pf) -> p */ rbc_le, /* ra <= rb -> r */ rbc_lt, /* ra < rb -> r */ rbc_ge, /* ra >= rb -> r */ rbc_gt, /* ra > rb -> r */ rbc_eq, /* ra == rb -> r -- does approx equal */ rbc_ne, /* ra != rb -> r -- does approx equal */ rbc_and, /* ra && rb -> r */ rbc_or, /* ra || rb -> r */ rbc_not, /* !ra -> r */ rbc_abs, /* abs(ra) -> r */ rbc_ret, /* returns pa */ rbc_jump, /* jump to ja */ rbc_jumpz, /* jump if ra == 0 to jb */ rbc_jumpnz, /* jump if ra != 0 to jb */ rbc_set, /* ra -> r */ rbc_setp, /* pa -> p*/ rbc_print, /* print(ra) -> r -- prints, leaves on stack */ rbc_rgba, /* rgba(ra, rb, rc, rd) -> p */ rbc_hsva, /* hsva(ra, rb, rc, rd) -> p */ rbc_alpha, /* alpha(pa) -> r */ rbc_log, /* log(ra) -> r */ rbc_exp, /* exp(ra) -> r */ rbc_det, /* det(ra, rb, rc, rd) -> r */ rbc_op_count }; /* rm_word was originally char, but even for some simpler expressions I was getting close to running out of register numbers. It should also simplify structure alignment issues. (I hope.) */ typedef int rm_word; #define RM_WORD_PACK "i" struct rm_op { rm_word code; /* op code */ rm_word ra; /* first operand */ rm_word rb; /* possible second operand */ rm_word rc; /* possible third operand */ rm_word rd; /* possible fourth operand */ rm_word rout; /* output register */ }; i_color i_rm_run(struct rm_op codes[], size_t code_count, double n_regs[], size_t n_regs_count, i_color c_regs[], size_t c_regs_count, i_img *images[], size_t image_count); /* op_run(fx, sizeof(fx), parms, 2)) */ #endif /* _REGMACH_H_ */ libimager-perl-1.004+dfsg.orig/FT2/0000755000175000017500000000000012617614576016173 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/FT2/typemap0000644000175000017500000000004212031434613017547 0ustar gregoagregoaImager::Font::FT2x T_PTROBJ libimager-perl-1.004+dfsg.orig/FT2/FT2.xs0000644000175000017500000002144612263740577017147 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "imft2.h" DEFINE_IMAGER_CALLBACKS; MODULE = Imager::Font::FT2 PACKAGE = Imager::Font::FT2x PREFIX=FT2_ #define FT2_DESTROY(font) i_ft2_destroy(font) void FT2_DESTROY(font) Imager::Font::FT2x font int FT2_CLONE_SKIP(...) CODE: (void)items; RETVAL = 1; OUTPUT: RETVAL MODULE = Imager::Font::FT2 PACKAGE = Imager::Font::FT2 Imager::Font::FT2x i_ft2_new(name, index) char *name int index const char * i_ft2_version(runtime) int runtime PREINIT: char buf[100]; CODE: if (!i_ft2_version(runtime, buf, sizeof(buf))) { XSRETURN_EMPTY; } RETVAL = buf; OUTPUT: RETVAL undef_int i_ft2_setdpi(font, xdpi, ydpi) Imager::Font::FT2x font int xdpi int ydpi void i_ft2_getdpi(font) Imager::Font::FT2x font PREINIT: int xdpi, ydpi; CODE: if (i_ft2_getdpi(font, &xdpi, &ydpi)) { EXTEND(SP, 2); PUSHs(sv_2mortal(newSViv(xdpi))); PUSHs(sv_2mortal(newSViv(ydpi))); } undef_int i_ft2_sethinting(font, hinting) Imager::Font::FT2x font int hinting undef_int i_ft2_settransform(font, matrix) Imager::Font::FT2x font PREINIT: double matrix[6]; int len; AV *av; SV *sv1; int i; CODE: if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("i_ft2_settransform: parameter 2 must be an array ref\n"); av=(AV*)SvRV(ST(1)); len=av_len(av)+1; if (len > 6) len = 6; for (i = 0; i < len; ++i) { sv1=(*(av_fetch(av,i,0))); matrix[i] = SvNV(sv1); } for (; i < 6; ++i) matrix[i] = 0; RETVAL = i_ft2_settransform(font, matrix); OUTPUT: RETVAL void i_ft2_bbox(font, cheight, cwidth, text_sv, utf8) Imager::Font::FT2x font double cheight double cwidth SV *text_sv int utf8 PREINIT: i_img_dim bbox[BOUNDING_BOX_COUNT]; int i; char *text; STRLEN text_len; int rc; PPCODE: text = SvPV(text_sv, text_len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8); if (rc) { EXTEND(SP, rc); for (i = 0; i < rc; ++i) PUSHs(sv_2mortal(newSViv(bbox[i]))); } void i_ft2_bbox_r(font, cheight, cwidth, text_sv, vlayout, utf8) Imager::Font::FT2x font double cheight double cwidth SV *text_sv int vlayout int utf8 PREINIT: i_img_dim bbox[8]; int i; const char *text; STRLEN len; PPCODE: text = SvPV(text_sv, len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif if (i_ft2_bbox_r(font, cheight, cwidth, text, len, vlayout, utf8, bbox)) { EXTEND(SP, 8); for (i = 0; i < 8; ++i) PUSHs(sv_2mortal(newSViv(bbox[i]))); } undef_int i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text_sv, align, aa, vlayout, utf8) Imager::Font::FT2x font Imager::ImgRaw im i_img_dim tx i_img_dim ty Imager::Color cl double cheight double cwidth SV *text_sv int align int aa int vlayout int utf8 PREINIT: const char *text; STRLEN len; CODE: text = SvPV(text_sv, len); #ifdef SvUTF8 if (SvUTF8(text_sv)) { utf8 = 1; } #endif RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, len, align, aa, vlayout, utf8); OUTPUT: RETVAL undef_int i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8) Imager::Font::FT2x font Imager::ImgRaw im i_img_dim tx i_img_dim ty int channel double cheight double cwidth SV *text_sv int align int aa int vlayout int utf8 PREINIT: char const *text; STRLEN len; CODE: text = SvPV(text_sv, len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, len, align, aa, vlayout, utf8); OUTPUT: RETVAL void ft2_transform_box(font, x0, x1, x2, x3) Imager::Font::FT2x font i_img_dim x0 i_img_dim x1 i_img_dim x2 i_img_dim x3 PREINIT: i_img_dim box[4]; PPCODE: box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3; ft2_transform_box(font, box); EXTEND(SP, 4); PUSHs(sv_2mortal(newSViv(box[0]))); PUSHs(sv_2mortal(newSViv(box[1]))); PUSHs(sv_2mortal(newSViv(box[2]))); PUSHs(sv_2mortal(newSViv(box[3]))); void i_ft2_has_chars(handle, text_sv, utf8) Imager::Font::FT2x handle SV *text_sv int utf8 PREINIT: char *text; STRLEN len; char *work; size_t count; size_t i; PPCODE: text = SvPV(text_sv, len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif work = mymalloc(len); count = i_ft2_has_chars(handle, text, len, utf8, work); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) { PUSHs(boolSV(work[i])); } } else { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(work, count))); } myfree(work); void i_ft2_face_name(handle) Imager::Font::FT2x handle PREINIT: char name[255]; size_t len; PPCODE: len = i_ft2_face_name(handle, name, sizeof(name)); if (len) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(name, 0))); } undef_int i_ft2_can_face_name() void i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1) Imager::Font::FT2x handle SV *text_sv int utf8 int reliable_only PREINIT: char const *text; STRLEN work_len; size_t len; char name[255]; SSize_t count = 0; PPCODE: i_clear_error(); text = SvPV(text_sv, work_len); len = work_len; #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif while (len) { unsigned long ch; if (utf8) { ch = i_utf8_advance(&text, &len); if (ch == ~0UL) { i_push_error(0, "invalid UTF8 character"); XSRETURN_EMPTY; } } else { ch = *text++; --len; } EXTEND(SP, count+1); if (i_ft2_glyph_name(handle, ch, name, sizeof(name), reliable_only)) { ST(count) = sv_2mortal(newSVpv(name, 0)); } else { ST(count) = &PL_sv_undef; } ++count; } XSRETURN(count); int i_ft2_can_do_glyph_names() int i_ft2_face_has_glyph_names(handle) Imager::Font::FT2x handle int i_ft2_is_multiple_master(handle) Imager::Font::FT2x handle void i_ft2_get_multiple_masters(handle) Imager::Font::FT2x handle PREINIT: i_font_mm mm; int i; PPCODE: if (i_ft2_get_multiple_masters(handle, &mm)) { EXTEND(SP, 2+mm.num_axis); PUSHs(sv_2mortal(newSViv(mm.num_axis))); PUSHs(sv_2mortal(newSViv(mm.num_designs))); for (i = 0; i < mm.num_axis; ++i) { AV *av = newAV(); SV *sv; av_extend(av, 3); sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name)); SvREFCNT_inc(sv); av_store(av, 0, sv); sv = newSViv(mm.axis[i].minimum); SvREFCNT_inc(sv); av_store(av, 1, sv); sv = newSViv(mm.axis[i].maximum); SvREFCNT_inc(sv); av_store(av, 2, sv); PUSHs(newRV_noinc((SV *)av)); } } undef_int i_ft2_set_mm_coords(handle, ...) Imager::Font::FT2x handle PROTOTYPE: DISABLE PREINIT: long *coords; int ix_coords, i; CODE: /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so transfer the array manually */ ix_coords = items-1; coords = mymalloc(sizeof(long) * ix_coords); for (i = 0; i < ix_coords; ++i) { coords[i] = (long)SvIV(ST(1+i)); } RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords); myfree(coords); OUTPUT: RETVAL BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; i_ft2_start(); libimager-perl-1.004+dfsg.orig/FT2/README0000644000175000017500000000102212263740577017044 0ustar gregoagregoaImager::Font::FT2 provides font support to Imager via the FreeType 2 library. It requires libfreetype and its development header files to be installed. For Linux distributions this typically requires installation of the associated -dev or -devel package. See Imager::Install for more information. Imager::Font::FT2 is currently shipped as part of Imager, but but Imager may install with out installing Imager::Font::FT2. If your module or application requires FreeType 2 support then add Imager::Font::FT2 as a prerequisite. libimager-perl-1.004+dfsg.orig/FT2/imft2.h0000644000175000017500000000454712263740577017375 0ustar gregoagregoa#ifndef IMAGER_FT2_H #define IMAGER_FT2_H #include "imdatatypes.h" typedef struct FT2_Fonthandle FT2_Fonthandle; typedef FT2_Fonthandle* Imager__Font__FT2x; extern int i_ft2_version(int runtime, char *buf, size_t buf_size); extern void i_ft2_start(void); extern FT2_Fonthandle * i_ft2_new(const char *name, int index); extern void i_ft2_destroy(FT2_Fonthandle *handle); extern int i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi); extern int i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi); extern int i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix); extern int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting); extern int i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char const *text, size_t len, i_img_dim *bbox, int utf8); extern int i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char const *text, size_t len, int vlayout, int utf8, i_img_dim *bbox); extern int i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const i_color *cl, double cheight, double cwidth, char const *text, size_t len, int align, int aa, int vlayout, int utf8); extern int i_ft2_cp(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, int channel, double cheight, double cwidth, char const *text, size_t len, int align, int aa, int vlayout, int utf8); extern size_t i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len, int utf8, char *work); extern size_t i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size); extern int i_ft2_can_face_name(void); extern int i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, size_t name_buf_size, int reliable_only); extern int i_ft2_can_do_glyph_names(void); extern int i_ft2_face_has_glyph_names(FT2_Fonthandle *handle); extern int i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm); extern int i_ft2_is_multiple_master(FT2_Fonthandle *handle); extern int i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords); void ft2_transform_box(FT2_Fonthandle *handle, i_img_dim bbox[4]); #endif libimager-perl-1.004+dfsg.orig/FT2/t/0000755000175000017500000000000012617614576016436 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/FT2/t/t10ft2.t0000644000175000017500000006066212263740577017653 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 204; use Cwd qw(getcwd abs_path); use Imager qw(:all); use Imager::Test qw(diff_text_with_nul is_color3 is_color4 isnt_image is_image); -d "testout" or mkdir "testout"; my @test_output; push @test_output, "t38ft2font.log"; Imager->open_log(log => "testout/t38ft2font.log"); my $deffont = "fontfiles/dodge.ttf"; my @base_color = (64, 255, 64); SKIP: { ok($Imager::formats{ft2}, "ft2 should be in %formats"); my $fontname=$ENV{'TTFONTTEST'} || $deffont; -f $fontname or skip("cannot find fontfile $fontname", 189); print STDERR "FreeType2 runtime ", Imager::Font::FT2::i_ft2_version(1), " compile-time ", Imager::Font::FT2::i_ft2_version(0), "\n"; my $bgcolor=i_color_new(255,0,0,0); my $overlay=Imager::ImgRaw::new(200,70,3); my $ttraw=Imager::Font::FT2::i_ft2_new($fontname, 0); $ttraw or print Imager::_error_as_msg(),"\n"; ok($ttraw, "loaded raw font"); my @bbox=Imager::Font::FT2::i_ft2_bbox($ttraw, 50.0, 0, 'XMCLH', 0); print "#bbox @bbox\n"; is(@bbox, 8, "i_ft2_bbox() returns 8 values"); ok(Imager::Font::FT2::i_ft2_cp($ttraw,$overlay,5,50,1,50.0,50, 'XMCLH',1,1, 0, 0), "drawn to channel"); i_line($overlay,0,50,100,50,$bgcolor,1); push @test_output, "t38ft2font.ppm"; open(FH,">testout/t38ft2font.ppm") || die "cannot open testout/t38ft2font.ppm\n"; binmode(FH); my $IO = Imager::io_new_fd(fileno(FH)); ok(i_writeppm_wiol($overlay, $IO), "saved image"); close(FH); $bgcolor=i_color_set($bgcolor,200,200,200,0); my $backgr=Imager::ImgRaw::new(500,300,3); # i_tt_set_aa(2); ok(Imager::Font::FT2::i_ft2_text($ttraw,$backgr,100,150,NC(255, 64, 64),200.0,50, 'MAW',1,1,0, 0), "drew MAW"); Imager::Font::FT2::i_ft2_settransform($ttraw, [0.9659, 0.2588, 0, -0.2588, 0.9659, 0 ]); ok(Imager::Font::FT2::i_ft2_text($ttraw,$backgr,100,150,NC(0, 128, 0),200.0,50, 'MAW',0,1, 0, 0), "drew rotated MAW"); i_line($backgr, 0,150, 499, 150, NC(0, 0, 255),1); push @test_output, "t38ft2font2.ppm"; open(FH,">testout/t38ft2font2.ppm") || die "cannot open testout/t38ft2font.ppm\n"; binmode(FH); $IO = Imager::io_new_fd(fileno(FH)); ok(i_writeppm_wiol($backgr,$IO), "saved second image"); close(FH); my $oof = Imager::Font->new(file=>$fontname, type=>'ft2', 'index'=>0); ok($oof, "loaded OO font"); my $im = Imager->new(xsize=>400, ysize=>250); ok($im->string(font=>$oof, text=>"Via OO", 'x'=>20, 'y'=>20, size=>60, color=>NC(255, 128, 255), aa => 1, align=>0), "drawn through OO interface"); ok($oof->transform(matrix=>[1, 0.1, 0, 0, 1, 0]), "set matrix via OO interface"); ok($im->string(font=>$oof, text=>"Shear", 'x'=>20, 'y'=>40, size=>60, sizew=>50, channel=>1, aa=>1, align=>1), "drawn transformed through OO"); use Imager::Matrix2d ':handy'; ok($oof->transform(matrix=>m2d_rotate(degrees=>-30)), "set transform from m2d module"); ok($im->string(font=>$oof, text=>"SPIN", 'x'=>20, 'y'=>50, size=>50, sizew=>40, color=>NC(255,255,0), aa => 1, align=>0, vlayout=>0), "drawn first rotated"); ok($im->string(font=>$oof, text=>"SPIN", 'x'=>20, 'y'=>50, size=>50, sizew=>40, channel=>2, aa => 1, align=>0, vlayout=>0), "drawn second rotated"); $oof->transform(matrix=>m2d_identity()); $oof->hinting(hinting=>1); # UTF8 testing # the test font (dodge.ttf) only supports one character above 0xFF that # I can see, 0x2010 HYPHEN (which renders the same as 0x002D HYPHEN MINUS) # an attempt at utf8 support # first attempt to use native perl UTF8 SKIP: { skip("no native UTF8 support in this version of perl", 1) unless $] >= 5.006; my $text; # we need to do this in eval to prevent compile time errors in older # versions eval q{$text = "A\x{2010}A"}; # A, HYPHEN, A in our test font #$text = "A".chr(0x2010)."A"; # this one works too unless (ok($im->string(font=>$oof, text=>$text, 'x'=>20, 'y'=>200, size=>50, color=>NC(0,255,0), aa=>1), "drawn UTF natively")) { print "# ",$im->errstr,"\n"; } } # an attempt using emulation of UTF8 my $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41); #my $text = "A\xE2\x80\x90\x41\x{2010}"; #substr($text, -1, 0) = ''; unless (ok($im->string(font=>$oof, text=>$text, 'x'=>20, 'y'=>230, size=>50, color=>NC(255,128,0), aa=>1, utf8=>1), "drawn UTF emulated")) { print "# ",$im->errstr,"\n"; } # just a bit of fun # well it was - it demostrates what happens when you combine # transformations and font hinting for my $steps (0..39) { $oof->transform(matrix=>m2d_rotate(degrees=>-$steps+5)); # demonstrates why we disable hinting on a doing a transform # if the following line is enabled then the 0 degrees output sticks # out a bit # $oof->hinting(hinting=>1); $im->string(font=>$oof, text=>"SPIN", 'x'=>160, 'y'=>70, size=>65, color=>NC(255, $steps * 5, 200-$steps * 5), aa => 1, align=>0, ); } push @test_output, "t38_oo.ppm"; $im->write(file=>'testout/t38_oo.ppm') or print "# could not save OO output: ",$im->errstr,"\n"; my (@got) = $oof->has_chars(string=>"\x01H"); ok(@got == 2, "has_chars returned 2 items"); ok(!$got[0], "have no chr(1)"); ok($got[1], "have 'H'"); is($oof->has_chars(string=>"H\x01"), "\x01\x00", "scalar has_chars()"); print "# OO bounding boxes\n"; @bbox = $oof->bounding_box(string=>"hello", size=>30); my $bbox = $oof->bounding_box(string=>"hello", size=>30); is(@bbox, 8, "list bbox returned 8 items"); ok($bbox->isa('Imager::Font::BBox'), "scalar bbox returned right class"); ok($bbox->start_offset == $bbox[0], "start_offset"); ok($bbox->end_offset == $bbox[2], "end_offset"); ok($bbox->global_ascent == $bbox[3], "global_ascent"); ok($bbox->global_descent == $bbox[1], "global_descent"); ok($bbox->ascent == $bbox[5], "ascent"); ok($bbox->descent == $bbox[4], "descent"); ok($bbox->advance_width == $bbox[6], "advance_width"); print "# aligned text output\n"; my $alimg = Imager->new(xsize=>300, ysize=>300); $alimg->box(color=>'40FF40', filled=>1); $oof->transform(matrix=>m2d_identity()); $oof->hinting(hinting=>1); align_test('left', 'top', 10, 10, $oof, $alimg); align_test('start', 'top', 10, 40, $oof, $alimg); align_test('center', 'top', 150, 70, $oof, $alimg); align_test('end', 'top', 290, 100, $oof, $alimg); align_test('right', 'top', 290, 130, $oof, $alimg); align_test('center', 'top', 150, 160, $oof, $alimg); align_test('center', 'center', 150, 190, $oof, $alimg); align_test('center', 'bottom', 150, 220, $oof, $alimg); align_test('center', 'baseline', 150, 250, $oof, $alimg); push @test_output, "t38aligned.ppm"; ok($alimg->write(file=>'testout/t38aligned.ppm'), "saving aligned output image"); my $exfont = Imager::Font->new(file=>'fontfiles/ExistenceTest.ttf', type=>'ft2'); SKIP: { ok($exfont, "loaded existence font") or diag(Imager->errstr); $exfont or skip("couldn't load test font", 11); # the test font is known to have a shorter advance width for that char my @bbox = $exfont->bounding_box(string=>"/", size=>100); is(@bbox, 8, "should be 8 entries"); isnt($bbox[6], $bbox[2], "different advance width"); my $bbox = $exfont->bounding_box(string=>"/", size=>100); ok($bbox->pos_width != $bbox->advance_width, "OO check"); cmp_ok($bbox->right_bearing, '<', 0, "check right bearing"); cmp_ok($bbox->display_width, '>', $bbox->advance_width, "check display width (roughly)"); # check with a char that fits inside the box $bbox = $exfont->bounding_box(string=>"!", size=>100); print "# pos width ", $bbox->pos_width, "\n"; is($bbox->pos_width, $bbox->advance_width, "check backwards compatibility"); cmp_ok($bbox->left_bearing, '>', 0, "left bearing positive"); cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive"); cmp_ok($bbox->display_width, '<', $bbox->advance_width, "display smaller than advance"); # name tests # make sure the number of tests on each branch match if (Imager::Font::FT2::i_ft2_can_face_name()) { my $facename = Imager::Font::FT2::i_ft2_face_name($exfont->{id}); print "# face name '$facename'\n"; is($facename, 'ExistenceTest', "test face name"); $facename = $exfont->face_name; is($facename, 'ExistenceTest', "test face name OO"); } else { # make sure we get the error we expect my $facename = Imager::Font::FT2::i_ft2_face_name($exfont->{id}); my ($msg) = Imager::_error_as_msg(); ok(!defined($facename), "test face name not supported"); print "# $msg\n"; ok(scalar($msg =~ /or later required/), "test face name not supported"); } } SKIP: { Imager::Font::FT2->can_glyph_names or skip("FT2 compiled without glyph names support", 9); # FT2 considers POST tables in TTF fonts unreliable, so use # a type 1 font, see below for TTF test my $exfont = Imager::Font->new(file=>'fontfiles/ExistenceTest.pfb', type=>'ft2'); SKIP: { ok($exfont, "load Type 1 via FT2") or skip("couldn't load type 1 with FT2", 8); my @glyph_names = Imager::Font::FT2::i_ft2_glyph_name($exfont->{id}, "!J/"); #use Data::Dumper; #print Dumper \@glyph_names; is($glyph_names[0], 'exclam', "check exclam name"); ok(!defined($glyph_names[1]), "check for no J name"); is($glyph_names[2], 'slash', "check slash name"); # oo interfaces @glyph_names = $exfont->glyph_names(string=>"!J/"); is($glyph_names[0], 'exclam', "check exclam name OO"); ok(!defined($glyph_names[1]), "check for no J name OO"); is($glyph_names[2], 'slash', "check slash name OO"); # make sure a missing string parameter is handled correctly eval { $exfont->glyph_names(); }; is($@, "", "correct error handling"); cmp_ok(Imager->errstr, '=~', qr/no string parameter/, "error message"); } # freetype 2 considers truetype glyph name tables unreliable # due to some specific fonts, supplying reliable_only=>0 bypasses # that check and lets us get the glyph names even for truetype fonts # so we can test this stuff # we can't use ExistenceTest.ttf since that's generated with # AppleStandardEncoding since the same .sfd needs to generate # a .pfb file, NameTest.ttf uses a Unicode encoding # we were using an unsigned char to store a unicode character # https://rt.cpan.org/Ticket/Display.html?id=7949 $exfont = Imager::Font->new(file=>'fontfiles/NameTest.ttf', type=>'ft2'); SKIP: { ok($exfont, "load TTF via FT2") or skip("could not load TTF with FT2", 1); my $text = pack("C*", 0xE2, 0x80, 0x90); # "\x{2010}" as utf-8 my @names = $exfont->glyph_names(string=>$text, utf8=>1, reliable_only=>0); is($names[0], "hyphentwo", "check utf8 glyph name"); } } # check that error codes are translated correctly my $errfont = Imager::Font->new(file=>"t/t10ft2.t", type=>"ft2"); is($errfont, undef, "new font vs non font"); cmp_ok(Imager->errstr, '=~', qr/unknown file format/, "check error message"); # Multiple Master tests # we check a non-MM font errors correctly print "# check that the methods act correctly for a non-MM font\n"; ok(!$exfont->is_mm, "exfont not MM"); ok((() = $exfont->mm_axes) == 0, "exfont has no MM axes"); cmp_ok(Imager->errstr, '=~', qr/no multiple masters/, "and returns correct error when we ask"); ok(!$exfont->set_mm_coords(coords=>[0, 0]), "fail setting axis on exfont"); cmp_ok(Imager->errstr, '=~', qr/no multiple masters/, "and returns correct error when we ask"); # try a MM font now - test font only has A defined print "# Try a multiple master font\n"; my $mmfont = Imager::Font->new(file=>"fontfiles/MMOne.pfb", type=>"ft2", color=>"white", aa=>1, size=>60); ok($mmfont, "loaded MM font") or print "# ", Imager->errstr, "\n"; ok($mmfont->is_mm, "font is multiple master"); my @axes = $mmfont->mm_axes; is(@axes, 2, "check we got both axes"); is($axes[0][0], "Weight", "name of first axis"); is($axes[0][1], 50, "min for first axis"); is($axes[0][2], 999, "max for first axis"); is($axes[1][0], "Slant", "name of second axis"); is($axes[1][1], 0, "min for second axis"); is($axes[1][2], 999, "max for second axis"); my $mmim = Imager->new(xsize=>200, ysize=>200); $mmim->string(font=>$mmfont, x=>0, 'y'=>50, text=>"A"); ok($mmfont->set_mm_coords(coords=>[ 700, 0 ]), "set to bold, unsloped"); $mmim->string(font=>$mmfont, x=>0, 'y'=>100, text=>"A", color=>'blue'); my @weights = qw(50 260 525 760 999); my @slants = qw(0 333 666 999); for my $windex (0 .. $#weights) { my $weight = $weights[$windex]; for my $sindex (0 .. $#slants) { my $slant = $slants[$sindex]; $mmfont->set_mm_coords(coords=>[ $weight, $slant ]); $mmim->string(font=>$mmfont, x=>30+32*$windex, 'y'=>50+45*$sindex, text=>"A"); } } push @test_output, "t38mm.ppm"; ok($mmim->write(file=>"testout/t38mm.ppm"), "save MM output"); SKIP: { print "# alignment tests\n"; my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2'); ok($font, "loaded deffont OO") or skip("could not load font:".Imager->errstr, 4); my $im = Imager->new(xsize=>140, ysize=>150); my %common = ( font=>$font, size=>40, aa=>1, ); $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue'); $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue'); $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); for my $args ([ x=>5, text=>"A", color=>"white" ], [ x=>40, text=>"y", color=>"white" ], [ x=>75, text=>"A", channel=>1 ], [ x=>110, text=>"y", channel=>1 ]) { ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); } push @test_output, "t38align.ppm"; ok($im->write(file=>'testout/t38align.ppm'), "save align image"); } { # outputting a space in non-AA could either crash # or fail (ft 2.2+) my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2'); my $im = Imager->new(xsize => 100, ysize => 100); ok($im->string(x => 10, y => 10, string => "test space", aa => 0, color => '#FFF', size => 8, font => $font), "draw space non-antialiased (color)"); ok($im->string(x => 10, y => 50, string => "test space", aa => 0, channel => 0, size => 8, font => $font), "draw space non-antialiased (channel)"); } { # cannot output "0" # https://rt.cpan.org/Ticket/Display.html?id=21770 my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2'); ok($font, "loaded imugly"); my $imbase = Imager->new(xsize => 100, ysize => 100); my $im = $imbase->copy; ok($im->string(x => 10, y => 50, string => "0", aa => 0, color => '#FFF', size => 20, font => $font), "draw '0'"); ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}), "make sure we actually drew it"); $im = $imbase->copy; ok($im->string(x => 10, y => 50, string => 0.0, aa => 0, color => '#FFF', size => 20, font => $font), "draw 0.0"); ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}), "make sure we actually drew it"); } { # string output cut off at NUL ('\0') # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2'); ok($font, "loaded imugly"); diff_text_with_nul("a\\0b vs a", "a\0b", "a", font => $font, color => '#FFFFFF'); diff_text_with_nul("a\\0b vs a", "a\0b", "a", font => $font, channel => 1); # UTF8 encoded \x{2010} my $dash = pack("C*", 0xE2, 0x80, 0x90); diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash, font => $font, color => '#FFFFFF', utf8 => 1); diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash, font => $font, channel => 1, utf8 => 1); } { # RT 11972 # when rendering to a transparent image the coverage should be # expressed in terms of the alpha channel rather than the color my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2'); my $im = Imager->new(xsize => 40, ysize => 20, channels => 4); ok($im->string(string => "AB", size => 20, aa => 1, color => '#F00', x => 0, y => 15, font => $font), "draw to transparent image"); my $im_noalpha = $im->convert(preset => 'noalpha'); my $im_pal = $im->to_paletted(make_colors => 'mediancut'); my @colors = $im_pal->getcolors; is(@colors, 2, "should be only 2 colors"); @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors; is_color3($colors[0], 0, 0, 0, "check we got black"); is_color3($colors[1], 255, 0, 0, "and red"); } { # RT 27546 my $im = Imager->new(xsize => 100, ysize => 100, channels => 4); $im->box(filled => 1, color => '#ff0000FF'); my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2'); ok($im->string(x => 0, 'y' => 40, text => 'test', size => 11, sizew => 11, font => $font, aa => 1), 'draw on translucent image') } { # RT 60199 # not ft2 specific, but Imager my $im = Imager->new(xsize => 100, ysize => 100); my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2'); my $imcopy = $im->copy; ok($im, "make test image"); ok($font, "make test font"); ok($im->align_string(valign => "center", halign => "center", x => 50, y => 50, string => "0", color => "#FFF", font => $font), "draw 0 aligned"); ok(Imager::i_img_diff($im->{IMG}, $imcopy->{IMG}), "make sure we drew the '0'"); } SKIP: { # RT 60509 # checks that a c:foo or c:\foo path is handled correctly on win32 my $type = "ft2"; $^O eq "MSWin32" || $^O eq "cygwin" or skip("only for win32", 2); my $dir = getcwd or skip("Cannot get cwd", 2); if ($^O eq "cygwin") { $dir = Cygwin::posix_to_win_path($dir); } my $abs_path = abs_path($deffont); my $font = Imager::Font->new(file => $abs_path, type => $type); ok($font, "found font by absolute path") or print "# path $abs_path\n"; undef $font; $^O eq "cygwin" and skip("cygwin doesn't support drive relative DOSsish paths", 1); my ($drive) = $dir =~ /^([a-z]:)/i or skip("cwd has no drive letter", 2); my $drive_path = $drive . $deffont; $font = Imager::Font->new(file => $drive_path, type => $type); ok($font, "found font by drive relative path") or print "# path $drive_path\n"; } { # RT 71469 my $font1 = Imager::Font->new(file => $deffont, type => "ft2", index => 0); my $font2 = Imager::Font::FT2->new(file => $deffont, index => 0); for my $font ($font1, $font2) { print "# ", join(",", $font->{color}->rgba), "\n"; my $im = Imager->new(xsize => 20, ysize => 20, channels => 4); ok($im->string(text => "T", font => $font, y => 15), "draw with default color") or print "# ", $im->errstr, "\n"; my $work = Imager->new(xsize => 20, ysize => 20); my $cmp = $work->copy; $work->rubthrough(src => $im); isnt_image($work, $cmp, "make sure something was drawn"); } } { # RT 73359 # non-AA font drawing isn't normal mode Imager->log("testing no-aa normal output\n"); my $font = Imager::Font->new(file => "fontfiles/ImUgly.ttf", type => "ft2"); ok($font, "make a work font"); my %common = ( x => 10, font => $font, size => 25, aa => 0, align => 0, ); # build our comparison image my $cmp = Imager->new(xsize => 120, ysize => 100); my $layer = Imager->new(xsize => 120, ysize => 100, channels => 4); ok($layer->string(%common, y => 10, text => "full", color => "#8080FF"), "draw non-aa text at full coverage to layer image"); ok($layer->string(%common, y => 40, text => "half", color => "#FF808080"), "draw non-aa text at half coverage to layer image"); ok($layer->string(%common, y => 70, text => "quarter", color => "#80FF8040"), "draw non-aa text at zero coverage to layer image"); ok($cmp->rubthrough(src => $layer), "rub layer onto comparison image"); my $im = Imager->new(xsize => 120, ysize => 100); ok($im->string(%common, y => 10, text => "full", color => "#8080FF"), "draw non-aa text at full coverage"); ok($im->string(%common, y => 40, text => "half", color => "#FF808080"), "draw non-aa text at half coverage"); ok($im->string(%common, y => 70, text => "quarter", color => "#80FF8040"), "draw non-aa text at zero coverage"); is_image($im, $cmp, "check the result"); push @test_output, "noaanorm.ppm", "noaacmp.ppm"; ok($cmp->write(file => "testout/noaacmp.ppm"), "save cmp image") or diag "Saving cmp image: ", $cmp->errstr; ok($im->write(file => "testout/noaanorm.ppm"), "save test image") or diag "Saving result image: ", $im->errstr; } } Imager->close_log(); END { unless ($ENV{IMAGER_KEEP_FILES}) { unlink map "testout/$_", @test_output; } } sub align_test { my ($h, $v, $x, $y, $f, $img) = @_; my @pos = $f->align(halign=>$h, valign=>$v, 'x'=>$x, 'y'=>$y, image=>$img, size=>15, color=>'FFFFFF', string=>"x$h ${v}y", channel=>1, aa=>1); @pos = $img->align_string(halign=>$h, valign=>$v, 'x'=>$x, 'y'=>$y, font=>$f, size=>15, color=>'FF99FF', string=>"x$h ${v}y", aa=>1); if (ok(@pos == 4, "$h $v aligned output")) { # checking corners my $cx = int(($pos[0] + $pos[2]) / 2); my $cy = int(($pos[1] + $pos[3]) / 2); print "# @pos cx $cx cy $cy\n"; okmatchcolor($img, $cx, $pos[1]-1, @base_color, "outer top edge"); okmatchcolor($img, $cx, $pos[3], @base_color, "outer bottom edge"); okmatchcolor($img, $pos[0]-1, $cy, @base_color, "outer left edge"); okmatchcolor($img, $pos[2], $cy, @base_color, "outer right edge"); okmismatchcolor($img, $cx, $pos[1], @base_color, "inner top edge"); okmismatchcolor($img, $cx, $pos[3]-1, @base_color, "inner bottom edge"); okmismatchcolor($img, $pos[0], $cy, @base_color, "inner left edge"); # okmismatchcolor($img, $pos[2]-1, $cy, @base_color, "inner right edge"); # XXX: This gets triggered by a freetype2 bug I think # $ rpm -qa | grep freetype # freetype-2.1.3-6 # # (addi: 4/1/2004). cross($img, $x, $y, 'FF0000'); cross($img, $cx, $pos[1]-1, '0000FF'); cross($img, $cx, $pos[3], '0000FF'); cross($img, $pos[0]-1, $cy, '0000FF'); cross($img, $pos[2], $cy, '0000FF'); } else { SKIP: { skip("couldn't draw text", 7) }; } } sub okmatchcolor { my ($img, $x, $y, $r, $g, $b, $about) = @_; my $c = $img->getpixel('x'=>$x, 'y'=>$y); my ($fr, $fg, $fb) = $c->rgba; ok($fr == $r && $fg == $g && $fb == $b, "want ($r,$g,$b) found ($fr,$fg,$fb)\@($x,$y) $about"); } sub okmismatchcolor { my ($img, $x, $y, $r, $g, $b, $about) = @_; my $c = $img->getpixel('x'=>$x, 'y'=>$y); my ($fr, $fg, $fb) = $c->rgba; ok($fr != $r || $fg != $g || $fb != $b, "don't want ($r,$g,$b) found ($fr,$fg,$fb)\@($x,$y) $about"); } sub cross { my ($img, $x, $y, $color) = @_; $img->setpixel('x'=>[$x, $x, $x, $x, $x, $x-2, $x-1, $x+1, $x+2], 'y'=>[$y-2, $y-1, $y, $y+1, $y+2, $y, $y, $y, $y], color => $color); } libimager-perl-1.004+dfsg.orig/FT2/t/t20thread.t0000644000175000017500000000277212263740577020426 0ustar gregoagregoa#!perl -w use strict; use Imager; use Config; my $loaded_threads; BEGIN { if ($Config{useithreads} && $] > 5.008007) { $loaded_threads = eval { require threads; threads->import; 1; }; } } use Test::More; $Config{useithreads} or plan skip_all => "can't test Imager's lack of threads support with no threads"; $] > 5.008007 or plan skip_all => "require a perl with CLONE_SKIP to test Imager's lack of threads support"; $loaded_threads or plan skip_all => "couldn't load threads"; $INC{"Devel/Cover.pm"} and plan skip_all => "threads and Devel::Cover don't get along"; # https://rt.cpan.org/Ticket/Display.html?id=65812 # https://github.com/schwern/test-more/issues/labels/Test-Builder2#issue/100 $Test::More::VERSION =~ /^2\.00_/ and plan skip_all => "threads are hosed in 2.00_06 and presumably all 2.00_*"; plan tests => 8; Imager->open_log(log => "testout/t20thread.log"); my $ft1 = Imager::Font->new(file => "fontfiles/dodge.ttf", type => "ft2"); ok($ft1, "make a font"); ok($ft1->_valid, "and it's valid"); my $ft2; my $thr = threads->create ( sub { ok(!$ft1->_valid, "first font no longer valid"); $ft2 = Imager::Font->new(file => "fontfiles/dodge.ttf", type => "ft2"); ok($ft2, "make a new font in thread"); ok($ft2->_valid, "and it's valid"); 1; }, ); ok($thr->join, "join the thread"); ok($ft1->_valid, "original font still valid in main thread"); is($ft2, undef, "font created in thread shouldn't be set in main thread"); Imager->close_log(); libimager-perl-1.004+dfsg.orig/FT2/t/t90std.t0000644000175000017500000000121012263740577017742 0ustar gregoagregoa#!perl -w use strict; use Imager::Test qw(std_font_tests std_font_test_count); use Imager::Font; use Test::More tests => std_font_test_count(); Imager->open_log(log => "testout/t90std.log"); my $font = Imager::Font->new(file => "fontfiles/dodge.ttf", type => "ft2"); my $name_font = Imager::Font->new(file => "fontfiles/ImUgly.ttf", type => "ft2"); SKIP: { $font or skip "Cannot load font", std_font_test_count(); std_font_tests ({ font => $font, has_chars => [ 1, 1, 1 ], files => 1, glyph_name_font => $name_font, glyph_names => [ "A", "uni2010", "A" ], }); } Imager->close_log; libimager-perl-1.004+dfsg.orig/FT2/Makefile.PL0000644000175000017500000001111112567572530020135 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Getopt::Long; use Config; my $verbose = $ENV{IM_VERBOSE}; my @libpaths; my @incpaths; GetOptions("incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$verbose); our $BUILDING_IMAGER; our %IMAGER_LIBS; my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; my %opts = ( NAME => 'Imager::Font::FT2', VERSION_FROM => 'FT2.pm', OBJECT => 'FT2.o freetyp2.o', clean => { FILES => 'testout' }, ); my @inc; if ($BUILDING_IMAGER) { push @inc, "-I.."; unshift @INC, "../lib"; } else { unshift @INC, "inc"; print "FreeType 2: building independently\n"; require Imager::ExtUtils; push @inc, Imager::ExtUtils->includes; $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ]; # Imager required configure through use my @Imager_req = ( Imager => "0.95" ); if ($MM_ver >= 6.46) { $opts{META_MERGE} = { configure_requires => { @Imager_req, }, build_requires => { @Imager_req, "Test::More" => "0.47", }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; $opts{PREREQ_PM} = { @Imager_req, 'Scalar::Util' => 1.00, XSLoader => 0, }; } } require Imager::Probe; my %probe = ( name => "FreeType 2", code => \&freetype2_probe_ftconfig, inccheck => sub { -e File::Spec->catfile($_[0], "freetype/ftbitmap.h") }, libbase => "freetype", testcode => _ft2_test_code(), testcodeheaders => [ "stdio.h", "string.h", "ft2build.h" ], testcodeprologue => _ft2_test_code_prologue(), incpath => \@incpaths, libpath => \@libpaths, alternatives => [ { incsuffix => "freetype2", }, { incsuffix => "freetype", }, ], verbose => $verbose, ); my $probe_res = Imager::Probe->probe(\%probe); if ($probe_res) { $IMAGER_LIBS{FT2} = 1; push @inc, $probe_res->{INC}; $opts{LIBS} = $probe_res->{LIBS}; $opts{DEFINE} = $probe_res->{DEFINE}; $opts{INC} = "@inc"; $opts{LDDLFLAGS} = $probe_res->{LDDLFLAGS} if $probe_res->{LDDLFLAGS}; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'FreeType 2 font driver for Imager'; } WriteMakefile(%opts); } else { $IMAGER_LIBS{FT2} = 0; if ($BUILDING_IMAGER) { ExtUtils::MakeMaker::WriteEmptyMakefile(%opts); } else { # fail in good way die "OS unsupported: FreeType 2 headers/libraries not found\n"; } } sub _ft2_test_code { return <<'CODE'; FT_Library library = 0; FT_Face face = 0; FT_Error error; error = FT_Init_FreeType(&library); if (error) { fprintf(stderr, "FreeType 2: cannot initialize library: %d\n", error); return 1; } error = FT_New_Face(library, "fontfiles/dodge.ttf", 0, &face); if (error) { fprintf(stderr, "FreeType 2: cannot load font: %d\n", error); return 1; } return 0; CODE } sub _ft2_test_code_prologue { return <<'CODE'; #include FT_FREETYPE_H CODE } sub is_exe { my ($name) = @_; my @exe_suffix = $Config{_exe}; if ($^O eq 'MSWin32') { push @exe_suffix, qw/.bat .cmd/; } elsif ($^O eq 'cygwin') { push @exe_suffix, ""; } for my $dir (File::Spec->path) { for my $suffix (@exe_suffix) { -x File::Spec->catfile($dir, "$name$suffix") and return 1; } } return; } # probes for freetype2 by trying to run freetype-config sub freetype2_probe_ftconfig { my ($req) = @_; is_exe('freetype-config') or return; my $cflags = `freetype-config --cflags` and !$? or return; chomp $cflags; my $lflags = `freetype-config --libs` and !$? or return; chomp $lflags; # before 2.1.5 freetype-config --cflags could output # the -I options in the wrong order, causing a conflict with # freetype1.x installed with the same --prefix # # can happen iff: # - both -Iprefix/include and -Iprefix/include/freetype2 are in cflags # in that order # - freetype 1.x headers are in prefix/include/freetype my @incdirs = map substr($_, 2), grep /^-I/, split ' ', $cflags; if (@incdirs == 2 && $incdirs[1] eq "$incdirs[0]/freetype2" && -e "$incdirs[0]/freetype/freetype.h" && -e "$incdirs[0]/freetype/fterrid.h") { print "** freetype-config provided -I options out of order, correcting\n" if $verbose; $cflags = join(' ', grep(!/-I/, split ' ', $cflags), map "-I$_", reverse @incdirs); } print "$req->{name}: configured via freetype-config\n"; return { INC => $cflags, LIBS => $lflags, }; } libimager-perl-1.004+dfsg.orig/FT2/fontfiles/0000755000175000017500000000000012617670351020155 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/FT2/fontfiles/ImUgly.ttf0000644000175000017500000013772012031434613022101 0ustar gregoagregoa €@OS/2ßI#•ÌVcmapËâ…$Úcvt %Ö*E’glyféÑûÆ”’lheadÕ§/—6hhea õü—8$hmtx‡‡vï—\ °kernþáÿ†¢ –loca±)7¢¤Zmaxpú­¨ nameš3ÔŒ¨ ˆpost¤Õ ª¨%ùôÈÈÈÈÈÈ1  €OPfEd@ $‡¡ý¡“ÔÀl@,~@HOdko~‰¡ØÜßõû3 (¼  )™¡§±¹ÁÇÍÓÝåõù  < C p Ž!!! !! !"!+!$n$‡ÿÿ ¡CLRhnr‰ ÕÛÞôø& '¼  , ¤ª´¼ÄÊÐÖàòø  < C p t!!! !! !"!+!`$`$tÿÿÿãÿÁÿ¿ÿ¼ÿºÿ·ÿµÿ³ÿ©ÿ“ÿ`ÿ^ÿ]ÿIÿGÿ+ÿ!þUþSþNþ4üºø\ø[ãfãdã^ã\ãZãXãVãTãRãPãNãLã@ã>â(âáýáÑáÎá]á\áZáKáFáEá=á Þ)Þ$  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿À!y\cáÛ`WiRÖZ®\•J^KÄN7?iTþùY^òf¸XõHEЇ„8ÎéG42* .&¶ÙN€n $…F<Lèx`½!nš.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!!MþÔ þõšýf!X>›ë°/°3±í±í°Ü°3±í±í01733#>\\\\äýùv\4Q;°/°3±í±í°Ü°3±í±í°/°3±í±í°ܰ3±í±í013#'3#îccºccýÛÞá;l“ÁÕ°/°3°3°3±í°2°3±í°2°3±í±í±í±í±í±í°ܰ3° 3° 3°3°3± í± í± í°2±í±í° 2±í±í°2±í±í°2±í°/°3°3°3°3°3±í±í±í±í±í±í°Ü°3°3°3°3°3±í±í±í± í± í± í0135%3533533#3##5##5#535#÷Ýþg`\Ý\cccc\Ý\``` ìì\ZZZZ\ì\WWWW\ì^ÿ¶Î&67CMW° /° 3°3°3°#3°&3°'3°83°C3±í±í± í± í±(í±)í±5í±6í±Dí±Mí°&/°'3°(3± í± í0115&/5#'&'231356767676'5&/5'&'&=472;1ÂDRE$L®WŽK) ¡*ˆK/Y¡W aU( ,³ Vw&cIWoj2|$ T6#IG:(kZâ'T>.J '  3e_øþÁu< %<þ¤5;> â#5GKû°B/°C3°D3°E3±' í±( í±) í±* í°0ܰ13°23°33±9 í±: í±; í±< í°ܰ3° 3°!3± í± í± í± í° Ü° 3°3°3± í± í± í± í± ?°/°3°J3°K3± í± í± í°Ü°3°3± í± í±# í°>ܰ?3°@3±, í±- í±. í°$ܰ%3°53±6 í±7 í±G í±H ?°I3±HK°H/±I í°K/±JQí±HK°I±H í°J±KQí01%"3276=4'&'2#"'&=476"3276=4'&'2#"'&=4763#  C,5(1D,5(þë  C,5(1D,5(›cþ`Ê     R9'-A,!:&-@-!t     R9'-A,!:&-@-! ý*37Ö E¦°(/°)3°*3°13°23°33°43± í± í± í±í±í±í±í°ܰ3±"í±<í±=í±>í±! ?°$/°%3°&3±í±í±í±"í±6 ?°73°83°93±í±í±í± ° /±Aí°/±B]í± °A± í°B±]í0176?4'#"32?67'#"'&547?&'&=476;27Û;AX+0 1-"½N?4&Bc6$3B Na)2C1'7?Š]?Zã+(("-ª0Z /gH[8#\>P?8D >4 $R ,$0H34±HWHi(ÉÖ °/°3±í±í± ?°/±í±í013#i``Ö®ZÿÂÿ° /° 3±í±í01#3&'&5476þ\< *\< ‡‡/q³MTY†3e²UMÿ³-°/°3°3°3±í±í±í±í° /° 3±í±í013#676=4'&\< )\< ‡‡/p³MTY†3d²UMFÛŸ-°/°3±í±í°/° 3°3°3±í±í±í±í01'773#''7#5Æ@J@AJ@€€@JA@J@€o+oo+oVo+oo+oVBب W°/±í°2°3±í°2°3° 3±í±í±í°2± í±í°2± í°/°3°3° 3±í±í±í±í017#53533##ß\\¯\\=ÿ©÷[(±°/± í°/±Rí±°± í°±Rí0173#š]]][²6¯€ °/°3±í±í°/°3±í±í01!!6Jþ¶ \N«\± ?°/±í±í0173#N\\\\+‰Ö7± ?°/± ?°3±°/±í°/±Ví±°±í°±Ví01 3 þ `þÖý*Ö1'Ö#/± ?°/°3±í± í± í± ?°3°#3±í±í±í01"3276=4'&'2#"'&=476,D.,=+6B/->+5dIMPHbdIMPHzTMl…R9ROm„R8\dk›Ÿl`dk›Ÿl`}5Ö"°/°3°3±í±í± ?°/± ?°30173#}\\\(®ý*(1'Ü+± ?°/±í±í±í0147676!!5676767654'&/&1\*7?9w1_ wH/†þ (loo6 ;8\(^2 I$-„_ W5,[[?JL Vc, #01ÿý'ÜC°3°?30147676'#&'&=33?3676574'�'&#&+"2G6?D)«bQ1&g/>=%=?@`7LI(;6GU0 E d6(E7* "‚€, D4>h.68:: ' A51B=(69 ,1'Ö 1± ?° /°ܰ 3° 3° 3±í±í±í±í±í± ?°3013!33##5!tÖÖþ¾@X\\ZþÂ^þ§Ñþ/V¯¯/ÿú(Ö0± ?°/±í±í01!!60/&'2'61?676=4'&'"#&/õþg«H„J!S 2OO50` $7 Xb:¢cs\² {/'k* / R7Lm1'×/.± ?°/°3±í± í± í°Ü°3°3±$í±%í±&í012#"'&=4763276=4'&#"7676767.O/=*5P1=,=;EiPHbpK?RGa>HF†e6#+A(6"*@(qb’§"!bD/°?3±í±í±í° ܰ 3° 3±í±í±í±+ ?°,3°-3±í±í±$í01%276574'&'#""3276574'&&5'476323#"'&=47.O/=&/ P/<*6; 0!: 1®5F7H];+9WPHbpK?P[7"+A(7"+A(!/7/7Ý4IU7,C2@L66^bDKg f( )RF(”" M,+; Ö S°/°3±í±í°ܰ 3±í±í±í±í± ?°/°3±í±í±í± ?°3°3±í±í± í01#3276?4'&'&!!2=¦¦ORTMKZ þþxhjfZqzýâJMZ\TS ý†Ö[\€„m`C¡Ö y°/°3±í±í°2±í±í°2± í±í°2± í°±í±í°± í± í± í± í± ?°/±í±í±?° 3±í±í± ?°3± í± í01!!5!35#5!¡ý¢^þùùþÖý*[ `·+‰Ö b°/°3±í±í±í°2±í±í°2±í°±í±í°± í± í± ?°/±?°3±í±í± ?°3±í± í01!335#5!‰ý¢`ùùþÖý*e`·3™Ö6<°5/°63±!í±2!í±3!í±4!í±+ ?°,/°-3°.3°Ü°63± í±&í±4í±5í01%'#&'&?67127363&'&+";27676=# %W0&ˆ „).R/iTAVWM-  ?RXWMO^ ò¯6 )RF(”" M,+‹K;xGRgGAQh >Kg V$‚Ö U°/°3±í±í± í± í°ܰ3°3° 3±í±í± ?°/°3°3°ܰ3± í± í± ?°3°3° 3013!3#!$\¦\\þZÖý*eþ›ÖþëE¡Ö°/°3±í±í± ?°/± ?°3013E\Öý*Ö3ÿý„Ö0° /°3±í±í°Ü°3°3°3±í±í±í± ?°/013'#&'&'537676=(\PCeAkMI\#4o! Öþ/vL>PKY~&U&3‘Ö 3°/°3±í±í± í± í± ?°/°3° 3± ?°3°3°301333 #3`•iþ‰wiþ³HÖþqþþ›,?í3‘Ö.°/°3±í±í±"í°2± ?°/±í±í± ?°3013!!3\ý¢Öý†\EùÖ °/°3±í± í± í°ܰ3°3±í±í± ?°/°3° 3° 3° 3± ?°3°3°3± ° ±í° /±]í± °± í°± ]í±°±í°± \í01333##E\þþ\\¾€¾Öýý*Ûþ%Ûþ%iÇÖ f°/°3±í±í± í°ܰ3°3±í±í± ?°/°3° 3± ?°3°3°3±°±#í°±fí±°±#í°±fí01333#i`•iiþkÖýÙ'ý*(ýØ;“Ö+j°%/°&3°'3±í±í±í±í° ܰ 3°3°3±í°2±í±í±í± ?°!/°"3±í± í± í± ?°3°*3°+3±í±í±í01"3276=4'5&'&'2#"'&'547672fW=;H;LU?=J-8xW[YGW xW[ZVwzROl|RBQPmzR1 \di˜˜j<di˜™jfA Ö 5± ?° /° ܰ3°3±í±í±í± ?°3°3±í±í± í0132754'&##!2#ý¨X&+ý\YtMDoAUzèrJ þ¼þÊÖA9Ux7!+ŠÖ.m°&/°'3°(3± í± í±í±í°ܰ3°3°3±í±í±í±í± ?°+/°,3°-3°.3±í± í± í± ?°!3°"3°#3±í±í±í012#"'&=476671'6=4'&'"#"232ZS@@H@OV>;I<øE*IHZVxyX\YVz^zRQjqTKROmyRCýÎE*I†W˜jfdi—™jg3‘Ö !¨°/°3±í±í±í±í°ܱí°2°3°3° 3±í±í±í±í±í± ?°/°3°3° ܰ3°3° 3°!3±í±í±í± ?°3°3±í± í± í±í±° /± í°±Rí±°± í°±Rí0132756=4'&####!2#“ù]%)(-sþÒ]`YvM 'cG[|èTK þ¸þÌ4þÌÖ? /?o=,]ÿûÇÛC°8/°93°:3°;301&/&&3'#&/?676'&'&''&'&=4?63ÁMnD+,ŽK)  žm 1?%"3hk.PW G-*wG."(²$£e;g"4H]Z|6 :* lQ =/%= /T8 5(,s\ J. 0 &#3‘Ö6°/°3±í±$í°2±í± ?°/± ?°3±í±í±í±í015!!#3^þÿ\z\\ý†z+ÿþ‰Ö@°/°3°3°3±í±í±í° ܰ 3° 3°3±í±í±í± ?°/°3°30137676=3'&'&=+`K'0+,Z*i\Ga,+qLEÖþ/W3 G'0Ñþ/yL:PIe+‰Ö=± ?°/± ?°3°3°3±°/±í°/±bí±°±í°±bí0133#+`ÏÆiþûWÖýÙ'ý*›Ö ‚± ?° /° 3° 3± ?°3°3°3°3°3± °/±í° /±[í± °±í°± [í±°/± í°± Yí± ° ±í° /±\í±°/±í°±]í01333# #`¢–]–“aÁ`™–TÖýÙ'ýÙ'ý*(ýØ+‰Ö V± ?°/° 3° 3± ?°3°3°3±°/±í°/±[í±°±í°±[í±°/±í°±Tí0133 # #+`ÏÆiþûiÆÏ`Öþïþþ›þûezÖK°/°3±í±í± ?°/± ?°3°3°3±°/±í°±Tí±°±í°±Tí0133#`ÌÉiþûWÖþïþþ›eE¤Ö )± ?°/±í±í±í± ?°3±í±í± í01!!!5!F^þäý¢àþ ÖZýß[[!i!ÖP°/°3±í±í°2±í±í°2°±%í±%í±%í±%í± ?°/±í±í± ?°3±í±í013#3#i¸\\¸Ö\ýâ\+‰Ö7± ?°/± ?°3±°/±í°/±\í±°±í°±\í01#›îpþÖý*Ön&Ö=°/±í°2°3±í°2±í±í± ?°/±í±í± ?°3±í±í01#3#3&¸\\¸Ö\ýâ\.|  73#'.]3K?'0|¤¤ZZÿ¢Xÿþ °/°3±&í±&í± ?°/±í±í01!!Xý¨\$(áÖ0± ?°/±°/±í°/±Tí±°±í°±Tí013#$`]]Ö®(Å$…°/°3°3°3±í±í±í±í° ܰ 3°3°3°3°3°"3°#3±í±$í± ?°/°3°3°3±í± í± í°±í±í± í±!í±#í±$í°±í±í±í01"3276=4'&#5#"'&=476;253 N/=*5P/;,Ã\EZpI=OF`ZE\i8$,A(7"*@*þ—22M?UeC;22ÿÿ9ÿþÖGG1À@!Ä#/± ?°/°3±í±í±í±?°3°3±í± í±!í013&'&#"32767##"'&=47632²\Y: $;›|<°/°3°3°3±í±í±í±í± ?°/±í±í°Ü°3±í±í01533#;````(TTdþ<ÿ7þ|E°/°3°3°3°3±í±í±í±í±í°/° 3° 3±í±í°ܰ3±í±í013##"/7?275ªTTT;- ,|Tdþÿ‹*s°/± í°2°3°3± í°2°3±í°2±)í±)í±)í±)í±)í±#í°$2±()í±' í°&2±))í±*)í°/°3±*í±*í±*í± ?°3±)í±*)í012+276=473675&'5'54>V 'v"  -H2ÿ þìEQó% H Ü~+¯Ãe-°/°3±í± í± í°ܰ3°3°3±í±í±í01756323276767#"'&'&#"+3Q)* 7 &9!#$(" E( ØZ30$ ]",&" \æÙA°/°3±+í±+í±+í±+í°±,í±,í± ?°/±í±í°ܰ3±-í±-í013'35#\Ї‡‡ýùN„!ÿ, (*.0017&'&=476?6767##&'1'? c C < mD4P/?cf? \? g+[? c Ãh hþ©9A( aO=McC( Q#(1XX"9ö_r m\ÿ&?Ö!6u°/° 3±.í±.í°ܱí±í±í°/°3°3± í± í±í°ܰ3°3°3°3°3±í±í± í±!í±"í±6í±& ?°'3°(3±/í±0í±1í013#17632'&+7676'1#531567632#&'&#"«³¨ c DuRº(+;cI/$QGftI(]6:X.›ZG1E [ …8ZZ)~OEM)8A T3A+̽.01&76?6'&'&7'/'7&?'767J(9+ (:*  I&"4B5JM9?8'" 7B6JM 2?7(*9(*9GO 5A5+8@8GO7B7.2@zÖ²°/°3°3°3± /í± /í±/í±/í°ܰ3±0í°2°3±0í°2°3±í± 1í° 2±í±1í°2±í±1í°2±í± ?°/°ܰ3°3°3± í± í± í± í°Ü°3° 3° 3± í± í± í± í± í± í± ?°3°3° 301#53'33733#3##5#535îžd˜`£Q¡iš~¸1ééWÎΪRÚÚÚÚRERüüRiÉÖ=°/°3°3°3±í±í±í±í± ?°/±.í±.í± ?°3±2í±2í013#3#i````8þÈÖþ¹)‘ÚU'± ?°/°3±S*í±T*í°/ܰ03±5*í±6*í±7*í0167676''&'#"'&74?&'&5'4737676=4/"'7632127Ð?%+EA$•0<1!\8)+51 =x&*-1"&D13H&7+01<0R6,"!5¦:3 8(8-!(<0 0% .88#2$>0!0 (.  > $.Ö <°/°3±*í±*í°Ü°3±í±í± ?°/°3°3±)í±)í±)í±)í013#'3#Ê??œEEHHH9NÖ'LŸ°"/°#3±í±í±í±í°BܰC3°D3°E3±/í±0í±1í±2í° Ü° 3°3°3±í±í± ?°/°3±í± í± í°>ܰ?3°@3±5í±6í±7í°+ܰ,3°-3±Gí±Hí±Ií± ?°3°'3±í±í±í01"3276=4'&'2#"'&/47676&'&#"327673#"'&=47632ÄXRYW{€XRYWzžrn iKh68Ÿrn ijš¯@#O/=%0 C6 \U=GpJ@PHbzF* |UNlrPOUNlqPOZe`‹ŽiJe`‹Žii þ´: 7"+A(2X3$L?VcC

^U b3"ÿÿiÇ´&1a¡Oÿÿ;“¬&2CäÖÿÿ;“g&2uÖIÿÿ;“¢&2AË‚ÿÿ;“´&2apOÿÿ;“F&2iË(ÿÿfÇx‡ôÿm-A-AÒ¾-A*ÿú‰Ö "/o°)/°*3°+3±í±í±í±í° ܰ 3°3°3±í±í±í°/°3°3°3±í±í±í±- ?°.3°ܰ3° 3±$í±%í±&í± ?°!3017&'=47632#"';276754'7#1&#"37²'G9J;27'G9K<25JZxW[OVi*IWxW[NM`&ÃGY}RA*EGY~RA,K8di˜hp6ÿÿ+ÿþ‰¬&8C×Öÿÿ+ÿþ‰g&8uÉIÿÿ+ÿþ‰¢&8A¾‚ÿÿ+ÿþ‰F&8i¾(ÿÿzg&<uºIA  .°/°3°3±í±í±í± ?° 3° 3±í±í± í0132754'&#'32+#3¢øªZ&+øøvLCjCXøa^|ærJ Z@7Tu:%þÊ Bÿ¨ì×?0147676'&/76767676/&'8?6'&'&CO0>\,  %. :3  <(<#e'& 14%N.BX€[2N46A'!) NF,   N 0.+ T ?&..ý€ÿÿ(›&DCœÿÅÿÿ(V&DuŽÿ8ÿÿ(‘&DAƒÿqÿÿ(£&Da'>ÿÿ(5&Diƒÿÿÿ(ÿ&DqqÝ­ÅLµ° /°!3°"3°#3± í± í±í±í°ܰ3°3°3°3°(3°)3°L3±*í±+í±Jí±Kí± ?°/°3°G3°H3°I3°K3°L3±í±í±í±@í±Aí±Bí°:ܰ<3°=3±í±í±2í±%?°&3°'3°)3°*3±í±í±í± í± í±í01!&'&#"%"3276=4'&#"'&=476325363201&132?#"'#*I X* þöO/=*5O/=*gEXqJ@PHcXE]EYqJ% oþï@^6U^YE]A 9K7"+A(7"+A(þÍ2L@UcD<2243L$/ " &4 0""33ÿÿ!ÿOÄ&Fyÿÿ$š&HCœÿÄÿÿ$U&HuŽÿ7ÿÿ$&HAƒÿpÿÿ$4&Hiƒÿÿÿ Ëš&òCêÄÿÿ¼U&òuÿÜÿ7ÿÿÿþÚ&òAÿÑÿpÿÿÿþÚ4&òiÿÑÿi±2k°!/°"3°#3°$3±í±í±í± í± í°ܰ3°3°3±í±í±í±í± ?°/°3°3± í± í±í±&?°'3±í±í±í01"003276=4'&+"'&=4763''7'774A&6!)@&6!|)G9K\=3G9L1NMCFFn9$-I*9%.I*;KhC7L@UhC7_(7(6#6%7%ÿÿ$¾¢&Qaÿú=ÿÿ$š&RCœÿÄÿÿ$U&RuŽÿ7ÿÿ$&RAƒÿpÿÿ$¢&Ra(=ÿÿ$4&Riƒÿ?%Õ• -°/°3±í±í°ܰ3±í±í°ܰ 3± í± í01735'5!'53âVø”óWyTT6VV’TT$ÿÎä */± ?°/°3±í±í±í±?° 3° 3±#í±$í±%í017'7&5476327#"73276=4'7&#"¬@A:AQHb=61A+@QHb= P/!ù¯O/K8DAWcC<973@WcCZ`@ÿÿ&†G&$YÆ(ÿÿ(6&DY’ÿÿÿ&ÿO†Ö&$GyéÀ@ÿÿ(ÿOÅ&DGyµÀ@ÿÿ3™g&&uÙIÿÿ!U&Fu‡ÿ7ÿÿ3™¢&&A΂ÿÿ!&FA|ÿpÿÿ3™Z&&ÿþÿÿ!H&F­ìÿÿ3™I&&Zó(ÿÿ!7&FZ¡ÿÿÿ; I&'Zó(ÿÿ0ÿþI&GZQ(ÿÿ%ïØ‘+ŽÖ-ɰ/°3° 3°!3±í±í±í±í°(ܰ)3±;í±;í° Ü° 3°3°3°3°3°&3°'3±(<í°)2°*3±)<í°(2°+3±í±=í°2±í±í±,í±-í± ?°/°3°3°3±í± í± í±#?°$3°%3±í±í±í°ܰ3°'3°(3±í±)í±*í±-í±+ ?°,301"3276=4'&'##5#"'&=476325#5353$O/=*5O/=%0`n`DVqJ@PHcVD€€`e7"+A(7"+A(Tþºâ00L?VcC<0”TZZÿÿC¡Z&(G<OZ`@ÿÿ$H&HGÿê=Z`@ÿÿC¡G&(Yå(ÿÿ$5&HY’ÿÿÿC¡Z&(þÿÿ$H&H³ìÿÿCÿO¡Ö&(GyÀ@ÿÿ$ÿOÄ&HGy‘À@ÿÿC¡I&(Zû(ÿÿ$7&HZ§ÿÿÿ3™¢&*A΂ÿÿ5ÿ:)&JAˆÿpÿÿ3™G&*YÝ(ÿÿ5ÿ:)5&JY—ÿÿÿ3™Z&*ÿþÿÿ5ÿ:)H&J¸ìÿÿ3ÿO™Ö&*yÓÿÿ5þ†)Ä&JyŒÿ7ÿÿ$‚¢&+A·‚ÿÿÿæ¼¢&KAÿ¹‚ ÀÖ e± ?°/°3°3±?°3±í±í°ܰ3° 3° 3°3°3°3±í±í±í± í± í± í±í±í±í± ?°3°3°3015#!!!'#5;5#3!33'#nhþÂ>þÂ`HH```>hRN|ZZTccTZZTýØeþ›(T*Öš°/°3± >í± >í°ܰ3±í°2°3±í°2°3±í±í±í± í± í° 2± í± í° 2± í°ܰ3°3±í±í±í±í± ?°/°3°3°ܰ3° 3° 3±í±í± í± í± ?°301##53533#6732#4Þ`TT`VVBKj! ZVE9;þÅ(TZZT(5þš>: $ÿÿÿ¤=´&,aÿzOÿÿÿ 8¢&òaÿu=ÿÿÿ‡ZZ&,Gÿ<OZ`@ÿÿÿƒUH&òGÿ7=Z`@ÿÿÞG&,Yä(ÿÿÿþÚ5&òYÿàÿÿÿÿOßÖ&,GyÀ@ÿÿÿýÿOÙ|&LGyÀ@ÿÿE°Z&,þ<œÄ°/°3±í±í± ?°/±?°3013#<``Äþ<ÿÿEÿýuÖ&,-ñÿÿ;ÿ7j|&LMlÿÿ3ÿýÊ¢&-AÁ‚ÿ75Í0°/°3°3±í±í±í°/°3°3± í± í±?°301#"/7?275'73#'þ;- ,P]3K?'0Äþ88BL)z1/ŠKùR\e91Ib'öl!6'p#  '%C5/G'0X0 G? \\ý /^@7ia79áFR°/°3±Aí±Aí°/±í°ܰ3°B3°C3±í±í±CD°C/±Fí°D/±E[í±CD°F±Cí°E±D[í015!3&'&'676'&'&'6766''&/676/739þ{LŠ'1k >!*KE"?5 )X*U>`2!f\O\‡Z\þõ?A%8X/B!C3: / E'I"4 W"Cb X9D/þôýƒÿÖFÖM`°/°3±Bí±Bí°)ܰ*3°+3°,3± í± í± í° Ü°3°3±@ í±A í±B í±C í±ICí°J2± ?°/±í±í±í±í0135!!1'547&'&?676=4'&''&'&'&=476736756?ãcýº„W`$Xk>SI[Fm  #) FIÿâLin-°/°3±UDí±VDí°/°3°T3°U3±í±í±Ví±Wí01!!&'&7277'676=4'1&'#'&'&'5&70367676?=1735!&'&?6&1&'&&7þã‡Zi), jLp;eHCq$@$8 neNL 1OŠ"dþþ*6 P"DL% JC~NA !Y    QMR &6?_   "  ; ?N") $ ( :ý¤8#" 9ÿåŽØ*0137676/!5!#'&5'7676'&'=3( VþúS¥-n> 9I‹W75>?8(C3F¨;*F^^)3f=.mhK 0 :N]at<.<2 "ÿå Ù@°5/°63°73°:3°;3±8í±9í016'6'&'#&'&'&'767&?656'&'&'537674'&#!5!!"?8(C$04' 0!þúèþÆ-G(9:«&S59!*c&¦O–]at;2 ];*7 ^^(5f=ÿÿ&þƆÖ&$q¦ü¶ÿÿ(þÆÅ&Dqsü¶ÿÿG¢Z&%éþÿÿ9ÿþZgG1À@ÿëþÿÿGÿ|¢Ö&% ÿ|ÿÿ9ÿ|ÖgG1À@žÿ|ÿÿGÿ|¢Ö&%G<þÍZ`@ÿÿÿ|ÖgG1À@GÿÒþÍZ`@ÿÿ3ÿO™g&&'yÓuÙIÿÿ!ÿOU&F'yu‡ÿ7ÿÿ; Z&'þÿÿ0ÿþZ&G]þÿÿ;ÿ| Ö&'ÿ|ÿÿ0ÿ|øÖ&GŸÿ|ÿÿ;ÿ| Ö&'G8þÍZ`@ÿÿÿ|øÖ&GGÿÓþÍZ`@ÿÿ;ÿO Ö&'yÖÿÿ0ÿOøÖ&Gyqÿÿ;ý Ö&'5 ýÿÿÿÙý7Ö&G5ÿ¦ýÿÿC¡0&(g<OZ`@CïZÿÿ$&Hgÿê=Z`@CœHÿÿC¡ë&(g<OZ`@uáÍÿÿ$Ù&Hgÿê=Z`@uŽÿ»ÿÿCý¡Ö&(5ýÿÿÿËý*Ä&H5ÿ™ýÿÿCÿ"¡Ö&(a{þsÿÿ$ÿ"Ä&HaþsÿÿCÿO¡G&('yÛYå(ÿÿ$ÿO5&H&ycY’ÿÿÿ+‰Z&)ñþÿÿ2Z&Iiþÿÿ3™Z&*G4OZ`@ÿÿ5ÿ:)H&JGÿú=Z`@ÿÿ$‚Z&+êþÿÿ$¼Z&Kÿëþÿÿ$ÿ|‚Ö&+êÿ|ÿÿ$ÿ|¼Ö&K‡ÿ|ÿÿ$‚F&+i·(ÿÿÿæ¼F&Ki¹(ÿÿ$ÿO‚Ö&+y¼ÿÿ$ÿO¼Ö&KyYÿÿÿ§ÿ"?Ö&,aÿ|þsÿÿÿŸÿ"7|&LaÿtþsÿÿÞ×&,&iÕ(uÿà¹ÿÿÿþÚÅ&ò'iÿÑÿuܧÿÿ3‘g&.uÑIÿÿ „g&NuËIÿÿ3ÿ|‘Ö&.ùÿ|ÿÿ+ÿ|„Ö&Nnÿ|ÿÿ3ÿ|‘Ö&.G,þÍZ`@ÿÿÿîÿ|ÁÖ&NGÿ£þÍZ`@ÿÿ3ÿ|‘Ö&/ùÿ|ÿÿ;ÿ|­Ö&Oÿ|ÿÿÿxÿ|‘Z&/'ùÿ|Gÿ,OZ`@ÿÿÿ‚ÿ|TZ&O'ÿ|Gÿ6OZ`@ÿÿ3ÿ|‘Ö&/G,þÍZ`@ÿÿÿ‚ÿ|TÖ&OGÿ6þÍZ`@ÿÿ3ý‘Ö&/5ýÿÿÿ<ýšÖ&O5ÿ ýÿÿEùg&0uIÿÿ\<U&Pu»ÿ7ÿÿEùZ&06þÿÿ\<H&PãìÿÿEÿ|ùÖ&06ÿ|ÿÿ\ÿ|<Ä&Pãÿ|ÿÿiÇZ&1/þÿÿ$¾H&Qˆìÿÿiÿ|ÇÖ&1/ÿ|ÿÿ$ÿ|¾Ä&Qˆÿ|ÿÿiÿ|ÇÖ&1GbþÍZ`@ÿÿÿ|ÚÄ&QGÿ¼þÍZ`@ÿÿiýÇÖ&156ýÿÿÿÂý Ä&Q5ÿýÿÿ;“E&2'apOuÖ'ÿÿ$3&R'a(=uŽÿÿ;“$&2'apOiËÿÿ$&R'a(=iƒÿôÿÿ;“0&2g1OZ`@CäZÿÿ$&Rgÿê=Z`@CœHÿÿ;“ë&2g1OZ`@uÖÍÿÿ$Ù&Rgÿê=Z`@uŽÿ»ÿÿA g&3ußIÿÿ-ÿ8!U&Su–ÿ7ÿÿA Z&3þÿÿ-ÿ8!H&S½ìÿÿ3‘Z&5ùþÿÿ+„H&Unìÿÿ3ÿ|‘Ö&5ùÿ|ÿÿ+ÿ|„Ä&Uÿòÿ|ÿÿ3ÿ|‘Z&5'ùÿ|G,OZ`@ÿÿÿîÿ|ÁH&U'ÿòÿ|Gÿ£=Z`@ÿÿ3ÿ|‘Ö&5G,þÍZ`@ÿÿÿrÿ|„Ä&UGÿ&þÍZ`@ÿÿ]ÿûÇ_&6,ÿÿ1ËH&V–ìÿÿ]ÿwÇÛ&6,ÿxÿÿ1ÿ|ËÄ&V–ÿ|ÿÿ]ÿûÇð&6'uM,“ÿÿ1ËÙ&V'unÿ7–}ÿÿ]ÿûÇÒ&6'Z,,uÿÿ1Ë»&V'Zˆÿ–_ÿÿ]ÿwÇ_&6',ÿx,ÿÿ1ÿ|ËH&V'–ÿ|–ìÿÿ3‘Z&7ùþÿÿ-V&WP¤ÿÿ3ÿ|‘Ö&7ùÿ|ÿÿ-ÿ|V|&WPÿ|ÿÿ3ÿ|‘Ö&7G,þÍZ`@ÿÿÿÐÿ|£|&WGÿ…þÍZ`@ÿÿ3ý‘Ö&75ýÿÿÿŠýé|&W5ÿXýÿÿ+ÿމÖ&8i¾ü¹ÿÿ$ÿ¾Ä&XiUüºÿÿ+ÿ ‰Ö&8acþrÿÿ$ÿ"¾Ä&Xaÿúþsÿÿ+ý‰Ö&85ÿøýÿÿÿÂý Ä&X5ÿýÿÿ+ÿþ‰E&8'acOuÉ'ÿÿ$¾3&X'aÿú=u`ÿÿ+ÿþ‰Ê&8g$OZ`@i¾¬ÿÿÚ¸&Xgÿ¼=Z`@iUšÿÿ+‰´&9acOÿÿ$¢&Ya'=ÿÿ+ÿ|‰Ö&9ñÿ|ÿÿ$ÿ|Ä&Yµÿ|ÿÿ›¬&:CYÖÿÿkš&ZCÁÿÄÿÿ›g&:uKIÿÿkU&Zu³ÿ7ÿÿ›F&:i@(ÿÿk4&Zi¨ÿÿÿ›Z&:rþÿÿkH&ZÚìÿÿÿ|›Ö&:rÿ|ÿÿÿ|kÄ&ZÚÿ|ÿÿ+‰Z&;ñþÿÿ$áH&[™ìÿÿ+‰F&;i¾(ÿÿ$á4&[igÿÿÿzZ&<âþÿÿ:ÿ:0H&\ÌìÿÿE¤¢&=AÙ‚ÿÿ+ &]AŠÿpÿÿEÿ|¤Ö&= ÿ|ÿÿ+ÿ| Ä&]¼ÿ|ÿÿEÿ|¤Ö&=G?þÍZ`@ÿÿ+ÿ| Ä&]GÿñþÍZ`@ÿÿÿ|ÙÖ&KGÿ»þÍZ`@ÿÿ-Vì&WiÎÿÿkþ&Zq–ÿÜÿÿ:ÿ:0þ&\qˆÿÜÿÿ&ÿ|†Ö&$êÿ|ÿÿ(ÿ|Å&D·ÿ|ÿÿ&†3&$'A·‚uÂÿÿ("&D'AƒÿquŽÿÿ&†x&$'A·‚CТÿÿ(g&D'AƒÿqCœ‘ÿÿ&†€&$'A·‚a\ÿÿ(o&D'Aƒÿqa' ÿÿ&ÿ|†¢&$'êÿ|A·‚ÿÿ(ÿ|‘&D'·ÿ|A…ÿqÿÿ&†Ø&$'YÆ(u¹ÿÿ(Ç&D'Y’ÿuÿ©ÿÿ&†&$'YÆ(CÐFÿÿ( &D'Y’ÿCž5ÿÿ&†%&$'YÆ(a\¿ÿÿ(&D'Y’ÿa)®ÿÿ&ÿ|†G&$'êÿ|YÆ(ÿÿ(ÿ|6&D'·ÿ|Y”ÿÿÿCÿ|¡Ö&( ÿ|ÿÿ$ÿ|Ä&H‘ÿ|ÿÿC¡´&(a{Oÿÿ$¢&Ha'=ÿÿC¡3&('AÖ‚uáÿÿ$!&H'AƒÿpuŽÿÿC¡x&('AÖ‚Cï¢ÿÿ$f&H'AƒÿpCœÿÿC¡€&('AÖ‚a{ÿÿ$n&H'Aƒÿpa' ÿÿCÿ|¡¢&(' ÿ|AÖ‚ÿÿ$ÿ|&H'‘ÿ|AƒÿpÿÿEÿ|µÖ&, ÿ|ÿÿ;ÿ|­|&Lÿ|ÿÿ;ÿ|“Ö&2þÿ|ÿÿ$ÿ|Ä&R¶ÿ|ÿÿ;“3&2'AË‚uÖÿÿ$!&R'AƒÿpuŽÿÿ;“x&2'AË‚Cä¢ÿÿ$f&R'AƒÿpCœÿÿ;“€&2'AË‚apÿÿ$n&R'Aƒÿpa( ÿÿ;ÿ|“¢&2'þÿ|AË‚ÿÿ$ÿ|&R'¶ÿ|Aƒÿpÿÿ;ag&2'j{u=Iÿÿ$èU&R'ðiuõÿ7ÿÿ;a¬&2'j{CKÖÿÿ$èš&R'ðiCÿÄÿÿ;a´&2'j{a×Oÿÿ$è¢&R'ðia=ÿÿ;ÿ|aÖ&2'j{þÿ|ÿÿ$ÿ|èÄ&R'ði¶ÿ|ÿÿ+ÿz‰Ö&8ñÿ{ÿÿ$ÿ|¾Ä&Xˆÿ|ÿÿz¬&<CÈÖÿÿ:ÿ:0š&\C²ÿÄÿÿÿ|zÖ&<àÿ|ÿÿ:þ¶0Ä&\Þþ¶ÿÿz´&<aTOÿÿ:ÿ:0¢&\a>=6¯€°/°3±í±í°/°3±í±í0175!6J¯VV6¯€°/°3±í±í°/°3±í±í0175!6J¯VV6¯°/°3±Eí±Eí°/°3±í±í0175!6è¯VV6¯º°/°3±Aí±Aí°/°3±í±í0175!6„¯VV6¯®°/°3±Fí±Fí°/°3±í±í0175!6x¯VV6¯–°/°3±Gí±Gí°/°3±í±í0175!6`¯VVÿÿ9kÖ&__Òÿÿ>âë&GN¯ e4° /° 3°3°3±Hí±Hí±Hí±Hí°/° 3° 3±9í±9í±9í012#"'&=476¬5-4-e+3+3ÿÿ1€—(€ Ìÿÿ1€—(€ Ìÿÿ1|—'} Ìÿÿ1€—(€ Ìÿÿ1€—(€ Ìÿÿ1€—(€ Ìÿÿ1—(€ Ìÿÿnd Ìÿÿÿò/4Bÿè Ìÿÿ,!’Y $ Ìÿÿÿíw$ ÿÜ„ ÌÿÿÿÞw$ ÿÜ„ ÌÿÿRnQÿù Ìÿÿ1ÿÄ—V(Å ÌÿÿÿÄ+VíÅ Ìÿÿ1ÿÆ—Y'Ç Ìÿÿ1ÿÅ—Y(Æ Ìÿÿ1ÿÄ—V(Å Ìÿÿ1ÿÀ—S' Ìÿÿ1ÿÄ—W(Å Ìÿÿ1ÿÄ—V(Å Ìÿÿ1ÿÄ—V(Å Ìÿÿ1ÿ×V(Å ÌÿÿÿVnÿ¨ÿS Ìÿÿÿòÿs4ÿ†ÿèÿQ Ìÿÿ,ÿe’ÿ $ÿV Ìÿÿÿíÿ»h ÜÈ ÌÿÿÿÞÿ»h ÜÈ Ìÿÿ2ôÖgDÜ#A!{&[GFÍ#Ã%òÿÿ2ÿþäÖgDÔ%Ï"&PGVõÿþ!>&_ÿÿ3™Ö&ÿÿ+£"&q& ÿÿ!ÿÿàígF!Ñ!Ž&üGRÿÿ(M&§ÿÿ,ÿù›gF%1!j&GX«ÿù"W%òÿÿ+¢"&q)A ÚC°/°3±í±í±í±í°/°3°3±í±í±í°ܰ3°3± í± í±í017;3276=4'&#!33732+Ž,J–}K=eFZþ§M,J–_0«–6E8Vj:(ý*x.'tÿÿ+ŠÖ4ÿÿ/x_/6 Ì0Åx Ì${D  ° /°3°30153##55373#5#'$y4^24(%û€€€’’[[[[ÿÿ&†&$q¦îÿÿE¡Ö,ÿÿE’Ö&,,ñÿÿEƒÖ&,',ñ,âÿÿEzÖ&,9ñÿÿ+‰Ö9ÿÿ+cÖ&9,Âÿÿ+TÖ&9',Â,³ÿÿ+EÖ&9',Â',³,¤ÿÿEzÖ&,;ñÿÿ+‰Ö;ÿÿ+[Ö&;,ºÿÿ+LÖ&;',º,«ÿÿ3‘Ö/ÿÿ3™Ö&ÿÿ; Ö'ÿÿEùÖ0ÿÿ;›|Lÿÿ;||&LLáÿÿ;]|&L'LáLÂÿÿ;ú|&LYáÿÿ$ÄYÿÿ$á|&YLFÿÿ$Â|&Y'LFL'ÿÿ$£|&Y'LF'L'Lÿÿ;Â|&L[áÿÿ$áÄ[ÿÿ$«|&[Lÿÿ$Œ|&['LLñÿÿ;›ÖOÿÿ!ÄFÿÿ0ÿþøÖGÿÿ\<ÄPÿÿ}5Öÿÿ1'Üÿÿ1ÿý'Üÿÿ1'Öÿÿ/ÿú(Öÿÿ1'×ÿÿ1'Öÿÿ1'Öÿÿ1ÿÿ'Öÿÿ}Ö&Xÿÿ}Ö&Xÿÿ}Ü&Xÿÿ}ÿýÜ&Xÿÿ}Ö&Xÿÿ}ÿú€Ö&XÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »DNЄ_<õè·ßvG·ßvGÿ<ý–¡ ÿ8Ðÿ<ÿG–¬°!MG>Š4æ;è^Ø>]3>i Z 'FB/=º6ùN²+X1X}X1X1X1X/X1X1X1X1; c3N,c3'3Ñ4¬&áGÙ3Ù;éC²+Ù3º$ñEÑ3Â3Ê3>EèiÊ;áA¾+á3è]Ñ3Ê+Â+ɺ+£éE«i²+«nN.X$F((9(!(0N$P^5ñ$á;7Ê+á;˜\é$>$N-N-é+ø1„-é$F$›$Ÿ:U+„lÒ9„>+G\(!Œ&+£/iº)7.Œ9@•-ãdø%ø8Ò…+Õÿü.(ÚAá:6DFDF)ç2%•- !¬" '3¬&¬&¬&¬&¬&¬&6&Ù3éCéCéCéCññ!ññ%èiÊ;Ê;Ê;Ê;Ê;Xf²*Ê+Ê+Ê+Ê+£áA.BF(F(F(F(F(F(Ì(!N$N$N$N$á ááÿþáÿþèié$>$>$>$>$>$?>$é$é$é$é$è:N-è:¬&F(¬&F(¬&F(Ù3(!Ù3(!Ù3(!Ù3(!Ù;N0%²+éCN$éCN$éCN$éCN$éCN$Ù3^5Ù3^5Ù3^5Ù3^5º$ñÿæà @*ñÿ¤áÿ ñÿ‡áÿƒñáÿþñáÿýñEá<ÂE°;Ñ37Â3Ê+æ6ÊáÊ3áÿýÊáÊ3';èié$èié$èié$Ê;>$Ê;>$Œ$á3é+á3éÿíá3é+è]ø1è]ø1è]ø1è]ø1Ñ3„-Ñ3Ê+é$Ê+éÊ+é$Ê+é$É›£è:£éEU+éEU+éEU+%Ê;>$Ê+éÊ+é$Ê+é$¬&F(Ù3^5èié$¬&F(è]ø1Ñ3„-¬&F(éCN$Ê;>$Ê;>$Ê;>$Ê;>$£è:« « V3Ð Ò)F)F(é'V<¬597FLÇ9."¬&F(áG(9áG(9áG(Ù3(!Ù;(0Ù;(0Ù;(Ù;(0Ù;(ÿÙéCN$éCN$éCNÿËéCN$éCN$²+PÙ3^5º$ñ$º$ñ$º$ñÿæº$ñ$ñÿ§áÿŸñáÿþÂ3Ê Â3Ê+Â3ÊÿîÊ3á;Êÿxáÿ‚Ê3áÿ‚Ê3áÿ<>E˜\>E˜\>E˜\èié$èié$èiéèiéÿÂÊ;>$Ê;>$Ê;>$Ê;>$áAN-áAN-á3é+á3é+á3éÿîá3éÿrè]ø1è]ø1è]ø1è]ø1è]ø1Ñ3„-Ñ3„-Ñ3„ÿÐÑ3„ÿŠÊ+é$Ê+é$Ê+éÿÂÊ+é$Ê+éÂ+F$Â+F$ɛɛɛɛɛº+$º+$£Ÿ:éEU+éEU+éEU+ñ„-›Ÿ:¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(éCN$éCN$éCN$éCN$éCN$éCN$ñEá;Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê+é$£Ÿ:£Ÿ:£Ÿ:º6º6X6ô6è6Ð6¤9Ž>YNX1X1x1x1x1x1x1kXÿòv,JÿíJÿÞaX1xx1x1x1x1x1x1x1x1kXÿòv,JÿíJÿÞ<2,2Ù3^+$!Ç,7+áA¾+Â/Â$¬&ñEâEÓE³EÂ+³+¤+•+«Eº+«+œ+Ê3Ù3Ù;>Eá;Â;£;';F$'$$é$ñ;$ñ$Ò$á;(!N0˜\X}X1X1X1X/X1X1X1X1°}°}°}°}°}°}nZnZnZnZnZnZnZnZnZÆZÆZÆZÆZÆZÆZÆZÆZÆZÆZÆZ’`ÿÜ3þù3Dÿˆ3Fÿˆ3Gÿˆ3Mÿ°3Rÿ’3Tÿˆ7Dÿ:7FÿN7Gÿ:7HÿL7PÿP7QÿO7RÿK7TÿC7UÿH7Vÿ87XÿO7ZÿM7\ÿ8=Mÿ°=Yÿš++++M|²Xt×MmŠŸÊ9Šò&zÚû€áL`ƒ– ! è F ¾ & ‚ Ö  ‹ Î ë . b ‰ ã,£åaë[ˆ×e­èMx¨¹Õús~Ì:•üŽÓJŠ£P¤q±D­îD`¬0LÄ =“nì­Ýœ¦ù  " Ä Ï! !/!d!´!Õ"$"Z"…"Ö"é"ó"þ##"#4#>#J#V#b#n#z#†#Ç#Ó#ß#ë#÷$$$$&$1$$›$§$³$¿$Ë$×$ä%b%n%z%†%’%ž%Þ&D&P&\&h&t&€&‹'Q']'i'u'''˜'¤'°'¼(;(G(S(_(k(w(ƒ(±) ))!)-)9)E)ª)¶)Ä)Ò)Þ)ê)ø******6*B*N*Z*f*r*~*†+,+:+H+T+`+l+x+†+”+ +¬+¸+Ä+Ð+Ü+è+ô,, ,,$,„,ü---"-0-;-G-U-c-o-‹-—-¢-®-ï-û../.:.E.Q.\.g.r.~.Š.–.¢.®.¹.Å.Ñ.ß.í.ù//X/d/p/|/ˆ/“/Ÿ/«/·/Ã/Ï/Û/ç/ò/þ0 00!0-090E0S0a0m0x0†0”0 0¬0¸0Ä0Ð0Ü0è0ô11 11 1,181J1\1l1{1‹1š1¬1¾1Ê1Ö1â1í1ý2 22$202<2H2T2`2k2}22¡2³2¿2Ë2Ý2ï2ý3 33#333>3l3Ÿ3§3²3ô4!4k4Ú5v66Ì77…7‘77©7¸7Ä7Ó7á7ò8888*868B8P8^8j8u888Ÿ8±8Ã8Õ8á8í8ù999$909<9J9X9d9p9|9ˆ9”9Ÿ9«9¶9Â9Î9Ý9ì9ø::::):7:C:O:a:s:::›:§:³:¿:Ë:×:ã:ï:û;;;;-;;;G;S;c;s;ƒ;“;¥;·;É;Û;ç;ó;ÿ< <<#>>>)>5>A>M>Y>e>q>}>‰>•>¡>­>¹>Å>Ñ>Ý>é>õ?? ??'?5?C?N?Z?f?r?~?Ž?ž?®?¾?Î?Þ?î?þ@@@.@>@N@^@n@~@Š@–@¢@®@¾@Î@Þ@î@þAAA.A:AFARA^AnA~AŽAžA®A¾AÎAÞAîAþBBB.B>BNB^BjBvB‚BŽBšB¦B²B¾BÚBöCC.CJCfCrC~C¶CÀCÊCÔCÞCèCòCüDDDD$D.D8DADJDSD\DeDnDwD€D‰D’DœD¦D°D¹DÂDÖDêDòDþEE&E2E€EˆE—E¾EÊEÒEÞEîEúFFFF2F>FFFRFbFjFrFzF‚FŠF–F¦F²FºFÆFÖFêFöFþG GG"G*G2G:GBGJGRGZGbGjGrGzG‚GŽGšG¦G²G¾GÊGÚGêGúH HH*H:HJHZHnH‚H–HªH¾HÒHæHúII"I6¬o@@û@AHPls{€‚ 6" Zh x €‚    6"  Z h  xCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ImUglyRegularPfaEdit : ImUgly : 2-9-2071ImUgly001.000ImUglyCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ImUglyRegularPfaEdit : ImUgly : 2-9-2071ImUgly001.000ImUglyÿœ2¬  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„…½–膎‹©¤ŠÚƒ“òó—ˆÃÞñžªõôö¢­ÉÇ®bcdËeÈÊÏÌÍÎéfÓÐѯgð‘ÖÔÕhëí‰jikmln oqprsutvwêxzy{}|¸¡~€ìîºýþ    ÿ øù !"#$%&'()*+ú×,-./0123456789:;<=>?@ABCD°±EFGHIJKLMNûüäåOPQRSTUVWXYZ[\]»^_`aæçbcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij²³klmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”Œ•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖר softhyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaronOmacronomacronObreveobreveRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflexuni0162uni0163TcaronUtildeutildeUmacronumacronUringuringUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentuni0189Ohornohornuni01D5uni01D6uni01D7uni01D8uni01DBuni01DCuni01DEuni01DFuni01F4uni01F5uni01F8uni01F9 Aringacute aringacute Scommaaccent scommaaccent Tcommaaccent tcommaaccentuni0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233 gravecomb acutecombuni0302 tildecombuni0306uni030Cuni0327uni0328uni0901uni0902uni0903uni0905uni0906uni0907uni0908uni0909uni090Auni1E00uni1E01uni1E02uni1E03uni1E04uni1E05uni1E06uni1E07uni1E08uni1E09uni1E0Auni1E0Buni1E0Cuni1E0Duni1E0Euni1E0Funi1E10uni1E11uni1E12uni1E13uni1E14uni1E15uni1E16uni1E17uni1E18uni1E19uni1E1Auni1E1Buni1E1Cuni1E1Duni1E1Euni1E1Funi1E20uni1E21uni1E22uni1E23uni1E24uni1E25uni1E26uni1E27uni1E28uni1E29uni1E2Cuni1E2Duni1E2Euni1E2Funi1E30uni1E31uni1E32uni1E33uni1E34uni1E35uni1E36uni1E37uni1E38uni1E39uni1E3Auni1E3Buni1E3Cuni1E3Duni1E3Euni1E3Funi1E40uni1E41uni1E42uni1E43uni1E44uni1E45uni1E46uni1E47uni1E48uni1E49uni1E4Auni1E4Buni1E4Cuni1E4Duni1E4Euni1E4Funi1E50uni1E51uni1E52uni1E53uni1E54uni1E55uni1E56uni1E57uni1E58uni1E59uni1E5Auni1E5Buni1E5Cuni1E5Duni1E5Euni1E5Funi1E60uni1E61uni1E62uni1E63uni1E64uni1E65uni1E66uni1E67uni1E68uni1E69uni1E6Auni1E6Buni1E6Cuni1E6Duni1E6Euni1E6Funi1E70uni1E71uni1E72uni1E73uni1E74uni1E75uni1E76uni1E77uni1E78uni1E79uni1E7Auni1E7Buni1E7Cuni1E7Duni1E7Euni1E7FWgravewgraveWacutewacute Wdieresis wdieresisuni1E86uni1E87uni1E88uni1E89uni1E8Auni1E8Buni1E8Cuni1E8Duni1E8Euni1E8Funi1E90uni1E91uni1E92uni1E93uni1E94uni1E95uni1E96uni1E97uni1E98uni1E99uni1EA0uni1EA1uni1EA4uni1EA5uni1EA6uni1EA7uni1EAAuni1EABuni1EACuni1EADuni1EAEuni1EAFuni1EB0uni1EB1uni1EB4uni1EB5uni1EB6uni1EB7uni1EB8uni1EB9uni1EBCuni1EBDuni1EBEuni1EBFuni1EC0uni1EC1uni1EC4uni1EC5uni1EC6uni1EC7uni1ECAuni1ECBuni1ECCuni1ECDuni1ED0uni1ED1uni1ED2uni1ED3uni1ED6uni1ED7uni1ED8uni1ED9uni1EDAuni1EDBuni1EDCuni1EDDuni1EE0uni1EE1uni1EE2uni1EE3uni1EE4uni1EE5Ygraveygraveuni1EF4uni1EF5uni1EF8uni1EF9uni2010uni2011 figuredash afii00208uni2016 exclamdbluni2043 zerosuperior foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperioruni207Auni207Buni207Cparenleftsuperiorparenrightsuperior nsuperior zeroinferior oneinferior twoinferior threeinferior fourinferior fiveinferior sixinferior seveninferior eightinferior nineinferioruni208Auni208Buni208Cparenleftinferiorparenrightinferioruni2100uni2101uni2102uni2103 afii61248uni2106uni2109uni2119uni211Auni2120uni212Buni2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216Funi2170uni2171uni2172uni2173uni2174uni2175uni2176uni2177uni2178uni2179uni217Auni217Buni217Cuni217Duni217Euni217Funi2460uni2461uni2462uni2463uni2464uni2465uni2466uni2467uni2468uni2469uni246Auni246Buni246Cuni246Duni246Euni2474uni2475uni2476uni2477uni2478uni2479uni247Auni247Buni247Cuni247Duni247Euni247Funi2480uni2481uni2482uni2483uni2484uni2485uni2486uni2487libimager-perl-1.004+dfsg.orig/FT2/fontfiles/ExistenceTest.ttf0000644000175000017500000000363412031434613023456 0ustar gregoagregoa €0OS/2QB_¥¼VcmapVÕJcvt å‡`glyfT{0Òp~headÖƒ#ð6hheatþ($hmtx-LlocaÖ` maxpI´l nameIôôŒâpostÿ¨Fp,èô ÈÈÈÈÈÈ1PfEd@ ~ÿÉZ7D(!/ÿÿ!/ÿÿÿâÿÕ!y~.–!nš.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!!MþÔ þõšýf!X3Ïâ*†± ?° 3° 3° 3±í±í±í±í°°Þ° 2°!2°"2±í±í±í±*í°$/°%3°&3°'3°(3±í±í±í°/°3°3°3°3°#3±í±í±í±í±í±,Ì01732+"'&=47632+"'&=476k2!  2!  ,!  ,!  ~ !  ! dþ6!  Ê! ÿÄÿÉ3 °/°/01;K"üµ$üè÷Å¡ƒ_<õèº2ïåº2ïåÿÄÿÉ3 ÿ8ZùÿÄÿÇ3°!M63ùÿÅ+++«¿+@†@ AO$W |Š ’€ ">HN˜´Ä €  " > HN ˜ ´ ÄCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ExistenceTestRegularPfaEdit : ExistenceTest : 28-11-2072ExistenceTest001.000ExistenceTestCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ExistenceTestRegularPfaEdit : ExistenceTest : 28-11-2072ExistenceTest001.000ExistenceTestÿœ2libimager-perl-1.004+dfsg.orig/FT2/fontfiles/NameTest.ttf0000644000175000017500000000343412031434613022405 0ustar gregoagregoa €@OS/2UÆÿÆHVcmap8#ñ´Rcvt !ygaspÿÿglyfÏ &€headÛê%Ì6hheaèí$hmtx é locaŠÔ maxpIS( name›œzÄpostèäéÜ6¾ ™_<õè½’ßž½’ßž!Zç"@.‡ôŠ»ŒŠ»ß1€PfEd@  ÿ8Z°!M'oçYL0 ! ÿÿ ! ÿÿÿõÿâßô!y+++_~!nš.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!!MþÔ þõšýf!Xo«!747632#"'&7#"'&547632o6<t@Y4f2#!"'&54763tþþfzº ÕHêY t§=|Ìã$4k–¹ z º  Õ Hê Y  t §Created by Tony Cook - test font for the glyph_names() methodCreated by Tony Cook - test font for the glyph_names() methodNameTestNameTestMediumMediumFontForge 1.0 : NameTest : 13-9-2004FontForge 1.0 : NameTest : 13-9-2004NameTestNameTestVersion 001.000 Version 001.000 NameTestNameTestÿœ2 hyphentwoÿÿlibimager-perl-1.004+dfsg.orig/FT2/fontfiles/dodge.ttf0000644000175000017500000002543012031434613021747 0ustar gregoagregoa €POS/2‚ep¿ÜNcmap¿ð4€,rglyféjjC žhead,.ºR@6hheaßÎx$hmtxdÁœèlocaŒ¦„ìmaxpZÓ!p nameSM !post C6Ê#¤cvt ŠÝ£%¸âfpgmƒ3ÂO*œprepŽè8r*°f뼊¼ŠÅ2Alts@ /ÿ:/¦DJ(~ ÿÿ ÿÿÿãà  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`anjkhibfgoedqpcmrl(~ ÿÿ ÿÿÿãà?¶/V@ @ Fv/7?'5#>z–@>Ì–@>¬šþÆ$<@šþÆ$<y×a5#×^__ÿ¼°‰!5!3576=4&#!#!546;53!!#Š–ÓQl__ý¤–dVXüìnOÍ–ýe5ššDDMMBL>DDB ––@>¬šþÆ$<ÿZRø#"&546;#R•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8ÿZRø32654&+3•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8m Î #5##3353 ®¯®®¯®Xvvuvvÿ`–š35#>––@>šþÆ$<àÛj=!!ÛþoàŠŠ–š35#––šš F13#¯]¯F°F#54632#!"&%5.#!"3!26'5#nO6OnnOýÊOnF5þ|5HH6Š0Mû–‘$DDB DDB ‘š´F75!35#!"3!26=4&#!463!ÂV„½ýÊOnb_5Rl__ý¤H6ŠšBBžU<þåNLMMBL>0°F#53!2#=4&#!„„½6On–H6þv¨žU<þÜ‘èp 0ÿþ°F(7)5#75!467;6+"&=67&'3štDDüêlQËNTËQl^^lR´n`´Rl^^œàFFŠBMMMMB::BMMMMB::´F!5#3!2656&#&3!#!òýª„½6Onb_ýÊQl__\H6þv¬BBþòžU<NLMMBL>0¯l3#535#53¯¯¯¯¯‘I’ÿo¯l 7#53#26=#¯®®®If®Ú’þU<‘RF%#"&546;#"3R•OnnO•=5HH6žžU<$ŠBþTššN+ú+%!"&=463!2#7.#!"3!/#73#'+#73*ýwC__CæC`TF5þ|5HH6…®I+<-•d.. p 0¨@ô__–°F'#7;#'+#3 5·lLLŒ–ªPZ‚®–ôªdHšýºààd°F%!#)%!5!536#!#ýÊH??ý‚~üì½6Ql^^lRý˽àFÐBšMMB::BMMj°F%3#!"&54637!"3!,„½ýÊOnnO6½ýe5HH6ŠžžU<$Bž‘ÙB°F#54632#!"&%26=.#!"3?3nO6OnnOýÊOn ~0MF5þ|5HH6t–‘$à°F!!3!26=4&#!53!5%"dVXüì½5Rl__ý¤›½ýÊOnŽ(DDBšMMBL>FšU<°F !#+537! –ªà½6½þp¬šš°F%5'3#!"&533!26–nOýÊOn–H6Š0Mðpæ’þÝLBššBL>@¦šš°F%#!=463!3!5#'!3°½ý __\–dVý¨½ýʽ›5šššBL>DDBššÿZRø#"&546;#R•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8 F!#3 ¯þ£¯FÿZRø32654&+3•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8j‘15!j‘‘ÿÿ$®F#26=#If®$U<‘°F'#7;#'+#3 5·lLLŒ–ªPZ‚®–ôªdHšýºààd°F%!#)%!5!536#!#ýÊH??ý‚~üì½6Ql^^lRý˽àFÐBšMMB::BMMj°F%3#!"&54637!"3!,„½ýÊOnnO6½ýe5HH6ŠžžU<$Bž‘ÙB°F#54632#!"&%26=.#!"3?3nO6OnnOýÊOn ~0MF5þ|5HH6t–‘$à°F53%6=4&#!#!54637!#½6Ql__ý¤–dVXüìnO6½ýe5ššMMBL>DDB >LBšýº  °F%#!#5%!5#'!3°½ýǺ"ŽýÖ*½ýʽ›5šššÌÌššF"#"&5463PLh’F’DuB‘~$zF232654&#PLh’F’DuB‘~$z –F5#>––@>¬šþÆ$<2_¥O@@ Fv/7/Ì–@>¦š:$<@š:$< zF 53.753.–@>Ì–@>¬šþÆ$<@šþÆ$< –F#––@>¦š:$< –F53.–@>¬šþÆ$<56µ>@@Fv/7/@@Fv/7/Ì–@>¬šþÆ$<@šþÆ$<nÓò_<õè­³Ñ{­³Ñ{ÿùÿZ´//ÿZÿùÿÞ´zô?XáÆy*¬ÇÇyMÿþÇ{Ç•ÇÇ9×ÿÿ„t„9UeN!øááNú5eeÿýeÿùMHð2eoáŠ||||¢ÔîRRRr²ðð8Rh€îd´òH¢ÚN¬Ìö4Z–ÚZ”ð<â ~ º Ø  R Š Ð n ª  ^ ´ Þ $ N Ž Ø p°Ê<vÒrÄ`¤ÌJ‚È nª^¸â(R’Ô^œœØØØøllÂJzš¸¸P¨ÂÂÂÂnžžžz,@ Êe;;AHNTU v\  Ò Þ  ì  ø   1999 - Iconian Fonts: http://members.xoom.com/iconianfonts/DodgerRegularDodgerDodger1Dodger1999 - Iconian Fonts: http://members.xoom.com/iconianfonts/DodgerRegularDodgerDodger1Dodgerÿ8ó  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘“–—ž ¡¢£¤¦©ª«¬­®¯°±²³´µ¶·¸º»½¾¿ÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÓÔÕÖØÙÚÞäåèéêëìíîïðâãæç’”•˜™š›œŸ¥§¨¹¼ÀÁÒ×ÛÜÝßàáHTglyph105ÿ;ÿø–…—†ˆW8°Á?äfkRC!“qãA:b¦F÷¤Ê¼³æÅF¤† ºñÝ5Hæ'A‰qF80šåœ‰N!´éŒƒo<€Œi6Q“ß´”#7Ö‚8±WEÞÔIá Ñ]1¬÷[+»‚]ƾdÌ×UBçîr€|²RŸì>`¥«%³%‚Ôf$¶}–X˜ÂIa«IŠß_‹}ˆÑ†Sg&Gȯ°uÈ ™àTFFÏñï$©H[â™*™BBûðN54À« 7í®mUKµèÚŸ]-ôµnMN®g—¾Öí8Ü'CwáZŽÁ=k´RùÉ–ˆ#½¾X¢l¢]“­ãþ3Ç=ÌÛ4 ÚÌ•£kßÔž¥(÷öØGM9ÓÃCJ;lž*Ü$äý!uñn¶fÀ(eÀK†±h†x¡ 8Ó%ld_]¦¬ôï5Ö Nü"d9££J/²üÜdV÷­]lN¾€ŽÐÖ0 ~,ËÑ4da5Ýð"|w(9‘ˆ27}Eæ“È¢\w >üàS© ‰¾á4Ç•q¼ZÆm-#BÏôLc¨Kã‚ –¶,feGD¾ŸñóÒ:+yU?çc†¨)6•å¹o1Ø”~v€†Ã鳌FÁ¿z+Fe޹Îó7Êp <>ÛQ†ã(o”<»¥7^ÖÓ}=]ñï)@ú¼‰8¬¦ ^¡ûW2f¸Tˆ­ÈëF’;1ù™¼m{ØÍú¯v7Зϗ}@»®úû¯P¸õñ¢!wg ’ï{B?®Ð"KØúAÜÄs¦ÿY˜Ôh¯ì]Ε äE2'¸Þ/UÚø@*(ÐZ¿7[熩§B^ÉÅ4% JûíŽd ¡þàÞÂ'aq­¸”ƒÑÔ_fàã{™á(‹·sdì–†7Òõ£ö‰à‡Ã¬`0˜šFôü%ž¿msµþËÌÐxœò™aV…­ïC`TäÖÐ%«:¼p‚Ö}]Éèvks~ ¦«êÜçmGÆ€dVF"µÁk——æ¬iyó‘vhæ[e6 \1õ£ŽŸg¡æïIðøÈ¡š%¸2ÉK û:Òd)…äÿ}èT>—àfcä5z«T€èùÿ»´ógèèi|”"ågµbÇPè.)?GîðJiú`ˆ‰Êg‰‚ìXÃAÉ´ße~‹C/ ö€•ô¶‘¼]+Åí몕ñeW‚:×Õœ!’ëܺÄÙêé€~°˜t;ÂfiAþ£~¡QHº'à1 XàE¿AämÖ‹Ì®6ÖÓ¤TA®bÄÚò’W©ŒÇ™Häw>= 2úm˜+à­z5kwZvrJ@-\¬ù¿n.³ŽfN¹ôãú ¥”©:–=ö9ãig[ö”ÛM†è¡Á$V mº líµtIB3š¯ØŒQ¾ ·×ä´â—wÒ†LIUË­`ø‹"wW[¡ËîãþÏNóšz ôÇ–ÖôR¸Ô†`Ìp&ó*:»CæG÷"Ê5%¢F|guæÜ•“<·óçÁ¥žMÎ-2ÂhoÑâ¹­ÛûÍWÌ'W»kMußÀK{"É…Ì¹ÚøŸŸr0+Xí¸Um5©Ï›¿Ù7‘LÊi]5—’®Ì¬ nŠƒP­ççdgZ_>L^˜_EI žÞRÓª1/Aà…bÏ!°I€bCNBçåáPi©2±ûò®xõ’ªÝuW™þT¦7¸=®qÙTS±eæxìBâ±ó$ÆÁbËÏ~8t"a;‹=U4ޝ—b¯ò#ÎÌ•L Ѫ¼ö!{ ,ä: ¡ÙÓͳ¬ ]%¯m]Z?è§xŸ>ñ¯;lZ/fÈ ”I9•;òª8Õâ¢Õ X’Îj-&ÐSrtVã‹Å[ÖÇ ÌŽs_´øƒD=¥_áœ|Žû,§6ÎÐkrÖaÎt,Ê¿;<žT ˆ<åþ¯£ƒä¬íH9ê£á]nüx¸ìxõš,­Kns]éZ3QóL‹qh*¶õ6Iª @Ñ×EìØH‡bìŸ-càÌPå: X´!û[¢@IÃoÍ<0'e5Imager::Color->new(255,0,0,255), size=>15, @_); unless ($hsh{file}) { $Imager::ERRSTR = "No font file specified"; return; } unless (-e $hsh{file}) { $Imager::ERRSTR = "Font file $hsh{file} not found"; return; } unless ($Imager::formats{ft2}) { $Imager::ERRSTR = "Freetype2 not supported in this build"; return; } my $id = i_ft2_new($hsh{file}, $hsh{'index'} || 0); unless ($id) { # the low-level code may miss some error handling $Imager::ERRSTR = Imager::_error_as_msg(); return; } return bless { id => $id, aa => $hsh{aa} || 0, file => $hsh{file}, type => 't1', size => $hsh{size}, color => $hsh{color}, utf8 => $hsh{utf8}, vlayout => $hsh{vlayout}, }, $class; } sub _draw { my $self = shift; $self->_valid or return; my %input = @_; if (exists $input{channel}) { i_ft2_cp($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'}, $input{channel}, $input{size}, $input{sizew} || 0, $input{string}, , $input{align}, $input{aa}, $input{vlayout}, $input{utf8}); } else { i_ft2_text($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'}, $input{color}, $input{size}, $input{sizew} || 0, $input{string}, $input{align}, $input{aa}, $input{vlayout}, $input{utf8}); } } sub _bounding_box { my $self = shift; my %input = @_; $self->_valid or return; my @result = i_ft2_bbox($self->{id}, $input{size}, $input{sizew}, $input{string}, $input{utf8}); unless (@result) { Imager->_set_error(Imager->_error_as_msg); return; } return @result; } sub dpi { my $self = shift; $self->_valid or return; my @old = i_ft2_getdpi($self->{id}); if (@_) { my %hsh = @_; my $result; unless ($hsh{xdpi} && $hsh{ydpi}) { if ($hsh{dpi}) { $hsh{xdpi} = $hsh{ydpi} = $hsh{dpi}; } else { $Imager::ERRSTR = "dpi method requires xdpi and ydpi or just dpi"; return; } i_ft2_setdpi($self->{id}, $hsh{xdpi}, $hsh{ydpi}) or return; } } return @old; } sub hinting { my ($self, %opts) = @_; $self->_valid or return; i_ft2_sethinting($self->{id}, $opts{hinting} || 0); } sub _transform { my $self = shift; $self->_valid or return; my %hsh = @_; my $matrix = $hsh{matrix} or return undef; return i_ft2_settransform($self->{id}, $matrix) } sub utf8 { return 1; } # check if the font has the characters in the given string sub has_chars { my ($self, %hsh) = @_; $self->_valid or return; unless (defined $hsh{string} && length $hsh{string}) { $Imager::ERRSTR = "No string supplied to \$font->has_chars()"; return; } if (wantarray) { my @result = i_ft2_has_chars($self->{id}, $hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0)); unless (@result) { Imager->_set_error(Imager->_error_as_msg); return; } return @result; } else { my $result = i_ft2_has_chars($self->{id}, $hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0)); unless (defined $result) { Imager->_set_error(Imager->_error_as_msg); return; } return $result; } } sub face_name { my ($self) = @_; $self->_valid or return; i_ft2_face_name($self->{id}); } sub can_glyph_names { my ($self) = @_; i_ft2_can_do_glyph_names() or return; if (ref $self) { $self->_valid or return; i_ft2_face_has_glyph_names($self->{id}) or return; } return 1; } sub glyph_names { my ($self, %input) = @_; $self->_valid or return; my $string = $input{string}; defined $string or return Imager->_set_error("no string parameter passed to glyph_names"); my $utf8 = _first($input{utf8}, 0); my $reliable_only = _first($input{reliable_only}, 1); my @names = i_ft2_glyph_name($self->{id}, $string, $utf8, $reliable_only); @names or return Imager->_set_error(Imager->_error_as_msg); return @names if wantarray; return pop @names; } sub is_mm { my ($self) = @_; $self->_valid or return; i_ft2_is_multiple_master($self->{id}); } sub mm_axes { my ($self) = @_; $self->_valid or return; my ($num_axis, $num_design, @axes) = i_ft2_get_multiple_masters($self->{id}) or return Imager->_set_error(Imager->_error_as_msg); return @axes; } sub set_mm_coords { my ($self, %opts) = @_; $self->_valid or return; $opts{coords} or return Imager->_set_error("Missing coords parameter"); ref($opts{coords}) && $opts{coords} =~ /ARRAY\(0x[\da-f]+\)$/ or return Imager->_set_error("coords parameter must be an ARRAY ref"); i_ft2_set_mm_coords($self->{id}, @{$opts{coords}}) or return Imager->_set_error(Imager->_error_as_msg); return 1; } # objects may be invalidated on thread creation (or Win32 fork emulation) sub _valid { my $self = shift; unless ($self->{id} && Scalar::Util::blessed($self->{id})) { Imager->_set_error("font object was created in another thread"); return; } return 1; } 1; __END__ =head1 NAME Imager::Font::FT2 - font support using FreeType 2 =head1 SYNOPSIS use Imager; my $img = Imager->new; my $font = Imager::Font->new(file => "foo.ttf", type => "ft2"); $img->string(... font => $font); =head1 DESCRIPTION This provides font support on FreeType 2. =head1 CAVEATS Unfortunately, older versions of Imager would install C even if FreeType 2 wasn't available, and if no font was created would succeed in loading the module. This means that an existing C could cause a probe success for supported font files, so I've renamed it. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Font. =cut libimager-perl-1.004+dfsg.orig/FT2/freetyp2.c0000644000175000017500000007775212263740577020117 0ustar gregoagregoa/* =head1 NAME freetyp2.c - font support via the FreeType library version 2. =head1 SYNOPSIS if (!i_ft2_init()) { error } FT2_Fonthandle *font; font = i_ft2_new(name, index); if (!i_ft2_setdpi(font, xdpi, ydpi)) { error } if (!i_ft2_getdpi(font, &xdpi, &ydpi)) { error } double matrix[6]; if (!i_ft2_settransform(font, matrix)) { error } i_img_dim bbox[BOUNDING_BOX_COUNT]; if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox, utf8)) { error } i_img *im = ...; i_color cl; if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align, aa, vlayout, utf8)) { error } if (!i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, length, align, aa)) { error } i_ft2_destroy(font); =head1 DESCRIPTION Implements Imager font support using the FreeType2 library. The FreeType2 library understands several font file types, including Truetype, Type1 and Windows FNT. =over =cut */ #include "imext.h" #include "imft2.h" #include #include #include #include #include FT_FREETYPE_H #ifdef FT_MULTIPLE_MASTERS_H #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT #define IM_FT2_MM #include FT_MULTIPLE_MASTERS_H #endif #endif static void ft2_push_message(int code); static void ft2_final(void *); static im_slot_t slot = -1; typedef struct { int initialized; FT_Library library; im_context_t ctx; } ft2_state; static ft2_state * i_ft2_init(void); static i_img_dim i_min(i_img_dim a, i_img_dim b); static i_img_dim i_max(i_img_dim a, i_img_dim b); int i_ft2_version(int runtime, char *buf, size_t buf_size) { char work[100]; i_clear_error(); if (buf_size == 0) { i_push_error(0, "zero size buffer supplied"); return 0; } if (runtime) { ft2_state *ft2; /* initialized to work around a bug in FT2 http://lists.nongnu.org/archive/html/freetype-devel/2002-09/msg00058.html Though I don't know why I still see this in 2.4.2 */ FT_Int major = 1, minor = 1, patch = 1; if ((ft2 = i_ft2_init()) == NULL) return 0; FT_Library_Version(ft2->library, &major, &minor, &patch); sprintf(work, "%d.%d.%d", (int)major, (int)minor, (int)patch); } else { sprintf(work, "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH); } strncpy(buf, work, buf_size); buf[buf_size-1] = '\0'; return 1; } void i_ft2_start(void) { if (slot == -1) slot = im_context_slot_new(ft2_final); } /* =item i_ft2_init(void) Initializes the Freetype 2 library. Returns ft2_state * on success or NULL on failure. =cut */ static ft2_state * i_ft2_init(void) { FT_Error error; im_context_t ctx = im_get_context(); ft2_state *ft2 = im_context_slot_get(ctx, slot); if (ft2 == NULL) { ft2 = mymalloc(sizeof(ft2_state)); ft2->initialized = 0; ft2->library = NULL; ft2->ctx = ctx; im_context_slot_set(ctx, slot, ft2); mm_log((1, "created FT2 state %p for context %p\n", ft2, ctx)); } i_clear_error(); if (!ft2->initialized) { error = FT_Init_FreeType(&ft2->library); if (error) { ft2_push_message(error); i_push_error(0, "Initializing Freetype2"); return NULL; } mm_log((1, "initialized FT2 state %p\n", ft2)); ft2->initialized = 1; } return ft2; } static void ft2_final(void *state) { ft2_state *ft2 = state; if (ft2->initialized) { mm_log((1, "finalizing FT2 state %p\n", state)); FT_Done_FreeType(ft2->library); ft2->library = NULL; ft2->initialized = 0; } mm_log((1, "freeing FT2 state %p\n", state)); myfree(state); } struct FT2_Fonthandle { FT_Face face; ft2_state *state; int xdpi, ydpi; int hint; FT_Encoding encoding; /* used to adjust so we can align the draw point to the top-left */ double matrix[6]; #ifdef IM_FT2_MM /* Multiple master data if any */ int has_mm; FT_Multi_Master mm; #endif }; /* the following is used to select a "best" encoding */ static struct enc_score { FT_Encoding encoding; int score; } enc_scores[] = { /* the selections here are fairly arbitrary ideally we need to give the user a list of encodings available and a mechanism to choose one */ { ft_encoding_unicode, 10 }, { ft_encoding_sjis, 8 }, { ft_encoding_gb2312, 8 }, { ft_encoding_big5, 8 }, { ft_encoding_wansung, 8 }, { ft_encoding_johab, 8 }, { ft_encoding_latin_2, 6 }, { ft_encoding_apple_roman, 6 }, { ft_encoding_adobe_standard, 6 }, { ft_encoding_adobe_expert, 6 }, }; /* =item i_ft2_new(char *name, int index) Creates a new font object, from the file given by I. I is the index of the font in a file with multiple fonts, where 0 is the first font. Return NULL on failure. =cut */ FT2_Fonthandle * i_ft2_new(const char *name, int index) { FT_Error error; FT2_Fonthandle *result; FT_Face face; int i, j; FT_Encoding encoding; int score; ft2_state *ft2; mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index)); if ((ft2 = i_ft2_init()) == NULL) return NULL; i_clear_error(); error = FT_New_Face(ft2->library, name, index, &face); if (error) { ft2_push_message(error); i_push_error(error, "Opening face"); mm_log((2, "error opening face '%s': %d\n", name, error)); return NULL; } encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode; score = 0; for (i = 0; i < face->num_charmaps; ++i) { FT_Encoding enc_entry = face->charmaps[i]->encoding; mm_log((2, "i_ft2_new, encoding %X platform %u encoding %u\n", (unsigned)enc_entry, face->charmaps[i]->platform_id, face->charmaps[i]->encoding_id)); for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) { if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) { encoding = enc_entry; score = enc_scores[j].score; break; } } } FT_Select_Charmap(face, encoding); mm_log((2, "i_ft2_new, selected encoding %X\n", (unsigned)encoding)); result = mymalloc(sizeof(FT2_Fonthandle)); result->face = face; result->state = ft2; result->xdpi = result->ydpi = 72; result->encoding = encoding; /* by default we disable hinting on a call to i_ft2_settransform() if we don't do this, then the hinting can the untransformed text to be a different size to the transformed text. Obviously we have it initially enabled. */ result->hint = 1; /* I originally forgot this: :/ */ /*i_ft2_settransform(result, matrix); */ result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0; result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0; #ifdef IM_FT2_MM { FT_Multi_Master *mm = &result->mm; int i; if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0 && (error = FT_Get_Multi_Master(face, mm)) == 0) { mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs)); for (i = 0; i < mm->num_axis; ++i) { mm_log((2, " axis %d name %s range %ld - %ld\n", i, mm->axis[i].name, (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum))); } result->has_mm = 1; } else { mm_log((2, "No multiple masters\n")); result->has_mm = 0; } } #endif return result; } /* =item i_ft2_destroy(FT2_Fonthandle *handle) Destroys a font object, which must have been the return value of i_ft2_new(). =cut */ void i_ft2_destroy(FT2_Fonthandle *handle) { FT_Done_Face(handle->face); myfree(handle); } /* =item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) Sets the resolution in dots per inch at which point sizes scaled, by default xdpi and ydpi are 72, so that 1 point maps to 1 pixel. Both xdpi and ydpi should be positive. Return true on success. =cut */ int i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) { i_clear_error(); if (xdpi > 0 && ydpi > 0) { handle->xdpi = xdpi; handle->ydpi = ydpi; return 1; } else { i_push_error(0, "resolutions must be positive"); return 0; } } /* =item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) Retrieves the current horizontal and vertical resolutions at which point sizes are scaled. =cut */ int i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) { *xdpi = handle->xdpi; *ydpi = handle->ydpi; return 1; } /* =item i_ft2_settransform(FT2_FontHandle *handle, double *matrix) Sets a transormation matrix for output. This should be a 2 x 3 matrix like: matrix[0] matrix[1] matrix[2] matrix[3] matrix[4] matrix[5] =cut */ int i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) { FT_Matrix m; FT_Vector v; int i; m.xx = matrix[0] * 65536; m.xy = matrix[1] * 65536; v.x = matrix[2]; /* this could be pels of 26.6 fixed - not sure */ m.yx = matrix[3] * 65536; m.yy = matrix[4] * 65536; v.y = matrix[5]; /* see just above */ FT_Set_Transform(handle->face, &m, &v); for (i = 0; i < 6; ++i) handle->matrix[i] = matrix[i]; handle->hint = 0; return 1; } /* =item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) If hinting is non-zero then glyph hinting is enabled, otherwise disabled. i_ft2_settransform() disables hinting to prevent distortions in gradual text transformations. =cut */ int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) { handle->hint = hinting; return 1; } /* =item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, i_img_dim *bbox) Retrieves bounding box information for the font at the given character width and height. This ignores the transformation matrix. Returns non-zero on success. =cut */ int i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char const *text, size_t len, i_img_dim *bbox, int utf8) { FT_Error error; i_img_dim width; int index; int first; int ascent = 0, descent = 0; int glyph_ascent, glyph_descent; FT_Glyph_Metrics *gm; int start = 0; int loadFlags = FT_LOAD_DEFAULT; int rightb = 0; i_clear_error(); mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %u, bbox %p)\n", handle, cheight, cwidth, text, (unsigned)len, bbox)); error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, handle->xdpi, handle->ydpi); if (error) { ft2_push_message(error); i_push_error(0, "setting size"); } if (!handle->hint) loadFlags |= FT_LOAD_NO_HINTING; first = 1; width = 0; while (len) { unsigned long c; if (utf8) { c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { c = (unsigned char)*text++; --len; } index = FT_Get_Char_Index(handle->face, c); error = FT_Load_Glyph(handle->face, index, loadFlags); if (error) { ft2_push_message(error); i_push_errorf(0, "loading glyph for character \\x%02lx (glyph 0x%04X)", c, index); return 0; } gm = &handle->face->glyph->metrics; glyph_ascent = gm->horiBearingY / 64; glyph_descent = glyph_ascent - gm->height/64; if (first) { start = gm->horiBearingX / 64; /* handles -ve values properly */ ascent = glyph_ascent; descent = glyph_descent; first = 0; } if (glyph_ascent > ascent) ascent = glyph_ascent; if (glyph_descent < descent) descent = glyph_descent; width += gm->horiAdvance / 64; if (len == 0) { /* last character handle the case where the right the of the character overlaps the right*/ rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64; /*if (rightb > 0) rightb = 0;*/ } } bbox[BBOX_NEG_WIDTH] = start; bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64; bbox[BBOX_POS_WIDTH] = width; if (rightb < 0) bbox[BBOX_POS_WIDTH] -= rightb; bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64; bbox[BBOX_DESCENT] = descent; bbox[BBOX_ASCENT] = ascent; bbox[BBOX_ADVANCE_WIDTH] = width; bbox[BBOX_RIGHT_BEARING] = rightb; mm_log((1, " bbox=> negw=%" i_DF " glob_desc=%" i_DF " pos_wid=%" i_DF " glob_asc=%" i_DF " desc=%" i_DF " asc=%" i_DF " adv_width=%" i_DF " rightb=%" i_DF "\n", i_DFc(bbox[0]), i_DFc(bbox[1]), i_DFc(bbox[2]), i_DFc(bbox[3]), i_DFc(bbox[4]), i_DFc(bbox[5]), i_DFc(bbox[6]), i_DFc(bbox[7]))); return BBOX_RIGHT_BEARING + 1; } /* =item transform_box(FT2_FontHandle *handle, int bbox[4]) bbox contains coorinates of a the top-left and bottom-right of a bounding box relative to a point. This is then transformed and the values in bbox[4] are the top-left and bottom-right of the new bounding box. This is meant to provide the bounding box of a transformed character box. The problem is that if the character was round and is rotated, the real bounding box isn't going to be much different from the original, but this function will return a _bigger_ bounding box. I suppose I could work my way through the glyph outline, but that's too much hard work. =cut */ void ft2_transform_box(FT2_Fonthandle *handle, i_img_dim bbox[4]) { double work[8]; double *matrix = handle->matrix; work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1]; work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1]; work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1]; work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1]; work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3]; work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3]; work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3]; work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3]; bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6]))); bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7]))); bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6]))); bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7]))); } /* =item expand_bounds(int bbox[4], int bbox2[4]) Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new bounding box in bbox[] that encloses both. =cut */ static void expand_bounds(i_img_dim bbox[4], i_img_dim bbox2[4]) { bbox[0] = i_min(bbox[0], bbox2[0]); bbox[1] = i_min(bbox[1], bbox2[1]); bbox[2] = i_max(bbox[2], bbox2[2]); bbox[3] = i_max(bbox[3], bbox2[3]); } /* =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int vlayout, int utf8, i_img_dim *bbox) Retrieves bounding box information for the font at the given character width and height. This version finds the rectangular bounding box of the glyphs, with the text as transformed by the transformation matrix. As with i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of the topline to the top-left of the bounding box. Unlike i_ft2_bbox() this could be near the bottom left corner of the box. (bbox[4], bbox[5]) is the offset to the start of the baseline. (bbox[6], bbox[7]) is the offset from the start of the baseline to the end of the baseline. Returns non-zero on success. =cut */ int i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char const *text, size_t len, int vlayout, int utf8, i_img_dim *bbox) { FT_Error error; int index; int first; i_img_dim ascent = 0, descent = 0; int glyph_ascent, glyph_descent; FT_Glyph_Metrics *gm; i_img_dim work[4]; i_img_dim bounds[4] = { 0 }; double x = 0, y = 0; int i; FT_GlyphSlot slot; int loadFlags = FT_LOAD_DEFAULT; if (vlayout) loadFlags |= FT_LOAD_VERTICAL_LAYOUT; if (!handle->hint) loadFlags |= FT_LOAD_NO_HINTING; error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, handle->xdpi, handle->ydpi); if (error) { ft2_push_message(error); i_push_error(0, "setting size"); } first = 1; while (len) { unsigned long c; if (utf8) { c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { c = (unsigned char)*text++; --len; } index = FT_Get_Char_Index(handle->face, c); error = FT_Load_Glyph(handle->face, index, loadFlags); if (error) { ft2_push_message(error); i_push_errorf(0, "loading glyph for character \\x%02lx (glyph 0x%04X)", c, index); return 0; } slot = handle->face->glyph; gm = &slot->metrics; /* these probably don't mean much for vertical layouts */ glyph_ascent = gm->horiBearingY / 64; glyph_descent = glyph_ascent - gm->height/64; if (vlayout) { work[0] = gm->vertBearingX; work[1] = gm->vertBearingY; } else { work[0] = gm->horiBearingX; work[1] = gm->horiBearingY; } work[2] = gm->width + work[0]; work[3] = work[1] - gm->height; if (first) { bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2]; bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5]; bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64; bbox[5] /= 64; } ft2_transform_box(handle, work); for (i = 0; i < 4; ++i) work[i] /= 64; work[0] += x; work[1] += y; work[2] += x; work[3] += y; if (first) { for (i = 0; i < 4; ++i) bounds[i] = work[i]; ascent = glyph_ascent; descent = glyph_descent; first = 0; } else { expand_bounds(bounds, work); } x += slot->advance.x / 64; y += slot->advance.y / 64; if (glyph_ascent > ascent) ascent = glyph_ascent; if (glyph_descent > descent) descent = glyph_descent; if (len == 0) { /* last character handle the case where the right the of the character overlaps the right*/ /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width; if (rightb < 0) width -= rightb / 64;*/ } } /* at this point bounds contains the bounds relative to the CP, and x, y hold the final position relative to the CP */ /*bounds[0] -= x; bounds[1] -= y; bounds[2] -= x; bounds[3] -= y;*/ bbox[0] = bounds[0]; bbox[1] = -bounds[3]; bbox[2] = bounds[2]; bbox[3] = -bounds[1]; bbox[6] = x; bbox[7] = -y; return 1; } static int make_bmp_map(FT_Bitmap *bitmap, unsigned char *map); /* =item i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, double cheight, double cwidth, char *text, size_t len, int align, int aa) Renders I to (I, I) in I using color I at the given I and I. If align is 0, then the text is rendered with the top-left of the first character at (I, I). If align is non-zero then the text is rendered with (I, I) aligned with the base-line of the characters. If aa is non-zero then the text is anti-aliased. Returns non-zero on success. =cut */ int i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const i_color *cl, double cheight, double cwidth, char const *text, size_t len, int align, int aa, int vlayout, int utf8) { FT_Error error; int index; FT_Glyph_Metrics *gm; i_img_dim bbox[BOUNDING_BOX_COUNT]; FT_GlyphSlot slot; int x, y; unsigned char map[256]; char last_mode = ft_pixel_mode_none; int last_grays = -1; int loadFlags = FT_LOAD_DEFAULT; i_render *render = NULL; unsigned char *work_bmp = NULL; size_t work_bmp_size = 0; mm_log((1, "i_ft2_text(handle %p, im %p, (tx,ty) (" i_DFp "), cl %p (#%02x%02x%02x%02x), cheight %f, cwidth %f, text %p, len %u, align %d, aa %d, vlayout %d, utf8 %d)\n", handle, im, i_DFcp(tx, ty), cl, cl->rgba.r, cl->rgba.g, cl->rgba.b, cl->rgba.a, cheight, cwidth, text, (unsigned)len, align, aa, vlayout, utf8)); i_clear_error(); if (vlayout) { if (!FT_HAS_VERTICAL(handle->face)) { i_push_error(0, "face has no vertical metrics"); return 0; } loadFlags |= FT_LOAD_VERTICAL_LAYOUT; } if (!handle->hint) loadFlags |= FT_LOAD_NO_HINTING; /* set the base-line based on the string ascent */ if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8)) return 0; render = i_render_new(im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]); work_bmp_size = bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]; work_bmp = mymalloc(work_bmp_size); if (!align) { /* this may need adjustment */ tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2]; ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5]; } while (len) { unsigned long c; if (utf8) { c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { c = (unsigned char)*text++; --len; } index = FT_Get_Char_Index(handle->face, c); error = FT_Load_Glyph(handle->face, index, loadFlags); if (error) { ft2_push_message(error); i_push_errorf(0, "loading glyph for character \\x%02lx (glyph 0x%04X)", c, index); if (render) i_render_delete(render); return 0; } slot = handle->face->glyph; gm = &slot->metrics; if (gm->width) { error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono); if (error) { ft2_push_message(error); i_push_errorf(0, "rendering glyph 0x%04lX (character \\x%02X)", c, index); if (render) i_render_delete(render); return 0; } if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) { unsigned char *bmp = slot->bitmap.buffer; if (work_bmp_size < slot->bitmap.width) { work_bmp_size = slot->bitmap.width; work_bmp = myrealloc(work_bmp, work_bmp_size); } for (y = 0; y < slot->bitmap.rows; ++y) { int pos = 0; int bit = 0x80; unsigned char *p = work_bmp; for (x = 0; x < slot->bitmap.width; ++x) { *p++ = (bmp[pos] & bit) ? 0xff : 0; bit >>= 1; if (bit == 0) { bit = 0x80; ++pos; } } i_render_color(render, tx + slot->bitmap_left, ty-slot->bitmap_top+y, slot->bitmap.width, work_bmp, cl); bmp += slot->bitmap.pitch; } } else { unsigned char *bmp = slot->bitmap.buffer; /* grey scale or something we can treat as greyscale */ /* we create a map to convert from the bitmap values to 0-255 */ if (last_mode != slot->bitmap.pixel_mode || last_grays != slot->bitmap.num_grays) { if (!make_bmp_map(&slot->bitmap, map)) return 0; last_mode = slot->bitmap.pixel_mode; last_grays = slot->bitmap.num_grays; } for (y = 0; y < slot->bitmap.rows; ++y) { if (last_mode == ft_pixel_mode_grays && last_grays != 255) { for (x = 0; x < slot->bitmap.width; ++x) bmp[x] = map[bmp[x]]; } i_render_color(render, tx + slot->bitmap_left, ty-slot->bitmap_top+y, slot->bitmap.width, bmp, cl); bmp += slot->bitmap.pitch; } } } tx += slot->advance.x / 64; ty -= slot->advance.y / 64; } if (render) i_render_delete(render); if (work_bmp) myfree(work_bmp); return 1; } /* =item i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel, double cheight, double cwidth, char *text, size_t len, int align, int aa, int vlayout, int utf8) Renders I to (I, I) in I to I at the given I and I. If align is 0, then the text is rendered with the top-left of the first character at (I, I). If align is non-zero then the text is rendered with (I, I) aligned with the base-line of the characters. If C is non-zero the text is treated as UTF-8 encoded If C is non-zero then the text is drawn anti-aliased. Returns non-zero on success. =cut */ int i_ft2_cp(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, int channel, double cheight, double cwidth, char const *text, size_t len, int align, int aa, int vlayout, int utf8) { i_img_dim bbox[8]; i_img *work; i_color cl; int y; unsigned char *bmp; mm_log((1, "i_ft2_cp(handle %p, im %p, (tx, ty) (" i_DFp "), channel %d, cheight %f, cwidth %f, text %p, len %u, align %d, aa %d, vlayout %d, utf8 %d)\n", handle, im, i_DFcp(tx, ty), channel, cheight, cwidth, text, (unsigned)len, align, aa, vlayout, utf8)); i_clear_error(); if (vlayout && !FT_HAS_VERTICAL(handle->face)) { i_push_error(0, "face has no vertical metrics"); return 0; } if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox)) return 0; work = i_img_8_new(bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1); cl.channel[0] = 255; cl.channel[1] = 255; if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, text, len, 1, aa, vlayout, utf8)) return 0; if (!align) { tx -= bbox[4]; ty += bbox[5]; } /* render to the specified channel */ /* this will be sped up ... */ bmp = mymalloc(work->xsize); for (y = 0; y < work->ysize; ++y) { i_gsamp(work, 0, work->xsize, y, bmp, NULL, 1); i_psamp(im, tx + bbox[0], tx + bbox[0] + work->xsize, ty + y + bbox[1], bmp, &channel, 1); } myfree(bmp); i_img_destroy(work); return 1; } /* =item i_ft2_has_chars(handle, char *text, size_t len, int utf8, char *out) Check if the given characters are defined by the font. Returns the number of characters that were checked. =cut */ size_t i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len, int utf8, char *out) { int count = 0; mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %u, utf8 %d)\n", handle, text, (unsigned)len, utf8)); i_clear_error(); while (len) { unsigned long c; int index; if (utf8) { c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { c = (unsigned char)*text++; --len; } index = FT_Get_Char_Index(handle->face, c); *out++ = index != 0; ++count; } return count; } /* uses a method described in fterrors.h to build an error translation function */ #undef __FTERRORS_H__ #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return; #define FT_ERROR_START_LIST #define FT_ERROR_END_LIST /* =back =head2 Internal Functions These functions are used in the implementation of freetyp2.c and should not (usually cannot) be called from outside it. =over =item ft2_push_message(int code) Pushes an error message corresponding to code onto the error stack. =cut */ #define UNKNOWN_ERROR_FORMAT "Unknown Freetype2 error code 0x%04X" static void ft2_push_message(int code) { char unknown[40]; switch (code) { #include FT_ERRORS_H } #ifdef IMAGER_SNPRINTF snprintf(unknown, sizeof(unknown), UNKNOWN_ERROR_FORMAT, code); #else sprintf(unknown, UNKNOWN_ERROR_FORMAT, code); #endif i_push_error(code, unknown); } /* =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) Creates a map to convert grey levels from the glyphs bitmap into values scaled 0..255. =cut */ static int make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) { int scale; int i; switch (bitmap->pixel_mode) { case ft_pixel_mode_grays: scale = bitmap->num_grays; break; default: i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode); return 0; } /* build the table */ for (i = 0; i < scale; ++i) map[i] = i * 255 / (bitmap->num_grays - 1); return 1; } /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */ #ifndef FREETYPE_PATCH #define FREETYPE_PATCH 4 #endif /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */ #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5) /* #define IM_HAS_FACE_NAME 0 */ /* =item i_ft2_face_name(handle, name_buf, name_buf_size) Fills the given buffer with the Postscript Face name of the font, if there is one. Returns the number of bytes copied, including the terminating NUL. =cut */ size_t i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) { #if IM_HAS_FACE_NAME char const *name = FT_Get_Postscript_Name(handle->face); i_clear_error(); if (name) { strncpy(name_buf, name, name_buf_size); name_buf[name_buf_size-1] = '\0'; return strlen(name) + 1; } else { i_push_error(0, "no face name available"); *name_buf = '\0'; return 0; } #else i_clear_error(); i_push_error(0, "Freetype 2.0.6 or later required"); *name_buf = '\0'; return 0; #endif } int i_ft2_can_face_name(void) { return IM_HAS_FACE_NAME; } /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */ /* well, I assume FREETYPE_MAJOR is 2, since we're here */ #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1) #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face)) #endif int i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, size_t name_buf_size, int reliable_only) { #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES i_clear_error(); *name_buf = '\0'; i_push_error(0, "FT2 configured without glyph name support"); return 0; #else FT_UInt index; i_clear_error(); if (!FT_HAS_GLYPH_NAMES(handle->face)) { i_push_error(0, "no glyph names in font"); *name_buf = '\0'; return 0; } if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) { i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway"); *name_buf = '\0'; return 0; } index = FT_Get_Char_Index(handle->face, ch); if (index) { FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf, name_buf_size); if (error) { ft2_push_message(error); *name_buf = '\0'; return 0; } if (strcmp(name_buf, ".notdef") == 0) { *name_buf = 0; return 0; } if (*name_buf) { return strlen(name_buf) + 1; } else { return 0; } } else { *name_buf = 0; return 0; } #endif } int i_ft2_can_do_glyph_names(void) { #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES return 0; #else return 1; #endif } int i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) { #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES return 0; #else return FT_HAS_GLYPH_NAMES(handle->face); /* return FT_Has_PS_Glyph_Names(handle->face);*/ #endif } int i_ft2_is_multiple_master(FT2_Fonthandle *handle) { i_clear_error(); #ifdef IM_FT2_MM return handle->has_mm; #else return 0; #endif } int i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) { #ifdef IM_FT2_MM int i; FT_Multi_Master *mms = &handle->mm; i_clear_error(); if (!handle->has_mm) { i_push_error(0, "Font has no multiple masters"); return 0; } mm->num_axis = mms->num_axis; mm->num_designs = mms->num_designs; for (i = 0; i < mms->num_axis; ++i) { mm->axis[i].name = mms->axis[i].name; mm->axis[i].minimum = mms->axis[i].minimum; mm->axis[i].maximum = mms->axis[i].maximum; } return 1; #else i_clear_error(); i_push_error(0, "Multiple master functions unavailable"); return 0; #endif } int i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) { #ifdef IM_FT2_MM int i; FT_Long ftcoords[T1_MAX_MM_AXIS]; FT_Error error; i_clear_error(); if (!handle->has_mm) { i_push_error(0, "Font has no multiple masters"); return 0; } if (coord_count != handle->mm.num_axis) { i_push_error(0, "Number of MM coords doesn't match MM axis count"); return 0; } for (i = 0; i < coord_count; ++i) ftcoords[i] = coords[i]; error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords); if (error) { ft2_push_message(error); return 0; } return 1; #else i_clear_error(); i_push_error(0, "Multiple master functions unavailable"); return 0; #endif } static i_img_dim i_min(i_img_dim a, i_img_dim b) { return a < b ? a : b; } static i_img_dim i_max(i_img_dim a, i_img_dim b) { return a > b ? a : b; } /* =back =head1 AUTHOR Tony Cook , with a fair amount of help from reading the code in font.c. =head1 SEE ALSO font.c, Imager::Font(3), Imager(3) http://www.freetype.org/ =cut */ libimager-perl-1.004+dfsg.orig/GIF/0000755000175000017500000000000012617614576016205 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/GIF/GIF.pm0000644000175000017500000000422512460670607017144 0ustar gregoagregoapackage Imager::File::GIF; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.90"; require XSLoader; XSLoader::load('Imager::File::GIF', $VERSION); } Imager->register_reader ( type=>'gif', single => sub { my ($im, $io, %hsh) = @_; if ($hsh{gif_consolidate}) { if ($hsh{colors}) { my $colors; ($im->{IMG}, $colors) =i_readgif_wiol( $io ); if ($colors) { ${ $hsh{colors} } = [ map { NC(@$_) } @$colors ]; } } else { $im->{IMG} =i_readgif_wiol( $io ); } } else { my $page = $hsh{page}; defined $page or $page = 0; $im->{IMG} = i_readgif_single_wiol($io, $page); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } if ($hsh{colors}) { ${ $hsh{colors} } = [ $im->getcolors ]; } return $im; } }, multiple => sub { my ($io, %hsh) = @_; my @imgs = i_readgif_multi_wiol($io); unless (@imgs) { Imager->_set_error(Imager->_error_as_msg); return; } return map bless({ IMG => $_, ERRSTR => undef }, "Imager"), @imgs; }, ); Imager->register_writer ( type=>'gif', single => sub { my ($im, $io, %hsh) = @_; $im->_set_opts(\%hsh, "i_", $im); $im->_set_opts(\%hsh, "gif_", $im); unless (i_writegif_wiol($io, \%hsh, $im->{IMG})) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, multiple => sub { my ($class, $io, $opts, @ims) = @_; Imager->_set_opts($opts, "gif_", @ims); my @work = map $_->{IMG}, @ims; unless (i_writegif_wiol($io, $opts, @work)) { Imager->_set_error(Imager->_error_as_msg); return; } return 1; }, ); __END__ =head1 NAME Imager::File::GIF - read and write GIF files =head1 SYNOPSIS use Imager; my $img = Imager->new; $img->read(file=>"foo.gif") or die $img->errstr; $img->write(file => "foo.gif") or die $img->errstr; =head1 DESCRIPTION Imager's GIF support is documented in L. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Files. =cut libimager-perl-1.004+dfsg.orig/GIF/testimg/0000755000175000017500000000000012617614576017661 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/GIF/testimg/screen3.gif0000644000175000017500000000027112031434614021671 0ustar gregoagregoaGIF89aÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿ NETSCAPE2.0!þMade with GIMP!ù2ÿ,7(*ÓC”YsQRë^¤ÕÒe ‡}›xB¥Ú©2¢“ùÒ¡¼jµë±±Ë ØÓ y9ái[¶ŒNJ!ù 2,  ºÜþ0¶@«½8ë};libimager-perl-1.004+dfsg.orig/GIF/testimg/bandw.gif0000644000175000017500000000005512031434614021422 0ustar gregoagregoaGIF89a €ÿÿÿ,  „©Ë£œ´Ú; ;libimager-perl-1.004+dfsg.orig/GIF/testimg/screen2.gif0000644000175000017500000000017312031434614021671 0ustar gregoagregoaGIF87a¡ÿÿÿÿÿ,5„Â2?RÍA©VƒñäÊaÔvy#š Xùˆ+ܹ§«ÚN3Ÿ³ýp5ߎ(;¦„JH, €ÿÿÿ „©Ë£œ´Ú; ;libimager-perl-1.004+dfsg.orig/GIF/testimg/nocmap.gif0000644000175000017500000000004712031434614021605 0ustar gregoagregoaGIF89a ,  „©Ë£œ´Ú; ;libimager-perl-1.004+dfsg.orig/GIF/testimg/scalei.gif0000644000175000017500000001033212031434614021566 0ustar gregoagregoaGIF89avUÆøøø÷÷÷óæáñ¡\ó¢[ù¨Xô¨Tú­QfDPùÓ¢ñ¤Vôõõôôôú¹cÞª“û°O­tSñŸZü«Tô£U=4%9#;*"úúúùùùûûûüüüØ…JþþþýýýÞHÊÄùËÍüÿÿÿ·¸ý¿¿þ¯®ý‘‘ÿ‰‰ÿýØÓïmmýrrÿwwþ||þ……ü\\þ^^ÿddþjjýUUÿ£¢û—﨨ýcdõi\ÇTTþFX¾TTýðŸ\‹ŠúTD}TTü##a(&iRR÷ SSù7[WærrüìAZÕ1D„+QQôúCXö3H{|øâq‚úyoΑ’üSSûï¡\SSúRRøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þMade with GIMP,vU@þ€‚ƒ…††ŒŒ” …ƒš›‡ž ¢£¤£¨©  ¥¤•°± ¶ ¹ ¼½¾ ÁÂÂŠÅÆ—¾ÊË  ±®¥ÖÖÐÛ®³ß☇‡¹ÌÍ ëìíìÁìÈé öùúâýÓ°Q«6ÏW…Ô’(ô®¡Ã‡át€Á– 2jÜh ذaÆ‚†,ÇFØS°/Ÿ¸ bƒ ½s:L°,— pñ¢(Œ£0b¤P±¢) c>F(6l]Jv-õ!‰ A "Š1âƒY³ Ò†‚‡þ߸qƒð!­]·vX p­ÂÑJSÆ < *^\¬×ní£²åË:2_ÞŒãƒCJrGÈ‘¹téË2dý{Yf°cÇ6bÌ1H¸q?ò0ZÌ#L–_B\8“#À™(Î äP>Œj@úƒêÕE9t"„[·Âw¸HcÆ Aè§ùé¢FŒK 3‰òäÍ‘Ù/ĹB…ìWþh`88ÅE O65ˆÜÄ'á„ÅÈc“.…Ô£KYuØ¡D’.È€š‰˜•fz˜ R¼£À0I „…5Á Uô8„N0¢›nþ@PM®þg›cþ€v]v‘@ $Ôà€¡‰Ò€|Þ§P§Ub#8¦©d!E O¬ B ‡AJÂàÙ¢>Œ¸è" C:„=  Ê-áÉ¢8 f#Èè"é. òbR(YŠbÀA1UЛ™B#‹ Ø¢‘!ºÐRH"$LI•6óžmJp€Gvê)5ñ%ÐI„öP?¤Ãhª–Ve•²í¨÷Ëìéaùð…oØd’˜DÁ:…K‹!U”AÈ” n &´Ûîº'œ€ÂUî¼O½Ñ®ãçqE ¨ÆÊË€ó@¸ï¤  c°2N“Zj«þ)¥ÂÅN©ÕG®Ž´Ž‘œDi¦•lrÉ1$¨`¦PÀ™e%ÛЗ¦½l(,8IJ˜!igCÁßÑBl âJ0×RO”•cÙµÖÕàaq²ùÙÇ·ULGÜpG<‡À¶ÄpƒÝÜs×Â0!… “ÎO–ö„¡Å €­À‚º'ÔðÈ$à~ì»?:M@.E¦¦UYf‘…üè1ŒMA¬“[nª«„Œ .¸p² ø£“âPL@«èþ Ba%Nl|jP¬:µâð“¨ÛB Ôóe¯ýT ‘ÁHþÖzÊ@¹ `¯Rùè+¹(8à€äÑ^åÀËóÕ=ZEüa;hú›bØ”!è 2©©Œ`#dcÌF½&HÁu$,aáË¡Ž³.9@QŒêDcAâ@€Bx½1£™ÚÔ^PAÓÁe”‡?jq T±ÐSј…¦ L…J†Ö°V5 *QU¢! ¨È-&åÂgQe{A„•À@Ño<#éË5z³—$a¥pZÂ":'0cQUTG½H·±”D`ˆôàW¾¾×Ñ)ÀWd;HAಙ1XÜW|!OÄ1Yd–ðØ‹zìËù˜™LþÙ 6õ…IhDp")n$@À&Fyd>¬ºŠ°ŽÔ݃%Ò Ý"“l‘%Dĉ]Ȩ‹Z¼ó«…à•ÛsPÞ{ Ï%úð€!äË_ò.ÂÜI1©ˆLdP vF ÆXЈ@{3º¾Úá"2Vã_(yNy‹U2,+ËÔ7< €óÜB#BIÅ^ŒÁ`ÌpMYÁ'ÕrOFò Bl`˜¢Æ£D‰Hú¬‰@@œR‘Ænb>˜†¯(0˜¥¨ ¦7Œ{þ6Û0.78™PO–pä0T¼1àPKæ_!àxÇ»L $$þ¤H Ð)ܦzਚ(9øA€ƒ l¦4*sÈÁä ÆIaAÔJ¯Ô@,"€ØRKCƒÕEB<ëÙV$s< Abi´%ÁœüQ‚ÉŒ8P4m‰«Zw˜Éðì3·Ø׺›'8A€Åð€Lþ'œm i»¢šs¨¶m@.t£Û–t§³ãíÝ<Ád%Û)j©rO Øçµ°E”së6ÇU ¢{H)rËIoþä¶®ÀA N»\¨c/dÒ zP]kèqûñ@è° ¼Z5¤D,DÃÒÃÄ•WBò°+7aC @¾ðËJ0C þp$ '0 RðÑâÁì5@¹äNøß ]"#xºØæš3j K˜?8À«6sÁáǃ<–Ũ‘ @¶ÃBáQ5*ðÀ”˜% X˜,ÑV€òDð¦,ÅÆ&@\¼  Ñ-) Ö>2£­(qÇÚÛÁè(@bܼjêðŒç±8+(xÄÀ ýX’îlÕ³ÌÀЈ.A 1É! 2[ÕÁÔLéJ¯‹Ú«c0²Ò¼]ÒÌ@£ÿ 7SR @ÛO7ìŸÜ‡û¿7wžŒÿ32~äWÉGtË7qëÇ~n¤ ü1ðà!åÑÐô±´òÀÊ–buÖ MÊ·c5áM }øÅ ×ç€x5x%R"%´tzÁþ÷1ø‚>ú’Kt é—râ²FÑ{Œ"æäP³Ní„8ÀxÜOó„Ò/DG p7xã k%sMCo·pÈ„ ž21cSµ3€iJxƒN¨bƒ…€œå%8bxRM$Ô6búä€ Ö€…ÃL±" Rqw÷B/Y1Ig-ÐNY¶.”X‰†6ve‡¡¢4`W3phñrêb4`?œòH‘ŠI1*@a“l)‘:8•yp6“"´MÐ(ÕVŃ"/3SÁPJ¬x1(°\¡æ1A3J³WBå\‡R`ÒXáCþS7UE¡\ac; QÙX28@Fµr¡E°WœqÙ€…q Œ©!Žñ‘3‘p;PCö„]c¹3½øj$`Ju$¨ÈG(5sRµUÅdîˆpq-Hâœá=€4üq2&…0Û`P /°-@W_1Ê´L!ð@‘Ž}õWRÖ3ÑðŒñ¥QFÃE)D`21F¢TkPÀ&wUPÂLtØ8¹`2¤…3éW¹¡d°«E G`6hIȱÎѰS %¤[>ø .ö[^âYÕO Ã7]¶•¤â=ùþ 9£;§ QàZh9÷þ‘þK°]ØA 9af±8‡æ±J†“þ˜>6ÿÕr ÁðZ²ÅöÁ6Õ•‡[¹U(àY¡)š¾G)Bqe±Q‰ñ_ÁP Ó@™ÌÁÂá“9›”I9šXY·¿GD©DƒW ¦1U‹Ða@6ÀÂ[Ò8Ôå8_õ%¾8—[2q¼JÚ •A¶ÑfÃEÎqΙüÑ6SОÀƒ{àЇ÷K?Q›¥ààyEÔT—a=Ð8nc ü±.’]Lß0‡Çoäv wAq\ß` þºÈЉš•ã±OŒ‰sjúàž÷Õ ð"PQ`-°) '7¥H‘ <ü:/ªúW» 7Š ¨£#"!‚B V"&Àl=9û26=Qêa+T(Ú °!Yª¥8¹g*Â"ð“é0À¦i21:RrhÒ³.&¶lÕôI ;Ës|“ÓðQG±‚a.ä‡Mùàfú·;$Tõ•)„7lÄl6°:ý ±ð‘0 ± o¢CÂh<¨8F°²$0žxñ4:¶cýȪ † >"( e€Å8þ{Qx " >ÙgA•váY€%ðÖ °!F/ï06I„=ä4@îÓc}$ ’ð]±?áxç;þêþú-0'/@1±C8Ak®À 5fRa]ׂ=hˆE PGï ¥“˜ÕPúj>úŸÚ4@8p;Žê#ka—1 ¨Ðj1Ñ<0 —6±6»iG‚¥D>¨²÷@g¸d§~â0@?©! Fâh‚™qdºÖ¦Æ@@ð£añ'0vŠˆµ4j¨> #e lEPì…(µ(ø#lR£°rn{+„ª1I bj2Epl­RuüzMvºkê<^N ({$!d=Ò?^ ²l[;žäk'Óg´‰è*ä!>¶©fê8ˆr%¹;libimager-perl-1.004+dfsg.orig/GIF/testimg/trimgdesc.gif0000644000175000017500000000002312031434614022303 0ustar gregoagregoaGIF89a €ÿÿÿlibimager-perl-1.004+dfsg.orig/GIF/testimg/loccmap.gif0000644000175000017500000000005512031434614021745 0ustar gregoagregoaGIF89a , €ÿÿÿ „©Ë£œ´Ú; ;libimager-perl-1.004+dfsg.orig/GIF/testimg/expected.gif0000644000175000017500000000015212031434614022126 0ustar gregoagregoaGIF87aÂÿÿÿÿÿÿÿÿÿÿÿÿ,7 Ñ!PŒ9sQRë^¤•BŒd¹‰ez©:-­ù¢1±x®ßzÏ÷¹° ®. ˆƒù;JJ;libimager-perl-1.004+dfsg.orig/GIF/testimg/badindex.gif0000644000175000017500000000005312031434614022103 0ustar gregoagregoaGIF87a¡ÿÿÿÿÿÿ,!C ;libimager-perl-1.004+dfsg.orig/GIF/testimg/scale.gif0000644000175000017500000001030012031434614021410 0ustar gregoagregoaGIF89avUÆøøø÷÷÷óæáñ¡\ó¢[ù¨Xô¨Tú­QfDPùÓ¢ñ¤Vôõõôôôú¹cÞª“û°O­tSñŸZü«Tô£U=4%9#;*"úúúùùùûûûüüüØ…JþþþýýýÞHÊÄùËÍüÿÿÿ·¸ý¿¿þ¯®ý‘‘ÿ‰‰ÿýØÓïmmýrrÿwwþ||þ……ü\\þ^^ÿddþjjýUUÿ£¢û—﨨ýcdõi\ÇTTþFX¾TTýðŸ\‹ŠúTD}TTü##a(&iRR÷ SSù7[WærrüìAZÕ1D„+QQôúCXö3H{|øâq‚úyoΑ’üSSûï¡\SSúRRøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þMade with GIMP,vUþ€‚ƒ…††ŒŒ” …ƒš›‡ž ¢£¤£¨©  ¥¤•°± ¶žº‰Š‹ –˜†œº Ê Ë ­®Ò©ÕÑÒ£²³ß ·ºº ½½ŒÁÂåËÍôõÚÛ£Ö¨Ö÷ð‰ª$¡à·oµnÅët]:uŒ"!€ ,Ù¼z ôP¡Â5Ö<ÄË „2,<äÀ¡Kt xö £Íf 4âÓga_ÏjDŽÜ&+œ­ HWjø²é™ nJÅj(·}ýí£ Ô*QJÅ!MZhÁBœ6•é`ªÛªþ^yv¤à³¯ÒJ¤…aÍ¿Ê$ ¡paµŠ º½ Š’WZ;J®°ï6 ³öЄCÍ© ‹>¼öÒ⌠b4tò>–KeÞ{ÐØ1š GëNÛ+-ÛÓôcV-ÍH×ýQ€ÄB’ 1ï¥}°@Ôg3F·{tbÓÀA,HœëžÈ³*ù¼”QÓ Vÿæä¦¡‹6™r7LX4ŧóKuä wÀÆõ„V8Á\Ê%‘De—Å'Á|QÙt_`Œ‰æý [BDÀ|gœd‘¡"t%眄IŒdáAHuÈgö(ࣇû1""x ù‰'Îþ7] ¡GA[‚Õ”„ x5B7™å ‡Áùèå¤ `˜üÚLð£:(£O BÉ€p²W#>^YÏ21æ—`F𧙌 €š$Z@¢‰ ¨› ×`=ovDã]ÒäŸ4•ÃeF€†ú§„f䨣Œ¦ŠbÕȨ•œÍÔ9chj«AZÓ9Ù} ª¨^èˆö¤j,£ó±ê*z°F¹ ?I@p«¦)6 k_HA 3ù ¬h_–ŠªÇ"{P¢“59)FºFAÓR+»Ž…”lÛ¡°‚î;•{ì7,£ºvÝ„@zÒÆ›'™tv‹þäk·‚ùK¦Æ^Ê= *0²‰2ÙdOK•“äDÁçig#“& …6æ—;9â9hJ®±+p°¤)'XÌÖ§¥ »VŒÀa H9:ï¶Ÿ·&࣡€}(Ñn.‹²ÒôÀt|:sH2!Á8·T]µ×<‡)faý)vΑ‚9ò7G/˜´Ò ¬=]}U7h`ïäs_µnA™ßB*àèØª°AÉAð"Ú ¤¨xAmÓ£ŒUÌÁì³w`{‘GÞÁåÞõÆ/[€fhš… ̘Ž6N«‡%ÅÂô!„@;ÕWÏ{wÃBl#þ‚§©(£Ç#|8Ú 4O‹3Á7"Ä/ÂòÇOÂý$à ìÆÞúè= hRÓ¡@Ç(8Mæ|ˆ›Ö4¥­rHM&(K`‚ Vp‚'8 ú'ªÐK#K«$å‹eGi À^h+N'œ©ÚÞW¤@8Äá XÐHðàW7*úhd#ŒŒ? МébHßIá0qŒÃnîC…G\à‚¼1°¡yht'pBü ­”0¹‹å*g‹»Ä2ñ€2ޱT,Ö »Æª`ˆ\Á Î8Q‘€ŒRXïzèÀõnþÇI ¬Ð@'ãè Ȥ#è¢aÀÊB‘4øPïöÆ/ l’‘yM HP¿ŒàÀæô@P=Ì.}ï‰ ¤7Lcr`˜°Æd¼øEV†Q‡¯ÁKv#¤Z®1U’tcr(Ђúp‚èLç f0ƒÔà“xQ ÜÉÎ fP‚& ]˜TUÂ@Œ¯dA"?€˜ÝËK`cdÜÀ€š/PeD#ÊE.úó€§Wð„¤å¢ eàƒkÌ¥š­leÅHĸD‚2™µÐHùã8È©NwšSø”§8hÂt,¸`¤@ÕiŒ˜4Ròš:\A,]êþ;ÿðÍ[Á H(Ÿzõ«` «b º;zåHjO¿jƒtù3Œ1X©!U€ª6…sSHº*Ö¾†Õ ² là×°ò“6hbo˜Ø©Ú•;¾hDV]Uö²:HÁ^ÀâP`˜õª b„k.‡)ˆÁC_àØÇ>¤;`è^CëWv³² ŠpY ÞÀ2±¦\«ÚˆòÀµQG»à4ɨu­:x.>Ç Å| ëNYÍÜ@&ªe%5EÚÔÖª¥ì0€ç£œ6×Mmªtuª¡V7™9€@ûU ò‹‡ì¡£·øÆw§-8/"! þaÄ ;™z_ã 9øA€ƒ ðÔ«eÏñQÔíºŒ,xÂOàÎúÅm¾:M°K"‰J¸‚:Yà ú B²ƒ,ÖŒÞj'Ppê nØ‚°˜—¿lfö`7‘þ>—èe°`ñë’â¤C€ €:" yÈÙõ* âEâª8 3€ò0³W½Úa n - Ü ç6zÝ¿Z3 ÙÐB BXcà‡  ,0Aj0?fR¯vœì•wgÌîYË‘è³u-ѤÛÀ<à TM I€ •V¸Œ¢¡ˆ×X¶`¢f3øž¶´½&\{ÛÙÞ¶Â ÞílCá·>÷ÎîtKÀ ì¦Ý(ã8rxì :È7¾ÍK€Èöè=Ñ)ÜH8À ×.8µ®ínKÈæHXB)(NÅ<˜uÆdíÞMµ\€ÊÕ9²Ÿàä:ÄÌeþj„#Û7§‘„(´ Š{=ˆßØíî¹5Ñ ‰Úö¢t<Áé.Y¨O’̼àL¨z˜k­kþ½+ùú¹Qàn¢}[ܪ4œ|ûôípwÈ$átpj¿:Û¯ö»ß7ðgWÞëµhâÕÊ‚1›ÌÛÈöêq#ﻟ8çêx—9ß»ÝwÍÓ ÒhÄÂå1_ôvXÍËúDjïwÇöÕ^{¿w÷(²ÐνÞ,´ÁŽë¤øªŒKÎú^ÀIÛ7ø* „ $!ó2È/´)ú"&®Oç{|ÁF?ª:Û¹#\áÝ6d6G#ìWî÷~Ñf5 ­³<@øSûp7>QPÐmyG{I dÎdˆ€´1 ЀJ;€W 8ÐM×}[c =þàS.жg)ëÇ~Aæ³(Óƒ#¨€&¨4…P50!c0(K7]:e= ~Χƒ08ðw%RÐ:‘ 4S5)9k'Õ±„[S¨/W;ôC5ð“µ~B!D6Bh!p 4sÓóK¾L¾„„¥1O½6L¸ónÙ;Af‡w80ãa! Ð ð"PQ`-àQ+€Z*ÐJ)PˆïW0†‚ˆ/Áu$zÈPÀƒ“X.j3 ¶ P'`,uT2@_÷6wXă¤ÌÀ!¾‚ 04³h,µØ`0"ЋG%Œø&þÜ(= ‰!46 Š.!.{Ò…ƒá9‰R‘ÐŽÙè_Á¸Sl…ëx,4 ÜGŽß‡ð…c   ŽÐÈŽåRcõxÇâSAŽP¢$J·lâC&Ær(‹âƒwh``óT.‹³È+yɵSàûHUS 40÷3' AM&A‰$êp$À'bˆ:ßàÅJŒõQÅEc80ã“( ‹&`N1Ë!Sþ >¢^ÿ!f\$V6àÕ±^R'2:`–l„(Z %’#БS—28™zã;ð€ ` Æ`2qR@þ†i˜Üh ö`[ 9†³ ‚€$0’MõE‰es‰"&#@O' 5½ÐÉ3c(P17PU0®9TÀélИ²0:(c ¢ "ð‡tC)yNöä=mb" ‘ü£¤YšM^ée1 ¬ùšCà») “e W¢€²ÐeLQƈ¸ƒ@Ñö"J%Í \¥\«YFàËFv“å—j‰$Õa] ÐLÓS“$PpžCÑ I˜ÆA?2ys¼\@4à-±’¿Ð`fÙ.Àµ°Ó“¿p"$š$'ò- 1ðƒÄE4þ"^& '؈ÈÙHe"M !¡Ý±;@•Åwe2NptÀ"$>Aé‘©‚/€!wlcå៘Ñeët¥6Y-Àœf££Œô¥ÂBKÁ¢€£+×/¢ :‚â”ÆB‚”S1àdÉ“ê§ÀÈS£q4¦~JKiᣀsX ð… °¦„‘(G4‰€:‹dâ#T#%¨€K2Ò< =ê§ž:ûI/†Z¤m6¨Ò¦ i©â0@©‚¤•´0™ªOÀ£¶z«ú©ª’a:ɇŠW1e¤A©©:‹0f}嚢a=>%›êÅèà¡þ‰ñ³K'à Ý>_ÓåòM³˜ÝÈEP6xuf>Ñ*3øS•`ŒÀØ%ÐQ*QP€à"ý±ŽÄj4`JÐpsÛ¶5uЈylÜ0±Q›/ùX9æÙVE@0°Ý¤ª‘¤À𬅖â€Ú†©,Ò&k²N£àI]V›\YŽZñYÜx˜>{ ¨B“Å3‰€âPZ’’±w¡°Ò„K0Ÿ¬V«l@U<®°\Ÿ%VPj°ºÑMÀ"0§é%ɺJQ¸~Ww@¶û¤=ðšU`µVku±‘‡­ •"Sqê¤Ç&b‹‹ 1´?Œ« ÀKñC ;m êK;libimager-perl-1.004+dfsg.orig/GIF/testimg/zerocomm.gif0000644000175000017500000000006012031434614022156 0ustar gregoagregoaGIF89a €ÿÿÿ,  „©Ë£œ´Ú; !þ;libimager-perl-1.004+dfsg.orig/GIF/testimg/trmiddesc.gif0000644000175000017500000000002412031434614022301 0ustar gregoagregoaGIF89a €ÿÿÿ,libimager-perl-1.004+dfsg.orig/GIF/imgif.c0000644000175000017500000015161412370401736017440 0ustar gregoagregoa#include "imgif.h" #include #ifdef _MSC_VER #include #else #include #endif #include #include #include #include /* =head1 NAME imgif.c - read and write gif files for Imager =head1 SYNOPSIS i_img *img; i_img *imgs[count]; int fd; int *colour_table, int colours; int max_colours; // number of bits per colour int pixdev; // how much noise to add i_color fixed[N]; // fixed palette entries int fixedlen; // number of fixed colours int success; // non-zero on success char *data; // a GIF file in memory int length; // how big data is int reader(char *, char *, int, int); int writer(char *, char *, int); char *userdata; // user's data, whatever it is i_quantize quant; i_gif_opts opts; img = i_readgif(fd, &colour_table, &colours); success = i_writegif(img, fd, max_colours, pixdev, fixedlen, fixed); success = i_writegifmc(img, fd, max_colours); img = i_readgif_scalar(data, length, &colour_table, &colours); img = i_readgif_callback(cb, userdata, &colour_table, &colours); success = i_writegif_gen(&quant, fd, imgs, count, &opts); success = i_writegif_callback(&quant, writer, userdata, maxlength, imgs, count, &opts); =head1 DESCRIPTION This source file provides the C level interface to reading and writing GIF files for Imager. This has been tested with giflib 3 and 4, though you lose the callback functionality with giflib3. =head1 REFERENCE =over =cut */ #ifdef GIFLIB_MAJOR #define IMGIFLIB_API_VERSION (GIFLIB_MAJOR * 100 + GIFLIB_MINOR) #else /* only matters for pre-5.0 which we either reject, or which contains no significant API changes */ #define IMGIFLIB_API_VERSION 0 #endif #if IMGIFLIB_API_VERSION >= 500 #define POST_SET_VERSION #define myDGifOpen(userPtr, readFunc, Error) DGifOpen((userPtr), (readFunc), (Error)) #define myEGifOpen(userPtr, readFunc, Error) EGifOpen((userPtr), (readFunc), (Error)) #define myGifError(gif) ((gif)->Error) #define MakeMapObject GifMakeMapObject #define FreeMapObject GifFreeMapObject #define gif_mutex_lock(mutex) #define gif_mutex_unlock(mutex) #else #define PRE_SET_VERSION static GifFileType * myDGifOpen(void *userPtr, InputFunc readFunc, int *error) { GifFileType *result = DGifOpen(userPtr, readFunc); if (!result) *error = GifLastError(); return result; } static GifFileType * myEGifOpen(void *userPtr, OutputFunc outputFunc, int *error) { GifFileType *result = EGifOpen(userPtr, outputFunc); if (!result) *error = GifLastError(); return result; } #define myGifError(gif) GifLastError() #define gif_mutex_lock(mutex) i_mutex_lock(mutex) #define gif_mutex_unlock(mutex) i_mutex_unlock(mutex) #endif #if IMGIFLIB_API_VERSION >= 501 #define myDGifCloseFile(gif, perror) (DGifCloseFile((gif), (perror))) #define myEGifCloseFile(gif, perror) (EGifCloseFile((gif), (perror))) #else static int myDGifCloseFile(GifFileType *GifFile, int *ErrorCode) { int result = DGifCloseFile(GifFile); if (result == GIF_ERROR) { if (ErrorCode) *ErrorCode = myGifError(GifFile); free(GifFile->Private); free(GifFile); } return result; } static int myEGifCloseFile(GifFileType *GifFile, int *ErrorCode) { int result = EGifCloseFile(GifFile); if (result == GIF_ERROR) { if (ErrorCode) *ErrorCode = myGifError(GifFile); free(GifFile->Private); free(GifFile); } return result; } #endif static char const *gif_error_msg(int code); static void gif_push_error(int code); /* Make some variables global, so we could access them faster: */ static const int InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */ InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */ #if IMGIFLIB_API_VERSION < 500 static i_mutex_t mutex; #endif void i_init_gif(void) { #if IMGIFLIB_API_VERSION < 500 mutex = i_mutex_new(); #endif } static void i_colortable_copy(int **colour_table, int *colours, ColorMapObject *colourmap) { GifColorType *mapentry; int q; int colourmapsize = colourmap->ColorCount; if(colours) *colours = colourmapsize; if(!colour_table) return; *colour_table = mymalloc(sizeof(int) * colourmapsize * 3); memset(*colour_table, 0, sizeof(int) * colourmapsize * 3); for(q=0; qColors[q]; (*colour_table)[q*3 + 0] = mapentry->Red; (*colour_table)[q*3 + 1] = mapentry->Green; (*colour_table)[q*3 + 2] = mapentry->Blue; } } #ifdef GIF_LIB_VERSION static const char gif_version_str[] = GIF_LIB_VERSION; double i_giflib_version(void) { const char *p = gif_version_str; while (*p && (*p < '0' || *p > '9')) ++p; if (!*p) return 0; return strtod(p, NULL); } #else double i_giflib_version(void) { return GIFLIB_MAJOR + GIFLIB_MINOR * 0.1; } #endif /* =item i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) Internal. Low-level function for reading a GIF file. The caller must create the appropriate GifFileType object and pass it in. =cut */ i_img * i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) { i_img *im; int i, j, Size, Row, Col, Width, Height, ExtCode, Count, x; int cmapcnt = 0, ImageNum = 0; ColorMapObject *ColorMap; GifRecordType RecordType; GifByteType *Extension; GifRowType GifRow; GifColorType *ColorMapEntry; i_color col; int error; mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours)); /* it's possible that the caller has called us with *colour_table being non-NULL, but we check that to see if we need to free an allocated colour table on error. */ if (colour_table) *colour_table = NULL; ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap); if (ColorMap) { i_colortable_copy(colour_table, colours, ColorMap); cmapcnt++; } if (!i_int_check_image_file_limits(GifFile->SWidth, GifFile->SHeight, 3, sizeof(i_sample_t))) { if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } (void)myDGifCloseFile(GifFile, NULL); mm_log((1, "i_readgif: image size exceeds limits\n")); return NULL; } im = i_img_8_new(GifFile->SWidth, GifFile->SHeight, 3); if (!im) { if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } (void)myDGifCloseFile(GifFile, NULL); return NULL; } Size = GifFile->SWidth * sizeof(GifPixelType); GifRow = mymalloc(Size); for (i = 0; i < GifFile->SWidth; i++) GifRow[i] = GifFile->SBackGroundColor; /* Scan the content of the GIF file and load the image(s) in: */ do { if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Unable to get record type"); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(GifFile) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Unable to get image descriptor"); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) { mm_log((1, "Adding local colormap\n")); if ( cmapcnt == 0) { i_colortable_copy(colour_table, colours, ColorMap); cmapcnt++; } } else { /* No colormap and we are about to read in the image - abandon for now */ mm_log((1, "Going in with no colormap\n")); i_push_error(0, "Image does not have a local or a global color map"); /* we can't have allocated a colour table here */ myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } Row = GifFile->Image.Top; /* Image Position relative to Screen. */ Col = GifFile->Image.Left; Width = GifFile->Image.Width; Height = GifFile->Image.Height; ImageNum++; mm_log((1,"i_readgif_low: Image %d at (%d, %d) [%dx%d]: \n",ImageNum, Col, Row, Width, Height)); if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth || GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) { i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } if (GifFile->Image.Interlace) { for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) { Count++; if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Reading GIF line"); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } for (x = 0; x < Width; x++) { ColorMapEntry = &ColorMap->Colors[GifRow[x]]; col.rgb.r = ColorMapEntry->Red; col.rgb.g = ColorMapEntry->Green; col.rgb.b = ColorMapEntry->Blue; i_ppix(im,Col+x,j,&col); } } } else { for (i = 0; i < Height; i++) { if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Reading GIF line"); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } for (x = 0; x < Width; x++) { ColorMapEntry = &ColorMap->Colors[GifRow[x]]; col.rgb.r = ColorMapEntry->Red; col.rgb.g = ColorMapEntry->Green; col.rgb.b = ColorMapEntry->Blue; i_ppix(im, Col+x, Row, &col); } Row++; } } break; case EXTENSION_RECORD_TYPE: /* Skip any extension blocks in file: */ if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Reading extension record"); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } while (Extension != NULL) { if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "reading next block of extension"); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } myfree(GifRow); i_img_destroy(im); (void)myDGifCloseFile(GifFile, NULL); return NULL; } } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be traps by DGifGetRecordType. */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); myfree(GifRow); if (myDGifCloseFile(GifFile, &error) == GIF_ERROR) { gif_push_error(error); i_push_error(0, "Closing GIF file object"); if (colour_table && *colour_table) { myfree(*colour_table); *colour_table = NULL; } i_img_destroy(im); return NULL; } i_tags_set(&im->tags, "i_format", "gif", -1); return im; } /* Internal function called by i_readgif_multi_low() in error handling */ static void free_images(i_img **imgs, int count) { int i; if (count) { for (i = 0; i < count; ++i) i_img_destroy(imgs[i]); myfree(imgs); } } /* =item i_readgif_multi_low(GifFileType *gf, int *count, int page) Reads one of more gif images from the given GIF file. Returns a pointer to an array of i_img *, and puts the count into *count. If page is not -1 then the given image _only_ is returned from the file, where the first image is 0, the second 1 and so on. Unlike the normal i_readgif*() functions the images are paletted images rather than a combined RGB image. This functions sets tags on the images returned: =over =item gif_left the offset of the image from the left of the "screen" ("Image Left Position") =item gif_top the offset of the image from the top of the "screen" ("Image Top Position") =item gif_interlace non-zero if the image was interlaced ("Interlace Flag") =item gif_screen_width =item gif_screen_height the size of the logical screen ("Logical Screen Width", "Logical Screen Height") =item gif_local_map Non-zero if this image had a local color map. =item gif_background The index in the global colormap of the logical screen's background color. This is only set if the current image uses the global colormap. =item gif_trans_index The index of the color in the colormap used for transparency. If the image has a transparency then it is returned as a 4 channel image with the alpha set to zero in this palette entry. ("Transparent Color Index") =item gif_delay The delay until the next frame is displayed, in 1/100 of a second. ("Delay Time"). =item gif_user_input whether or not a user input is expected before continuing (view dependent) ("User Input Flag"). =item gif_disposal how the next frame is displayed ("Disposal Method") =item gif_loop the number of loops from the Netscape Loop extension. This may be zero. =item gif_comment the first block of the first gif comment before each image. =back Where applicable, the ("name") is the name of that field from the GIF89 standard. =cut */ i_img ** i_readgif_multi_low(GifFileType *GifFile, int *count, int page) { i_img *img; int i, j, Size, Width, Height, ExtCode, Count; int ImageNum = 0, ColorMapSize = 0; ColorMapObject *ColorMap; GifRecordType RecordType; GifByteType *Extension; GifRowType GifRow; int got_gce = 0; int trans_index = 0; /* transparent index if we see a GCE */ int gif_delay = 0; /* delay from a GCE */ int user_input = 0; /* user input flag from a GCE */ int disposal = 0; /* disposal method from a GCE */ int got_ns_loop = 0; int ns_loop = 0; char *comment = NULL; /* a comment */ i_img **results = NULL; int result_alloc = 0; int channels; int image_colors = 0; i_color black; /* used to expand the palette if needed */ int error; for (i = 0; i < MAXCHANNELS; ++i) black.channel[i] = 0; *count = 0; mm_log((1,"i_readgif_multi_low(GifFile %p, , count %p)\n", GifFile, count)); Size = GifFile->SWidth * sizeof(GifPixelType); GifRow = (GifRowType) mymalloc(Size); /* Scan the content of the GIF file and load the image(s) in: */ do { if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Unable to get record type"); free_images(results, *count); (void)myDGifCloseFile(GifFile, NULL); myfree(GifRow); if (comment) myfree(comment); return NULL; } switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(GifFile) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Unable to get image descriptor"); free_images(results, *count); (void)myDGifCloseFile(GifFile, NULL); myfree(GifRow); if (comment) myfree(comment); return NULL; } Width = GifFile->Image.Width; Height = GifFile->Image.Height; if (page == -1 || page == ImageNum) { if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) { mm_log((1, "Adding local colormap\n")); ColorMapSize = ColorMap->ColorCount; } else { /* No colormap and we are about to read in the image - abandon for now */ mm_log((1, "Going in with no colormap\n")); i_push_error(0, "Image does not have a local or a global color map"); free_images(results, *count); (void)myDGifCloseFile(GifFile, NULL); myfree(GifRow); if (comment) myfree(comment); return NULL; } channels = 3; if (got_gce && trans_index >= 0) channels = 4; if (!i_int_check_image_file_limits(Width, Height, channels, sizeof(i_sample_t))) { free_images(results, *count); mm_log((1, "i_readgif: image size exceeds limits\n")); (void)myDGifCloseFile(GifFile, NULL); myfree(GifRow); if (comment) myfree(comment); return NULL; } img = i_img_pal_new(Width, Height, channels, 256); if (!img) { free_images(results, *count); (void)myDGifCloseFile(GifFile, NULL); if (comment) myfree(comment); myfree(GifRow); return NULL; } /* populate the palette of the new image */ mm_log((1, "ColorMapSize %d\n", ColorMapSize)); for (i = 0; i < ColorMapSize; ++i) { i_color col; col.rgba.r = ColorMap->Colors[i].Red; col.rgba.g = ColorMap->Colors[i].Green; col.rgba.b = ColorMap->Colors[i].Blue; if (channels == 4 && trans_index == i) col.rgba.a = 0; else col.rgba.a = 255; i_addcolors(img, &col, 1); } image_colors = ColorMapSize; ++*count; if (*count > result_alloc) { if (result_alloc == 0) { result_alloc = 5; results = mymalloc(result_alloc * sizeof(i_img *)); } else { /* myrealloc never fails (it just dies if it can't allocate) */ result_alloc *= 2; results = myrealloc(results, result_alloc * sizeof(i_img *)); } } results[*count-1] = img; i_tags_set(&img->tags, "i_format", "gif", -1); i_tags_setn(&img->tags, "gif_left", GifFile->Image.Left); /**(char *)0 = 1;*/ i_tags_setn(&img->tags, "gif_top", GifFile->Image.Top); i_tags_setn(&img->tags, "gif_interlace", GifFile->Image.Interlace); i_tags_setn(&img->tags, "gif_screen_width", GifFile->SWidth); i_tags_setn(&img->tags, "gif_screen_height", GifFile->SHeight); i_tags_setn(&img->tags, "gif_colormap_size", ColorMapSize); if (GifFile->SColorMap && !GifFile->Image.ColorMap) { i_tags_setn(&img->tags, "gif_background", GifFile->SBackGroundColor); } if (GifFile->Image.ColorMap) { i_tags_setn(&img->tags, "gif_localmap", 1); } if (got_gce) { if (trans_index >= 0) { i_color trans; i_tags_setn(&img->tags, "gif_trans_index", trans_index); i_getcolors(img, trans_index, &trans, 1); i_tags_set_color(&img->tags, "gif_trans_color", 0, &trans); } i_tags_setn(&img->tags, "gif_delay", gif_delay); i_tags_setn(&img->tags, "gif_user_input", user_input); i_tags_setn(&img->tags, "gif_disposal", disposal); } got_gce = 0; if (got_ns_loop) i_tags_setn(&img->tags, "gif_loop", ns_loop); if (comment) { i_tags_set(&img->tags, "gif_comment", comment, strlen(comment)); myfree(comment); comment = NULL; } mm_log((1,"i_readgif_multi_low: Image %d at (%d, %d) [%dx%d]: \n", ImageNum, GifFile->Image.Left, GifFile->Image.Top, Width, Height)); if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth || GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) { i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum); free_images(results, *count); (void)myDGifCloseFile(GifFile, NULL); myfree(GifRow); if (comment) myfree(comment); return(0); } if (GifFile->Image.Interlace) { for (Count = i = 0; i < 4; i++) { for (j = InterlacedOffset[i]; j < Height; j += InterlacedJumps[i]) { Count++; if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Reading GIF line"); free_images(results, *count); (void)myDGifCloseFile(GifFile, NULL); myfree(GifRow); if (comment) myfree(comment); return NULL; } /* range check the scanline if needed */ if (image_colors != 256) { int x; for (x = 0; x < Width; ++x) { while (GifRow[x] >= image_colors) { /* expand the palette since a palette index is too big */ i_addcolors(img, &black, 1); ++image_colors; } } } i_ppal(img, 0, Width, j, GifRow); } } } else { for (i = 0; i < Height; i++) { if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Reading GIF line"); free_images(results, *count); (void)myDGifCloseFile(GifFile, NULL); myfree(GifRow); if (comment) myfree(comment); return NULL; } /* range check the scanline if needed */ if (image_colors != 256) { int x; for (x = 0; x < Width; ++x) { while (GifRow[x] >= image_colors) { /* expand the palette since a palette index is too big */ i_addcolors(img, &black, 1); ++image_colors; } } } i_ppal(img, 0, Width, i, GifRow); } } /* must be only one image wanted and that was it */ if (page != -1) { myfree(GifRow); (void)myDGifCloseFile(GifFile, NULL); if (comment) myfree(comment); return results; } } else { /* skip the image */ /* whether interlaced or not, it has the same number of lines */ /* giflib does't have an interface to skip the image data */ for (i = 0; i < Height; i++) { if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Reading GIF line"); free_images(results, *count); myfree(GifRow); (void)myDGifCloseFile(GifFile, NULL); if (comment) myfree(comment); return NULL; } } /* kill the comment so we get the right comment for the page */ if (comment) { myfree(comment); comment = NULL; } } ImageNum++; break; case EXTENSION_RECORD_TYPE: /* Skip any extension blocks in file: */ if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "Reading extension record"); free_images(results, *count); myfree(GifRow); (void)myDGifCloseFile(GifFile, NULL); if (comment) myfree(comment); return NULL; } /* possibly this should be an error, but "be liberal in what you accept" */ if (!Extension) break; if (ExtCode == 0xF9) { got_gce = 1; if (Extension[1] & 1) trans_index = Extension[4]; else trans_index = -1; gif_delay = Extension[2] + 256 * Extension[3]; user_input = (Extension[1] & 2) != 0; disposal = (Extension[1] >> 2) & 7; } if (ExtCode == 0xFF && *Extension == 11) { if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) { if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "reading loop extension"); free_images(results, *count); myfree(GifRow); (void)myDGifCloseFile(GifFile, NULL); if (comment) myfree(comment); return NULL; } if (Extension && *Extension == 3) { got_ns_loop = 1; ns_loop = Extension[2] + 256 * Extension[3]; } } } else if (ExtCode == 0xFE) { /* while it's possible for a GIF file to contain more than one comment, I'm only implementing a single comment per image, with the comment saved into the following image. If someone wants more than that they can implement it. I also don't handle comments that take more than one block. */ if (!comment) { comment = mymalloc(*Extension+1); memcpy(comment, Extension+1, *Extension); comment[*Extension] = '\0'; } } while (Extension != NULL) { if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) { gif_push_error(myGifError(GifFile)); i_push_error(0, "reading next block of extension"); free_images(results, *count); myfree(GifRow); (void)myDGifCloseFile(GifFile, NULL); if (comment) myfree(comment); return NULL; } } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be trapped by DGifGetRecordType. */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); if (comment) { if (*count) { i_tags_set(&(results[*count-1]->tags), "gif_comment", comment, strlen(comment)); } myfree(comment); } myfree(GifRow); if (myDGifCloseFile(GifFile, &error) == GIF_ERROR) { gif_push_error(error); i_push_error(0, "Closing GIF file object"); free_images(results, *count); return NULL; } if (ImageNum && page != -1) { /* there were images, but the page selected wasn't found */ i_push_errorf(0, "page %d not found (%d total)", page, ImageNum); free_images(results, *count); return NULL; } return results; } static int io_glue_read_cb(GifFileType *gft, GifByteType *buf, int length); /* =item i_readgif_multi_wiol(ig, int *count) =cut */ i_img ** i_readgif_multi_wiol(io_glue *ig, int *count) { GifFileType *GifFile; int gif_error; i_img **result; gif_mutex_lock(mutex); i_clear_error(); if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) { gif_push_error(gif_error); i_push_error(0, "Cannot create giflib callback object"); mm_log((1,"i_readgif_multi_wiol: Unable to open callback datasource.\n")); gif_mutex_unlock(mutex); return NULL; } result = i_readgif_multi_low(GifFile, count, -1); gif_mutex_unlock(mutex); return result; } static int io_glue_read_cb(GifFileType *gft, GifByteType *buf, int length) { io_glue *ig = (io_glue *)gft->UserData; return i_io_read(ig, buf, length); } i_img * i_readgif_wiol(io_glue *ig, int **color_table, int *colors) { GifFileType *GifFile; int gif_error; i_img *result; gif_mutex_lock(mutex); i_clear_error(); if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) { gif_push_error(gif_error); i_push_error(0, "Cannot create giflib callback object"); mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n")); gif_mutex_unlock(mutex); return NULL; } result = i_readgif_low(GifFile, color_table, colors); gif_mutex_unlock(mutex); return result; } /* =item i_readgif_single_low(GifFile, page) Lower level function to read a single image from a GIF. page must be non-negative. =cut */ static i_img * i_readgif_single_low(GifFileType *GifFile, int page) { int count = 0; i_img **imgs; imgs = i_readgif_multi_low(GifFile, &count, page); if (imgs && count) { i_img *result = imgs[0]; myfree(imgs); return result; } else { /* i_readgif_multi_low() handles the errors appropriately */ return NULL; } } /* =item i_readgif_single_wiol(ig, page) Read a single page from a GIF image file, where the page is indexed from 0. Returns NULL if the page isn't found. =cut */ i_img * i_readgif_single_wiol(io_glue *ig, int page) { GifFileType *GifFile; int gif_error; i_img *result; i_clear_error(); if (page < 0) { i_push_error(0, "page must be non-negative"); return NULL; } gif_mutex_lock(mutex); if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) { gif_push_error(gif_error); i_push_error(0, "Cannot create giflib callback object"); mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n")); gif_mutex_unlock(mutex); return NULL; } result = i_readgif_single_low(GifFile, page); gif_mutex_unlock(mutex); return result; } /* =item do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data) Internal. Low level image write function. Writes in interlace if that was requested in the GIF options. Returns non-zero on success. =cut */ static undef_int do_write(GifFileType *gf, int interlace, i_img *img, i_palidx *data) { if (interlace) { int i, j; for (i = 0; i < 4; ++i) { for (j = InterlacedOffset[i]; j < img->ysize; j += InterlacedJumps[i]) { if (EGifPutLine(gf, data+j*img->xsize, img->xsize) == GIF_ERROR) { gif_push_error(myGifError(gf)); i_push_error(0, "Could not save image data:"); mm_log((1, "Error in EGifPutLine\n")); return 0; } } } } else { int y; for (y = 0; y < img->ysize; ++y) { if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) { gif_push_error(myGifError(gf)); i_push_error(0, "Could not save image data:"); mm_log((1, "Error in EGifPutLine\n")); return 0; } data += img->xsize; } } return 1; } /* =item do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index) Internal. Writes the GIF graphics control extension, if necessary. Returns non-zero on success. =cut */ static int do_gce(GifFileType *gf, i_img *img, int want_trans, int trans_index) { unsigned char gce[4] = {0}; int want_gce = 0; int delay; int user_input; int disposal_method; if (want_trans) { gce[0] |= 1; gce[3] = trans_index; ++want_gce; } if (i_tags_get_int(&img->tags, "gif_delay", 0, &delay)) { gce[1] = delay % 256; gce[2] = delay / 256; ++want_gce; } if (i_tags_get_int(&img->tags, "gif_user_input", 0, &user_input) && user_input) { gce[0] |= 2; ++want_gce; } if (i_tags_get_int(&img->tags, "gif_disposal", 0, &disposal_method)) { gce[0] |= (disposal_method & 3) << 2; ++want_gce; } if (want_gce) { if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) { gif_push_error(myGifError(gf)); i_push_error(0, "Could not save GCE"); } } return 1; } /* =item do_comments(gf, img) Write any comments in the image. =cut */ static int do_comments(GifFileType *gf, i_img *img) { int pos = -1; while (i_tags_find(&img->tags, "gif_comment", pos+1, &pos)) { if (img->tags.tags[pos].data) { if (EGifPutComment(gf, img->tags.tags[pos].data) == GIF_ERROR) { return 0; } } else { char buf[50]; #ifdef IMAGER_SNPRINTF snprintf(buf, sizeof(buf), "%d", img->tags.tags[pos].idata); #else sprintf(buf, "%d", img->tags.tags[pos].idata); #endif if (EGifPutComment(gf, buf) == GIF_ERROR) { return 0; } } } return 1; } /* =item do_ns_loop(GifFileType *gf, i_gif_opts *opts) Internal. Add the Netscape2.0 loop extension block, if requested. Giflib/libungif prior to 4.1.1 didn't support writing application extension blocks, so we don't attempt to write them for older versions. Giflib/libungif prior to 4.1.3 used the wrong write mechanism when writing extension blocks so that they could only be written to files. =cut */ static int do_ns_loop(GifFileType *gf, i_img *img) { /* EGifPutExtension() doesn't appear to handle application extension blocks in any way Since giflib wraps the fd with a FILE * (and puts that in its private data), we can't do an end-run and write the data directly to the fd. There's no open interface that takes a FILE * either, so we can't workaround it that way either. If giflib's callback interface wasn't broken by default, I'd force file writes to use callbacks, but it is broken by default. */ /* yes this was another attempt at supporting the loop extension */ int loop_count; if (i_tags_get_int(&img->tags, "gif_loop", 0, &loop_count)) { unsigned char nsle[12] = "NETSCAPE2.0"; unsigned char subblock[3]; subblock[0] = 1; subblock[1] = loop_count % 256; subblock[2] = loop_count / 256; #if IMGIFLIB_API_VERSION >= 500 if (EGifPutExtensionLeader(gf, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR || EGifPutExtensionBlock(gf, 11, nsle) == GIF_ERROR || EGifPutExtensionBlock(gf, 3, subblock) == GIF_ERROR || EGifPutExtensionTrailer(gf) == GIF_ERROR) { gif_push_error(myGifError(gf)); i_push_error(0, "writing loop extension"); return 0; } #else if (EGifPutExtensionFirst(gf, APPLICATION_EXT_FUNC_CODE, 11, nsle) == GIF_ERROR) { gif_push_error(myGifError(gf)); i_push_error(0, "writing loop extension"); return 0; } if (EGifPutExtensionLast(gf, APPLICATION_EXT_FUNC_CODE, 3, subblock) == GIF_ERROR) { gif_push_error(myGifError(gf)); i_push_error(0, "writing loop extension sub-block"); return 0; } #endif } return 1; } /* =item make_gif_map(i_quantize *quant, int want_trans) Create a giflib color map object from an Imager color map. =cut */ static ColorMapObject * make_gif_map(i_quantize *quant, i_img *img, int want_trans) { GifColorType colors[256]; int i; int size = quant->mc_count; int map_size; ColorMapObject *map; i_color trans; for (i = 0; i < quant->mc_count; ++i) { colors[i].Red = quant->mc_colors[i].rgb.r; colors[i].Green = quant->mc_colors[i].rgb.g; colors[i].Blue = quant->mc_colors[i].rgb.b; } if (want_trans) { if (!i_tags_get_color(&img->tags, "gif_trans_color", 0, &trans)) trans.rgb.r = trans.rgb.g = trans.rgb.b = 0; colors[size].Red = trans.rgb.r; colors[size].Green = trans.rgb.g; colors[size].Blue = trans.rgb.b; ++size; } map_size = 1; while (map_size < size) map_size <<= 1; /* giflib spews for 1 colour maps, reasonable, I suppose */ if (map_size == 1) map_size = 2; while (i < map_size) { colors[i].Red = colors[i].Green = colors[i].Blue = 0; ++i; } map = MakeMapObject(map_size, colors); mm_log((1, "XXX map is at %p and colors at %p\n", map, map->Colors)); if (!map) { i_push_error(0, "Could not create color map object"); return NULL; } #if IMGIFLIB_API_VERSION >= 500 map->SortFlag = 0; #endif return map; } /* =item need_version_89a(i_quantize *quant, i_img *imgs, int count) Return true if the file we're creating on these images needs a GIF89a header. =cut */ static int need_version_89a(i_quantize *quant, i_img **imgs, int count) { int need_89a = 0; int temp; int i; for (i = 0; i < count; ++i) { if (quant->transp != tr_none && (imgs[i]->channels == 2 || imgs[i]->channels == 4)) { need_89a = 1; break; } if (i_tags_get_int(&imgs[i]->tags, "gif_delay", 0, &temp)) { need_89a = 1; break; } if (i_tags_get_int(&imgs[i]->tags, "gif_user_input", 0, &temp) && temp) { need_89a = 1; break; } if (i_tags_get_int(&imgs[i]->tags, "gif_disposal", 0, &temp)) { need_89a = 1; break; } if (i_tags_get_int(&imgs[i]->tags, "gif_loop", 0, &temp)) { need_89a = 1; break; } } return need_89a; } static int in_palette(i_color *c, i_quantize *quant, int size) { int i; for (i = 0; i < size; ++i) { if (c->channel[0] == quant->mc_colors[i].channel[0] && c->channel[1] == quant->mc_colors[i].channel[1] && c->channel[2] == quant->mc_colors[i].channel[2]) { return i; } } return -1; } /* =item has_common_palette(imgs, count, quant) Tests if all the given images are paletted and their colors are in the palette produced. Previously this would build a consolidated palette from the source, but that meant that if the caller supplied a static palette (or specified a fixed palette like "webmap") then we wouldn't be quantizing to the caller specified palette. =cut */ static int has_common_palette(i_img **imgs, int count, i_quantize *quant) { int i; int imgn; char used[256]; int col_count; /* we try to build a common palette here, if we can manage that, then that's the palette we use */ for (imgn = 0; imgn < count; ++imgn) { int eliminate_unused; if (imgs[imgn]->type != i_palette_type) return 0; if (!i_tags_get_int(&imgs[imgn]->tags, "gif_eliminate_unused", 0, &eliminate_unused)) { eliminate_unused = 1; } if (eliminate_unused) { i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize); int x, y; memset(used, 0, sizeof(used)); for (y = 0; y < imgs[imgn]->ysize; ++y) { i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line); for (x = 0; x < imgs[imgn]->xsize; ++x) used[line[x]] = 1; } myfree(line); } else { /* assume all are in use */ memset(used, 1, sizeof(used)); } col_count = i_colorcount(imgs[imgn]); for (i = 0; i < col_count; ++i) { i_color c; i_getcolors(imgs[imgn], i, &c, 1); if (used[i]) { if (in_palette(&c, quant, quant->mc_count) < 0) { mm_log((1, " color not found in palette, no palette shortcut\n")); return 0; } } } } mm_log((1, " all colors found in palette, palette shortcut\n")); return 1; } static i_palidx * quant_paletted(i_quantize *quant, i_img *img) { i_palidx *data = mymalloc(sizeof(i_palidx) * img->xsize * img->ysize); i_palidx *p = data; i_palidx trans[256]; int i; i_img_dim x, y; /* build a translation table */ for (i = 0; i < i_colorcount(img); ++i) { i_color c; i_getcolors(img, i, &c, 1); trans[i] = in_palette(&c, quant, quant->mc_count); } for (y = 0; y < img->ysize; ++y) { i_gpal(img, 0, img->xsize, y, data+img->xsize * y); for (x = 0; x < img->xsize; ++x) { *p = trans[*p]; ++p; } } return data; } /* =item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts) Internal. Low-level function that does the high-level GIF processing :) Returns non-zero on success. =cut */ static undef_int i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { unsigned char *result = NULL; int color_bits; ColorMapObject *map; int scrw = 0, scrh = 0; int imgn, orig_count, orig_size; int posx, posy; int trans_index = -1; int *localmaps; int anylocal; i_img **glob_imgs; /* images that will use the global color map */ int glob_img_count; i_color *orig_colors = quant->mc_colors; i_color *glob_colors = NULL; int glob_color_count = 0; int glob_want_trans; int glob_paletted = 0; /* the global map was made from the image palettes */ int colors_paletted = 0; int want_trans = 0; int interlace; int gif_background; int error; mm_log((1, "i_writegif_low(quant %p, gf %p, imgs %p, count %d)\n", quant, gf, imgs, count)); /* *((char *)0) = 1; */ /* used to break into the debugger */ if (count <= 0) { i_push_error(0, "No images provided to write"); return 0; /* what are you smoking? */ } /* sanity is nice */ if (quant->mc_size > 256) quant->mc_size = 256; if (quant->mc_count > quant->mc_size) quant->mc_count = quant->mc_size; if (!i_tags_get_int(&imgs[0]->tags, "gif_screen_width", 0, &scrw)) scrw = 0; if (!i_tags_get_int(&imgs[0]->tags, "gif_screen_height", 0, &scrh)) scrh = 0; anylocal = 0; localmaps = mymalloc(sizeof(int) * count); glob_imgs = mymalloc(sizeof(i_img *) * count); glob_img_count = 0; glob_want_trans = 0; for (imgn = 0; imgn < count; ++imgn) { i_img *im = imgs[imgn]; if (im->xsize > 0xFFFF || im->ysize > 0xFFFF) { i_push_error(0, "image too large for GIF"); return 0; } posx = posy = 0; i_tags_get_int(&im->tags, "gif_left", 0, &posx); if (posx < 0) posx = 0; i_tags_get_int(&im->tags, "gif_top", 0, &posy); if (posy < 0) posy = 0; if (im->xsize + posx > scrw) scrw = im->xsize + posx; if (im->ysize + posy > scrh) scrh = im->ysize + posy; if (!i_tags_get_int(&im->tags, "gif_local_map", 0, localmaps+imgn)) localmaps[imgn] = 0; if (localmaps[imgn]) anylocal = 1; else { if (im->channels == 4) { glob_want_trans = 1; } glob_imgs[glob_img_count++] = im; } } glob_want_trans = glob_want_trans && quant->transp != tr_none ; if (scrw > 0xFFFF || scrh > 0xFFFF) { i_push_error(0, "screen size too large for GIF"); return 0; } orig_count = quant->mc_count; orig_size = quant->mc_size; if (glob_img_count) { /* this is ugly */ glob_colors = mymalloc(sizeof(i_color) * quant->mc_size); quant->mc_colors = glob_colors; memcpy(glob_colors, orig_colors, sizeof(i_color) * quant->mc_count); /* we have some images that want to use the global map */ if (glob_want_trans && quant->mc_count == 256) { mm_log((2, " disabling transparency for global map - no space\n")); glob_want_trans = 0; } if (glob_want_trans && quant->mc_size == 256) { mm_log((2, " reserving color for transparency\n")); --quant->mc_size; } i_quant_makemap(quant, glob_imgs, glob_img_count); glob_paletted = has_common_palette(glob_imgs, glob_img_count, quant); glob_color_count = quant->mc_count; quant->mc_colors = orig_colors; } /* use the global map if we have one, otherwise use the local map */ gif_background = 0; if (glob_colors) { quant->mc_colors = glob_colors; quant->mc_count = glob_color_count; want_trans = glob_want_trans && imgs[0]->channels == 4; if (!i_tags_get_int(&imgs[0]->tags, "gif_background", 0, &gif_background)) gif_background = 0; if (gif_background < 0) gif_background = 0; if (gif_background >= glob_color_count) gif_background = 0; } else { want_trans = quant->transp != tr_none && imgs[0]->channels == 4; i_quant_makemap(quant, imgs, 1); colors_paletted = has_common_palette(imgs, 1, quant); } if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; (void)myEGifCloseFile(gf, NULL); mm_log((1, "Error in MakeMapObject")); return 0; } color_bits = 1; if (anylocal) { /* since we don't know how big some the local palettes could be we need to base the bits on the maximum number of colors */ while (orig_size > (1 << color_bits)) ++color_bits; } else { int count = quant->mc_count; if (want_trans) ++count; while (count > (1 << color_bits)) ++color_bits; } if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, gif_background, map) == GIF_ERROR) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; gif_push_error(myGifError(gf)); i_push_error(0, "Could not save screen descriptor"); FreeMapObject(map); myfree(result); (void)myEGifCloseFile(gf, NULL); mm_log((1, "Error in EGifPutScreenDesc.")); return 0; } FreeMapObject(map); if (!i_tags_get_int(&imgs[0]->tags, "gif_left", 0, &posx)) posx = 0; if (!i_tags_get_int(&imgs[0]->tags, "gif_top", 0, &posy)) posy = 0; if (!localmaps[0]) { map = NULL; colors_paletted = glob_paletted; } else { /* if this image has a global map the colors in quant don't belong to this image, so build a palette */ if (glob_colors) { /* generate the local map for this image */ quant->mc_colors = orig_colors; quant->mc_size = orig_size; quant->mc_count = orig_count; want_trans = quant->transp != tr_none && imgs[0]->channels == 4; /* if the caller gives us too many colours we can't do transparency */ if (want_trans && quant->mc_count == 256) want_trans = 0; /* if they want transparency but give us a big size, make it smaller to give room for a transparency colour */ if (want_trans && quant->mc_size == 256) --quant->mc_size; i_quant_makemap(quant, imgs, 1); colors_paletted = has_common_palette(imgs, 1, quant); if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); (void)myEGifCloseFile(gf, NULL); quant->mc_colors = orig_colors; mm_log((1, "Error in MakeMapObject")); return 0; } } else { /* the map we wrote was the map for this image - don't set the local map */ map = NULL; } } if (colors_paletted) result = quant_paletted(quant, imgs[0]); else result = i_quant_translate(quant, imgs[0]); if (!result) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; (void)myEGifCloseFile(gf, NULL); return 0; } if (want_trans) { i_quant_transparent(quant, result, imgs[0], quant->mc_count); trans_index = quant->mc_count; } if (!do_ns_loop(gf, imgs[0])) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; return 0; } if (!do_gce(gf, imgs[0], want_trans, trans_index)) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; myfree(result); (void)myEGifCloseFile(gf, NULL); return 0; } if (!do_comments(gf, imgs[0])) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; myfree(result); (void)myEGifCloseFile(gf, NULL); return 0; } if (!i_tags_get_int(&imgs[0]->tags, "gif_interlace", 0, &interlace)) interlace = 0; if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize, interlace, map) == GIF_ERROR) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; gif_push_error(myGifError(gf)); i_push_error(0, "Could not save image descriptor"); (void)myEGifCloseFile(gf, NULL); mm_log((1, "Error in EGifPutImageDesc.")); return 0; } if (map) FreeMapObject(map); if (!do_write(gf, interlace, imgs[0], result)) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; (void)myEGifCloseFile(gf, NULL); myfree(result); return 0; } myfree(result); /* that first awful image is out of the way, do the rest */ for (imgn = 1; imgn < count; ++imgn) { if (localmaps[imgn]) { quant->mc_colors = orig_colors; quant->mc_count = orig_count; quant->mc_size = orig_size; want_trans = quant->transp != tr_none && imgs[imgn]->channels == 4; /* if the caller gives us too many colours we can't do transparency */ if (want_trans && quant->mc_count == 256) want_trans = 0; /* if they want transparency but give us a big size, make it smaller to give room for a transparency colour */ if (want_trans && quant->mc_size == 256) --quant->mc_size; if (has_common_palette(imgs+imgn, 1, quant)) { result = quant_paletted(quant, imgs[imgn]); } else { i_quant_makemap(quant, imgs+imgn, 1); result = i_quant_translate(quant, imgs[imgn]); } if (!result) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; (void)myEGifCloseFile(gf, NULL); mm_log((1, "error in i_quant_translate()")); return 0; } if (want_trans) { i_quant_transparent(quant, result, imgs[imgn], quant->mc_count); trans_index = quant->mc_count; } if ((map = make_gif_map(quant, imgs[imgn], want_trans)) == NULL) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; myfree(result); (void)myEGifCloseFile(gf, NULL); mm_log((1, "Error in MakeMapObject.")); return 0; } } else { quant->mc_colors = glob_colors; quant->mc_count = glob_color_count; if (glob_paletted) result = quant_paletted(quant, imgs[imgn]); else result = i_quant_translate(quant, imgs[imgn]); want_trans = glob_want_trans && imgs[imgn]->channels == 4; if (want_trans) { i_quant_transparent(quant, result, imgs[imgn], quant->mc_count); trans_index = quant->mc_count; } map = NULL; } if (!do_gce(gf, imgs[imgn], want_trans, trans_index)) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; myfree(result); (void)myEGifCloseFile(gf, NULL); return 0; } if (!do_comments(gf, imgs[imgn])) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; myfree(result); (void)myEGifCloseFile(gf, NULL); return 0; } if (!i_tags_get_int(&imgs[imgn]->tags, "gif_left", 0, &posx)) posx = 0; if (!i_tags_get_int(&imgs[imgn]->tags, "gif_top", 0, &posy)) posy = 0; if (!i_tags_get_int(&imgs[imgn]->tags, "gif_interlace", 0, &interlace)) interlace = 0; if (EGifPutImageDesc(gf, posx, posy, imgs[imgn]->xsize, imgs[imgn]->ysize, interlace, map) == GIF_ERROR) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; gif_push_error(myGifError(gf)); i_push_error(0, "Could not save image descriptor"); myfree(result); if (map) FreeMapObject(map); (void)myEGifCloseFile(gf, NULL); mm_log((1, "Error in EGifPutImageDesc.")); return 0; } if (map) FreeMapObject(map); if (!do_write(gf, interlace, imgs[imgn], result)) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; (void)myEGifCloseFile(gf, NULL); myfree(result); return 0; } myfree(result); } if (myEGifCloseFile(gf, &error) == GIF_ERROR) { myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); gif_push_error(error); i_push_error(0, "Could not close GIF file"); mm_log((1, "Error in EGifCloseFile\n")); return 0; } if (glob_colors) { int i; for (i = 0; i < glob_color_count; ++i) orig_colors[i] = glob_colors[i]; } myfree(glob_colors); myfree(localmaps); myfree(glob_imgs); quant->mc_colors = orig_colors; return 1; } static int io_glue_write_cb(GifFileType *gft, const GifByteType *data, int length) { io_glue *ig = (io_glue *)gft->UserData; return i_io_write(ig, data, length); } /* =item i_writegif_wiol(ig, quant, opts, imgs, count) =cut */ undef_int i_writegif_wiol(io_glue *ig, i_quantize *quant, i_img **imgs, int count) { GifFileType *GifFile; int gif_error; int result; gif_mutex_lock(mutex); i_clear_error(); #ifdef PRE_SET_VERSION EGifSetGifVersion(need_version_89a(quant, imgs, count) ? "89a" : "87a"); #endif if ((GifFile = myEGifOpen((void *)ig, io_glue_write_cb, &gif_error )) == NULL) { gif_push_error(gif_error); i_push_error(0, "Cannot create giflib callback object"); mm_log((1,"i_writegif_wiol: Unable to open callback datasource.\n")); gif_mutex_unlock(mutex); return 0; } #ifdef POST_SET_VERSION EGifSetGifVersion(GifFile, need_version_89a(quant, imgs, count)); #endif result = i_writegif_low(quant, GifFile, imgs, count); gif_mutex_unlock(mutex); if (i_io_close(ig)) return 0; return result; } /* =item gif_error_msg(int code) Grabs the most recent giflib error code from GifLastError() and returns a string that describes that error. Returns NULL for unknown error codes. =cut */ static char const * gif_error_msg(int code) { #if IMGIFLIB_API_VERSION >= 500 return GifErrorString(code); #else switch (code) { case E_GIF_ERR_OPEN_FAILED: /* should not see this */ return "Failed to open given file"; case E_GIF_ERR_WRITE_FAILED: return "Write failed"; case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */ return "Screen descriptor already passed to giflib"; case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */ return "Image descriptor already passed to giflib"; case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */ return "Neither global nor local color map set"; case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */ return "Too much pixel data passed to giflib"; case E_GIF_ERR_NOT_ENOUGH_MEM: return "Out of memory"; case E_GIF_ERR_DISK_IS_FULL: return "Disk is full"; case E_GIF_ERR_CLOSE_FAILED: /* should not see this */ return "File close failed"; case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */ return "File not writable"; case D_GIF_ERR_OPEN_FAILED: return "Failed to open file"; case D_GIF_ERR_READ_FAILED: return "Failed to read from file"; case D_GIF_ERR_NOT_GIF_FILE: return "File is not a GIF file"; case D_GIF_ERR_NO_SCRN_DSCR: return "No screen descriptor detected - invalid file"; case D_GIF_ERR_NO_IMAG_DSCR: return "No image descriptor detected - invalid file"; case D_GIF_ERR_NO_COLOR_MAP: return "No global or local color map found"; case D_GIF_ERR_WRONG_RECORD: return "Wrong record type detected - invalid file?"; case D_GIF_ERR_DATA_TOO_BIG: return "Data in file too big for image"; case D_GIF_ERR_NOT_ENOUGH_MEM: return "Out of memory"; case D_GIF_ERR_CLOSE_FAILED: return "Close failed"; case D_GIF_ERR_NOT_READABLE: return "File not opened for read"; case D_GIF_ERR_IMAGE_DEFECT: return "Defective image"; case D_GIF_ERR_EOF_TOO_SOON: return "Unexpected EOF - invalid file"; default: return NULL; } #endif } /* =item gif_push_error(code) Utility function that takes the current GIF error code, converts it to an error message and pushes it on the error stack. =cut */ static void gif_push_error(int code) { const char *msg = gif_error_msg(code); if (msg) i_push_error(code, msg); else i_push_errorf(code, "Unknown GIF error %d", code); } /* =head1 AUTHOR Arnar M. Hrafnkelsson, addi@umich.edu Tony Cook =head1 SEE ALSO perl(1), Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/GIF/README0000644000175000017500000000104012263740577017056 0ustar gregoagregoaImager::File::GIF provides GIF file format support for Imager. It requires libgif to be installed, including development headers. For Linux distributions this typically requires installation of the associated -dev or -devel package. See Imager::Install for more information. Imager::File::GIF is currently shipped as part of Imager, but Imager may install with out installing Imager::File::GIF, so if you need GIF support, add a dependency on Imager::File::GIF. Makefile.PL will reject libgif 4.2.0 and 5.0.0 due to bugs in those releases.libimager-perl-1.004+dfsg.orig/GIF/t/0000755000175000017500000000000012617614576016450 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/GIF/t/t10gif.t0000644000175000017500000006575512263740577017747 0ustar gregoagregoa#!perl -w =pod IF THIS TEST CRASHES Giflib/libungif have a long history of bugs, so if this script crashes and you aren't running version 4.1.4 of giflib or libungif then UPGRADE. =cut use strict; $|=1; use Test::More; use Imager qw(:all); use Imager::Test qw(is_color3 test_image test_image_raw test_image_mono); use Imager::File::GIF; use Carp 'confess'; $SIG{__DIE__} = sub { confess @_ }; -d "testout" or mkdir "testout"; init_log("testout/t105gif.log",1); plan tests => 146; my $green=i_color_new(0,255,0,255); my $blue=i_color_new(0,0,255,255); my $red=i_color_new(255,0,0,255); my $img=test_image_raw; my $gifver = Imager::File::GIF::i_giflib_version(); diag("giflib version (from header) $gifver"); { open(FH,">testout/t105.gif") || die "Cannot open testout/t105.gif\n"; binmode(FH); my $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_writegif_wiol($io, {}, $img), "write low") or die "Cannot write testout/t105.gif\n"; $io->close; close(FH); } { open(FH,"testout/t105.gif") || die "Cannot open testout/t105.gif\n"; binmode(FH); my $io = Imager::io_new_fd(fileno(FH)); ok($img=Imager::File::GIF::i_readgif_wiol($io), "read low") or die "Cannot read testout/t105.gif\n"; close(FH); } { open(FH,"testout/t105.gif") || die "Cannot open testout/t105.gif\n"; binmode(FH); my $io = Imager::io_new_fd(fileno(FH)); ($img, my $palette)=Imager::File::GIF::i_readgif_wiol($io); ok($img, "read palette") or die "Cannot read testout/t105.gif\n"; close(FH); $palette=''; # just to skip a warning. } # check that reading interlaced/non-interlaced versions of # the same GIF produce the same image # I could replace this with code that used Imager's built-in # image comparison code, but I know this code revealed the error { open(FH, "testout/t105i.ppm" or die "Cannot create testout/t105i.ppm"; binmode FH; my $IO = Imager::io_new_fd( fileno(FH) ); i_writeppm_wiol($imgi, $IO) or die "Cannot write testout/t105i.ppm"; close FH; open FH, ">testout/t105ni.ppm" or die "Cannot create testout/t105ni.ppm"; binmode FH; $IO = Imager::io_new_fd( fileno(FH) ); i_writeppm_wiol($imgni, $IO) or die "Cannot write testout/t105ni.ppm"; close FH; # compare them open FH, " }; close FH; open FH, " }; close FH; is($datai, $datani, "images match"); } { # reading with a callback # various sizes to make sure the buffering works # requested size open FH, "testout/t105_gen.gif" or die $!; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_writegif_wiol ($io, { make_colors=>'webmap', translate=>'errdiff', errdiff=>'custom', errdiff_width=>2, errdiff_height=>2, errdiff_map=>[0, 1, 1, 0]}, $img), "webmap, custom errdif map"); close FH; } print "# the following tests are fairly slow\n"; # test animation, mc_addi, error diffusion, ordered transparency my @imgs; my $sortagreen = i_color_new(0, 255, 0, 63); for my $i (0..4) { my $im = Imager::ImgRaw::new(200, 200, 4); _add_tags($im, gif_delay=>50, gif_disposal=>2); for my $j (0..$i-1) { my $fill = i_color_new(0, 128, 0, 255 * ($i-$j)/$i); i_box_filled($im, 0, $j*40, 199, $j*40+40, $fill); } i_box_filled($im, 0, $i*40, 199, 199, $blue); push(@imgs, $im); } { my @gif_delays = (50) x 5; my @gif_disposal = (2) x 5; open FH, ">testout/t105_anim.gif" or die $!; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_writegif_wiol ($io, { make_colors=>'addi', translate=>'closest', gif_delays=>\@gif_delays, gif_disposal=>\@gif_disposal, gif_positions=> [ map [ $_*10, $_*10 ], 0..4 ], gif_user_input=>[ 1, 0, 1, 0, 1 ], transp=>'ordered', 'tr_orddith'=>'dot8'}, @imgs), "write anim gif"); close FH; } @imgs = (); my $c = i_color_new(0,0,0,0); for my $g (0..3) { my $im = Imager::ImgRaw::new(200, 200, 3); _add_tags($im, gif_local_map=>1, gif_delay=>150, gif_loop=>10); for my $x (0 .. 39) { for my $y (0 .. 39) { $c->set($x * 6, $y * 6, 32*$g+$x+$y, 255); i_box_filled($im, $x*5, $y*5, $x*5+4, $y*5+4, $c); } } push(@imgs, $im); } # test giflib with multiple palettes # (it was meant to test the NS loop extension too, but that's broken) # this looks better with make_colors=>'addi', translate=>'errdiff' # this test aims to overload the palette for each image, so the # output looks moderately horrible { open FH, ">testout/t105_mult_pall.gif" or die "Cannot create file: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_writegif_wiol ($io, { #make_colors=>'webmap', translate=>'giflib', }, @imgs), "write multiple palettes") or print "# ", join(":", map $_->[1], Imager::i_errors()),"\n"; close FH; } { # regression test: giflib doesn't like 1 colour images my $img1 = Imager::ImgRaw::new(100, 100, 3); i_box_filled($img1, 0, 0, 100, 100, $red); open FH, ">testout/t105_onecol.gif" or die $!; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_writegif_wiol($io, { translate=>'giflib'}, $img1), "single colour write regression"); close FH; } { # transparency test # previously it was harder do write transparent images # tests the improvements my $timg = Imager::ImgRaw::new(20, 20, 4); my $trans = i_color_new(255, 0, 0, 127); i_box_filled($timg, 0, 0, 20, 20, $green); i_box_filled($timg, 2, 2, 18, 18, $trans); open FH, ">testout/t105_trans.gif" or die $!; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_writegif_wiol ($io, { make_colors=>'addi', translate=>'closest', transp=>'ordered', }, $timg), "write transparent"); close FH; } # some error handling tests # open a file handle for read and try to save to it # is this idea portable? # whether or not it is, giflib segfaults on this #open FH, "testout/t105_none.gif" or die "Cannot open testout/t105_none.gif: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); if (ok(!Imager::File::GIF::i_writegif_wiol($io, {}, "hello"), "shouldn't be able to write a string as a gif")) { print "# ",Imager::_error_as_msg(),"\n"; } } # try to read a truncated gif (no image descriptors) read_failure('testimg/trimgdesc.gif'); # file truncated just after the image descriptor tag read_failure('testimg/trmiddesc.gif'); # image has no colour map read_failure('testimg/nocmap.gif'); { # image has a local colour map open FH, "< testimg/loccmap.gif" or die "Cannot open testimg/loccmap.gif: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_readgif_wiol($io), "read an image with only a local colour map"); close FH; } { # image has global and local colour maps open FH, "< testimg/screen2.gif" or die "Cannot open testimg/screen2.gif: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); my $ims = Imager::File::GIF::i_readgif_wiol($io); unless (ok($ims, "read an image with global and local colour map")) { print "# ",Imager::_error_as_msg(),"\n"; } close FH; open FH, "< testimg/expected.gif" or die "Cannot open testimg/expected.gif: $!"; binmode FH; $io = Imager::io_new_fd(fileno(FH)); my $ime = Imager::File::GIF::i_readgif_wiol($io); close FH; ok($ime, "reading testimg/expected.gif"); SKIP: { skip("could not read one or both of expected.gif or loccamp.gif", 1) unless $ims and $ime; unless (is(i_img_diff($ime, $ims), 0, "compare loccmap and expected")) { # save the bad one open FH, "> testout/t105_screen2.gif" or die "Cannot create testout/t105_screen.gif: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); Imager::File::GIF::i_writegif_wiol($io, {}, $ims) or print "# could not save t105_screen.gif\n"; close FH; } } } { # test reading a multi-image file into multiple images open FH, "< testimg/screen2.gif" or die "Cannot open testimg/screen2.gif: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); @imgs = Imager::File::GIF::i_readgif_multi_wiol($io); ok(@imgs, "read multi-image file into multiple images"); close FH; is(@imgs, 2, "should be 2 images"); my $paletted = 1; for my $img (@imgs) { unless (Imager::i_img_type($img) == 1) { $paletted = 0; last; } } ok($paletted, "both images should be paletted"); is(Imager::i_colorcount($imgs[0]), 4, "4 colours in first image"); is(Imager::i_colorcount($imgs[1]), 2, "2 colours in second image"); ok(Imager::i_tags_find($imgs[0], "gif_left", 0), "gif_left tag should be there"); my @tags = map {[ Imager::i_tags_get($imgs[1], $_) ]} 0..Imager::i_tags_count($imgs[1])-1; my ($left) = grep $_->[0] eq 'gif_left', @tags; ok($left && $left->[1] == 3, "check gif_left value"); } { # screen3.gif was saved with open FH, "< testimg/screen3.gif" or die "Cannot open testimg/screen3.gif: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); @imgs = Imager::File::GIF::i_readgif_multi_wiol($io); ok(@imgs, "read screen3.gif"); close FH; eval { require 'Data/Dumper.pm'; Data::Dumper->import(); }; unless ($@) { # build a big map of all tags for all images my @tags = map { my $im = $_; [ map { join ",", map { defined() ? $_ : "undef" } Imager::i_tags_get($im, $_) } 0..Imager::i_tags_count($_)-1 ] } @imgs; my $dump = Dumper(\@tags); $dump =~ s/^/# /mg; print "# tags from gif\n", $dump; } # at this point @imgs should contain only paletted images ok(Imager::i_img_type($imgs[0]) == 1, "imgs[0] paletted"); ok(Imager::i_img_type($imgs[1]) == 1, "imgs[1] paletted"); # see how we go saving it open FH, ">testout/t105_pal.gif" or die $!; binmode FH; $io = Imager::io_new_fd(fileno(FH)); ok(Imager::File::GIF::i_writegif_wiol ($io, { make_colors=>'addi', translate=>'closest', transp=>'ordered', }, @imgs), "write from paletted") or diag(Imager->_error_as_msg()); close FH; # make sure nothing bad happened open FH, "< testout/t105_pal.gif" or die $!; binmode FH; $io = Imager::io_new_fd(fileno(FH)); ok((my @imgs2 = Imager::File::GIF::i_readgif_multi_wiol($io)) == 2, "re-reading saved paletted images"); ok(i_img_diff($imgs[0], $imgs2[0]) == 0, "imgs[0] mismatch"); ok(i_img_diff($imgs[1], $imgs2[1]) == 0, "imgs[1] mismatch"); } # test that the OO interface warns when we supply old options { my @warns; local $SIG{__WARN__} = sub { push(@warns, "@_") }; my $ooim = Imager->new; ok($ooim->read(file=>"testout/t105.gif"), "read into object"); ok($ooim->write(file=>"testout/t105_warn.gif", interlace=>1), "save from object") or print "# ", $ooim->errstr, "\n"; ok(grep(/Obsolete .* interlace .* gif_interlace/, @warns), "check for warning"); init(warn_obsolete=>0); @warns = (); ok($ooim->write(file=>"testout/t105_warn.gif", interlace=>1), "save from object"); ok(!grep(/Obsolete .* interlace .* gif_interlace/, @warns), "check for warning"); } # test that we get greyscale from 1 channel images # we check for each makemap, and for each translate print "# test writes of grayscale images - ticket #365\n"; my $ooim = Imager->new(xsize=>50, ysize=>50, channels=>1); for (my $y = 0; $y < 50; $y += 10) { $ooim->box(box=>[ 0, $y, 49, $y+9], color=>NC($y*5,0,0), filled=>1); } my $ooim3 = $ooim->convert(preset=>'rgb'); #$ooim3->write(file=>'testout/t105gray.ppm'); my %maxerror = ( mediancut => 51000, addi => 0, closest => 0, perturb => 0, errdiff => 0 ); for my $makemap (qw(mediancut addi)) { print "# make_colors => $makemap\n"; ok( $ooim->write(file=>"testout/t105gray-$makemap.gif", make_colors=>$makemap, gifquant=>'gen'), "writing gif with makemap $makemap"); my $im2 = Imager->new; if (ok($im2->read(file=>"testout/t105gray-$makemap.gif"), "reading written grayscale gif")) { my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG}); ok($diff <= $maxerror{$makemap}, "comparing images $diff"); #$im2->write(file=>"testout/t105gray-$makemap.ppm"); } else { SKIP: { skip("could not get test image", 1); } } } for my $translate (qw(closest perturb errdiff)) { print "# translate => $translate\n"; my @colors = map NC($_*50, $_*50, $_*50), 0..4; ok($ooim->write(file=>"testout/t105gray-$translate.gif", translate=>$translate, make_colors=>'none', colors=>\@colors, gifquant=>'gen'), "writing gif with translate $translate"); my $im2 = Imager->new; if (ok($im2->read(file=>"testout/t105gray-$translate.gif"), "reading written grayscale gif")) { my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG}); ok($diff <= $maxerror{$translate}, "comparing images $diff"); #$im2->write(file=>"testout/t105gray-$translate.ppm"); } else { SKIP: { skip("could not load test image", 1) } } } # try to write an image with no colors - should error ok(!$ooim->write(file=>"testout/t105nocolors.gif", make_colors=>'none', colors=>[], gifquant=>'gen'), "write with no colors"); # try to write multiple with no colors, with separate maps # I don't see a way to test this, since we don't have a mechanism # to give the second image different quant options, we can't trigger # a failure just for the second image # check that the i_format tag is set for both multiple and single # image reads { my @anim = Imager->read_multi(file=>"testout/t105_anim.gif"); ok(@anim == 5, "check we got all the images"); for my $frame (@anim) { my ($type) = $frame->tags(name=>'i_format'); is($type, 'gif', "check i_format for animation frame"); } my $im = Imager->new; ok($im->read(file=>"testout/t105.gif"), "read some gif"); my ($type) = $im->tags(name=>'i_format'); is($type, 'gif', 'check i_format for single image read'); } { # check file limits are checked my $limit_file = "testout/t105.gif"; ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149"); my $im = Imager->new; ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image width/, "check message"); ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image height/, "check message"); ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside width limit"); ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside height limit"); # 150 x 150 x 3 channel image uses 67500 bytes ok(Imager->set_file_limits(reset=>1, bytes=>67499), "set bytes limit 67499"); ok(!$im->read(file=>$limit_file), "should fail - too many bytes"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/storage size/, "check error message"); ok(Imager->set_file_limits(reset=>1, bytes=>67500), "set bytes limit 67500"); ok($im->read(file=>$limit_file), "should succeed - just inside bytes limit"); Imager->set_file_limits(reset=>1); } { print "# test OO interface reading of consolidated images\n"; my $im = Imager->new; ok($im->read(file=>'testimg/screen2.gif', gif_consolidate=>1), "read image to consolidate"); my $expected = Imager->new; ok($expected->read(file=>'testimg/expected.gif'), "read expected via OO"); is(i_img_diff($im->{IMG}, $expected->{IMG}), 0, "compare them"); # check the default read doesn't match ok($im->read(file=>'testimg/screen2.gif'), "read same image without consolidate"); isnt(i_img_diff($im->{IMG}, $expected->{IMG}), 0, "compare them - shouldn't include the overlayed second image"); } { print "# test the reading of single pages\n"; # build a test file my $test_file = 'testout/t105_multi_sing.gif'; my $im1 = Imager->new(xsize=>100, ysize=>100); $im1->box(filled=>1, color=>$blue); $im1->addtag(name=>'gif_left', value=>10); $im1->addtag(name=>'gif_top', value=>15); $im1->addtag(name=>'gif_comment', value=>'First page'); my $im2 = Imager->new(xsize=>50, ysize=>50); $im2->box(filled=>1, color=>$red); $im2->addtag(name=>'gif_left', value=>30); $im2->addtag(name=>'gif_top', value=>25); $im2->addtag(name=>'gif_comment', value=>'Second page'); my $im3 = Imager->new(xsize=>25, ysize=>25); $im3->box(filled=>1, color=>$green); $im3->addtag(name=>'gif_left', value=>35); $im3->addtag(name=>'gif_top', value=>45); # don't set comment for $im3 ok(Imager->write_multi({ file=> $test_file}, $im1, $im2, $im3), "write test file for single page reads"); my $res = Imager->new; # check we get the first image ok($res->read(file=>$test_file), "read default (first) page"); is(i_img_diff($im1->{IMG}, $res->{IMG}), 0, "compare against first"); # check tags is($res->tags(name=>'gif_left'), 10, "gif_left"); is($res->tags(name=>'gif_top'), 15, "gif_top"); is($res->tags(name=>'gif_comment'), 'First page', "gif_comment"); # get the second image ok($res->read(file=>$test_file, page=>1), "read second page") or print "# ",$res->errstr, "\n"; is(i_img_diff($im2->{IMG}, $res->{IMG}), 0, "compare against second"); # check tags is($res->tags(name=>'gif_left'), 30, "gif_left"); is($res->tags(name=>'gif_top'), 25, "gif_top"); is($res->tags(name=>'gif_comment'), 'Second page', "gif_comment"); # get the third image ok($res->read(file=>$test_file, page=>2), "read third page") or print "# ",$res->errstr, "\n"; is(i_img_diff($im3->{IMG}, $res->{IMG}), 0, "compare against third"); is($res->tags(name=>'gif_left'), 35, "gif_left"); is($res->tags(name=>'gif_top'), 45, "gif_top"); is($res->tags(name=>'gif_comment'), undef, 'gif_comment undef'); # try to read a fourth page ok(!$res->read(file=>$test_file, page=>3), "fail reading fourth page"); cmp_ok($res->errstr, "=~", 'page 3 not found', "check error message"); } SKIP: { skip("gif_loop not supported on giflib before 4.1", 6) unless $gifver >= 4.1; # testing writing the loop extension my $im1 = Imager->new(xsize => 100, ysize => 100); $im1->box(filled => 1, color => '#FF0000'); my $im2 = Imager->new(xsize => 100, ysize => 100); $im2->box(filled => 1, color => '#00FF00'); ok(Imager->write_multi({ gif_loop => 5, gif_delay => 50, file => 'testout/t105loop.gif' }, $im1, $im2), "write with loop extension"); my @im = Imager->read_multi(file => 'testout/t105loop.gif'); is(@im, 2, "read loop images back"); is($im[0]->tags(name => 'gif_loop'), 5, "first loop read back"); is($im[1]->tags(name => 'gif_loop'), 5, "second loop read back"); is($im[0]->tags(name => 'gif_delay'), 50, "first delay read back"); is($im[1]->tags(name => 'gif_delay'), 50, "second delay read back"); } SKIP: { # check graphic control extension and ns loop tags are read correctly print "# check GCE and netscape loop extension tag values\n"; my @im = Imager->read_multi(file => 'testimg/screen3.gif'); is(@im, 2, "read 2 images from screen3.gif") or skip("Could not load testimg/screen3.gif:".Imager->errstr, 11); is($im[0]->tags(name => 'gif_delay'), 50, "0 - gif_delay"); is($im[0]->tags(name => 'gif_disposal'), 2, "0 - gif_disposal"); is($im[0]->tags(name => 'gif_trans_index'), undef, "0 - gif_trans_index"); is($im[0]->tags(name => 'gif_user_input'), 0, "0 - gif_user_input"); is($im[0]->tags(name => 'gif_loop'), 0, "0 - gif_loop"); is($im[1]->tags(name => 'gif_delay'), 50, "1 - gif_delay"); is($im[1]->tags(name => 'gif_disposal'), 2, "1 - gif_disposal"); is($im[1]->tags(name => 'gif_trans_index'), 7, "1 - gif_trans_index"); is($im[1]->tags(name => 'gif_trans_color'), 'color(255,255,255,0)', "1 - gif_trans_index"); is($im[1]->tags(name => 'gif_user_input'), 0, "1 - gif_user_input"); is($im[1]->tags(name => 'gif_loop'), 0, "1 - gif_loop"); } { # manually modified from a small gif, this had the palette # size changed to half the size, leaving an index out of range my $im = Imager->new; ok($im->read(file => 'testimg/badindex.gif', type => 'gif'), "read bad index gif") or print "# ", $im->errstr, "\n"; my @indexes = $im->getscanline('y' => 0, type => 'index'); is_deeply(\@indexes, [ 0..4 ], "check for correct indexes"); is($im->colorcount, 5, "check the palette was adjusted"); is_color3($im->getpixel('y' => 0, x => 4), 0, 0, 0, "check it was black added"); is($im->tags(name => 'gif_colormap_size'), 4, 'color map size tag'); } { ok(grep($_ eq 'gif', Imager->read_types), "check gif in read types"); ok(grep($_ eq 'gif', Imager->write_types), "check gif in write types"); } { # check screen tags handled correctly note the screen size # supplied is larger than the box covered by the images my $im1 = Imager->new(xsize => 10, ysize => 8); $im1->settag(name => 'gif_top', value => 4); $im1->settag(name => 'gif_screen_width', value => 18); $im1->settag(name => 'gif_screen_height', value => 16); my $im2 = Imager->new(xsize => 7, ysize => 10); $im2->settag(name => 'gif_left', value => 3); my @im = ( $im1, $im2 ); my $data; ok(Imager->write_multi({ data => \$data, type => 'gif' }, @im), "write with screen settings") or print "# ", Imager->errstr, "\n"; my @result = Imager->read_multi(data => $data); is(@result, 2, "got 2 images back"); is($result[0]->tags(name => 'gif_screen_width'), 18, "check result screen width"); is($result[0]->tags(name => 'gif_screen_height'), 16, "check result screen height"); is($result[0]->tags(name => 'gif_left'), 0, "check first gif_left"); is($result[0]->tags(name => 'gif_top'), 4, "check first gif_top"); is($result[1]->tags(name => 'gif_left'), 3, "check second gif_left"); is($result[1]->tags(name => 'gif_top'), 0, "check second gif_top"); } { # test colors array returns colors my $data; my $im = test_image(); my @colors; ok($im->write(data => \$data, colors => \@colors, make_colors => 'webmap', translate => 'closest', gifquant => 'gen', type => 'gif'), "write using webmap to check color table"); is(@colors, 216, "should be 216 colors in the webmap"); is_color3($colors[0], 0, 0, 0, "first should be 000000"); is_color3($colors[1], 0, 0, 0x33, "second should be 000033"); is_color3($colors[8], 0, 0x33, 0x66, "9th should be 003366"); } { # a zero length extension could make read_/read_multi crash my ($im) = Imager->read_multi(file => "testimg/zerocomm.gif"); ok($im, "read image with zero-length extension"); } { # check close failures are handled correctly my $im = test_image_mono(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; ok(!$im->write(type => "gif", callback => sub { 1 }, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } sub test_readgif_cb { my ($size) = @_; open FH, "deltag(code=>0); } } sub _add_tags { my ($img, %tags) = @_; for my $key (keys %tags) { Imager::i_tags_add($img, $key, 0, $tags{$key}, 0); } } sub ext_test { my ($testnum, $code, $count, $name) = @_; $count ||= 1; $name ||= "gif$testnum"; # build our code my $script = "testout/$name.pl"; if (open SCRIPT, "> $script") { print SCRIPT <<'PROLOG'; #!perl -w if (lc $^O eq 'mswin32') { # avoid the dialog box that window's pops up on a GPF # if you want to debug this stuff, I suggest you comment out the # following eval { require Win32API::File; Win32API::File::SetErrorMode( Win32API::File::SEM_NOGPFAULTERRORBOX()); }; } PROLOG print SCRIPT $code; close SCRIPT; my $perl = $^X; $perl = qq/"$perl"/ if $perl =~ / /; print "# script: $script\n"; my $cmd = "$perl -Mblib $script"; print "# command: $cmd\n"; my $ok = 1; my @out = `$cmd`; # should work on DOS and Win32 my $found = 0; for (@out) { if (/^not ok\s+(?:\d+\s*)?#(.*)/ || /^not ok/) { my $msg = $1 || ''; ok(0, $msg); $ok = 0; ++$found; } elsif (/^ok\s+(?:\d+\s*)?#(.*)/ || /^ok/) { my $msg = $1 || ''; ok(1, $msg); ++$found; } } unless ($count == $found) { print "# didn't see enough ok/not ok\n"; $ok = 0; } return $ok; } else { return skip("could not create test script $script: $!"); return 0; } } libimager-perl-1.004+dfsg.orig/GIF/t/t50header.t0000644000175000017500000000135512263740577020420 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 4; use Imager; use Imager::Test qw(test_image); # giflib 4.2.0 and 5.0.0 had a bug with producing the wrong # GIF87a/GIF89a header, test we get the right header # https://rt.cpan.org/Ticket/Display.html?id=79679 # https://sourceforge.net/tracker/?func=detail&aid=3574283&group_id=102202&atid=631304 my $im = test_image()->to_paletted(); { my $data; ok($im->write(data => \$data, type => "gif"), "write with no tags, should be GIF87a"); is(substr($data, 0, 6), "GIF87a", "check header is GIF87a"); } { my $data; ok($im->write(data => \$data, type => "gif", gif_loop => 1), "write with loop tags, should be GIF89a"); is(substr($data, 0, 6), "GIF89a", "check header is GIF89a"); } libimager-perl-1.004+dfsg.orig/GIF/t/t30fixed.t0000644000175000017500000000316312263740577020264 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 9; use Imager; use Imager::Test qw(test_image); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t30fixed.log"); { # RT 67912 # previously, if you tried to write a paletted image to GIF: # - specified a fixed palette with make_colors => "mono", "web" or "none" # - there was room for the colors in the image in the rest of the # palette (or they were found in the generated palette) # the GIF would be written with essentially it's original palette # instead of the specified palette # # This was confusing, especially if you specified a restricted # palette such as mono or a small greyscale ramp my $src = test_image(); ok($src, "make source image"); my $pal = $src->to_paletted(max_colors => 250); ok($pal, "make paletted version"); cmp_ok($pal->colorcount, "<=", 250, "make sure not too many colors"); my $mono = $src->to_paletted(make_colors => "mono", translate => "errdiff"); ok($mono, "make mono image directly"); ok($mono->write(file => "testout/t30monodirect.gif", type => "gif"), "save mono direct image"); Imager->log("Save manually paletted version\n"); ok($pal->write(file => "testout/t30color.gif"), "save generated palette version"); Imager->log("Save mono version\n"); ok($pal->write(file => "testout/t30monoind.gif", type => "gif", make_colors => "mono", translate => "errdiff"), "write paletted with mono colormap"); my $rd = Imager->new(file => "testout/t30monoind.gif", type => "gif"); ok($rd, "read it back in"); is($rd->colorcount, 2, "should only have 2 colors"); } Imager->close_log; libimager-perl-1.004+dfsg.orig/GIF/t/t20new.t0000644000175000017500000000604212263740577017754 0ustar gregoagregoa#!perl -w # Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) use strict; use Test::More tests => 21; use Imager qw(:all :handy); use Imager::Test qw(test_image is_color3); -d "testout" or mkdir "testout"; Imager::init('log'=>'testout/t70newgif.log'); my $green=i_color_new(0,255,0,0); my $blue=i_color_new(0,0,255,0); { my $img = test_image(); ok($img->write(file=>'testout/t70newgif.gif',type=>'gif',gifplanes=>1,gifquant=>'lm',lmfixed=>[$green,$blue])) or print "# failed: ",$img->{ERRSTR}, "\n"; } SKIP: { # make sure the palette is loaded properly (minimal test) my $im2 = Imager->new(); my $map; ok($im2->read(file=>'testimg/bandw.gif', colors=>\$map)) or skip("Can't load bandw.gif", 5); # check the palette ok($map) or skip("No palette", 4); is(@$map, 2) or skip("Bad map count", 3); my @sorted = sort { comp_entry($a,$b) } @$map; # first entry must be #000000 and second #FFFFFF is_color3($sorted[0], 0,0,0, "check first palette entry"); is_color3($sorted[1], 255,255,255, "check second palette entry"); } { # test the read_multi interface my @imgs = Imager->read_multi(); ok(!@imgs, "read with no sources should fail"); like(Imager->errstr, qr/callback parameter missing/, "check error"); print "# ",Imager->errstr,"\n"; @imgs = Imager->read_multi(type=>'gif'); ok(!@imgs, "read multi no source but type should fail"); like(Imager->errstr, qr/file/, "check error"); # kill warning *NONESUCH = \20; @imgs = Imager->read_multi(type=>'gif', fh=>*NONESUCH); ok(!@imgs, "read from bad fh"); like(Imager->errstr, qr/fh option not open/, "check message"); print "# ",Imager->errstr,"\n"; { @imgs = Imager->read_multi(type=>'gif', file=>'testimg/screen2.gif'); is(@imgs, 2, "should read 2 images"); isa_ok($imgs[0], "Imager"); isa_ok($imgs[1], "Imager"); is($imgs[0]->type, "paletted"); is($imgs[1]->type, "paletted"); my @left = $imgs[0]->tags(name=>'gif_left'); is(@left, 1); my $left = $imgs[1]->tags(name=>'gif_left'); is($left, 3); } { open FH, "< testimg/screen2.gif" or die "Cannot open testimg/screen2.gif: $!"; binmode FH; my $cb = sub { my $tmp; read(FH, $tmp, $_[0]) and $tmp }; @imgs = Imager->read_multi(type=>'gif', callback => $cb); close FH; is(@imgs, 2, "read multi from callback"); open FH, "< testimg/screen2.gif" or die "Cannot open testimg/screen2.gif: $!"; binmode FH; my $data = do { local $/; ; }; close FH; @imgs = Imager->read_multi(type=>'gif', data=>$data); is(@imgs, 2, "read multi from data"); } } sub comp_entry { my ($l, $r) = @_; my @l = $l->rgba; my @r = $r->rgba; return $l[0] <=> $r[0] || $l[1] <=> $r[1] || $l[2] <=> $r[2]; } libimager-perl-1.004+dfsg.orig/GIF/t/t40limit.t0000644000175000017500000000556012263740577020307 0ustar gregoagregoa#!perl -w use Imager; use Test::More tests => 22; use Imager::Test qw(is_image); { # GIF files are limited to 0xFFFF x 0xFFFF pixels { my $im = Imager->new(xsize => 0x10000, ysize => 1); my $data = ''; ok(!$im->write(data => \$data, type => "gif"), "fail to write too wide an image"); is($im->errstr, "image too large for GIF", "check error message"); } SKIP: { my $im = Imager->new(xsize => 0xFFFF, ysize => 1); $im->box(fill => { hatch => "check4x4" }); my $data = ''; ok($im->write(data => \$data, type => "gif"), "write image at width limit"); my $im2 = Imager->new(data => $data, ftype => "gif"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is_image($im, $im2, "check we read what we wrote"); is($im->getwidth, 0xffff, "check width"); is($im->getheight, 1, "check height"); } { my $im = Imager->new(xsize => 1, ysize => 0x10000); my $data = ''; ok(!$im->write(data => \$data, type => "gif"), "fail to write too tall an image"); is($im->errstr, "image too large for GIF", "check error message"); } SKIP: { my $im = Imager->new(xsize => 1, ysize => 0xFFFF); $im->box(fill => { hatch => "check2x2" }); my $data = ''; ok($im->write(data => \$data, type => "gif"), "write image at width limit"); my $im2 = Imager->new(data => $data, ftype => "gif"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is_image($im, $im2, "check we read what we wrote"); is($im->getwidth, 1, "check width"); is($im->getheight, 0xffff, "check height"); } } { my $im = Imager->new(xsize => 1, ysize => 1); $im->settag(name => "gif_screen_width", value => 65536); my $data = ''; ok(!$im->write(data => \$data, type => "gif"), "save a with a large explicit screen width should fail"); is($im->errstr, "screen size too large for GIF", "check error message"); } { my $im = Imager->new(xsize => 0x8000, ysize => 1); $im->settag(name => "gif_left", value => 32768); my $data = ''; ok(!$im->write(data => \$data, type => "gif"), "save a with a large implicit screen width should fail"); is($im->errstr, "screen size too large for GIF", "check error message"); } { my $im = Imager->new(xsize => 1, ysize => 1); $im->settag(name => "gif_screen_height", value => 65536); my $data = ''; ok(!$im->write(data => \$data, type => "gif"), "save a with a large explicit screen height should fail"); is($im->errstr, "screen size too large for GIF", "check error message"); } { my $im = Imager->new(xsize => 1, ysize => 0x8000); $im->settag(name => "gif_top", value => 32768); my $data = ''; ok(!$im->write(data => \$data, type => "gif"), "save a with a large implicit screen height should fail"); is($im->errstr, "screen size too large for GIF", "check error message"); } libimager-perl-1.004+dfsg.orig/GIF/Makefile.PL0000644000175000017500000001267412567572530020166 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Getopt::Long; use Config; my $verbose = $ENV{IM_VERBOSE}; my @libpaths; my @incpaths; GetOptions("incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$verbose); our $BUILDING_IMAGER; our %IMAGER_LIBS; my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; my %opts = ( NAME => 'Imager::File::GIF', VERSION_FROM => 'GIF.pm', OBJECT => 'GIF.o imgif.o', clean => { FILES => 'testout' }, ); my @inc; if ($BUILDING_IMAGER) { unshift @inc, "-I.."; unshift @INC, "../lib"; } else { unshift @INC, "inc"; print "GIF: building independently\n"; require Imager::ExtUtils; push @inc, Imager::ExtUtils->includes; $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ]; # Imager required configure through use my @Imager_req = ( Imager => "0.94" ); if ($MM_ver >= 6.46) { $opts{META_MERGE} = { configure_requires => { @Imager_req, }, build_requires => { @Imager_req, "Test::More" => "0.47", }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; $opts{PREREQ_PM} = { @Imager_req, XSLoader => 0, }; } } require Imager::Probe; my %probe = ( name => "GIF", inccheck => sub { -e File::Spec->catfile($_[0], "gif_lib.h") }, libbase => "gif", testcode => _gif_test_code(), testcodeheaders => [ "stddef.h", "gif_lib.h", "stdio.h", "errno.h", "string.h" ], incpath => \@incpaths, libpath => \@libpaths, verbose => $verbose, ); my $probe_res = Imager::Probe->probe(\%probe); if ($probe_res) { $IMAGER_LIBS{GIF} = 1; push @inc, $probe_res->{INC}; $opts{LIBS} = $probe_res->{LIBS}; $opts{DEFINE} = $probe_res->{DEFINE}; $opts{INC} = "@inc"; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'GIF Image file support'; } WriteMakefile(%opts); } else { $IMAGER_LIBS{GIF} = 0; if ($BUILDING_IMAGER) { ExtUtils::MakeMaker::WriteEmptyMakefile(%opts); } else { # fail in good way die "OS unsupported: GIF libraries or headers not found\n"; } } sub _gif_test_code { return <<'CODE'; /* TODO: test DGifOpen() and processing with callbacks */ GifFileType *gf; #ifdef GIF_LIB_VERSION const char vers[] = GIF_LIB_VERSION; const char *versp = vers; int ver_maj; int ver_min; #else int ver_maj = GIFLIB_MAJOR; int ver_min = GIFLIB_MINOR; #endif GifColorType colors[2]; ColorMapObject *map; FILE *fh; char buf[6]; int mode; int error; #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 gf=DGifOpenFileName("testimg/expected.gif", &error); #else gf=DGifOpenFileName("testimg/expected.gif"); #endif if (!gf) { fprintf(stderr, "GIF: Cannot open testimg/expected.gif\n"); return 1; } if (gf->SWidth != 16 || gf->SHeight != 16) { fprintf(stderr, "GIF: bad screen description (%d x %d)\n", gf->SWidth, gf->SHeight); return 1; } #if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5 /* crashes in older versions of giflib, not used in giflib 5 */ EGifSetGifVersion("89a"); EGifSetGifVersion("87a"); #endif #ifdef GIF_LIB_VERSION /* skip the " Version " */ while (*versp && (*versp < '0' || *versp > '9')) ++versp; if (!*versp) { fprintf(stderr, "GIF: Cannot find version number in '%s'\n", vers); return 1; } ver_maj = 0; while (*versp && *versp >= '0' && *versp <= '9') { ver_maj *= 10; ver_maj += *versp++ - '0'; } if (*versp != '.' || versp[1] < '0' || versp[1] > '9') { fprintf(stderr, "Cannot parse major version number in '%s'\n", vers); return 1; } ++versp; /* skip '.' */ ver_min = 0; while (*versp && *versp >= '0' && *versp <= '9') { ver_min *= 10; ver_min += *versp++ - '0'; } #endif if (ver_maj < 4) { fprintf(stderr, "GIF: gif lib version 3 is no longer supported\n"); return 1; } if (ver_maj == 4 && ver_min < 1) { fprintf(stderr, "GIF: you need at least giflib 4.1\n"); return 1; } /* test we write both GIF87a and GIF89a files */ for (mode = 0; mode < 2; ++mode) { #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 gf=EGifOpenFileName("probe.gif", 0, &error); EGifSetGifVersion(gf, mode); #else gf=EGifOpenFileName("probe.gif", 0); EGifSetGifVersion(mode ? "89a" : "87a"); #endif if (!gf) { fprintf(stderr, "GIF: cannot create probe.gif for testing\n"); return 1; } colors[0].Red = colors[0].Green = colors[0].Blue = 0; colors[1].Red = colors[1].Green = colors[1].Blue = 0; #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 map = GifMakeMapObject(2, colors); #else map = MakeMapObject(2, colors); #endif EGifPutScreenDesc(gf, 1, 1, 1, 0, map); EGifPutImageDesc(gf, 0, 0, 1, 1, 0, NULL); EGifPutPixel(gf, 0); #if defined(GIFLIB_MAJOR) && ((GIFLIB_MAJOR >= 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR >= 6) EGifCloseFile(gf, &error); #else EGifCloseFile(gf); #endif fh = fopen("probe.gif", "r"); if (!fh) { fprintf(stderr, "GIF: cannot open probe.gif for reading\n"); return 1; } errno = 0; memset(buf, 0, sizeof(buf)); if (fread(buf, 1, 6, fh) != 6) { fprintf(stderr, "GIF: cannot read probe.gif header (%d)\n", errno); return 1; } fclose(fh); remove("probe.gif"); if (memcmp(buf, mode ? "GIF89a" : "GIF87a", 6)) { fprintf(stderr, "GIF: incorrect header on test - 4.2.0 bug? (mode %d, buf %-6s)\n", mode, buf); return 1; } } fprintf(stderr, "GIF: Major %d, Minor %d\n", ver_maj, ver_min); return 0; CODE } libimager-perl-1.004+dfsg.orig/GIF/GIF.xs0000644000175000017500000000725112263740577017171 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "imgif.h" #include "imextpl.h" DEFINE_IMAGER_CALLBACKS; DEFINE_IMAGER_PERL_CALLBACKS; MODULE = Imager::File::GIF PACKAGE = Imager::File::GIF double i_giflib_version() undef_int i_writegif_wiol(ig, opts,...) Imager::IO ig PREINIT: i_quantize quant; i_img **imgs = NULL; int img_count; int i; HV *hv; CODE: if (items < 3) croak("Usage: i_writegif_wiol(IO,hashref, images...)"); if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1)))) croak("i_writegif_callback: Second argument must be a hash ref"); hv = (HV *)SvRV(ST(1)); memset(&quant, 0, sizeof(quant)); quant.version = 1; quant.mc_size = 256; quant.transp = tr_threshold; quant.tr_threshold = 127; ip_handle_quant_opts(aTHX_ &quant, hv); img_count = items - 2; RETVAL = 1; if (img_count < 1) { RETVAL = 0; } else { imgs = mymalloc(sizeof(i_img *) * img_count); for (i = 0; i < img_count; ++i) { SV *sv = ST(2+i); imgs[i] = NULL; if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) { imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv))); } else { RETVAL = 0; break; } } if (RETVAL) { RETVAL = i_writegif_wiol(ig, &quant, imgs, img_count); } myfree(imgs); if (RETVAL) { ip_copy_colors_back(aTHX_ hv, &quant); } } ST(0) = sv_newmortal(); if (RETVAL == 0) ST(0)=&PL_sv_undef; else sv_setiv(ST(0), (IV)RETVAL); ip_cleanup_quant_opts(aTHX_ &quant); void i_readgif_wiol(ig) Imager::IO ig PREINIT: int* colour_table; int colours, q, w; i_img* rimg; SV* temp[3]; AV* ct; SV* r; PPCODE: colour_table = NULL; colours = 0; if(GIMME_V == G_ARRAY) { rimg = i_readgif_wiol(ig,&colour_table,&colours); } else { /* don't waste time with colours if they aren't wanted */ rimg = i_readgif_wiol(ig,NULL,NULL); } if (colour_table == NULL) { EXTEND(SP,1); r=sv_newmortal(); sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg); PUSHs(r); } else { /* the following creates an [[r,g,b], [r, g, b], [r, g, b]...] */ /* I don't know if I have the reference counts right or not :( */ /* Neither do I :-) */ /* No Idea here either */ ct=newAV(); av_extend(ct, colours); for(q=0; q; chomp($a); die "Aborted!\n" if $a =~ /^n/i; print "Generating info about system\n"; open OSTD, '>&STDOUT' or die $!; open STDOUT, '>report.txt' or die $!; open STDERR, '>&STDOUT' or die $!; rcomm('rm testout/*'); rcomm(@precommands); my $make = $Config{make}; rcomm("$^X Makefile.PL --verbose") || rcomm("$make") || rcomm("$make test TEST_VERBOSE=1"); head("Logfiles from run"); dumplogs(); pconf(); rcomm(@postcommands); sub pconf { head("perl Config parameters"); for(sort keys %Config) { print $_,"=>",(defined $Config{$_} ? $Config{$_} : '(undef)'),"\n"; } print "\n"; } sub rcomm { my @commands=@_; my ($comm,$R); for $comm(@commands) { print "Executing '$comm'\n"; print OSTD "Executing '$comm'\n"; $R=system($comm); print "warning - rc=$R\n" if $R; print "=====================\n\n"; } return $R; } sub head { my $h=shift; print "=========================\n"; print $h; print "\n=========================\n"; } sub dumplogs { opendir(DH,"testout") || die "Cannot open dir testout: $!\n"; my @fl=sort grep(/\.log$/,readdir(DH)); for my $f (@fl) { print "::::::::::::::\ntestout/$f\n::::::::::::::\n"; open(FH,"testout/$f") || warn "Cannot open testout/$f: $!\n"; print while(); close(FH); } } libimager-perl-1.004+dfsg.orig/immacros.h0000644000175000017500000001377112614520110017545 0ustar gregoagregoa/* Imager "functions" implemented as macros I suppose these could go in imdatatypes, but they aren't types. */ #ifndef IMAGER_IMMACROS_H_ #define IMAGER_IMMACROS_H_ /* =item i_img_has_alpha(C) =category Image Information Return true if the image has an alpha channel. =cut */ #define i_img_has_alpha(im) (i_img_alpha_channel((im), NULL)) /* =item i_psamp(im, left, right, y, samples, channels, channel_count) =category Drawing Writes sample values from C to C for the horizontal line (left, y) to (right-1, y) inclusive for the channels specified by C, an array of C with C elements. If C is C then the first C channels are written to for each pixel. Returns the number of samples written, which should be (right - left) * channel_count. If a channel not in the image is in channels, left is negative, left is outside the image or y is outside the image, returns -1 and pushes an error. =cut */ #define i_psamp(im, l, r, y, samps, chans, count) \ (((im)->i_f_psamp)((im), (l), (r), (y), (samps), (chans), (count))) /* =item i_psampf(im, left, right, y, samples, channels, channel_count) =category Drawing Writes floating point sample values from C to C for the horizontal line (left, y) to (right-1, y) inclusive for the channels specified by C, an array of C with C elements. If C is C then the first C channels are written to for each pixel. Returns the number of samples written, which should be (right - left) * channel_count. If a channel not in the image is in channels, left is negative, left is outside the image or y is outside the image, returns -1 and pushes an error. =cut */ #define i_psampf(im, l, r, y, samps, chans, count) \ (((im)->i_f_psampf)((im), (l), (r), (y), (samps), (chans), (count))) #ifndef IMAGER_DIRECT_IMAGE_CALLS #define IMAGER_DIRECT_IMAGE_CALLS 1 #endif #if IMAGER_DIRECT_IMAGE_CALLS #define i_ppix(im, x, y, val) (((im)->i_f_ppix)((im), (x), (y), (val))) #define i_gpix(im, x, y, val) (((im)->i_f_gpix)((im), (x), (y), (val))) #define i_ppixf(im, x, y, val) (((im)->i_f_ppixf)((im), (x), (y), (val))) #define i_gpixf(im, x, y, val) (((im)->i_f_gpixf)((im), (x), (y), (val))) #define i_plin(im, l, r, y, val) (((im)->i_f_plin)(im, l, r, y, val)) #define i_glin(im, l, r, y, val) (((im)->i_f_glin)(im, l, r, y, val)) #define i_plinf(im, l, r, y, val) (((im)->i_f_plinf)(im, l, r, y, val)) #define i_glinf(im, l, r, y, val) (((im)->i_f_glinf)(im, l, r, y, val)) #define i_gsamp(im, l, r, y, samps, chans, count) \ (((im)->i_f_gsamp)((im), (l), (r), (y), (samps), (chans), (count))) #define i_gsampf(im, l, r, y, samps, chans, count) \ (((im)->i_f_gsampf)((im), (l), (r), (y), (samps), (chans), (count))) #endif #define i_gsamp_bits(im, l, r, y, samps, chans, count, bits) \ (((im)->i_f_gsamp_bits) ? ((im)->i_f_gsamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1) #define i_psamp_bits(im, l, r, y, samps, chans, count, bits) \ (((im)->i_f_psamp_bits) ? ((im)->i_f_psamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1) #define i_findcolor(im, color, entry) \ (((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0) #define i_gpal(im, l, r, y, vals) \ (((im)->i_f_gpal) ? ((im)->i_f_gpal)((im), (l), (r), (y), (vals)) : 0) #define i_ppal(im, l, r, y, vals) \ (((im)->i_f_ppal) ? ((im)->i_f_ppal)((im), (l), (r), (y), (vals)) : 0) #define i_addcolors(im, colors, count) \ (((im)->i_f_addcolors) ? ((im)->i_f_addcolors)((im), (colors), (count)) : -1) #define i_getcolors(im, index, color, count) \ (((im)->i_f_getcolors) ? \ ((im)->i_f_getcolors)((im), (index), (color), (count)) : 0) #define i_setcolors(im, index, color, count) \ (((im)->i_f_setcolors) ? \ ((im)->i_f_setcolors)((im), (index), (color), (count)) : 0) #define i_colorcount(im) \ (((im)->i_f_colorcount) ? ((im)->i_f_colorcount)(im) : -1) #define i_maxcolors(im) \ (((im)->i_f_maxcolors) ? ((im)->i_f_maxcolors)(im) : -1) #define i_findcolor(im, color, entry) \ (((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0) #define i_img_virtual(im) ((im)->virtual) #define i_img_type(im) ((im)->type) #define i_img_bits(im) ((im)->bits) #define pIMCTX im_context_t my_im_ctx #ifdef IMAGER_NO_CONTEXT #define dIMCTXctx(ctx) pIMCTX = (ctx) #define dIMCTX dIMCTXctx(im_get_context()) #define dIMCTXim(im) dIMCTXctx((im)->context) #define dIMCTXio(io) dIMCTXctx((io)->context) #define aIMCTX my_im_ctx #else #define aIMCTX im_get_context() #endif #define i_img_8_new(xsize, ysize, channels) im_img_8_new(aIMCTX, (xsize), (ysize), (channels)) #define i_img_16_new(xsize, ysize, channels) im_img_16_new(aIMCTX, (xsize), (ysize), (channels)) #define i_img_double_new(xsize, ysize, channels) im_img_double_new(aIMCTX, (xsize), (ysize), (channels)) #define i_img_pal_new(xsize, ysize, channels, maxpal) im_img_pal_new(aIMCTX, (xsize), (ysize), (channels), (maxpal)) #define i_img_alloc() im_img_alloc(aIMCTX) #define i_img_init(im) im_img_init(aIMCTX, im) #define i_set_image_file_limits(width, height, bytes) im_set_image_file_limits(aIMCTX, width, height, bytes) #define i_get_image_file_limits(width, height, bytes) im_get_image_file_limits(aIMCTX, width, height, bytes) #define i_int_check_image_file_limits(width, height, channels, sample_size) im_int_check_image_file_limits(aIMCTX, width, height, channels, sample_size) #define i_clear_error() im_clear_error(aIMCTX) #define i_push_errorvf(code, fmt, args) im_push_errorvf(aIMCTX, code, fmt, args) #define i_push_error(code, msg) im_push_error(aIMCTX, code, msg) #define i_errors() im_errors(aIMCTX) #define io_new_fd(fd) im_io_new_fd(aIMCTX, (fd)) #define io_new_bufchain() im_io_new_bufchain(aIMCTX) #define io_new_buffer(data, len, closecb, closectx) im_io_new_buffer(aIMCTX, (data), (len), (closecb), (closectx)) #define io_new_cb(p, readcb, writecb, seekcb, closecb, destroycb) \ im_io_new_cb(aIMCTX, (p), (readcb), (writecb), (seekcb), (closecb), (destroycb)) #endif libimager-perl-1.004+dfsg.orig/Changes0000644000175000017500000022465112617611507017074 0ustar gregoagregoaImager release history. Older releases can be found in Changes.old Imager 1.004 - 8 Nov 2015 ============ - Imager::Color::Table is now pre-loaded by the preload() method. https://rt.cpan.org/Ticket/Display.html?id=104896 - fix an assertion triggered under perl 5.23.4. Thanks to A. Sinan Unur for the report and the patch. - Imager->new can now be used to read raw image files. https://rt.cpan.org/Ticket/Display.html?id=106836 - deal with output changes from Pod::Spell https://github.com/perl-pod/Pod-Spell/issues/21 Imager 1.003 - 12 May 2015 ============ - update 1.002 release notes to include the center change for filled circle drawing. - flood_fill() would escape beyond a 4-connected space under some circumstances. Added many more flood_fill() tests. https://rt.cpan.org/Ticket/Display.html?id=103786 Imager 1.002 - 3 Apr 2015 ============ - drawing anti-aliased filled circles is now 10 to 50 times faster depending on the size of the circle. This also changed the center from being the center of the pixel to being the top left of the pixel to match the filled arcs drawn by arc(). https://rt.cpan.org/Ticket/Display.html?id=101682 - enhancements to polygon filling: - added a mode parameter to control how overlapping regions behave - added a polypolygon() method to fill more than one polygon at a time - polygon filling is now exposed through the API. - added colormodel(), alphachannel() and colorchannels() methods. These were added for two reasons: - a future version of Imager may allow the number of channels in an image to not directly represent the color model of an image. eg. a greyscale TIFF image with multiple alpha channels. - a future version of Imager may allow an image to be read without translation, for example a TIFF file that contains measurements from an instrument. Currently Imager transforms the samples into the range 0.0 ... 1.0 which may means the user has to translates the value back. An untranslated image would be unusable as image data, so colormodel() would return "unknown" in this case. Similarly a CMYK image might be returned as an "unknown" color model image, if the caller chooses to disable translation to RGB. Imager 1.001 - 2 Jan 2015 ============ - both Imager and perl 5.21.3 define my_strerror(), prevent a conflict Thanks to Slaven Rezic for the report and the patch. https://rt.cpan.org/Public/Bug/Display.html?id=98234 - GIF: clean-up a test file if the test for the giflib 4.2.0 file version bug fails. - fix Imager::Matrix2d::rotate()'s centre point handling https://rt.cpan.org/Public/Bug/Display.html?id=99959 - ICO: don't apply the icon mask to images with an alpha channel by default https://rt.cpan.org/Public/Bug/Display.html?id=99507 - make verbose probing output more verbose - use Imager::Probe to probe for freetype 1.x https://rt.cpan.org/Ticket/Display.html?id=100502 - The --enable and --disable parameters to the top-level Makefile.PL work again. - update the bundled/modified Devel::CheckLib to handle the gcc-4 symlink on Cygwin Imager 1.000 - 28 Jul 2014 ============ There's nothing special about Imager 1.000, it's just another release. - fix the skip check for the iolayer qr// buffer test - improve error reporting for the iolayer test failing on a small number of Win32 CPAN testers Imager 0.99_02 - 21 Jul 2014 ============== - Imager::Filter::Mandelbrot (and dynfilt/mandelbrot.c) - initialize the blue channel in the generated palette, and allow each color component to be in the range 100..255 instead of just 100..254. Thanks to Ralf Neubauer. https://rt.cpan.org/Ticket/Display.html?id=97086 - revert "improved the XS for i_io_read() and i_io_raw_read()" This caused problems with older perls and didn't provide much of a performance improvement. - support Inline 0.57 and later. Inline 0.57 changed the "with" interface. https://rt.cpan.org/Ticket/Display.html?id=97108 - don't define our own MAXINT macro, it conflicts with windows header files and in a few places it was the wrong value to use anyway. https://rt.cpan.org/Ticket/Display.html?id=96425 Imager 0.99_01 - 29 Jun 2014 ============== - GIF: add support for giflib 5.1.0, which added error code pointer parameters to EGifCloseFile() and DGifCloseFile(). https://rt.cpan.org/Ticket/Display.html?id=96756 - GIF: avoid a double-free when do_write() fails. - fix SV type probing to work on perl before 5.12. Broken in 0.99. https://rt.cpan.org/Ticket/Display.html?id=96761 - PNG: skip the benign error test before libpng 1.6.0, since the error we're testing didn't exist before 1.6.0. https://rt.cpan.org/Ticket/Display.html?id=94717 (continued) Imager 0.99 - 25 Jun 2014 =========== - Imager::IO->new_buffer() (and hence Imager->read()'s data parameter) now accepts a reference to a scalar as well as just a plain scalar. https://rt.cpan.org/Ticket/Display.html?id=92785 - Imager::IO->new_buffer() now always makes a copy of the passed in buffer to avoid problems with temporary objects used for the return value of SvPVbyte(). https://rt.cpan.org/Ticket/Display.html?id=92785 - improved the XS for i_io_read() and i_io_raw_read() https://rt.cpan.org/Ticket/Display.html?id=92738 - load plugins from absolute paths on Android Thanks to Brian Fraser. https://rt.cpan.org/Ticket/Display.html?id=93272 - added the jpeg_optimize parameter for writing JPEG files. This can significantly reduce file sizes, but uses more memory and time. https://rt.cpan.org/Ticket/Display.html?id=94292 - the autolevels filter now works on the luminosity of the image rather then working per channel. The old autolevels filter is still available as "autolevels_skew". https://rt.cpan.org/Ticket/Display.html?id=94413 - Imager::File::PNG now supports libpng 1.6.10. 1.6.10 changed CRC errors from benign errors to normal errors, which broke the test which used CRC errors to check for benign error support. Switched to using a 1-bit grey-scale image with a palette to test for benign errors. https://rt.cpan.org/Ticket/Display.html?id=94717 Imager 0.98 - 3 Jan 2014 =========== Incompatible changes: - the return value of setpixel() has changed. Previously the return values for undrawable pixels vs caller errors changed depending on whether you used the multiple pixel calling mechanism, or the single pixel mechanism. Now: - for an invalid parameter, such as an unknown colour, or missing parameter, an empty list (or undef in scalar context) is returned, and errstr() is set, - otherwise the number of pixels drawn is returned. If none of the pixels could be drawn (they were all outside the image), "0 but true" is returned. https://rt.cpan.org/Ticket/Display.html?id=87650 Other changes: - when drawing on an image with an alpha channel where the source minimum is greater than zero, Imager would read from beyond the end of a malloc() allocated buffer. In rare circumstances this could lead to some of the source image not being written to the target image, or possibly to a segmentation fault. I don't believe this has any security concerns beyond that. - if the first text drawn with Imager::Font::T1 is not anti-aliased, text drawn would be nonsense. This would also read beyond the end of a malloced buffer. - non-AA text drawn with an Imager::Font::TT (Truetype 1) font would be truncated early. https://rt.cpan.org/Ticket/Display.html?id=88993 - Imager::Font::Wrap no longer requires the image parameter. https://rt.cpan.org/Ticket/Display.html?id=87338 - a documentation typo fix in Imager::Transformations Thanks to Adrian Yee. https://rt.cpan.org/Ticket/Display.html?id=88598 - Image::Probe, Imager's internal module for probing library locations now searches the directories specified by LD_RUN_PATH, LD_LIBRARY_PATH, DYLD_LIBRARY_PATH and LIBRARY_PATH for libraries, and the corresponing s/\blib$/include/ directories for header files. https://rt.cpan.org/Ticket/Display.html?id=86428 Imager 0.97 - 15 Jul 2013 =========== No changes from 0.96_02. Imager 0.96_02 - 8 Jul 2013 ============== - PNG: treat a version mismatch between headers and library as a probe failure. https://rt.cpan.org/Ticket/Display.html?id=86659 - PNG: the check for benign error support is more complex than a simple library version check, check for the appropriate macro. Thanks for Slaven Rezic for following up on my CPAN Testers result queries. https://rt.cpan.org/Ticket/Display.html?id=86659 - W32: add a missing head1 AUTHORS to the old Win32.pm https://rt.cpan.org/Ticket/Display.html?id=86658 Imager 0.96_01 - 1 Jul 2013 ============== - TIFF: handle SampleFormat = 2 by translating the signed integer values to unsigned by flipping their sign bits. Handle SampleFormat = 3 where possible. SampleFormat is ignored for paletted images. Mixed SampleFormat are handled incorrectly, since libtiff returns only the first SampleFormat value, and an image with both an alpha channel and SampleFormat = 2 for color channels probably has a different SampleFormat for the alpha channel. https://rt.cpan.org/Ticket/Display.html?id=74540 - XS clean up: https://rt.cpan.org/Ticket/Display.html?id=69243 - Imager::Color's rgba() method now returns its values as integers instead of floating point. (IV instead of NV). - The XS for i_map() and i_matrix_transform() now use the AV * typemap instead of rolling their own. - The XS for DSO_call() now uses the HV * typemap instead of rolling it's own. - The XS for i_poly_aa(), i_poly_aa_cfill(), i_transform() and i_gradgen() now use a new T_AVARRAY typemap that greatly simplifies the XS code. - many other minor XS changes - some XS code formatting - TT (Freetype 1.x) and FT2 (Freetype 2.x) non-antialiased rendering now renders in alpha-combining mode, to match antialiased output. https://rt.cpan.org/Ticket/Display.html?id=73359 - add sample code and cookbook notes for drawing a blurred drop-shadow. - add support for libpng 1.6, which changed the defaults for reporting some types of error. https://rt.cpan.org/Ticket/Display.html?id=85746 - FT2: use gsamp/psamp() to transfer pixels from the work image to the output image instead of gpix/ppix. https://rt.cpan.org/Ticket/Display.html?id=83478 - eliminate various GCC warnings, mostly initialized but otherwise unused variables. Imager 0.96 - 19 May 2013 =========== - rearrange Imager's test files. https://rt.cpan.org/Ticket/Display.html?id=84596 - Imager::Probe::_gcc_lib_paths now forces C locale. A sufficiently recent gcc prints localized keys for the search paths, which avoids that localization. https://rt.cpan.org/Ticket/Display.html?id=84963 - fix a pod error detected by Pod::Simple 3.27 and laterm and skip pod tests unless AUTOMATED_TESTING or IMAGER_AUTHOR_TESTING is set and true. https://rt.cpan.org/Ticket/Display.html?id=85262 reported by Andreas König - add a test for unclosed POD in C source, and fix the errors it found. https://rt.cpan.org/Ticket/Display.html?id=74875 - fix some spelling errors detected by the newer aspell in Debian Wheezy. - remove a trailing ' from lib/Imager/Font/Test.pm's POD thanks to gregor herrmann https://rt.cpan.org/Ticket/Display.html?id=85413 - add a test for standard =head1 commands and fix the errors found Imager 0.95 - 19 Apr 2013 =========== - handle the SVf_UTF8 flag correctly on magic strings passed to Imager::IO's write() and raw_write() methods. This may misbehave in perl 5.6.x since the UTF8 flag may not be visible in the main SV after SvGETMAGIC(). https://rt.cpan.org/Ticket/Display.html?id=83438 - document that bounding_box() ignores the transformation matrix supplied to tranform() for fonts. https://rt.cpan.org/Ticket/Display.html?id=84106 Imager 0.94_02 - 5 Apr 2013 ============== - enable debug logging for the standard font tests - skip the overloaded UTF-8 text output checks on 5.6.x and earlier, due to a bug in that version of perl. - don't test for read() failing on a write-only handle in 5.8.x and earlier, this was fixed in change 862083f7e4 in perl. - report the version of Inline found during testing (an attempt to diagnose some intermittent failures.) Imager 0.94_01 - 2 Mar 2013 ============== - NOTE: possibly backward incompatible: support reading from/writing to perl filehandes that aren't raw files. This allows Imager's I/O to honour handles with layers such as gzip, scalar file handles or tied file handles. This is backward incompatible in that previous Imager would simply use fileno() to retrieve the fd for the file and call write(2) etc on it directly. https://rt.cpan.org/Ticket/Display.html?id=78843 - moved most of README to lib/Imager/Install.pod which should make it more accessible to the "web" generation, also significantly updated and re-worked it. - updated README's for the separately distributed modules to refer to Imager::Install, and that they need -dev versions of packages https://rt.cpan.org/Ticket/Display.html?id=81265 - the JPEG test code now reports the compile-time library version - avoid a possible compiler optimization issue on CentOS 5.9 i386 by rearranging (and mildly optimizing) some code. https://rt.cpan.org/Ticket/Display.html?id=83212 - fix a POD error in Imager::Fill (detected on new Pod-Simple) https://rt.cpan.org/Ticket/Display.html?id=83434 - fix a broken link to Graphics::Magick https://rt.cpan.org/Ticket/Display.html?id=82743 - drawing text to a channel with FT2 would draw with random coverage due to an uninitialized alpha channel. - marked the function pointer underlying the mm_log() API with the correct gcc magic and fixed the resulting warnings. - fixed some other compiler warnings - Imager::Font::W32 now properly reports text drawing errors https://rt.cpan.org/Ticket/Display.html?id=70098 - handle the SVf_UTF8 flag correctly on magic (eg. overloaded) strings passed as text to draw(), bounding_box(), has_chars(), glyph_names() (where supported) in each of the font drivers. This may misbehave in perl 5.6.x since the UTF8 flag may not be visible in the main SV after SvGETMAGIC(). https://rt.cpan.org/Ticket/Display.html?id=83438 (partial) Imager 0.94 - 15 Dec 2012 ========================= Variations on some of these changes were included in development releases. - improved thread safety - the internal error stack and log file handle are now in a per-thread context object - JPEG now captures IPTC information in a thread-safe way - avoid globals where possible for warning capture in libtiff - use a mutex to avoid re-entering thread-unsafe giflib - use a mutex to avoid re-entering thread-unsafe tifflib - use a mutex to avoid re-entering thread-unsafe T1Lib - use a library handle per thread for freetype 2. - use an engine handle per thread for freetype 1.x. - originally these changes broke ABI compatibility, this has been restored. - clarify the return value of getpixel(); https://rt.cpan.org/Ticket/Display.html?id=81198 - fixed a race condition in parallel testing for T1 - fixed a bug in handling yoff for untransformed image-based fills - documentation improvements for Imager::Fill - FT2: report the library version while testing. Imager 0.93 - 15 Oct 2012 =========== Bug fixes: - previously a transparency enabled GIF write (the default) would always use a GIF89a header even if none of the images were transparent. - previously the probe step for freetype-config would fail on cygwin - catch an invalid matrix parameter to convert() instead of crashing https://rt.cpan.org/Ticket/Display.html?id=79922 - remove the 16-bit/sample limitation from the documentation for setsamples(), it hasn't applied for many releases. https://rt.cpan.org/Ticket/Display.html?id=79989 - don't copy setsamples() data parameter, it may be a large scalar https://rt.cpan.org/Ticket/Display.html?id=79990 - clean up .dSYM directories generated performing probes on OS X Mountain Lion. - pass the --verbose command-line option through to Imager::Probe in sub-module's Makefile.PLs https://rt.cpan.org/Ticket/Display.html?id=75878 Enhancements: - support for giflib 5.0. (5.0.1 and later) https://rt.cpan.org/Ticket/Display.html?id=79029 The giflib API Imager uses doesn't have a mechanism to set the header version in 5.0.0. - update the GIF library probe code to check for the new giflib 5.0.1 EGifSetGifVersion() function, and to check for the giflib 4.2.0 uninitialized gif89 bug. https://rt.cpan.org/Ticket/Display.html?id=79679 http://sourceforge.net/tracker/?func=detail&aid=3574283&group_id=102202&atid=631304 - avoid static variables when capturing IPTC data from JPEG files - match Imager::Font;:T1's error message translations to those from later versions of T1Lib. - for libtiff versions that support extended warning handlers (3.8.0 or later), use them to avoid some global variables. - note Image::ExifTool for better metadata support. https://rt.cpan.org/Ticket/Display.html?id=79251 Imager 0.92 - 14 Aug 2012 =========== - giflib 4.2 eliminates the GIF_LIB_VERSION macro, handle that correctly for both probing and runtime. https://rt.cpan.org/Ticket/Display.html?id=77672 - allow building JPEG/imexif.c on C89 compilers. - allow building GIF/imgif.c on C89 compilers. Imager 0.91 - 4 Jun 2012 =========== Bug fixes: - The size of rotated images is no longer rounded up so aggressively. Added rounding to the linear interpolation done for rotate() and matrix_transform() for 1 and 3 channel 8-bit images. Adjusted the two tranlate matrices used to build the final rotation matrix to use the distance between the outlier pixels rather than the pixel dimensions (ie. dimension-1). With all of this the output of rotate(degrees => 270) on an 8-bit image exactly matches the output of rotate(right => 270). https://rt.cpan.org/Ticket/Display.html?id=77063 Other changes: - eliminate the old IIM_new(), IIM_DESTROY() names from Imager's internals, those names only matter for the XS interface. - improve error reporting when PERL_INITIALIZE_IMAGER_CALLBACKS finds the API level compiled into a loadable module such as Imager::File::GIF doesn't match that of Imager. Previously it could be difficult to determine exactly which module was failing to load. https://rt.cpan.org/Ticket/Display.html?id=77173 - added Imager->check_file_limits() as an interface to the i_int_check_image_file_limits() API. - Imager->set_file_limits(reset => 1) now resets the limits to the defaults rather than setting them all to unlimited. - wrote a brief security note as Imager::Security https://rt.cpan.org/Ticket/Display.html?id=68910 Imager 0.90 - 30 Apr 2012 =========== Bug fixes: - Imager::Test::is_imaged() attempted to process an "epsilon" parameter but the prototype didn't allow for the extra parameter. Corrected the prototype. - when downconverting samples (eg. from floating point to 8 bit) Imager now rounds the sample value rather than attempting to allocate input values over output values equally. The old behaviour had the probably surprising effect of converting a floating point 2.1/255.0 into an 8-bit 3 rather than the expected 2. This may result in slightly different 8 or 16-bit output images. - BI_BITFIELD BMP images were handled incorrectly, both in incorrectly calculating the space required for the masks and in processing the image data itself. https://rt.cpan.org/Ticket/Display.html?id=76736 - some odd width BMP BI_RLE4 images use run lengths that run one off the edge of the image. Imager now allows this, discarding the extra column. - odd length RLE4 runs in BMP images were decoded incorrectly. - pkg-config could sometimes return a library that was in a directory EU::MM / $Config{libpth} doesn't know about, but the compiler did. If no -L is included in the pkg-config library information check if EU::MM can find the library, and if not, search our configured directories and insert that into the library flags. https://rt.cpan.org/Ticket/Display.html?id=75869 - Imager::Probe can now probe for libraries with dependent libraries, common for static linking, eg. libpng requires libz. https://rt.cpan.org/Ticket/Display.html?id=74043 - libpng 1.5 specific probes were looking for libpng 1.4 filenames. - added alternative probe configurations that try to link libz, to handle a statically linked libpng. https://rt.cpan.org/Ticket/Display.html?id=74043 - if a probe includes testcode, Imager::Probe now checks that code as part of the process of checking each configuration rather than as a post test of the found configuration. This allows alternate configurations to be checked if a matching but non-working configuration is found. https://rt.cpan.org/Ticket/Display.html?id=74043 Other changes: - when reading or writing images via callbacks, the default callbacks now push an error message indicating that a required callback was called but not supplied. https://rt.cpan.org/Ticket/Display.html?id=76782 - clarify which callbacks are required for reading and writing TIFF images. - improve logging for creation of callback I/O layers. - a little more documentation for Imager::Probe. - the i_get_file_background() and i_get_file_backgroundf() APIs now return int to indicate whether the i_background tag was found. - PNG rework - improve error reporting - add png_interlace, png_bits tags - read paletted images as paletted images, including transparency - read 1 bit greyscale images as a type suitable for other file handlers to write as bilevel - read 16 bit/sample PNG as 16-bit/sample Imager images - write "bilevel" paletted images as 1 bit grayscale images - write paletted images as paletted images - write 16-bit (or higher)/sample images as 16-bit/sample PNG images - improved metadata support https://rt.cpan.org/Ticket/Display.html?id=29268 Imager 0.89 - 18 Mar 2012 =========== Bug fixes: - getpixel(..., type => "float") and the API i_gpixf() have been broken on paletted images since they were implemented. https://rt.cpan.org/Ticket/Display.html?id=75258 Other changes: - links in the METHOD INDEX now point at the method documentation rather than the heading you can find them under. https://rt.cpan.org/Ticket/Display.html?id=71495 - Imager (and the bundled dynamic modules) no longer fallback to using DynaLoader if loading via XSLoader fails. For the bundled modules this could hide useful error messages. https://rt.cpan.org/Ticket/Display.html?id=75560 - IM_DEBUG_MALLOC mymalloc() no longer sn?printfs() a string to a buffer in the array of allocations, but just stores the filename pointer and line number. https://rt.cpan.org/Ticket/Display.html?id=70388 Imager 0.88 - 22 Feb 2012 =========== - describe how to build libgif etc on OS X in such a way as to be compatible with a fat binary perl (such as the system perl), in README. https://rt.cpan.org/Ticket/Display.html?id=73371 - update the change notes for 0.77_01 to indicate that libungif support was removed. - add some other imaging modules to SEE ALSO https://rt.cpan.org/Ticket/Display.html?id=73906 - note that the generator of the apparently non-DFSG-free postscript in MMOne.pfb is a Debian package. - setsamples() is now a true complement to getsamples() - it can write 8-bit or floating point samples from a scalar or array reference. This adds i_psamp() and i_psampf() to the C level API. - the XS interfaces to i_gsamp(), i_gsampf() and i_gsamp_bits() have changed to make better use of the typemap, but these aren't part of the perl level API anyway. There were no changes to the C level interfaces to these functions. - getpixel() and setpixel() now accept a mix of scalar and array references for the x and y parameters, and unequal array lengths is no longer an error. https://rt.cpan.org/Ticket/Display.html?id=73697 Bug fixes: - correctly calculate the size of a rotated image https://rt.cpan.org/Ticket/Display.html?id=69261 - fix incorrect rounding of color values for matrix_transform() and rotate(). https://rt.cpan.org/Ticket/Display.html?id=69261 - Win32 text output is now done in normal combine mode, the alpha component of the color is now significant. https://rt.cpan.org/Ticket/Display.html?id=70014 - remove long unused gif case from read() https://rt.cpan.org/Ticket/Display.html?id=69244 (partial) - the getsamples() target parameter was being treated as a hashref when it's meant to be an array reference. https://rt.cpan.org/Ticket/Display.html?id=74882 - getpixel() and setpixel() now returns an empty list when invalid parameters are supplied. Invalid values for type now result in an error for getpixel(). https://rt.cpan.org/Ticket/Display.html?id=73697 Imager 0.87 - 03 Jan 2012 =========== - document the return value of the filter() method. https://rt.cpan.org/Ticket/Display.html?id=72369 - document i_gsamp_bits() and i_psamp_bits(). https://rt.cpan.org/Ticket/Display.html?id=68815 - properly increment the Imager::Matrix2d $VERSION. - actually include the Imager::Test tests in the dist - correctly read and write 256x256 pixel ICO files https://rt.cpan.org/Ticket/Display.html?id=69599 - make the error message from read() or read_multi() when they can't identify the file type match reality. https://rt.cpan.org/Ticket/Display.html?id=72475 - read() now uses $FORMATGUESS if it can't determine the file type based on the file header, to match read_multi(). - re-work and add tests for def_guess_type(). def_guess_type() no longer returns any random file extension as the file type. - add gray4, gray16 and gray as presets for make_colors. https://rt.cpan.org/Ticket/Display.html?id=67911 - add make_palette() method that produces a palette from one or more images. - fix the Imager dependency for the separately distributed font drivers. https://rt.cpan.org/Ticket/Display.html?id=72643 - fix i_render_color() to properly draw in "normal" mode - ie. when writing to a 1 or 3 channel image the second or fourth channel of the source color was being ignored, it is now significant. https://rt.cpan.org/Ticket/Display.html?id=71564 Imager 0.86 - 31 Oct 2011 =========== - improve error reporting for W32 tests Imager 0.85_02 - 24 Oct 2011 ============== Bug fixes: - eliminate unused i_gif_opts type (clean-up) https://rt.cpan.org/Ticket/Display.html?id=69245 - fix combine=0 fill color anti-aliasing on the double/sample path https://rt.cpan.org/Ticket/Display.html?id=71309 - make default text color non-transparent https://rt.cpan.org/Ticket/Display.html?id=71469 - apply the last of the Debian unforwarded spelling fixes https://rt.cpan.org/Ticket/Display.html?id=70656 - the log() method used its message parameter as a C level format string. https://rt.cpan.org/Ticket/Display.html?id=71653 - provide our own STRLEN typemap entry for older perls. https://rt.cpan.org/Ticket/Display.html?id=71641 - add extra ppport.h configuration to support older perls. - depend on Scalar::Util, since we use it and older perls don't have it. - add overloaded eq to Imager::Matrix2d, since older perls don't seem to synthesize it from overloaded "". - use T1_StrError() for error messages on modern libt1 https://rt.cpan.org/Ticket/Display.html?id=69879 - actually load the font rather than just adding it to the catalog on creation. - Imager::Font->new now produces better error messages for the T1 engine. - the font has_chars() method now returns perl's true and false values in list context rather than integers, which should be more efficient. https://rt.cpan.org/Ticket/Display.html?id=69158 - the btm data structure used by the flood_fill code is now initialized more efficiently. https://rt.cpan.org/Ticket/Display.html?id=68994 - updated the Thanks list in README https://rt.cpan.org/Ticket/Display.html?id=71607 - check there's at least one coefficient for the convolution filter https://rt.cpan.org/Ticket/Display.html?id=68993 - make the APIRef synopsis ordering consistent, older versions of perl could order it differently. https://rt.cpan.org/Ticket/Display.html?id=71675 - we rely on Config.pm's d_vsnprintf as to whether we use vsnprintf/snprintf, which is defined in the Win32 Config.pm even though it only has _ prefixed versions of these. Define our own prefixed names on Win32. https://rt.cpan.org/Ticket/Display.html?id=71642 - fix library detection with MSVC - search a few more library directories, so EU::MM doesn't discard them. Hopefully fixes: https://rt.cpan.org/Ticket/Display.html?id=71643 Imager 0.85_01 - 10 Oct 2011 ============== - add simple tests for the Imager::Test test_image generators - io_glue I/O buffering re-work: - reorganize io_glue to do it's own buffering by default - the unbuffered functions are available as i_io_raw_read() (or raw_read() from perl) etc but are not recommended for typical use. - use the new i_io_peekn() when checking for file magic to avoid seek, allowing Imager to detect the file type and read the file from an unseekable stream (for formats that don't use random access) - added several new I/O layer API functions. - fix the TGA performance problem, most noticably on Win32 https://rt.cpan.org/Ticket/Display.html?id=70037 - TIFF now uses wrapper functions of the correct types to avoid casts https://rt.cpan.org/Ticket/Display.html?id=69912 - the callback IO object did its own buffering, controlled by the maxbuffer parameter supplied to the read() and write() methods. This buffering has been removed, to avoid redundancy with the common io_glue buffering. This also avoids a bug in that code which could rarely pass a zero length to the read callback and then panic about the result. - the callback IO object now tests the result of calling the close callback, which should return true for success. - the PNM reader did its own buffering. This buffering has been removed to avoid redundancy with the common io_glue buffering. - previously the read handlers for fd and callback I/O layers would call the underlying interface (POSIX read or your supplied callback) until it filled the buffer. It now only makes one call. - added public constructors for I/O layer objects (see Imager::IO) - all core file handlers now use the i_io_foo() wrappers to gain access to buffered I/O rather than calling the I/O layer callbacks directly. - all core file handlers now check for error on close. - Backward compatibility: if you hava custom file handlers, you can use i_io_write() etc since they're available as macros in older versions of Imager. - eliminate the final remnants of io_glue_commit_types(). - bump IMAGER_API_VERSION, since the above may break assumptions. - removed the long unused i_gen_reader() and i_gen_writer() utility functions. Imager 0.85 - 29 Aug 2011 =========== The main changes in the release versus 0.84 are: - on 64-bit systems, 64-bit types are consistently used for image dimensions and co-ordinated, and for memory block sizes. - handle IFD loops in TIFF files correctly. Previously this would lead to an infinite loop. Bug fixes: - fix the link in the getheight() entry in the method index Imager 0.84_02 - 22 Aug 2011 ============== Development release, this will become 0.85 if CPAN testers is favourable. Bug fixes: - the image file limits set by set_file_limits() weren't being checked when reading TIFF files. https://rt.cpan.org/Ticket/Display.html?id=69915 - Provide more information about file format module load errors on a failed image file read() or write(). https://rt.cpan.org/Ticket/Display.html?id=69194 - use TIFFReadDirectory() instead of TIFFSetDirectory() to iterate through TIFF images, since it checks for IFD loops. https://rt.cpan.org/Ticket/Display.html?id=69914 - don't leak memory when out of range palette indexes are supplied to setscanline(). https://rt.cpan.org/Ticket/Display.html?id=69242 - require a later version of CPAN::Meta to ensure JSON::PP and CPAN::Meta::YAML are available. https://rt.cpan.org/Ticket/Display.html?id=69008 - hoist the per-line calculations for the flines implementations, and modernize the tests a bit. https://rt.cpan.org/Ticket/Display.html?id=70126 - detect snprintf()/vsnprintf() (cheat by using Config.pm) and use them when available. https://rt.cpan.org/Ticket/Display.html?id=69147 - if t1lib failed to reinitialize it would be left as marked initialized. https://rt.cpan.org/Ticket/Display.html?id=69877 - update the bundled (and still modified) Devel::CheckLib https://rt.cpan.org/Ticket/Display.html?id=69170 Imager 0.84_01 - 8 Aug 2011 ============== Development release as a sanity check for the types re-work. Massive types re-work: - the type used internally for pixel co-ordinates and image sizes is now 64-bit on 64-bit platforms (at least sane ones). - size_t is now used consistently for memory block sizes. - since this changes the binary interface, the Imager API version has been incremented. Any module that uses the API will need to be rebuilt. In most cases that will be enough, but calls to any APIs that take a pointer to image sizes may need source changes. - you should be able to create very large images on 64-bit systems, if you have enough memory. Successfully created a 32768 x 49192 x 3 channel image, filled with a tiled image and scaled it. The unscaled image was also successfully saved to a JPEG. - check the image size before attempting to write BMP, GIF, JPEG, PNG, SGI, TGA, TIFF images. - correctly handle reading TGA images over 32767 pixels wide or tall. Incidental changes: - the gif_left and gif_top tags are now clamped to non-negative values when writing a GIF image. - removed dead callback read/write code The default maximum memory size when reading files is now 1G. Imager 0.84 - 20 Jun 2011 =========== - Imager no longer inherits from Exporter (unless you're running an old, old perl. - Imager can now write progressive JPEGs (it could always read them). https://rt.cpan.org/Ticket/Display.html?id=68691 Bug fixes: - re-work, document and test Imager's logging facility. https://rt.cpan.org/Ticket/Display.html?id=65227 - fix META.yml testing and the generated META.yml https://rt.cpan.org/Ticket/Display.html?id=65235 - test and add error reporting to to_*() family methods - add to_rgb_double() method. https://rt.cpan.org/Ticket/Display.html?id=65101 - Imager no longer exports anything by default https://rt.cpan.org/Ticket/Display.html?id=65228 - convert colors to grayscale if the supplied (or generated) palette contains only grays when performing error diffusion color translation. https://rt.cpan.org/Ticket/Display.html?id=68508 - writing a paletted image to GIF wouldn't always use the colors supplied (or generated, eg. via make_colors => "mono"), which was confusing at best. https://rt.cpan.org/Ticket/Display.html?id=67912 - replace (imager|tony)@imager.perl.org in the doc, since I don't plan to continue receiving mail at that address. https://rt.cpan.org/Ticket/Display.html?id=68591 Imager 0.83 - 21 May 2011 =========== Bug fixes: - diag() the error message on failure for some TIFF tests that are failing on a Solaris smoker. http://www.cpantesters.org/cpan/report/6396db1e-8090-11e0-9682-112b785ebe45 Imager 0.82_01 - 17 May 2011 ============== Dev release, in case the compose tests are too sensitive. Bug fixes: - Imager::Font::T1 incorrectly checked for absolute filename under Win32. Thanks to kmx for the report and fix. https://rt.cpan.org/Ticket/Display.html?id=67963 - compose() with the target, source or mask position off the top or left of the target image didn't clip the source image correctly. https://rt.cpan.org/Ticket/Display.html?id=67220 - compose() now returns a useful error message on a non-positive opacity. - compose.im now at 100% test coverage. (As opposed to, umm, much, much less.) Imager 0.82 - 14 Mar 2011 =========== Bug fixes: - eliminate calls to i_has_format() from the test suite, since it's no longer a useful way to check for file format support. Eliminate i_has_format() from the functions exposed via XS. https://rt.cpan.org/Ticket/Display.html?id=65863 - eliminate calls to note(), which isn't in the (very old) version of Test::More we have as a pre-requisite. note() is modern enough that I don't feel a need to require a Test::More upgrade for it. https://rt.cpan.org/Ticket/Display.html?id=65864 - skip the threads tests on Test::More 2.00_* https://rt.cpan.org/Ticket/Display.html?id=65812 - add an (unshipped) test to check Imager's internal POD links https://rt.cpan.org/Ticket/Display.html?id=65749 - improve the library detection summary https://rt.cpan.org/Ticket/Display.html?id=9675 - increase the version of Imager::Font::Type1 so that upgrades don't downgrade the version in this file. https://rt.cpan.org/Ticket/Display.html?id=66250 - if we see an -rpath (or -R) option in $Config{lddlflags} supply that option for the directories that would normally go in LD_RUN_PATH. Typically an explicit -rpath overrides LD_RUN_PATH. https://rt.cpan.org/Ticket/Display.html?id=65955 Imager 0.81 - 14 Feb 2011 =========== - added coverage tests for masked images (maskimg.c @100% test coverage) - add hsv() method to Imager::Color Thanks to Leolo (Philip Gwyn) https://rt.cpan.org/Ticket/Display.html?id=65385 - split libt1 Type 1 font support into a sub-module https://rt.cpan.org/Ticket/Display.html?id=49616 (partial) - add a preload() class method for use in forking servers, and to work around limitations in PAR. https://rt.cpan.org/Ticket/Display.html?id=65665 Bug fixes: - paletted writes to a masked image are now masked correctly. Revealed by new coverage tests. - update the filter plugin documentation. https://rt.cpan.org/Ticket/Display.html?id=56513 - add the matrix() method to Imager::Matrix2d to allow creation of a matrix with specified co-efficients. You can now multiple an Imager::Matrix2d object by a 9 element array ref or a number. https://rt.cpan.org/Ticket/Display.html?id=29938 - really fix loading TTF fonts with FT2 when FT1 isn't available. Thanks to Leolo (Philip Gwyn) https://rt.cpan.org/Ticket/Display.html?id=65386 https://rt.cpan.org/Ticket/Display.html?id=62855 - make sure each test script that needs testout/ creates it. https://rt.cpan.org/Ticket/Display.html?id=65088 - handle a slightly different warning from libtiff 4.x https://rt.cpan.org/Ticket/Display.html?id=65268 - the sat transform2() op returned an incorrect saturation. https://rt.cpan.org/Ticket/Display.html?id=65391 Imager 0.80 - 17 Jan 2011 =========== - added coverage tests for Imager::Fountain and Imager::Color::Float - Imager is now maintained in git http://git.imager.perl.org/imager.git git://git.imager.perl.org/imager.git Bug fixes: - images with an translucent alpha channel were not scaled correctly by the default (qtype=normal) scaling method. https://rt.cpan.org/Public/Bug/Display.html?id=63922 - Imager::Color::Float now translates "#FFFFFF" to white instead of just a little darker. - make the default color map build algorithm "mediancut". This changes the default color map builder for writing GIFs back to what it was in 0.77, reverting a performance regression. https://rt.cpan.org/Ticket/Display.html?id=64785 - handle failure to create a masked image correctly Imager 0.79 - 10 Dec 2010 =========== - add Imager::Test to the POD coverage tests and document the missing functions. - the convert() method now optimizes the case where all output channels are either 0, sourced from a single input channel or 1. This significantly speeds up presets like "addalpha", "green". https://rt.cpan.org/Ticket/Display.html?id=51254 - add wiggle.pl sample, as suggested by Dan Oppenheim. - add the combine() method to combine channels from multiple source images into a new image https://rt.cpan.org/Ticket/Display.html?id=11872 Bug fixes: - treat the co-efficients for convert() as doubles instead of floats. - If a higher (earlier) priority font handler failed to load, that would crash preventing loading of later font handlers. https://rt.cpan.org/Ticket/Display.html?id=62855 - parse defines from the options returned by pkg-config --cflags https://rt.cpan.org/Ticket/Display.html?id=63223 - a regen of the MANIFEST revealed that GIF and FT2 tests weren't included in the tarball. They are now included. Imager 0.78 - 4 Oct 2010 =========== Bug fixes: - don't access deprecated members of the png_structp. https://rt.cpan.org/Ticket/Display.html?id=60242 - document that using color objects is faster than supplying colors by name, etc. https://rt.cpan.org/Ticket/Display.html?id=61047 - Imager::Probe now accepts array references for incpath and libpath. https://rt.cpan.org/Ticket/Display.html?id=60244 Imager 0.77_02 - 27 Sep 2010 ============== - moved Win32, FreeType 2 font support into sub-modules. https://rt.cpan.org/Ticket/Display.html?id=49616 (partial) Uses Imager::Probe now. https://rt.cpan.org/Public/Bug/Display.html?id=61328 - tested successfully with jpeg-8b https://rt.cpan.org/Ticket/Display.html?id=60221 Bug fixes: - from _01: look for missing file support test files in the right places. - flood_fill() wouldn't fill the right side of a single scan-line fill area. Thanks to Nicolas Roggli for reporting this. - flood_fill wouldn't fill to the left edge of the image if the starting line didn't reach the left edge. Thanks to Nicolas Roggli for reporting this. Imager 0.77_01 - 13 Sep 2010 ============== - add each library-directory/pkgconfig/ to the pkg-config search path in Imager::Probe. Thanks to Justin Davis. https://rt.cpan.org/Ticket/Display.html?id=60491 - moved GIF, TIFF, JPEG file handling code into sub-modules in preparation for separate distribution. https://rt.cpan.org/Ticket/Display.html?id=49616 (partial) Note: this removed support for libungif from Imager. - optimize filled box drawing (color, not fill) Bug fixes: - Imager::Probe was calling ExtUtils::Liblist to initialize LD_RUN_PATH supplying an undefined value rather than the found directory. Thanks to Justin Davis. https://rt.cpan.org/Ticket/Display.html?id=60491 - only prepend ./ to font filenames when passing them to T1Lib and then only when it would use its search mechanisms. https://rt.cpan.org/Ticket/Display.html?id=60509 - fix the cache check for the X rgb.txt loader. This is typically used for color translation on Unix-like systems, and the fix improves performance of supplying colors by name by about 80 times. Test code that managed 3400 10x10 pixel boxes/second sped up to 25700 boxes/second. - clarify that Imager doesn't write EXIF metadata to images. https://rt.cpan.org/Ticket/Display.html?id=60637 - Imager::Probe can now search subdirectories under its include path. Used by the PNG Makefile.PL to find headers and libraries when they aren't in the base directory, as in cygwin. https://rt.cpan.org/Ticket/Display.html?id=60635 Imager 0.77 - 11 Aug 2010 =========== I don't want Imager::File::PNG indexed as part of Imager, but forgot to update the META.yml before updating the version. - don't index Imager::File::PNG as part of Imager - add resources to META.yml Imager 0.76 - not released =========== Bug fixes: - the align_string() method would ignore a string of "0" due to a mis-use of C< ||= >. Thanks to Maurice Height for reporting this. https://rt.cpan.org/Ticket/Display.html?id=60199 Imager 0.75_03 - 09 Aug 2010 ============== Bug fixes: - read_types() and write_types() would include png when it wasn't available due to a problem with the %formats tie - handle dependent libraries correctly (eg -lpng requiring -lz) in the code run phase of library probing. Imager 0.75_02 - 07 Aug 2010 ============== Bug fixes: - add file missing from MANIFEST, which was causing TIFF failures. Imager 0.75_01 - 06 Aug 2010 ============== Test release for the new PNG probe. - added the ability to read multiple-image PNM files. Note that unlike the pbm/pgm/ppm specification this accepts mixed format files and allows white space padding between files. Thanks to Philip Gwyn (Leolo) for this patch. - moved the PNG file handling code into a sub-module in preparation for separate distribution. https://rt.cpan.org/Ticket/Display.html?id=49616 (partial) Also helps avoid complications from -I/-L compile/link options from other libraries. Bugs: - Imager->new(data => $data) didn't try to process image file data in $data https://rt.cpan.org/Ticket/Display.html?id=58761 - t/t50basicoo.t no longer depends on the other tests to generate its input files. https://rt.cpan.org/Ticket/Display.html?id=9798 Also, it wasn't testing pnm (pnm vs ppm mix-up) - update the documentation of hardinvert to match the change in 0.62. https://rt.cpan.org/Ticket/Display.html?id=59785 - added hardinvertall filter which also inverts the alpha channel (sorry for the mess) - when probing for TIFF, set LD_RUN_PATH just as the Makefile does so the probe can find the library for the test run. https://rt.cpan.org/Ticket/Display.html?id=57518 Imager 0.75 - 20 Jun 2010 =========== - use PERL_NO_GET_CONTEXT to slightly improve performance on threaded perls (not measured) Bugs: - an opacity fill based on a fountain fill would segfault when filling an 8-bit/sample image. - merge thickline branch polygon fix https://rt.cpan.org/Ticket/Display.html?id=43518 Imager 0.74 - 7 May 2010 =========== Bug fixes: - read_multi() didn't handle a missing file format library correctly, aborting on failing to call i_readgif_multi_wiol() or i_readtiff_multi_wiol(). - fix spelling errors patched by Debian http://svn.debian.org/viewsvn/pkg-perl/trunk/libimager-perl/debian/patches/spelling.patch?revision=54839&view=markup - add an (unshipped) author test to spellcheck Imager's POD. - update the TIFF file format documentation https://rt.cpan.org/Ticket/Display.html?id=56510 - lib/Imager/IO.pod was written almost 4 years ago but never shipped. Imager 0.73 - 15 Mar 2010 =========== - implement outline circles, both anti-aliased and not https://rt.cpan.org/Ticket/Display.html?id=19755 - a combine => "none" fill to a 1 or 3 channel image would produce the incorrect colour. Imager 0.72 - 09 Dec 2009 =========== Bump version for release, since 0.71_03 is stable with CPAN testers. Imager 0.71_03 - 5 Dec 2009 ============== - further adjust the threads test so it only performs the tests on perls where it's expected to work, and only if the threads module can be loaded. Imager 0.71_02 - 1 Dec 2009 ============== - adjust the way we load the threads module for the threads test so it works with non-threaded perls Imager 0.71_01 - 30 Nov 2009 =========== Bug fixes: - use scanline oriented operations to flip images instead of pixel operations https://rt.cpan.org/Ticket/Display.html?id=39278 - use double/sample operations to flip large sample images instead of 8-bit sample operations. https://rt.cpan.org/Ticket/Display.html?id=39280 - fix POD nits https://rt.cpan.org/Ticket/Display.html?id=51874 - prevent double-frees when someone creates Imager objects and then creates a thread. Note: this just handles some simple cases, Imager doesn't support perl threads, and isn't likely to. https://rt.cpan.org/Ticket/Display.html?id=52268 Imager 0.71 - 16 Nov 2009 =========== - add the opacity fill type - an adaptor that modifies the opacity of another fill. Bug fixes: - the conv filter now enforces that the sum of the coefficients is non-zero. Also, rather than skipping pixels off the edge off the edge of the image, the closest edge pixel is used. Previously dividing by the zero sum of coefficients could cause invalid results or runtime exceptions. Thanks to David Cantrell's Alpha-NetBSD CPAN test box for revealing this bug. Imager 0.70 - 21 Sep 2009 =========== Bug fixes: - release image row and comments memory on all error returns in gif reader - handle zero length extensions, previously this would cause a null pointer dereference Thanks to Krzysztof WojtaÅ› for the test data and fix for this. - an integer division meant that preview scaling to below 1 pixel wide or high (which isn't too useful anyway) was calculating using NaNs on most platforms, and causing an exception on others. Thanks to David Cantrell for producing a backtrace of the crash on his Alpha-NetBSD CPAN test box which made it possible to track this down. Imager 0.69 - 08 Sep 2009 =========== Bug fixes: - broken test fix - was attempting to call a function skip_all, when that should be a parameter to plan(). - briefly document apidocs.perl, the tool used to build Imager::APIRef and make some minor enhancements - various minor documentation enhancements and fixes. Imager 0.68 - 07 Sep 2009 =========== - Imager->new(file => $filename) and other similar incantations will load the given file. https://rt.cpan.org/Ticket/Display.html?id=48261 Bug fixes: - avoid using CHECK as a label in Imager::Test http://nntp.x.perl.org/group/perl.cpan.testers/5220921 - re-work most image file test files that require a library into separate library present/not present files to remove stupidly long conditionals - don't treat rubthrough() outside the bounds of the target image as an error. http://nntp.x.perl.org/group/perl.cpan.testers/5185716 Imager 0.67_01 - 02 Sep 2009 ============== Bug fixes: - correct documentation of default of raw image interleave read parameter https://rt.cpan.org/Ticket/Display.html?id=42074 - add raw_ prefix to raw read parameters, though the original names still work. - fail the read if an invalid raw_interleave parameter is supplied - warn if no interleave or raw_interleave parameter is supplied, since the documented default was wrong, and incompatible with the write format - for reading raw images, if raw_storechannels > raw_datachannels, set the extra channels in the image to 0 - when probing for executables like freetype-config, search for .bat and .cmd on MSWin32, as well as .exe. https://rt.cpan.org/Ticket/Display.html?id=49275 - re-work the external libraries section of README: - list Debian and Redhat package names for each library - reformatting - update URLs - use the new EU::MM META_MERGE facility instead of generating META.yml from scratch https://rt.cpan.org/Ticket/Display.html?id=47888 - use Devel::CheckLib (bundled, modified) to check which release of libtiff is installed and reject 3.9.0 http://bugzilla.maptools.org/show_bug.cgi?id=2088 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=543079 Imager 0.67 - 12 Dec 2008 =========== Bug fixes: - fix a packaging error Imager 0.66 - 12 Dec 2008 =========== - 24-bit color .ICO/.CUR files can now be read. Bug fixes: - an optimization skipping 0 src alpha values could cause the rubthrough() to read past the end of a buffer. http://www.nntp.perl.org/group/perl.cpan.testers/2008/05/msg1509184.html - corrected a reference leak where writing GIFs would leak memory. This could also happen calling to_paletted(). Also documented the underlying long existing feature where the colors parameter is filled with the generated color table and added tests for it. http://rt.cpan.org/Ticket/Display.html?id=41028 - write out the image size in bytes field of a BMP correctly. http://rt.cpan.org/Ticket/Display.html?id=41406 - add limited tests for Imager::ExtUtils - make Imager::ExtUtils->includes use an absolute path, since a relative path could cause failures using Inline::C. http://rt.cpan.org/Ticket/Display.html?id=37353 - re-arrange the POD for Imager::Font::BBox: - mark total_width(), pos_width(), end_offset() obsolete, since they're mostly for backwards compatibility - group width methods and height methods https://rt.cpan.org/Ticket/Display.html?id=39999 Imager 0.65 - 20 May 2008 =========== Bug fixes: - In some cases when an error occurs reading those parts of a JPEG file after the image the scan-line buffer could be freed a second time. In cases where the the error occured while reading the image data it's possible that the buffer could have leaked. Thanks to Gabriel Vasseur for reporting this and help in tracking it down. - the gif_screen_height tag was overriding the screen width and being ignored for the screen height when present. https://rt.cpan.org/Public/Bug/Display.html?id=35568 Imager 0.64 - 23 April 2008 =========== This is a bug fix release. This includes a fix for a possible security issue. Bug fixes: - Possible security issue: The floating point sample path for image based fills had a buffer overflow. This would overwrite the end of a malloc()ed buffer with double precision floats. http://rt.cpan.org/Ticket/Display.html?id=35324 CVE-2008-1928 - check that the result of fileno($fh) is defined rather than simply true when read() or write() is supplied with an fh parameter. http://rt.cpan.org/Ticket/Display.html?id=35139 - i_scale_axis() wasn't checking the result of i_img_new_ch() resulting in a SIGSEGV when attempting to scale an image to a size too large to fit in memory. This is a NULL pointer access issue, not a buffer overflow. Added a check for the failure. scale_calculate() (and hence scale()) will now fail if any of the scale size parameters are a reference. http://rt.cpan.org/Ticket/Display.html?id=35172 - Regression: filling a greyscale image with a hatch used the wrong color channels from the supplied fg/bg colors. https://rt.cpan.org/Ticket/Display.html?id=35278 - fixed a related problem for image fills. Imager 0.63 - 7 April 2008 =========== This release primarily contains changes to improve ease of use - rather than you having to convert images to the appropriate number of channels, Imager handles it internally. How to handle drawing colors and the default combine mode is a thornier problem left for some other release. - the font libraries are now only initialized when needed. http://rt.cpan.org/Ticket/Display.html?id=28825 - moved the imtoc.perl code into Imager::Preprocess - paste() and rubthrough() now adapt the source image data to the destination, so you can now safely paste/rubthrough from greyscale images to color images or back, or from alpha channel images to noalpha channels or back. https://rt.cpan.org/Ticket/Display.html?id=30908 - rubthrough() now falls back to pasting when the source doesn't have an alpha channel. This effectively treats the source as having a max alpha channel, the right thing to do. http://rt.cpan.org/Ticket/Display.html?id=29944 - re-worked most of the area filling code to use a common set of functions when filling. Corrected normal combine mode. Rewrote most of the combine modes to match the way the SVG draft defines them with respect to a translucent source and destination. Added tests for translucent source and destination. Added tests to check 8-bit/sample and double/sample combines work similarly. https://rt.cpan.org/Ticket/Display.html?id=29879 - writing a 2 or 4 channel image to a JPEG file will now write that image as if composited against a background, black by default, overridable with the i_background tag/parameter. https://rt.cpan.org/Ticket/Display.html?id=29876 - writing a 2 or 4 channel image to a PGM/PPM file will now write that image as if composited against a background, black by default, overridable with the i_background tag/parameter. http://rt.cpan.org/Ticket/Display.html?id=30074 - writing a 2 or 4 channel image to a BMP file will now write that image as if composited against a background, black by default, overridable with the i_background tag/parameter. http://rt.cpan.org/Ticket/Display.html?id=30075 Bug fixes: - Imager::Matrix2d->translate() now only requires one of the x or y parameters. http://rt.cpan.org/Ticket/Display.html?id=29937 - mixing qtype scaling now sets all channels of a pixel to zero if the pixel has zero coverage (zero alpha). This should produce more compressible output files. http://rt.cpan.org/Ticket/Display.html?id=32324 - removed the pointless #! line from lib/Imager/Font/Wrap.pm Noticed when I saw: https://bugzilla.redhat.com/show_bug.cgi?id=166254 I'm not changing the #! lines of the sample code, since it's sample code, not intended for installation. http://rt.cpan.org/Ticket/Display.html?id=33408 - some TGA images weren't being detected correctly as TGA images https://rt.cpan.org/Ticket/Display.html?id=32925 - handling of the left-over bit for 16-bit/pixel TGA images has been changed to match the behaviour of the GIMP. Previously the bit being set was treated as an opaque pixel, but one user reported a problem with loading such an image. I haven't been able to find any tools beyond the GIMP that handle alpha-channel 16-bit TGAs, so I'll match it's behaviour. See issue 114913 in the GIMP's bugzilla. http://rt.cpan.org/Ticket/Display.html?id=32926 Imager 0.62 - 10 December 2007 =========== - Makefile.PL now expands ~/path supplied to --incpath or --libpath to /path under your home directory. http://rt.cpan.org/Ticket/Display.html?id=29484 - the old dynaload code used Mach API functions to load dynamic libraries on Mac OS X. These APIs have been deprecated in OS X 10.5 and were causing some build problems. So henceforth Imager uses the dlopen() family of functions, and you will need version 10.3 or later of OS X. - added the det() function to the transform2() engine. added the sample quad_to_square.pl Courtesy Richard Fairhurst. http://rt.cpan.org/Ticket/Display.html?id=31244 Bug fixes: - samples/gifscale.pl sourced the base value for gif_top from gif_left. Thanks to Eleneldil G. Arilou for pointing this out. - t/t82inline.t no longer loads B at runtime, to work around a bug in some 5.005_0[45] installations. http://rt.cpan.org/Ticket/Display.html?id=30508 - work around Module::Depends::Intrusive bug #21229 http://rt.cpan.org/Ticket/Display.html?id=30520 - the hardinvert filter no-longer inverts the alpha channel. http://rt.cpan.org/Ticket/Display.html?id=30002 - the hardinvert filter now supports large samples Imager 0.61_02 - 28 November 2007 ============== - major TIFF support re-work http://rt.cpan.org/Ticket/Display.html?id=20329 - added a C level image interface for accessing samples from 1-32 bits, exposed this at the perl level in getsamples() - the conv filter now works at floating point precision for high bit images - added is_bilevel method to test whether an image should be written as a bilevel image if the image format supports it. - added -log-stderr as an Imager import list option - added some important types to Imager::APIRef - added test_image_double() to Imager::Test Bug fixes: - Imager::Fountain couldn't read GIMP gradient files with 10 or more segments - the scale() method with qtype mixing now handles images with an alpha channel correctly. - fixed a broken link from the "animated GIF" entry in the concept index. Thanks to Slaven Rezic. http://rt.cpan.org/Ticket/Display.html?id=30889 - on some perl's the infix expression parser test would fail due to actions in the grammar returning false. Made sure all actions return a true value. Thanks to Richard Fairhurst for spending a lot of time in tracking down this problem. http://rt.cpan.org/Public/Bug/Display.html?id=29562 Imager 0.61 - 5 November 2007 =========== - added samples/gifscale.pl, which adjusts the screen size/position tags when scaling an animated gif http://rt.cpan.org/Ticket/Display.html?id=27591 Bug fixes: - correct handling of sz in matrix_transform() - this should allow perspective type transformations to work now. http://rt.cpan.org/Ticket/Display.html?id=29936 - prevent a cast to integer warning on x64 builds in datatypes.c also fixed some other type warnings https://rt.cpan.org/Ticket/Display.html?id=30204 - some sub-directory tests depended on files produced by the parent directory tests http://rt.cpan.org/Ticket/Display.html?id=30203 - Imager::Font::Wrap doesn't correctly set savepos thanks to Nikita Dedik and Eleneldil G. Arilou for reporting this. http://rt.cpan.org/Ticket/Display.html?id=29771 - test 171 in t/t01introvert.t was failing on perls configured to use long double. http://rt.cpan.org/Ticket/Display.html?id=29413 - the code for the transform2() uminus operator was missing a break. Added tests for better code coverage of the ops. http://rt.cpan.org/Ticket/Display.html?id=29296 - the SGI RLE compression code could overflow its compression buffer http://rt.cpan.org/Ticket/Display.html?id=30334 - the 32-bit output function used by the SGI code only handled values under 0x10000. This was most noticable when writing large RLE images. http://rt.cpan.org/Ticket/Display.html?id=30335 - validate chan_count for chans == NULL for each of the i_gsamp() implementations. http://rt.cpan.org/Ticket/Display.html?id=28985 - attempt to work around the test failure at http://www.nntp.perl.org/group/perl.cpan.testers/2007/09/msg650810.html http://rt.cpan.org/Ticket/Display.html?id=29562 - improve the error messages produced when attempting to read or write an unknown image file format. http://rt.cpan.org/Ticket/Display.html?id=30103 - improve the transform2() documentation http://rt.cpan.org/Ticket/Display.html?id=29267 - correctly generate the author key in META.yml http://rt.cpan.org/Ticket/Display.html?id=30377 - correctly blend a rotated (or matrix_transformed()) image when performing interpolation in the presence of an alpha channel. Also corrected the centring of the rotated image on the output image. Imager 0.60 - 30 August 2007 =========== - Finished/rewrote Arnar's old SGI RGB file format support, so Imager now has full SGI RGB image format, including RLE and 16-bit/sample images. https://rt.cpan.org/Ticket/Display.html?id=8666 - logging functions are now available in the API - applied Gabriel Vasseur's patch added documentation, further tests, and support for greyscale images Obviously problems are my fault :) https://rt.cpan.org/Ticket/Display.html?id=28142 - the mask for ICO/CUR images is now applied as an alpha channel to the returned image. For the old behaviour, supply ico_masked => 0 to read() or read_multi(). This should be less confusing when using Imager as a general image processor. https://rt.cpan.org/Ticket/Display.html?id=29001 Bug fixes: - in some cases it's possible for giflib/libungif to return color indexes outside the range of colors defined by the image's palette. We now expand the palette to match the indexes used. Thanks to Gabriel Vasseur for reporting this. - fixed various memory leaks that could occur when failing to read png, jpeg, bmp or tga files. - to avoid confusion, channels not present in the image are returned as zero by getscanline(). This has no effect on the C level i_glin() and i_glinf() API functions which continue to not set the unused channels. - the convert() method now returns an image of the same sample size as the source image. https://rt.cpan.org/Ticket/Display.html?id=28492 - remove repeated text in Imager::Files http://rt.cpan.org/Ticket/Display.html?id=27589 - be even more explicit that scale() and friends don't modify the source image, but return a new image. http://rt.cpan.org/Ticket/Display.html?id=28570 - improve the error message from errstr() when you try to load a font for which the driver hasn't been built in Imager. http://rt.cpan.org/Ticket/Display.html?id=27571 - transparency is now enabled by default when writing GIF images http://rt.cpan.org/Ticket/Display.html?id=27615 - Imager would not load on Windows 98 http://rt.cpan.org/Ticket/Display.html?id=27653 Imager 0.59 - 14 June 2007 =========== Bug fixes: - fixes a regression introduced by the fixes for RT 11972 http://rt.cpan.org/Ticket/Display.html?id=27546 - cropping outside the image would return an Imager object with no low-level image object, instead of returning false. Fixed by: Philip Gwyn (Leolo) http://rt.cpan.org/Ticket/Display.html?id=27509 Imager 0.58 - 16 May 2007 =========== No significant changes from 0.57_01. Imager 0.57_01 - 11 May 2007 ============== - added to_rgb16 to produce a 16-bit/sample version of an image - improve freetype 1.x text output efficiency Bug fixes: - search another place for rgb.txt, and check all the places Imager::Color checks when deciding whether to skip testing it http://rt.cpan.org/Ticket/Display.html?id=26064 - use a convolution kernel size based on the stddev rather than a fixed size when performing a gaussian blur http://rt.cpan.org/Ticket/Display.html?id=25645 - document the difference() method's mindist parameter, and debug it. - put the Imager release number in the Inline::C generated code to regenerate Inline code when a new release of Imager is installed. http://rt.cpan.org/Ticket/Display.html?id=26278 - fix rendering on alpha channel images for the FreeType 1.x driver. http://rt.cpan.org/Ticket/Display.html?id=11972 - fix rendering on alpha channel images for the T1lib driver. http://rt.cpan.org/Ticket/Display.html?id=11972 - reworked library probing, we can now set more than one probe function for a library. Disabled the default (non-freetype-config) library probe and added an extra probe function that searches for both ft2build.h and whatever it includes, and adds -I as needed. Hopefully this will fix build problems like http://www.nntp.perl.org/group/perl.cpan.testers/2007/05/msg472281.html http://rt.cpan.org/Ticket/Display.html?id=26086 Imager 0.57 - 30 Apr 2007 =========== This is a maintenence release fixing a security issue in Imager. - CRITICAL: a specially crafted compressed BMP file can cause a buffer overflow in malloced memory. There will be further discussion of this issue in the ticket below. http://rt.cpan.org/Ticket/Display.html?id=26811 CVE-2007-2459 CVE-2007-2413 The descriptions at cve.mitre.org varied in quality, please see the ticket at rt.cpan.org for a more accurate description of the issue. Imager 0.56 - 1 Apr 2007 =========== - added support for reading 16-bit/sample PGM/PPM images - added support for writing 16-bit/sample PGM/PPM images - improved performance of reading PBM/PGM/PPM images - added support for writing PBM images if the image is paletted and contains only black and white - added a new make_colors value - "mono" - switched from the svn log Changes to a manual Changes to reduce noise - new sample code - samples/flasher.pl Bug fixes: - CRITICAL: the "Imager" typemap entry (not used by Imager itself) was returning an image object with an extra reference, this resulted in a memory leak. http://rt.cpan.org/Ticket/Display.html?id=24992 - fix rendering on alpha channel images for the FreeType 2.x driver http://rt.cpan.org/Ticket/Display.html?id=11972 - reading bmp files now consitently handles short reads. You can now supply a parameter to treat a short read as successful and set i_incomplete http://rt.cpan.org/Ticket/Display.html?id=8426 - previously, reading ASCII PBM files required spaces between samples, even though the format doesn't require that - improved documentation of the unsharpmask filter (I hope) http://rt.cpan.org/Ticket/Display.html?id=25531 - force flushing of the output from i_tt_dump_names() and test output in t/t35ttfont.t to prevent output from being mixed up. https://rt.cpan.org/Ticket/Display.html?id=24859 - rewrite a conditional expression as an if() to hopefully work around a bug in the pre-4.0 GCC Apple shipped with OS X 10.4. https://rt.cpan.org/Ticket/Display.html?id=25561 - avoid Data::Dumper in regops.perl to support older releases of perl https://rt.cpan.org/Ticket/Display.html?id=24391 Imager 0.55 - 16 Dec 2006 =========== This is primarily a bug fix release. Note: Test::More is now a pre-requisite for Imager and is no longer bundled. There is one new feature: - the Win32 font driver now supports UTF8 (RT 22166) http://www.cpanforum.com/threads/3276 http://rt.cpan.org/Ticket/Display.html?id=22166 Several bugs were fixed: - the string() method would not output the string "0" http://rt.cpan.org/Public/Bug/Display.html?id=21770 - fills.c was failing to compile on Solaris 10 (compiler unknown) http://rt.cpan.org/Public/Bug/Display.html?id=21944 - the gif_disposal and gif_user_input tags weren't being read from the file correctly http://rt.cpan.org/Public/Bug/Display.html?id=22192 - gif.c was failing to build under MSVC http://rt.cpan.org/Ticket/Display.html?id=23922 - in some cases strings passed to the string() method were treated as terminated by NUL (chr 0) http://rt.cpan.org/Public/Bug/Display.html?id=21770 - on "MSWin32" perl builds we now link to -lzlib instead of -lz since that's the default build name for zlib on Win32. http://rt.cpan.org/Ticket/Display.html?id=23064 - search $Config{incpath} for headers too, which we should have been doing all along. Win32 font driver fixes: - the global descent value from bounding box was the wrong sign http://www.cpanforum.com/threads/3276 - if the first or last glyph overflowed the left or right side of the advance width they would be clipped Imager 0.54 - 14 Sep 2006 =========== This is primarily a feature release: - a new qtype value 'mixing' has been added to the scale() method. This is faster than 'normal', slower than 'preview'. This is based on the method used by pnmscale, and seems to produce less blurry results than normal. http://rt.cpan.org/Public/Bug/Display.html?id=20677 - the rubthrough() method can now render onto images with an alpha channel. http://rt.cpan.org/Ticket/Display.html?id=20678 - the read_multi() method now falls back to calling doing a single image read via the read() method and write_multi() will now fall back to calling write() if a single image is supplied. This means you can simply call the read_multi() or write_multi() functions without having to check if the type is formatted by that method. http://rt.cpan.org/Ticket/Display.html?id=19457 http://rt.cpan.org/Ticket/Display.html?id=19458 - the GIF loop extension can now be written. If you don't have libungif/giflib 4.1.4 (or some distribution's bugfixed equivalent) you should upgrade. http://rt.cpan.org/Ticket/Display.html?id=21185 - getscanline() and setscanline() can now read/write palette index based data from/to the image for paletted images, by setting type to 'index'. http://rt.cpan.org/Ticket/Display.html?id=20338 - we no longer hassle you to disable GIF support http://rt.cpan.org/Ticket/Display.html?id=20687 - minor documentation fixes Imager 0.53 - 26 Jul 2006 =========== This is a bugfix release. Some test code was left in a code path not covered by the test suite. A test was added to cover this code path and the test code was removed. http://rt.cpan.org/Public/Bug/Display.html?id=20705 Imager 0.52 - 25 Jul 2006 =========== This is primarily a feature release, but contains a fair few bug fixes, new features: - ability to read and write MS Windows ICO and CUR files - you can now add file format plugins to support new file formats - add POD coverage tests - setcolors() and addcolors() now accept color names and so on instead of requiring Imager::Color objects. http://rt.cpan.org/Ticket/Display.html?id=20056 - flood_fill() can now fill to a specified border color instead of just to the area the same color as the seed. http://rt.cpan.org/Ticket/Display.html?id=19618 Bug fixes: - bounding_box for the T1 driver wasn't converting UTF8 to ascii when calculating the advance width. http://rt.cpan.org/Public/Bug/Display.html?id=20554 - bounding_box for the T1 driver wasn't including leading and trailing spaces in the bounding box as the other drivers did, it also produced strange results for empty strings or strings containing only spaces - when reading CMYK jpeg images they were being transferred to the image object as is, producing a four channel image. It only looked ok due to an old still unfixed Photoshop bug. We now convert from the inverted CMYK that photoshop (and Corel for example) produce into RGB. http://rt.cpan.org/Ticket/Display.html?id=20416 - reading a CYMK TIFF would result in a 4 channel image, reading any image with more than 4 channels (eg. RGB with 2 alpha channels) would result in an error. http://rt.cpan.org/Ticket/Display.html?id=20415 - added /usr/local/include to the default include search path, since we were already searching /usr/local/lib for libraries. And various minor fixes and documentation updates. Imager 0.51 - 23 Apr 2006 =========== - fix a validation bug when processing JPEG EXIF data that can cause a crash http://rt.cpan.org/Public/Bug/Display.html?id=18496 - fix mis-processing of the src_maxx and src_maxy parameters of the paste() method http://rt.cpan.org/Public/Bug/Display.html?id=18712 - fix a problem in Imager's "smart" handling of the color parameter to various methods. http://rt.cpan.org/Public/Bug/Display.html?id=18561 Imager 0.50 - 29 Mar 2006 =========== - CRITICAL: fixes a segmentation fault from attempting to write a 2 or 4 channel image to jpeg or a 2 channel image to tga where the output is an in-memeory buffer. http://rt.cpan.org/Public/Bug/Display.html?id=18397 - fixes an incorrect pointer parameter in the PNG code http://rt.cpan.org/Public/Bug/Display.html?id=18051 - skip Inline::C tests when building in a directory with spaces http://rt.cpan.org/Public/Bug/Display.html?id=18049libimager-perl-1.004+dfsg.orig/JPEG/0000755000175000017500000000000012617614576016325 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/JPEG/JPEG.pm0000644000175000017500000000247312460670607017407 0ustar gregoagregoapackage Imager::File::JPEG; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.90"; require XSLoader; XSLoader::load('Imager::File::JPEG', $VERSION); } Imager->register_reader ( type=>'jpeg', single => sub { my ($im, $io, %hsh) = @_; ($im->{IMG},$im->{IPTCRAW}) = i_readjpeg_wiol( $io ); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, ); Imager->register_writer ( type=>'jpeg', single => sub { my ($im, $io, %hsh) = @_; $im->_set_opts(\%hsh, "i_", $im); $im->_set_opts(\%hsh, "jpeg_", $im); $im->_set_opts(\%hsh, "exif_", $im); my $quality = $hsh{jpegquality}; defined $quality or $quality = 75; if ( !i_writejpeg_wiol($im->{IMG}, $io, $quality)) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, ); __END__ =head1 NAME Imager::File::JPEG - read and write JPEG files =head1 SYNOPSIS use Imager; my $img = Imager->new; $img->read(file=>"foo.jpg") or die $img->errstr; $img->write(file => "foo.jpg") or die $img->errstr; =head1 DESCRIPTION Imager's JPEG support is documented in L. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Files. =cut libimager-perl-1.004+dfsg.orig/JPEG/imexif.c0000644000175000017500000011617712263740600017750 0ustar gregoagregoa#include "imext.h" #include "imexif.h" #include #include #include #include /* =head1 NAME imexif.c - EXIF support for Imager =head1 SYNOPSIS if (i_int_decode_exif(im, app1data, app1datasize)) { // exif block seen } =head1 DESCRIPTION This code provides a basic EXIF data decoder. It is intended to be called from the JPEG reader code when an APP1 data block is found, and will set tags in the supplied image. =cut */ typedef enum tiff_type_tag { tt_intel = 'I', tt_motorola = 'M' } tiff_type; typedef enum { ift_byte = 1, ift_ascii = 2, ift_short = 3, ift_long = 4, ift_rational = 5, ift_sbyte = 6, ift_undefined = 7, ift_sshort = 8, ift_slong = 9, ift_srational = 10, ift_float = 11, ift_double = 12, ift_last = 12 /* keep the same as the highest type code */ } ifd_entry_type; static int type_sizes[] = { 0, /* not used */ 1, /* byte */ 1, /* ascii */ 2, /* short */ 4, /* long */ 8, /* rational */ 1, /* sbyte */ 1, /* undefined */ 2, /* sshort */ 4, /* slong */ 8, /* srational */ 4, /* float */ 8, /* double */ }; typedef struct { int tag; int type; int count; int item_size; int size; int offset; } ifd_entry; typedef struct { int tag; char const *name; } tag_map; typedef struct { int tag; char const *name; tag_map const *map; int map_count; } tag_value_map; #define PASTE(left, right) PASTE_(left, right) #define PASTE_(left, right) left##right #define QUOTE(value) #value #define VALUE_MAP_ENTRY(name) \ { \ PASTE(tag_, name), \ "exif_" QUOTE(name) "_name", \ PASTE(name, _values), \ ARRAY_COUNT(PASTE(name, _values)) \ } /* we don't process every tag */ #define tag_make 271 #define tag_model 272 #define tag_orientation 274 #define tag_x_resolution 282 #define tag_y_resolution 283 #define tag_resolution_unit 296 #define tag_copyright 33432 #define tag_software 305 #define tag_artist 315 #define tag_date_time 306 #define tag_image_description 270 #define tag_exif_ifd 34665 #define tag_gps_ifd 34853 #define resunit_none 1 #define resunit_inch 2 #define resunit_centimeter 3 /* tags from the EXIF ifd */ #define tag_exif_version 0x9000 #define tag_flashpix_version 0xA000 #define tag_color_space 0xA001 #define tag_component_configuration 0x9101 #define tag_component_bits_per_pixel 0x9102 #define tag_pixel_x_dimension 0xA002 #define tag_pixel_y_dimension 0xA003 #define tag_maker_note 0x927C #define tag_user_comment 0x9286 #define tag_related_sound_file 0xA004 #define tag_date_time_original 0x9003 #define tag_date_time_digitized 0x9004 #define tag_sub_sec_time 0x9290 #define tag_sub_sec_time_original 0x9291 #define tag_sub_sec_time_digitized 0x9292 #define tag_image_unique_id 0xA420 #define tag_exposure_time 0x829a #define tag_f_number 0x829D #define tag_exposure_program 0x8822 #define tag_spectral_sensitivity 0x8824 #define tag_iso_speed_ratings 0x8827 #define tag_oecf 0x8828 #define tag_shutter_speed 0x9201 #define tag_aperture 0x9202 #define tag_brightness 0x9203 #define tag_exposure_bias 0x9204 #define tag_max_aperture 0x9205 #define tag_subject_distance 0x9206 #define tag_metering_mode 0x9207 #define tag_light_source 0x9208 #define tag_flash 0x9209 #define tag_focal_length 0x920a #define tag_subject_area 0x9214 #define tag_flash_energy 0xA20B #define tag_spatial_frequency_response 0xA20C #define tag_focal_plane_x_resolution 0xA20e #define tag_focal_plane_y_resolution 0xA20F #define tag_focal_plane_resolution_unit 0xA210 #define tag_subject_location 0xA214 #define tag_exposure_index 0xA215 #define tag_sensing_method 0xA217 #define tag_file_source 0xA300 #define tag_scene_type 0xA301 #define tag_cfa_pattern 0xA302 #define tag_custom_rendered 0xA401 #define tag_exposure_mode 0xA402 #define tag_white_balance 0xA403 #define tag_digital_zoom_ratio 0xA404 #define tag_focal_length_in_35mm_film 0xA405 #define tag_scene_capture_type 0xA406 #define tag_gain_control 0xA407 #define tag_contrast 0xA408 #define tag_saturation 0xA409 #define tag_sharpness 0xA40A #define tag_device_setting_description 0xA40B #define tag_subject_distance_range 0xA40C /* GPS tags */ #define tag_gps_version_id 0 #define tag_gps_latitude_ref 1 #define tag_gps_latitude 2 #define tag_gps_longitude_ref 3 #define tag_gps_longitude 4 #define tag_gps_altitude_ref 5 #define tag_gps_altitude 6 #define tag_gps_time_stamp 7 #define tag_gps_satellites 8 #define tag_gps_status 9 #define tag_gps_measure_mode 10 #define tag_gps_dop 11 #define tag_gps_speed_ref 12 #define tag_gps_speed 13 #define tag_gps_track_ref 14 #define tag_gps_track 15 #define tag_gps_img_direction_ref 16 #define tag_gps_img_direction 17 #define tag_gps_map_datum 18 #define tag_gps_dest_latitude_ref 19 #define tag_gps_dest_latitude 20 #define tag_gps_dest_longitude_ref 21 #define tag_gps_dest_longitude 22 #define tag_gps_dest_bearing_ref 23 #define tag_gps_dest_bearing 24 #define tag_gps_dest_distance_ref 25 #define tag_gps_dest_distance 26 #define tag_gps_processing_method 27 #define tag_gps_area_information 28 #define tag_gps_date_stamp 29 #define tag_gps_differential 30 /* don't use this on pointers */ #define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array)) /* in memory tiff structure */ typedef struct { /* the data we use as a tiff */ unsigned char *base; size_t size; /* intel or motorola byte order */ tiff_type type; /* initial ifd offset */ unsigned long first_ifd_offset; /* size (in entries) and data */ int ifd_size; ifd_entry *ifd; unsigned long next_ifd; } imtiff; static int tiff_init(imtiff *tiff, unsigned char *base, size_t length); static int tiff_load_ifd(imtiff *tiff, unsigned long offset); static void tiff_final(imtiff *tiff); static void tiff_clear_ifd(imtiff *tiff); #if 0 /* currently unused, but that may change */ static int tiff_get_bytes(imtiff *tiff, unsigned char *to, size_t offset, size_t count); #endif static int tiff_get_tag_double(imtiff *, int index, double *result); static int tiff_get_tag_int(imtiff *, int index, int *result); static unsigned tiff_get16(imtiff *, unsigned long offset); static unsigned tiff_get32(imtiff *, unsigned long offset); static int tiff_get16s(imtiff *, unsigned long offset); static int tiff_get32s(imtiff *, unsigned long offset); static double tiff_get_rat(imtiff *, unsigned long offset); static double tiff_get_rats(imtiff *, unsigned long offset); static void save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset, unsigned long *gps_ifd_offset); static void save_exif_ifd_tags(i_img *im, imtiff *tiff); static void save_gps_ifd_tags(i_img *im, imtiff *tiff); static void copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count); static void copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count); static void copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count); static void copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count); static void copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count); static void process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size); /* =head1 PUBLIC FUNCTIONS These functions are available to other parts of Imager. They aren't intended to be called from outside of Imager. =over =item i_int_decode_exit i_int_decode_exif(im, data_base, data_size); The data from data_base for data_size bytes will be scanned for EXIF data. Any data found will be used to set tags in the supplied image. The intent is that invalid EXIF data will simply fail to set tags, and write to the log. In no case should this code exit when supplied invalid data. Returns true if an Exif header was seen. =cut */ int i_int_decode_exif(i_img *im, unsigned char *data, size_t length) { imtiff tiff; unsigned long exif_ifd_offset = 0; unsigned long gps_ifd_offset = 0; /* basic checks - must start with "Exif\0\0" */ if (length < 6 || memcmp(data, "Exif\0\0", 6) != 0) { return 0; } data += 6; length -= 6; if (!tiff_init(&tiff, data, length)) { mm_log((2, "Exif header found, but no valid TIFF header\n")); return 1; } if (!tiff_load_ifd(&tiff, tiff.first_ifd_offset)) { mm_log((2, "Exif header found, but could not load IFD 0\n")); tiff_final(&tiff); return 1; } save_ifd0_tags(im, &tiff, &exif_ifd_offset, &gps_ifd_offset); if (exif_ifd_offset) { if (tiff_load_ifd(&tiff, exif_ifd_offset)) { save_exif_ifd_tags(im, &tiff); } else { mm_log((2, "Could not load Exif IFD\n")); } } if (gps_ifd_offset) { if (tiff_load_ifd(&tiff, gps_ifd_offset)) { save_gps_ifd_tags(im, &tiff); } else { mm_log((2, "Could not load GPS IFD\n")); } } tiff_final(&tiff); return 1; } /* =back =head1 INTERNAL FUNCTIONS =head2 EXIF Processing =over =item save_ifd0_tags save_ifd0_tags(im, tiff, &exif_ifd_offset, &gps_ifd_offset) Scans the currently loaded IFD for tags expected in IFD0 and sets them in the image. Sets *exif_ifd_offset to the offset of the EXIF IFD if found. =cut */ static tag_map ifd0_string_tags[] = { { tag_make, "exif_make" }, { tag_model, "exif_model" }, { tag_copyright, "exif_copyright" }, { tag_software, "exif_software" }, { tag_artist, "exif_artist" }, { tag_date_time, "exif_date_time" }, { tag_image_description, "exif_image_description" }, }; static const int ifd0_string_tag_count = ARRAY_COUNT(ifd0_string_tags); static tag_map ifd0_int_tags[] = { { tag_orientation, "exif_orientation", }, { tag_resolution_unit, "exif_resolution_unit" }, }; static const int ifd0_int_tag_count = ARRAY_COUNT(ifd0_int_tags); static tag_map ifd0_rat_tags[] = { { tag_x_resolution, "exif_x_resolution" }, { tag_y_resolution, "exif_y_resolution" }, }; static tag_map resolution_unit_values[] = { { 1, "none" }, { 2, "inches" }, { 3, "centimeters" }, }; static tag_value_map ifd0_values[] = { VALUE_MAP_ENTRY(resolution_unit), }; static void save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset, unsigned long *gps_ifd_offset) { int tag_index; int work; ifd_entry *entry; for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { switch (entry->tag) { case tag_exif_ifd: if (tiff_get_tag_int(tiff, tag_index, &work)) *exif_ifd_offset = work; break; case tag_gps_ifd: if (tiff_get_tag_int(tiff, tag_index, &work)) *gps_ifd_offset = work; break; } } copy_string_tags(im, tiff, ifd0_string_tags, ifd0_string_tag_count); copy_int_tags(im, tiff, ifd0_int_tags, ifd0_int_tag_count); copy_rat_tags(im, tiff, ifd0_rat_tags, ARRAY_COUNT(ifd0_rat_tags)); copy_name_tags(im, tiff, ifd0_values, ARRAY_COUNT(ifd0_values)); /* copy_num_array_tags(im, tiff, ifd0_num_arrays, ARRAY_COUNT(ifd0_num_arrays)); */ } /* =item save_exif_ifd_tags save_exif_ifd_tags(im, tiff) Scans the currently loaded IFD for the tags expected in the EXIF IFD and sets them as tags in the image. =cut */ static tag_map exif_ifd_string_tags[] = { { tag_exif_version, "exif_version", }, { tag_flashpix_version, "exif_flashpix_version", }, { tag_related_sound_file, "exif_related_sound_file", }, { tag_date_time_original, "exif_date_time_original", }, { tag_date_time_digitized, "exif_date_time_digitized", }, { tag_sub_sec_time, "exif_sub_sec_time" }, { tag_sub_sec_time_original, "exif_sub_sec_time_original" }, { tag_sub_sec_time_digitized, "exif_sub_sec_time_digitized" }, { tag_image_unique_id, "exif_image_unique_id" }, { tag_spectral_sensitivity, "exif_spectral_sensitivity" }, }; static const int exif_ifd_string_tag_count = ARRAY_COUNT(exif_ifd_string_tags); static tag_map exif_ifd_int_tags[] = { { tag_color_space, "exif_color_space" }, { tag_exposure_program, "exif_exposure_program" }, { tag_metering_mode, "exif_metering_mode" }, { tag_light_source, "exif_light_source" }, { tag_flash, "exif_flash" }, { tag_focal_plane_resolution_unit, "exif_focal_plane_resolution_unit" }, { tag_subject_location, "exif_subject_location" }, { tag_sensing_method, "exif_sensing_method" }, { tag_custom_rendered, "exif_custom_rendered" }, { tag_exposure_mode, "exif_exposure_mode" }, { tag_white_balance, "exif_white_balance" }, { tag_focal_length_in_35mm_film, "exif_focal_length_in_35mm_film" }, { tag_scene_capture_type, "exif_scene_capture_type" }, { tag_contrast, "exif_contrast" }, { tag_saturation, "exif_saturation" }, { tag_sharpness, "exif_sharpness" }, { tag_subject_distance_range, "exif_subject_distance_range" }, }; static const int exif_ifd_int_tag_count = ARRAY_COUNT(exif_ifd_int_tags); static tag_map exif_ifd_rat_tags[] = { { tag_exposure_time, "exif_exposure_time" }, { tag_f_number, "exif_f_number" }, { tag_shutter_speed, "exif_shutter_speed" }, { tag_aperture, "exif_aperture" }, { tag_brightness, "exif_brightness" }, { tag_exposure_bias, "exif_exposure_bias" }, { tag_max_aperture, "exif_max_aperture" }, { tag_subject_distance, "exif_subject_distance" }, { tag_focal_length, "exif_focal_length" }, { tag_flash_energy, "exif_flash_energy" }, { tag_focal_plane_x_resolution, "exif_focal_plane_x_resolution" }, { tag_focal_plane_y_resolution, "exif_focal_plane_y_resolution" }, { tag_exposure_index, "exif_exposure_index" }, { tag_digital_zoom_ratio, "exif_digital_zoom_ratio" }, { tag_gain_control, "exif_gain_control" }, }; static const int exif_ifd_rat_tag_count = ARRAY_COUNT(exif_ifd_rat_tags); static tag_map exposure_mode_values[] = { { 0, "Auto exposure" }, { 1, "Manual exposure" }, { 2, "Auto bracket" }, }; static tag_map color_space_values[] = { { 1, "sRGB" }, { 0xFFFF, "Uncalibrated" }, }; static tag_map exposure_program_values[] = { { 0, "Not defined" }, { 1, "Manual" }, { 2, "Normal program" }, { 3, "Aperture priority" }, { 4, "Shutter priority" }, { 5, "Creative program" }, { 6, "Action program" }, { 7, "Portrait mode" }, { 8, "Landscape mode" }, }; static tag_map metering_mode_values[] = { { 0, "unknown" }, { 1, "Average" }, { 2, "CenterWeightedAverage" }, { 3, "Spot" }, { 4, "MultiSpot" }, { 5, "Pattern" }, { 6, "Partial" }, { 255, "other" }, }; static tag_map light_source_values[] = { { 0, "unknown" }, { 1, "Daylight" }, { 2, "Fluorescent" }, { 3, "Tungsten (incandescent light)" }, { 4, "Flash" }, { 9, "Fine weather" }, { 10, "Cloudy weather" }, { 11, "Shade" }, { 12, "Daylight fluorescent (D 5700 Ð 7100K)" }, { 13, "Day white fluorescent (N 4600 Ð 5400K)" }, { 14, "Cool white fluorescent (W 3900 Ð 4500K)" }, { 15, "White fluorescent (WW 3200 Ð 3700K)" }, { 17, "Standard light A" }, { 18, "Standard light B" }, { 19, "Standard light C" }, { 20, "D55" }, { 21, "D65" }, { 22, "D75" }, { 23, "D50" }, { 24, "ISO studio tungsten" }, { 255, "other light source" }, }; static tag_map flash_values[] = { { 0x0000, "Flash did not fire." }, { 0x0001, "Flash fired." }, { 0x0005, "Strobe return light not detected." }, { 0x0007, "Strobe return light detected." }, { 0x0009, "Flash fired, compulsory flash mode" }, { 0x000D, "Flash fired, compulsory flash mode, return light not detected" }, { 0x000F, "Flash fired, compulsory flash mode, return light detected" }, { 0x0010, "Flash did not fire, compulsory flash mode" }, { 0x0018, "Flash did not fire, auto mode" }, { 0x0019, "Flash fired, auto mode" }, { 0x001D, "Flash fired, auto mode, return light not detected" }, { 0x001F, "Flash fired, auto mode, return light detected" }, { 0x0020, "No flash function" }, { 0x0041, "Flash fired, red-eye reduction mode" }, { 0x0045, "Flash fired, red-eye reduction mode, return light not detected" }, { 0x0047, "Flash fired, red-eye reduction mode, return light detected" }, { 0x0049, "Flash fired, compulsory flash mode, red-eye reduction mode" }, { 0x004D, "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected" }, { 0x004F, "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected" }, { 0x0059, "Flash fired, auto mode, red-eye reduction mode" }, { 0x005D, "Flash fired, auto mode, return light not detected, red-eye reduction mode" }, { 0x005F, "Flash fired, auto mode, return light detected, red-eye reduction mode" }, }; static tag_map sensing_method_values[] = { { 1, "Not defined" }, { 2, "One-chip color area sensor" }, { 3, "Two-chip color area sensor" }, { 4, "Three-chip color area sensor" }, { 5, "Color sequential area sensor" }, { 7, "Trilinear sensor" }, { 8, "Color sequential linear sensor" }, }; static tag_map custom_rendered_values[] = { { 0, "Normal process" }, { 1, "Custom process" }, }; static tag_map white_balance_values[] = { { 0, "Auto white balance" }, { 1, "Manual white balance" }, }; static tag_map scene_capture_type_values[] = { { 0, "Standard" }, { 1, "Landscape" }, { 2, "Portrait" }, { 3, "Night scene" }, }; static tag_map gain_control_values[] = { { 0, "None" }, { 1, "Low gain up" }, { 2, "High gain up" }, { 3, "Low gain down" }, { 4, "High gain down" }, }; static tag_map contrast_values[] = { { 0, "Normal" }, { 1, "Soft" }, { 2, "Hard" }, }; static tag_map saturation_values[] = { { 0, "Normal" }, { 1, "Low saturation" }, { 2, "High saturation" }, }; static tag_map sharpness_values[] = { { 0, "Normal" }, { 1, "Soft" }, { 2, "Hard" }, }; static tag_map subject_distance_range_values[] = { { 0, "unknown" }, { 1, "Macro" }, { 2, "Close view" }, { 3, "Distant view" }, }; #define focal_plane_resolution_unit_values resolution_unit_values static tag_value_map exif_ifd_values[] = { VALUE_MAP_ENTRY(exposure_mode), VALUE_MAP_ENTRY(color_space), VALUE_MAP_ENTRY(exposure_program), VALUE_MAP_ENTRY(metering_mode), VALUE_MAP_ENTRY(light_source), VALUE_MAP_ENTRY(flash), VALUE_MAP_ENTRY(sensing_method), VALUE_MAP_ENTRY(custom_rendered), VALUE_MAP_ENTRY(white_balance), VALUE_MAP_ENTRY(scene_capture_type), VALUE_MAP_ENTRY(gain_control), VALUE_MAP_ENTRY(contrast), VALUE_MAP_ENTRY(saturation), VALUE_MAP_ENTRY(sharpness), VALUE_MAP_ENTRY(subject_distance_range), VALUE_MAP_ENTRY(focal_plane_resolution_unit), }; static tag_map exif_num_arrays[] = { { tag_iso_speed_ratings, "exif_iso_speed_ratings" }, { tag_subject_area, "exif_subject_area" }, { tag_subject_location, "exif_subject_location" }, }; static void save_exif_ifd_tags(i_img *im, imtiff *tiff) { int i, tag_index; ifd_entry *entry; char *user_comment; unsigned long maker_note_offset = 0; size_t maker_note_size = 0; for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { switch (entry->tag) { case tag_user_comment: /* I don't want to trash the source, so work on a copy */ user_comment = mymalloc(entry->size); memcpy(user_comment, tiff->base + entry->offset, entry->size); /* the first 8 bytes indicate the encoding, make them into spaces for better presentation */ for (i = 0; i < entry->size && i < 8; ++i) { if (user_comment[i] == '\0') user_comment[i] = ' '; } /* find the actual end of the string */ while (i < entry->size && user_comment[i]) ++i; i_tags_set(&im->tags, "exif_user_comment", user_comment, i); myfree(user_comment); break; case tag_maker_note: maker_note_offset = entry->offset; maker_note_size = entry->size; break; /* the following aren't processed yet */ case tag_oecf: case tag_spatial_frequency_response: case tag_file_source: case tag_scene_type: case tag_cfa_pattern: case tag_device_setting_description: case tag_subject_area: break; } } copy_string_tags(im, tiff, exif_ifd_string_tags, exif_ifd_string_tag_count); copy_int_tags(im, tiff, exif_ifd_int_tags, exif_ifd_int_tag_count); copy_rat_tags(im, tiff, exif_ifd_rat_tags, exif_ifd_rat_tag_count); copy_name_tags(im, tiff, exif_ifd_values, ARRAY_COUNT(exif_ifd_values)); copy_num_array_tags(im, tiff, exif_num_arrays, ARRAY_COUNT(exif_num_arrays)); /* This trashes the IFD - make sure it's done last */ if (maker_note_offset) { process_maker_note(im, tiff, maker_note_offset, maker_note_size); } } static tag_map gps_ifd_string_tags[] = { { tag_gps_version_id, "exif_gps_version_id" }, { tag_gps_latitude_ref, "exif_gps_latitude_ref" }, { tag_gps_longitude_ref, "exif_gps_longitude_ref" }, { tag_gps_altitude_ref, "exif_gps_altitude_ref" }, { tag_gps_satellites, "exif_gps_satellites" }, { tag_gps_status, "exif_gps_status" }, { tag_gps_measure_mode, "exif_gps_measure_mode" }, { tag_gps_speed_ref, "exif_gps_speed_ref" }, { tag_gps_track_ref, "exif_gps_track_ref" }, }; static tag_map gps_ifd_int_tags[] = { { tag_gps_differential, "exif_gps_differential" }, }; static tag_map gps_ifd_rat_tags[] = { { tag_gps_altitude, "exif_gps_altitude" }, { tag_gps_time_stamp, "exif_gps_time_stamp" }, { tag_gps_dop, "exif_gps_dop" }, { tag_gps_speed, "exif_gps_speed" }, { tag_gps_track, "exif_track" } }; static tag_map gps_differential_values [] = { { 0, "without differential correction" }, { 1, "Differential correction applied" }, }; static tag_value_map gps_ifd_values[] = { VALUE_MAP_ENTRY(gps_differential), }; static tag_map gps_num_arrays[] = { { tag_gps_latitude, "exif_gps_latitude" }, { tag_gps_longitude, "exif_gps_longitude" }, }; static void save_gps_ifd_tags(i_img *im, imtiff *tiff) { /* int i, tag_index; int work; ifd_entry *entry; */ /* for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { switch (entry->tag) { break; } }*/ copy_string_tags(im, tiff, gps_ifd_string_tags, ARRAY_COUNT(gps_ifd_string_tags)); copy_int_tags(im, tiff, gps_ifd_int_tags, ARRAY_COUNT(gps_ifd_int_tags)); copy_rat_tags(im, tiff, gps_ifd_rat_tags, ARRAY_COUNT(gps_ifd_rat_tags)); copy_name_tags(im, tiff, gps_ifd_values, ARRAY_COUNT(gps_ifd_values)); copy_num_array_tags(im, tiff, gps_num_arrays, ARRAY_COUNT(gps_num_arrays)); } /* =item process_maker_note This is a stub for processing the maker note tag. Maker notes aren't covered by EXIF itself and in general aren't documented by the manufacturers. =cut */ static void process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size) { /* this will be added in a future release */ } /* =back =head2 High level TIFF functions To avoid relying upon tifflib when we're not processing an image we have some simple in-memory TIFF file management. =over =item tiff_init imtiff tiff; if (tiff_init(tiff, data_base, data_size)) { // success } Initialize the tiff data structure. Scans for the byte order and version markers, and stores the offset to the first IFD (IFD0 in EXIF) in first_ifd_offset. =cut */ static int tiff_init(imtiff *tiff, unsigned char *data, size_t length) { int version; tiff->base = data; tiff->size = length; if (length < 8) /* well... would have to be much bigger to be useful */ return 0; if (data[0] == 'M' && data[1] == 'M') tiff->type = tt_motorola; else if (data[0] == 'I' && data[1] == 'I') tiff->type = tt_intel; else return 0; /* invalid header */ version = tiff_get16(tiff, 2); if (version != 42) return 0; tiff->first_ifd_offset = tiff_get32(tiff, 4); if (tiff->first_ifd_offset > length || tiff->first_ifd_offset < 8) return 0; tiff->ifd_size = 0; tiff->ifd = NULL; tiff->next_ifd = 0; return 1; } /* =item tiff_final tiff_final(&tiff) Clean up the tiff structure initialized by tiff_init() =cut */ static void tiff_final(imtiff *tiff) { tiff_clear_ifd(tiff); } /* =item tiff_load_ifd if (tiff_load_ifd(tiff, offset)) { // process the ifd } Loads the IFD from the given offset into the tiff objects ifd. This can fail if the IFD extends beyond end of file, or if any data offsets combined with their sizes, extends beyond end of file. Returns true on success. =cut */ static int tiff_load_ifd(imtiff *tiff, unsigned long offset) { unsigned count; int ifd_size; ifd_entry *entries = NULL; int i; unsigned long base; tiff_clear_ifd(tiff); /* rough check count + 1 entry + next offset */ if (offset + (2+12+4) > tiff->size) { mm_log((2, "offset %lu beyond end off Exif block", offset)); return 0; } count = tiff_get16(tiff, offset); /* check we can fit the whole thing */ ifd_size = 2 + count * 12 + 4; /* count + count entries + next offset */ if (offset + ifd_size > tiff->size) { mm_log((2, "offset %lu beyond end off Exif block", offset)); return 0; } entries = mymalloc(count * sizeof(ifd_entry)); memset(entries, 0, count * sizeof(ifd_entry)); base = offset + 2; for (i = 0; i < count; ++i) { ifd_entry *entry = entries + i; entry->tag = tiff_get16(tiff, base); entry->type = tiff_get16(tiff, base+2); entry->count = tiff_get32(tiff, base+4); if (entry->type >= 1 && entry->type <= ift_last) { entry->item_size = type_sizes[entry->type]; entry->size = entry->item_size * entry->count; if (entry->size / entry->item_size != entry->count) { myfree(entries); mm_log((1, "Integer overflow calculating tag data size processing EXIF block\n")); return 0; } else if (entry->size <= 4) { entry->offset = base + 8; } else { entry->offset = tiff_get32(tiff, base+8); if (entry->offset + entry->size > tiff->size) { mm_log((2, "Invalid data offset processing IFD\n")); myfree(entries); return 0; } } } else { entry->size = 0; entry->offset = 0; } base += 12; } tiff->ifd_size = count; tiff->ifd = entries; tiff->next_ifd = tiff_get32(tiff, base); return 1; } /* =item tiff_clear_ifd tiff_clear_ifd(tiff) Releases any memory associated with the stored IFD and resets the IFD pointers. This is called by tiff_load_ifd() and tiff_final(). =cut */ static void tiff_clear_ifd(imtiff *tiff) { if (tiff->ifd_size && tiff->ifd) { myfree(tiff->ifd); tiff->ifd_size = 0; tiff->ifd = NULL; } } /* =item tiff_get_tag_double double value; if (tiff_get_tag(tiff, index, &value)) { // process value } Attempts to retrieve a double value from the given index in the current IFD. The value must have a count of 1. =cut */ static int tiff_get_tag_double_array(imtiff *tiff, int index, double *result, int array_index) { ifd_entry *entry; unsigned long offset; if (index < 0 || index >= tiff->ifd_size) { mm_log((3, "tiff_get_tag_double_array() tag index out of range")); return 0; } entry = tiff->ifd + index; if (array_index < 0 || array_index >= entry->count) { mm_log((3, "tiff_get_tag_double_array() array index out of range")); return 0; } offset = entry->offset + array_index * entry->item_size; switch (entry->type) { case ift_short: *result = tiff_get16(tiff, offset); return 1; case ift_long: *result = tiff_get32(tiff, offset); return 1; case ift_rational: *result = tiff_get_rat(tiff, offset); return 1; case ift_sshort: *result = tiff_get16s(tiff, offset); return 1; case ift_slong: *result = tiff_get32s(tiff, offset); return 1; case ift_srational: *result = tiff_get_rats(tiff, offset); return 1; case ift_byte: *result = *(tiff->base + offset); return 1; } return 0; } /* =item tiff_get_tag_double double value; if (tiff_get_tag(tiff, index, &value)) { // process value } Attempts to retrieve a double value from the given index in the current IFD. The value must have a count of 1. =cut */ static int tiff_get_tag_double(imtiff *tiff, int index, double *result) { ifd_entry *entry; if (index < 0 || index >= tiff->ifd_size) { mm_log((3, "tiff_get_tag_double() index out of range")); return 0; } entry = tiff->ifd + index; if (entry->count != 1) { mm_log((3, "tiff_get_tag_double() called on tag with multiple values")); return 0; } return tiff_get_tag_double_array(tiff, index, result, 0); } /* =item tiff_get_tag_int_array int value; if (tiff_get_tag_int_array(tiff, index, &value, array_index)) { // process value } Attempts to retrieve an integer value from the given index in the current IFD. =cut */ static int tiff_get_tag_int_array(imtiff *tiff, int index, int *result, int array_index) { ifd_entry *entry; unsigned long offset; if (index < 0 || index >= tiff->ifd_size) { mm_log((3, "tiff_get_tag_int_array() tag index out of range")); return 0; } entry = tiff->ifd + index; if (array_index < 0 || array_index >= entry->count) { mm_log((3, "tiff_get_tag_int_array() array index out of range")); return 0; } offset = entry->offset + array_index * entry->item_size; switch (entry->type) { case ift_short: *result = tiff_get16(tiff, offset); return 1; case ift_long: *result = tiff_get32(tiff, offset); return 1; case ift_sshort: *result = tiff_get16s(tiff, offset); return 1; case ift_slong: *result = tiff_get32s(tiff, offset); return 1; case ift_byte: *result = *(tiff->base + offset); return 1; } return 0; } /* =item tiff_get_tag_int int value; if (tiff_get_tag_int(tiff, index, &value)) { // process value } Attempts to retrieve an integer value from the given index in the current IFD. The value must have a count of 1. =cut */ static int tiff_get_tag_int(imtiff *tiff, int index, int *result) { ifd_entry *entry; if (index < 0 || index >= tiff->ifd_size) { mm_log((3, "tiff_get_tag_int() index out of range")); return 0; } entry = tiff->ifd + index; if (entry->count != 1) { mm_log((3, "tiff_get_tag_int() called on tag with multiple values")); return 0; } return tiff_get_tag_int_array(tiff, index, result, 0); } /* =back =head2 Table-based tag setters This set of functions checks for matches between the current IFD and tags supplied in an array, when there's a match it sets the appropriate tag in the image. =over =item copy_int_tags Scans the IFD for integer tags and sets them in the image, =cut */ static void copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) { int i, tag_index; ifd_entry *entry; for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { for (i = 0; i < map_count; ++i) { int value; if (map[i].tag == entry->tag && tiff_get_tag_int(tiff, tag_index, &value)) { i_tags_setn(&im->tags, map[i].name, value); break; } } } } /* =item copy_rat_tags Scans the IFD for rational tags and sets them in the image. =cut */ static void copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) { int i, tag_index; ifd_entry *entry; for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { for (i = 0; i < map_count; ++i) { double value; if (map[i].tag == entry->tag && tiff_get_tag_double(tiff, tag_index, &value)) { i_tags_set_float2(&im->tags, map[i].name, 0, value, 6); break; } } } } /* =item copy_string_tags Scans the IFD for string tags and sets them in the image. =cut */ static void copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) { int i, tag_index; ifd_entry *entry; for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { for (i = 0; i < map_count; ++i) { if (map[i].tag == entry->tag) { int len = entry->type == ift_ascii ? entry->size - 1 : entry->size; i_tags_set(&im->tags, map[i].name, (char const *)(tiff->base + entry->offset), len); break; } } } } /* =item copy_num_array_tags Scans the IFD for arrays of numbers and sets them in the image. =cut */ /* a more general solution would be better in some ways, but we don't need it */ #define MAX_ARRAY_VALUES 10 #define MAX_ARRAY_STRING (MAX_ARRAY_VALUES * 20) static void copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, int map_count) { int i, j, tag_index; ifd_entry *entry; for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { for (i = 0; i < map_count; ++i) { if (map[i].tag == entry->tag && entry->count <= MAX_ARRAY_VALUES) { if (entry->type == ift_rational || entry->type == ift_srational) { double value; char workstr[MAX_ARRAY_STRING]; size_t len = 0, item_len; *workstr = '\0'; for (j = 0; j < entry->count; ++j) { if (!tiff_get_tag_double_array(tiff, tag_index, &value, j)) { mm_log((3, "unexpected failure from tiff_get_tag_double_array(..., %d, ..., %d)\n", tag_index, j)); return; } if (len >= sizeof(workstr) - 1) { mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag)); return; } if (j) { strcat(workstr, " "); ++len; } #ifdef IMAGER_SNPRINTF item_len = snprintf(workstr + len, sizeof(workstr)-len, "%.6g", value); #else item_len = sprintf(workstr + len, "%.6g", value); #endif len += item_len; } i_tags_set(&im->tags, map[i].name, workstr, -1); } else if (entry->type == ift_short || entry->type == ift_long || entry->type == ift_sshort || entry->type == ift_slong || entry->type == ift_byte) { int value; char workstr[MAX_ARRAY_STRING]; size_t len = 0, item_len; *workstr = '\0'; for (j = 0; j < entry->count; ++j) { if (!tiff_get_tag_int_array(tiff, tag_index, &value, j)) { mm_log((3, "unexpected failure from tiff_get_tag_int_array(..., %d, ..., %d)\n", tag_index, j)); return; } if (len >= sizeof(workstr) - 1) { mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag)); return; } if (j) { strcat(workstr, " "); ++len; } #ifdef IMAGER_SNPRINTF item_len = snprintf(workstr + len, sizeof(workstr) - len, "%d", value); #else item_len = sprintf(workstr + len, "%d", value); #endif len += item_len; } i_tags_set(&im->tags, map[i].name, workstr, -1); } break; } } } } /* =item copy_name_tags This function maps integer values to descriptions for those values. In general we handle the integer value through copy_int_tags() and then the same tage with a "_name" suffix here. =cut */ static void copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, int map_count) { int i, j, tag_index; ifd_entry *entry; for (tag_index = 0, entry = tiff->ifd; tag_index < tiff->ifd_size; ++tag_index, ++entry) { for (i = 0; i < map_count; ++i) { int value; if (map[i].tag == entry->tag && tiff_get_tag_int(tiff, tag_index, &value)) { tag_map const *found = NULL; for (j = 0; j < map[i].map_count; ++j) { if (value == map[i].map[j].tag) { found = map[i].map + j; break; } } if (found) { i_tags_set(&im->tags, map[i].name, found->name, -1); } break; } } } } /* =back =head2 Low level data access functions These functions use the byte order in the tiff object to extract various types of data from the tiff data. These functions will abort if called with an out of range offset. The intent is that any offset checks should have been done by the caller. =over =item tiff_get16 Retrieve a 16 bit unsigned integer from offset. =cut */ static unsigned tiff_get16(imtiff *tiff, unsigned long offset) { if (offset + 2 > tiff->size) { mm_log((3, "attempt to get16 at %lu in %lu image", offset, (unsigned long)tiff->size)); return 0; } if (tiff->type == tt_intel) return tiff->base[offset] + 0x100 * tiff->base[offset+1]; else return tiff->base[offset+1] + 0x100 * tiff->base[offset]; } /* =item tiff_get32 Retrieve a 32-bit unsigned integer from offset. =cut */ static unsigned tiff_get32(imtiff *tiff, unsigned long offset) { if (offset + 4 > tiff->size) { mm_log((3, "attempt to get16 at %lu in %lu image", offset, (unsigned long)tiff->size)); return 0; } if (tiff->type == tt_intel) return tiff->base[offset] + 0x100 * tiff->base[offset+1] + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3]; else return tiff->base[offset+3] + 0x100 * tiff->base[offset+2] + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset]; } #if 0 /* currently unused, but that may change */ /* =item tiff_get_bytes Retrieve a byte string from offset. This isn't used much, you can usually deal with the data in-situ. This is intended for use when you need to modify the data in some way. =cut */ static int tiff_get_bytes(imtiff *tiff, unsigned char *data, size_t offset, size_t size) { if (offset + size > tiff->size) return 0; memcpy(data, tiff->base+offset, size); return 1; } #endif /* =item tiff_get16s Retrieve a 16-bit signed integer from offset. =cut */ static int tiff_get16s(imtiff *tiff, unsigned long offset) { int result; if (offset + 2 > tiff->size) { mm_log((3, "attempt to get16 at %lu in %lu image", offset, (unsigned long)tiff->size)); return 0; } if (tiff->type == tt_intel) result = tiff->base[offset] + 0x100 * tiff->base[offset+1]; else result = tiff->base[offset+1] + 0x100 * tiff->base[offset]; if (result > 0x7FFF) result -= 0x10000; return result; } /* =item tiff_get32s Retrieve a 32-bit signed integer from offset. =cut */ static int tiff_get32s(imtiff *tiff, unsigned long offset) { unsigned work; if (offset + 4 > tiff->size) { mm_log((3, "attempt to get16 at %lu in %lu image", offset, (unsigned long)tiff->size)); return 0; } if (tiff->type == tt_intel) work = tiff->base[offset] + 0x100 * tiff->base[offset+1] + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3]; else work = tiff->base[offset+3] + 0x100 * tiff->base[offset+2] + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset]; /* not really needed on 32-bit int machines */ if (work > 0x7FFFFFFFUL) return work - 0x80000000UL; else return work; } /* =item tiff_get_rat Retrieve an unsigned rational from offset. =cut */ static double tiff_get_rat(imtiff *tiff, unsigned long offset) { unsigned long numer, denom; if (offset + 8 > tiff->size) { mm_log((3, "attempt to get_rat at %lu in %lu image", offset, (unsigned long)tiff->size)); return 0; } numer = tiff_get32(tiff, offset); denom = tiff_get32(tiff, offset+4); if (denom == 0) { return -DBL_MAX; } return (double)numer / denom; } /* =item tiff_get_rats Retrieve an signed rational from offset. =cut */ static double tiff_get_rats(imtiff *tiff, unsigned long offset) { long numer, denom; if (offset + 8 > tiff->size) { mm_log((3, "attempt to get_rat at %lu in %lu image", offset, (unsigned long)tiff->size)); return 0; } numer = tiff_get32s(tiff, offset); denom = tiff_get32s(tiff, offset+4); if (denom == 0) { return -DBL_MAX; } return (double)numer / denom; } /* =back =head1 SEE ALSO L, jpeg.c http://www.exif.org/ =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut */ libimager-perl-1.004+dfsg.orig/JPEG/testimg/0000755000175000017500000000000012617614576020001 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/JPEG/testimg/scmyk.jpg0000644000175000017500000000074512031434614021616 0ustar gregoagregoaÿØÿàJFIFHHÿîAdobedÿÛC     ÿÀCMYKÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÚCMYK?ýP—ý[ý ~§K*ßç^‡½~¨y©ýõüëòµ"}ëò7_JþY%‰üÇù©í_ËÜ‘¹‘þFê{Sëôõ¶”ôô¯êz±"•̉ó·QÞ¿•¸¥1>vê;×ë/”ŸÜ_Ê™å'÷ò¯ê~(ÆŸ"ô«ú¡‹ýZ}.Åþèü«ÿÙlibimager-perl-1.004+dfsg.orig/JPEG/testimg/209_yonge.jpg0000644000175000017500000022350412031434614022203 0ustar gregoagregoaÿØÿàJFIFHHÿá$ExifII* z€”œ(2¤i‡¸hCanonCanon PowerShot S70´´2005:08:27 12:18:31š‚2‚:0220BV‘‘j’ r’z’ ‚’Š’ ’ ’’|’€š†’ 0100  € à¢¢"¢¢£¤¤¤¤*¤ 2 2005:08:27 12:18:312005:08:27 12:18:31 _ _ º .lÈÐ"Ø(0h pPB  ¨8ÈÒ $Ò\@ÿÿÿ–º bÀÿÿÿÿ ÿÿº#ÚD€ _|bú €à æ))Öý*Öý*Öý*ÔÿÔÿÔÿ,,, IMG:PowerShot S70 JPEGFirmware Version 1.00[ €àH €€€€€€€€€@, OÿØðÿ`€àÄ SÕ R980100€à¶¾(Æ4´´ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÄ“"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷ú+Í“Æúß6gë ÿâª_øNµEÈe±Ï§–Ãÿf§as‰EyòøóQ8ͽ¡ÊßãR¯/;ÙÛŸ£0¢ÁÌw”Wž9¹=tøý¶#ÿe§ÿÂs6üKS?õðøš,ÈèuU4¨cs°³¶6³HÇlš¤ž+´rŽLã<?û5r¾©6¹ OtÝ•Š$–àê*µž15ʹÀ9r­iÒæW2NVz x’f °:`ýjAâ rü›€½Ï–kÎc²³7dn@„‘¿åÅ]m>Ëa+pŸ†Ïð«TS%ÕhïáÖ!šå!Ê¡³óºÛ‘Z5æÃK†àŸÄJô <Ý:ÚLä´JOåYÔ§Èi ó(¢ŠÈÐ(¢Š(¢Š(¢ŠùJ='Å H°ÈÓŽ× >0}O5cOÔe¶ŠíoÞAr‘‘²V,|ÎFÏNXµñ ¸ŸIiYœ°bØzVÎ_̉ Ù4›Ka¨Ý—’m~îV:\rÄpKn*±È㯽]²ÿ„È,+8*c!¥ûøž¢Ÿ¥ëZ5ŠC=Ä’õg ÿãÕfÏ^Ñ∉mîÝÉ$•8þMT¹Iië¡ö¯F…¼™æT8c ƒÜb®XëÖ·R\ÌZáP0ü­¸õ\wÅZ³ñL³%ñrÄå”cðjå¦q$³H¬ÛÙ€'¶i6–Å%vz›p¾²žUI#HpÇ Àéí[‰mx[ˆ èúÃÿÄÖ› Má!d›Ë³ÇÉäsìkj-Dïl]¯@>úÿ…tP·.§=[ßA#Žq{…Š.â0d8éëŒÕ׊ÿÊpÖÖäm9ÅÃÿ…PK£öï0ÏÙÞXz}1úV¼ß/¡9óÕøšÞ¬Ì§{¡DwJÙ:j±=ÅÑþµÞxyËèvû“c.T®sŒ1šó2÷X3¶ÝiþNÞ6HÏnÕÞø^c&Ÿ2—V)1åNG ξ±¹t´•Ê(¢¹¢Š(¢Š(¢Š(æ-WHÔ¬4縹¶Ó–>thá¹8ã'€³¢ªbÃj‘Á­ÿê6³[ÛÁk}5Ê—,ên@08àŸzƱhßQ‡Í”C°,Åöàg·½)[›B¡µÙÑͤ]Û@fšÏLÚ:íW&ðƧobnå°ÒÄAóŠŽòóN–Ž=Y›s€Ûî‹=pMnk:†„t‰RË^yæ8 ]’#9ÕJÝ KœÛh÷‚ÌÜÿgiÞ^Íÿë\c>•ÊõŒô^+³¼¸±]&e‹WgB@íî8éŠâ‹7”G §nƒƒ½ÏXÓÕ#Ð4ÔxÙɲÂäéZP›C4›¢$qÿ,[ÓéY2¹¶±°R‘°[d3c·ÿZ«Cy‰$/ J¬ß+3àN+®„š‚±ËU''©­‹oíÌcÊóÊcö±Z^FšzÛGøÛÿõ«žù…Ö~Í>á¸zV‡›r:épþ µ­6õ"} ŤÐ4VùéÌC¯å]7…ç³µšêÞѶ2€B‚yá\J<¸ÿP?1èŒä}GãK$[]Uíd O b9=øöªåDë{3ÚÚÇ hõ+IXtDpIú ¬ä„ õÏçZ𢄶\ÛÉ-_ÔŠÌQ¾x£üÒ(?L•†Ñè'Þš”h…„VÇœñ“Ç¥Qf¥¹X×vrÙfô_o\Õ¿Ë*kb8ÊŸô|’Ã8ÁúûÖd¯©y0´‰ÖnÊzà{úbºi_‘µ-Ìîjéwf(Ñäl|àçëŠê>Þåx€ãÿüMq<ß`œ±LÙOøÖ—‡nµ;ÛYn Å¿Œz“[R–¶3¨¶7×Sh˃oœ1<úÿv’æâŸ$O1‡• ÜG\tö¨Osw9ç÷>ßZ|‰¨"–xÙÀ´’m4ÉŽ4z®‘x—ú\¬¡” 8Áõ«µÎx2ëí:;Žr’¶r1ךèëÏjÎÇjÕexƒ\ƒAÓZæL4‡åŽ<ýæÿ Õ¯øª5ljZÕ˜ˆmQT(îÄn?Ì~T ÃÖQúWI¢xžÏH³0I§<äÅ‹Ís9@òBçæ sŠÓédÍ{޹6Íþ1ºÕVjÌÜ·ñm¥½õÍÉÓäa66®ñòcß½$¾,´—RŽìØÌ5ÛåîžyÏãXËŽÃ+qv}ų…(‡F,@º»Ïqöfãô§v+"÷ˆ¼Ek¬[A½‹Û”“q%÷gŠÉÓ—ÌÕ,ãæ¹AúÒ]­’IÚK+õÝæDSqš›D]þ$Ó>Їb)7w¨Ò²ÐìÞÕ ô,ßÓí!´2Ȥlê¸ÂÖÏö¦›6žÞ}ÜUv“¼dûŠæ.$’ãHB®HÇï¾;Wöé<ÆÛ¦?‡)ÎŽátû«‡™Ògf?y {g¥’š´ÁòÀëE;±Û&û¸UÁÚX€Iëé^w{eýŸ*-¬êå6†h˜zwÁY•I„¦TB„¸‘ŸÄŠÝŸZûR”{¸Bœ.ï˧Jiè6µGY¢Al4ˆYá”’»²!b9çÒ©ø}­eÕ/|Èå`İÛ6xè=êý—Œü?m¥Cm½Œ±Æá8ÈëY^ñ™¥ËtnäFóT®O銫ê'³fO G[‰ FUXG …Nr{Tü1oiÀörzûfŸâNßT×^æÔþëËU¥ðŽ[ÅÖGko8ÿ€µf÷ØÖ×§Câ[㵋 T$}¨Þü¸„y ‘—=CÓ§ëOÖf€ëW»ÊßÈ$f©›Ûi6©xqÜc½tÁû¨æ”nÙkM“u¼¹ÎC‘ÍZðÍØ[‹.l¢ä çÔÕ Y-Ù$Û±°Äd àÕKI>Ã;¼r[°a‚®œ­ š¼Ní¯]eBm¦äÕ}½ê;¡¸2ýšmÀó÷{ÿÀ«]dœ†ÀãÑúôõÖÈÏî¬WýØó]Ñw0ä}Ž÷—¢/Ú« ™‘לgןjõo1ñ¯ç^á븤ž™È&ÀeP~µßÎbŽÞIL,ˆªIrü w®9«Ïs¦2´N7âþµkw¬Á§[a¥¶LNëêy øuükÍ]ŽÂ;Ód™žâGi ŒìX¹þ"{Ôlê¹àZÁ½MÍ n– ."¯–ÉÏLÿ^µ‡g‹©$%U[F?Z͚֚ÌÇ !Šç×±úÔ6 ‘†àà²òr8ÅEB¨ SÏb?ÆŠÚþÕ¶›÷›‘sü?7R‡ocuq™ LëœdTßÙWÙÏÙØ~"³R{ÈÎ"»ž(ñ©!5a'Ô<‚çQ»Ïýu4ìe¯ì»ßù÷oÌS¿³/sþ¡¿J§ Ö¤îµ ¬×Í=)­{ª+5ž¿ß4X/¥ÇÈ Î’.c"·ü‡ñ\û±¹ý sŠîåžiI ù™ŽI®“ÀÖ²\ø‘ÄR˜Ù`fÜ{ßëJÀ&¸êè1¨òjÞ‰¬z}ó ëk)䆺ÏÛÍo¯Ü´‘º0·#GVZØ·Õ!†Þ8€|"ÑƮ賤ÚÄó/ñCÐã'z~ :W Ì2Ù͈ãéÃ9ÏlzÖ<"Ó.îV {Øžg?*‚I?¥m&u<šòÝnÒÈëWÕI1Ép;ר©!{~uæzî“,ºõì¡ðBqM; £,ZØ+n™õÞ*@–‹Óoýü¨ßIUŽÿºqQÉ£Ýv¸'€k‘ðl2ZxºÍÎgê+³{ØôÿZÜHÄ.æR@'9ÿõÒ½Øí¡ÐGà=`^A,çÿf¤> Òc;–'#»ÿñThLYÅÌ…QrÇÉn™ÓÞ —â„W`–lž‡Ê"®È›“ÿÂ)¥Æw,‚:rÿüUº, £ÏK£Æxñ‘õ¬›ˆZ43´Nó‡ ´¯—ßó¥ÿ„ßOxÖ5‚åé# ½2G¯µê ³Ía½ò"3PGãEU× 6úÝäj‡o˜XqØóýh¬œK$(þ䟥8h¿ìIúSWŲ·üºÁÿOøSÇŠä-³Aéþ¿ÿ­LBý™?Jwö'û2~”\¹e÷ÂÊOô¦ŸÝ“¦1×Ì?á@ùXñ¢.@+'?Jé|§}Žîåþa”ç¯Z "E#¥€,£‘Öµ´@<냌ôíîh:Ç<Õåþ´|MlÁ]]þ`z5zfGLsô®_K𵮟o¨ÇspÒd’Œr¿0=¿hC¯R¸ÁlãÞ¼÷ÄQÎ5Û¦ˆÉ°²ãi?ÝÝ¶æ…æ¼Æ·71ø²ñØ.Ô ÷$všMˆŸÃW/*foŸ ÃæéÅyíõÄeG›!ã?x×¢ü?šIü/:ÈÚO¶­yýõ‹€3$ʧúÓbF焟Œ³’VA’O­u ù5Hf'åŽT|ûW%áäky6»)pÊØSŸóÖºÿª¤eß?2 cžõ#èr+½åݲJ…U]`ƒ3ïÜV3ÄðÝÇKל–­‘5¬~!”y“<ÛˆòÆ0ÜõÝèk¢·–OÝÊê~lD2?SUq(ê?\5U› OÏŸë]ûáNåIAÁû5`jÒÛ2Ú4°Üoò°rÁO®µt+¨ L)x°d8ãû¾ô15¡Ö. ê,ì ³(ûéETŽþxã ˆún¢Ž`¹å nU² Gf—9<×A{¤ß_ê’,MæµQž§­KeáíJ ¼ö"< ù•6¶=‰÷¬Ô“Ù–Ó[£-ìF|’UûŸjˆh!ŒL'HÜ픀k©Ôt›ò?qä!ld/˯֡:6·{ 4‚Õà¶Ã7–ëòÔñß½R3Úçª[¾õ–|i¨ÄCÜrx=iì1]nLAŽEy?#vñdìªpѧO÷q[þÖ®u›ËŹھ\k·hõ&º;Ûø-.ü·‘w`qšhÏü:•¡Ñn£lŒÏžÝá\~©cpתÁ+bS¨Ozôøõ»%ÎéW'¶2hmrÌ )-î"oðª±' ¤Ç,3Ö¬ŸºL³+ «ëÅv:é/¦Å#àƒ'¶0*î¥Ã…]ù'þy°™kV+.…Ó“¤gØÔ±£–—º–§÷?‰¢§RùL·Ðu5C#[¸É%”Z±á=-sZ[9ä1FQ˜È;p=*ÔWSÍ ÑšidTÛ‰ç~µ_Â塺ž}ÅDis×úi¾¦•¡nOÄô…ð߆¬üqtcó®co–ð9ʧ 6îÊôí\•šýª'îMî2z’)#ñ^­>™ý‘-¼)dç$¬d1;³’s×5kLÚ×±wÀ95¤š{ÉXÑÓeÆXœ0_¼ÀÖöœXZ€ŸŸü*”¡¼„(iÁ 3üªÖJY`³?ÌNXòkÇ—aÆ)lp¾5f¯ ¹*>lœgŠÌdÝ Ú#:lj$?0?ìú ÕñƒoÕQ€ÈÃ:¦Ø:±*IÈ=qÂÕŒÝðdj`šûãbIJñÈÙÍ3ÅñY­å¨Ý**Ï'ÜU¯"›â=G°¨¼io$×VF(ËFÎÑî)uB6÷1!Yßc¹ã ‚Fzàþ•vyÊ]"cÈç~;úb©è¥ž[hV ËËcøN¥i^ÚÊ.T¬E€3Þ§–P˜“LÈ™¶Ê:ðÝOZÍñ×ðÆ±´Ê`v,‰ŒdŽ¿Ÿæ+^êÒo1ÙbrqÖ±|JÒÏÊDE^9là7åÅ*j×¹­ÕîwoC´ ÎöaZú^›.§¥È¹Æ]P1€O ?—þjÕÿ€5¥³Š8¢Y¤YˆnÜ×v=^îãœýÕ±rîÑí]BUCeAÎ@ÿÜ4ýA&–ÊÝ­‚ƒulŒëÆx¹¢øJú=9-µ‘ÿ¶§ŽÿíØÿ„l,[ Ä8È<㌠v5JÇ;½ô9˜­î%1[˜ÀÉ?ëEI{cªÚÞK ‰[*TŒóýh­ï.’BJ=bÎnÖhä''V`E]ãPoz(®^‡LÞ¨tñæ”n ê}Å:ݹ\;;(§ÐË©´åipF>õt:]ºÁdˆ¥'–9=h¢¡ËCLµc½£ÜÇœ“R}†×hJ=h¢¬K(#rñ®Ã‚8¤¹?dµšdÃ0\üã#¥R0´õJ£,Àp@È>¢ºåve9==QZOrc±Zfb¿x¥akV1_Z”˜¹äaär_ÀQEB)™–Þ^“±[Á+9cæe¿­'¿FÅ€qýÏþ½S)›Å›£~ñýÔª/âQó›¶üQ@ŠÍ©Þ»k—$÷¢Š)ˆÿÙÿÛC  !"$"$ÿÛCÿÀ€à"ÿÄ ÿÄ]  !1AQ"aq‘±Á2¡Ñ#BRráð$3b‚’²ÂÒñ%4Sƒ„¢5CDTc“”&EUdst£³Ó6VÃâFe¤ÿÄÿÄ2!1AQa"2¡R#±ð3q‘ÁáÑBbÿÚ ?û.•*T©R¥@ •*T©R¥@ •*T©R¥@ •*T©R¥@ •*T©R¥@ •*£âýVóJ´†k8ávy9XIœcî x}T½”)cÄï,p®Æ) 2 æÁ Gv(…fb2&CëB)ÑÑ(×™¨s]4j –’œqÔâídîx=ôPÔþkÚŽep2^ ¿•Љcª¥ÛˆÄÄdŒp{·ÞŠa©t©žÖ^èãÿÄý•ÂÜH]“±Ýqœ8dšó4×m'}»ŸS/ß\µÃ£èÓyÇ~ú(-)S»wÛÌ=€ü s%äQ£;¤Êª2$Çoe‰4ªα¥Û\{‹ø"•qÌŒà‘šž0FFô€T©R b¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*ò—ªY¬1Ù%äí3'#ÀÆÇâgnX]Æœ×Ïüf]=b–c rL¼x€Á=FÜP©É&L›Kb{ðûÏs4׎—$ŒÃ~ièÀ6ÃoHM ìm¡hVúeûë>]'NmÓ\¾«ÂiÁ¥D›Ä:‚ÿ¼©ùW žÕhâ|‡iº—ÒÖÞ;Ð_©åÔä#ÔoS—IÖÇÕ½›Öº³ŠVs#9+Ä7€®Ù.„ŸOOe<¶:Ž'ÅW z£#áT—û~B ôî!¶/µ1¸]MNÞÔ¨ºU‡ó4¶÷ºšà‘”¼Œg¿¼ußì yâÖíâ2'¸•FÅ8÷o k'['$Bª¾FP6|÷T¿ö_IѨˆ8À¡«\Ñ7ÝQî.8¿O(æúõDžfZ(Ûp ¾ÀÐM­çJ¼ÑkÐŒ5¶N|zÓ·2qÂ*I«ØÈ«’?$êrAÍàÇÛŠuk„Øz·|rƒ"òäúì#?Û¯>ŸÆã™äcey¬Ò;›ÓAãYãÄmÆ•'¬Ê>úqx‹dÅ¥Éê¸|>oþ0®ß‰øÍähÄQ4ˆpÊlÛ9À9Û ÞŸˆøÅ쥶’Ò$VRÂÚPÀçÃA6ÜAÆ+z×ÑYÛ·iÕEá죧'òs×¼Õ‚ñ§§×Ñ~¥ÚŽ*{köþGoü²ÊmJýîóT´e29/"ÆáW= ôÀñ­ŠÊNÖÒN5ox¬"û8’æÊ[Y¸r줈Êy&ˆ‘F~·\Mé|oÄ𕼳Ùñ$R`2Fc cÍêp;«˜1FÑË\Ÿ@Ò¨šUßÓôËkÞÉáíâY;6Ç2äg.¹Ð©R¥@ÅJ•*T©R J•*T©R J•*T©R J•*T©R J•*T©R ŸG–>:@9´}óÞƒûTü~Y8Ä}}JoÕ‘ÇÌÐdh VÀ8ñá,¬ú†Õ¥˜$¿ÆG囉ü§ ÙÕº#äiøü´ëÄœ'“{ÿõ $$õSí§J ŽÇ"–Þ‡_!úùj»_„¦þmÒŸ•>¾ZO(gá-@þ¬¨k9\}P€v§!s“ò£oA¿³FO-V|¾ ê«üèþúy<³i„yü?«(õ!ùÖNí—lFEv0ÃÙLJJz~Íe|³èáô­eO¢Û›áO§–>#/i¬'®É«Qƒ±#u9æàc$wÑH-û6%òÃÁçë¾£ëY¸§“Êß0Ëj2§ë[¸ùV-•rWoJéFdå8ûzQH.^͵|«p:ô+úÈÃåN'•mÇÚZ°ùV' ¡r}UÈXð0«¾{¨¨…ËßàÝÊ?7N%°ö¹R#ãÎ «Äºg¶u‚¤Ì‘G©AëÙZ•Ã[D}h(ÒƒTýþ?ôߌxMþ¯i>Û´:y8›‡êkú[z®ã?:ùå´ÛŒÚ@O‡ ¦†bK)²€€ZP\¤“[Ñd8W°cü›„?:§â>;áª]êöfbØ1$¡F3’$ ÆçÄVt{Ùê>'Üš&”ä–´ =$ÐâŸÕ#`*z£öZ]ÂÜ\´Mʪ¯Ýžƒ¼ŠÏ¸Î9eÓàHJ¬8ºó»öªžÑì,u–šÖJ’¹”üE\ñ4«Ïc|~[?a:ˆ*ÉSÚ ú‡ݬ’ßË=¡fˆÄܨàrºs`ú׺ÝÂa¸ŠæÕ¹båT•d#';s¿_UëoÒå!ÔôèGˆ©Öp¯ÑâP|{ñíê{#ÍîJý@²’Õ×P±´žt©eL.68}ù©ç†´#ÿª ÍÅXhÊ?…¿ÂX}‹V\f’Fr“°OWÐ4‹K .-ìR)SXâû*ÒtügèÊ=DÑG ?tÀ ŒcúB¨×%|v®N¡ÜŽœâs¤h:}à•¦YÁF¼“º `x¿¦¬ iÿ™q¨§ªòO¾¤pˆæk×>«àƒ8®Œ-hF9$ÔÝ?Šñâõ]U=WøƒKñf`<Î ÕÖc?Ø¢…EåÜdçØq+O§Ñåì Óô-BH9Óˆ.“•™9L1‘H=ތԡ¢kKºëá¿^ÕOÀŠ»ÑPî×ô.¤÷ŸX,káS5ÁzÝò +ˆ¦©dß­jÃûUÅÍ—Go$’M§Èˆ¼Ì6ûnwÚ‹V% àt®n-Ã@êC)ΔôÁø9{¸*a? ØÈ7üŸ/¸‘ò«šòS9—„£V;Ç!_°‰4[^ÕI£Ô‡Ú…J•*’ÅJ•*T©R J•*T©R J•*T©R J•*T©R J•*T©R m8džæØkVc» )8‡@góu?q×é ÷×Í‘ëQ)fxŸ-àA©QëVØ‹®qÔ½-L…“èÓ¯èa”¦¯§ŸܧßRcÖôf<ÿ…lÉê~úùÖ BÞR Ml bží „`ª7_4d~ÃKS+·òm÷zôÿIu±ºÒZÜ(<ÒÜrr1ö}µì¾¬Ã™“(”òÝäf²n¸°Òï$›Y°¹¸Icü’ÊëÍéïÚÖ8i4éôË ,lÞ‡iùYòØ\ŒŸ±­#Á›Ž“¯Âwç*Ñi¬sÝv¹ýóNéÂ]Ïwkr°Á=¹]–@A 3‘ãÐÐV£­pº¹šmòÝ dtqËÏ“¿^™É i–è],—K)n^T%ÜçÓ¾j[ò‡9:>€Y¢mËç.3]#GÍ…å=Ùæï¬¹22÷ù¬@öÓ3Þv`²jE2m)ÕSÜf K“è(ÙÜa‡†zS±…ç'q_; z4ó¼£Ì'iœøTîâk88ŽÐßj“½§12eØôRGÛŠ¥+d84}ÈÜœÀ’IÛ#zì®Øc’k4ã.9áùønt°¿š;®täÃ2œón}Äíê K~+Ô$p±ëó§1Û3œRsô(Å˃è¤NU‡ØkÔ¸$àäÖ ë€EÖ¾)7q ª2ê÷G=ÌA4µ¶_jFÿÊZ2Á±“úÕ qŸ²F{v1»!"# àú÷²3ÅüJ""=frç˜6û*Óƒµ BóN^ñ$v2 ±/W,K·MÏÛT¤ß$K¢i‹ÄšCD’¯®á] ÒYr.BãÅ|ºÔ l-¹õ!pM¼²4Àlß[z±öP®·«iº]ÅôZö›z"]£P¥Øgûs쪖ÞIÜÔøm㺧ŠExÚ0ÊÀìAÿ \[ œ·6QßÃ$Öþye‰X¶|Ð>®ýMÿ“î«y{¦ß%Û†[sqaNpyŽ=5 ëÒ ¿µfÙ) ' úµ8¤ã™2æ¿–ÑFl8PŒ I}Ip)ágÃy²kQàm‰.‡³­XZÊ—Ü¡ÊL¥—=p—û?h§1Ý^¿ê¤üžeÖvº ó‰/u˜ó!ä)qr<Ý·8=zõÞ¥Çw[×w8øÔ›\bLcëš|K<¨O »*õ(ô±c'ÑõýFy29a–éÙ_pw¨¦“[ÓÔrµÊ‚ÁPç¦B‚ßo5aËhå7)«3w¨ËCô©ˆ+ÊàÊÜz|kŸ¹I£¦X¤ÒHŠ—cð¤w‰ÎEàã÷ñ®ü©ñtº½í¨²‡è±C*©¶|3Þ:mé5Á¯4DÈz‘WÜ–ô¶ „ƒ…#£§q|Ǥ^¶Ì"jÙ®`[½L Pâë † gáZ¼q§'›€*qFMÈèêÆ£GÇÍi­<†ÜÙÝ3ƒõ;3œÔ?†õ+·“µ·’]ðèA5õ¿Ñàççìãæý.QšãtG×01ˆà_y,~êy#ÇnHéßrtÏ›îíg³¸xœ²•$ddmÒº†öú#æ\ÈqÜNE}CÂÜ?¥ÝðͧÓtë[‚èYŒ‘‚w$ü EÕ|˜p}ð$é"ÝÏçÀì‡ÝÓìªìA®I–D¤ÕG khuÛ8õxÖKV™D¤<Üü(¯[Cn"fК6¶h‡ÔÉ^mò7îÆ6©\käÛOᨓR´½¸ž2ü‚T Î{úc¥ Z®m¤+ g ± IÇ…sdއ¥3h}_Q»hàÁab¡X4¥È«ûk ¿D(T!¹ƒd{è¹xç\m;±0Y+4]ƒ?fÙäÆ?KÃÔ%3 e úÛ®v¨”­‹^öl?äõ Q”//5Ø^˜èеVþS–G–ÙVi#UËl•Å1ä>nžOªúC·¡PT)D‹ÕEÁë×w"’Þdäà¿ü1q¬hvÖúÅÝ­·Ð’8Ÿk)ÏÚ¾ê5x›ÅzÀõ²•Ú×úmÔoÍü`cóÈ#ÞMj¢=‰½Î-.Ñæu¦¨³á=FQ#'jiË!C…CœlOJ’8CVÍâíCÛgåE4E£¸É2øOø~ÿ¾+ª*5Âÿƒ’IògúŸ ë6–R\¿]\GæhÚLJM«ÑivI+¨ÌpåSò¢Þ'‹ éðˆ¨~#æ ×R–¥HéÁ'$ì®=¨j÷&8ua ‰<ã%ºÉÌIðÛWg€µœäjús~¶œ¹øÑ dêW#þ춉Ö2k~EÁZ_ðg–rR33Àºø>n¡£·®Äz83Šæ;ãù/´¶R§½¶ˆ~ÔgÜ‘˜¦Æ0ÝvI¥™99ò·(ÇLg®}ïà®>±Z·êjS ûèöQË®ÛÞ[È=ÅOÌÔþBiF÷úC¸ÌÌAå #¶Ÿ#~®ª~uÚ\ùAˆ’ÚEñÏè߯ßZPCÜ+ ŒÑÚÅû,;ÑMärûVyLâ;~&×!šÎI ¬ò© òI;û²–\ªQ¤e‰KR(Ìc°P†3œämœýõâ´‘ÀÎdˆ¸Æ1ÖšŽÝž`ă¾ ñ®šÁÀÇæ“ûšä= È¡ä%¦|úßz9àþ°âG’Kùn•m¢v2ß4£[ZOv‚îò;HùóÚÈŒFÛãlï€kXà®#áÉá“]µ’Ie-Ì¡€ßln=Ó†Q‹¶a–U ò><“ððmÖ¨¾«“M^y0Ñ­í%uMe{4-µÑÆÃ4D8熿öÕ Áï|S·hZtöðëºxytÀ Ù[Ë4kÿ8©X .˜ú½ÞŸ¥ ©íûG󥉰à(' Ñ<>L£9x³^SûI¨:ú=¦¹ ôºþ’ÑÆŒ.W9;|(¾>'ÐYrºÞ™í¹Lüjqä„c½TµOé(“Y‡Ôã=q}sf¨µ=>]^YɨÜj8žs—ÁU8öŠÐ‰tRp58¼¦~4¯Ç¡=ÓÁ¨é¯Ú¹#qî3ëëŠYrFI%Bé^™6Éšñ#iVó/_[óÆ®"[u*€€qÖ¥ž â°<Ï(7g×l¿}Úkš2À‘&£l{5 ´‹·u=øcK'úßúb·îâø9¥ªÌ‡ÊN¯hÚlmªq+ê°ÈHHÚ¥NÛû‰ irÈ„ó ó×§ï½iþ]nâ¹Ó,~$r ‘åpNHÏ»²ëX 6ãµ`vè|>uÅ•ÆRm˜oJYä,J:“¶ f£Ï# cm‰$÷cÇz—” R½Û.ÄS ‰ãBlq’+4ÍZ7¿!\éÀ‘LsÜJßn>UʧÓÿööörÜÛAfìDG0Nr}þŸY«¯#ˆüŸéìIÌ­¿¦FÇÙSu3tuË£mp‘ˆŒ0Á† ùšÛ¦Òó}\¹ïFÀ¦‰&¥|!šÏA¹hí Äye‹ŽVÛÎßb=ôz¼C|‘°nÔÆÝÏ þ:¡Ðìo4kimôûÔŽ&30äq°ßa°©·wšÒYÊÿO€áßGëèë^Ä2c‚¤¿'›8NOrV‹¯]F’°áíREk‡l§dz’qõúƒ·²§Ž"›wë#Ô‘íÕ6›6­¯g ä!9ØžhrI$’zøæ¦­î¶J´8ñ€ýõQÍ ãòKÅ+½¯ô[¸N‰«D^ïr¯¤áŽ*¶Ý‡f»w •ª]ëé×Í=¡£`ܱpAôÕ qê%CEu^àc9Ǿ¹óMI­&ø"â·/4I4ýUÝ­®®‘ˆ#.F œŸE_'Ù¯cª/®ÉèW‡ÿ ®¡‹g³yÊ6L¨Áy|ÓÝßš$ÿÒ¢F#Ò< ŠééÕÃÿxäÜS§3Èߎû9ʹQ¥mÌ×+ë¶|«‰%⌌Ùé^É\|«Ÿ¤q&7Ótöõ]0þÍt¨ü~Lnø§D]FÂv»*‘‰–†Ñâ©‘ñ¿ ?Õ×-3ér;è/Ê×îxg•´xÕ–eeh'.äï°¢²Ä·ÔcDÚ ¬3“Êã©Ï‡…råYT¾…±´`¤·gÒPqGJHX²lÞ ™¹¡Hžn­bÛ­|ýäúVN-·km&öD…“ÂÎpëQµlâå ân ½'а7öêñ¬}i¢e³Õ5–Â[[ËydŽäl’q‚~B¶øØ:SÃ"¾yÔæ´1©†ní%YP¬Íl€(æä©8&·Ž›·ÐleÎK[¦}x®¾5$ÎΑíE…*T«€í*T¨R¥J€*T¨R¥J€*T¨R¥J€*T¨R¥J€*T¨R¥J€?1 ¼2)ìÌŒIØ«½Cç\41åYGœ¥Î=~ŸU7Ì["ÒøàTí\IÁsž@mõËÓ(„çßR ËÕ BËçö’“–É9|tÚ¦XÇ#’ÇêíÊ߯ˆunm:Æk©"¾Eq.‹ËžŸ¥°¡èâ‰Â;ž÷ÇJ‰*ظ4ø&ö1vLc”Œø®ÿ¶¸!V ‚Bõäï^3*y¨cqŽ\ïéî¦%@äF³XæôŠÌÖýO;¢ÄJ û|)Ç·ìÊ(RL}Ædçˆt¯ k¨Òðá¹|ËpË·­ÎþÕ=xVã$4š€eÝXÛŒ¾ß\â·Ñ#(®@²›’¼À³w¨Àôt§ûiCœ© ŽOãE£…\–V{«ææÙ°SÝIøRà•"ë ki ?aÞ Zâ ˆU˜…ðÛp‡ÓèëJ+Tíy$æv%B¨$xú³¶‹ È¥OÓPðmçÁ?Я†¦H²×Ñ3ƒÔÃ>ãÃøº]¹ª§ÑT¦Vá2¿žÁÓ^ÜÀ—‘•T77(Á8ôx¨¡ø^pŽþÜî0Í…ÿéøÓiÃò7ð«^cõ[’@Aþ… „å`·`NC4`7F*v ¿Zí-@—ê`|zô¢Y¸nîBU® hñŽRÌôýQß^¾Ï1»µ2Tžp ª9p¤A\„Æ\/ægº•äEóCw£qß^êšlÖw ˜›#þÁ ÝÝÓ¾½0«Úv¬î1×9éPöظ«[;þO%˜pG…@¸uúJ…rvï9ÿ šì½Ï?Ÿ¹¨3K¶R€y½ûçr3MGÒ¾Lê.ÑÕR"­nç;’|=4Σ¬é¶ZÕ䆡io8*y`9AÎø«ÎˆEÁZ$`ctýE5RÚ.›©ñV¥5õœ7åP]#Ettpמ¬ãê%¦0œE †³`Þï®oµíí$ «X±Ûa:çã]jÜ5¡G¨XÅ•hI0êc0Ûmûª|œ'ÂË;pþ™…'èÉ÷W¯™;¹qðyòΩmÉÃZÒ{ NÏ<ÇþsÔÔµÕtæmý©õJµ‡¸K†nôkYît->Y7fIï÷=•<ð/7^Óª)ǤM^¯Àžu| ^ßZ=”Án bPôpj ¬ñv ‹õGx©¯p|ZuÄñpý’ILèÊ„@'>ú®´Ó4é ŽIlmÝÙfhÔ’k ø»mofزkE†ª&¨‹‘ \/)^T`øßU\§Cœ¾—yìd?:‹†´=Jú½:ƒy9rŒ€FvÇuYÿÉ¿~n—Ëú³¸ùÖÝ>9J¥FY´jܲ<[nØÆŸz?š§ç^¯Zž¶w£ý˜?:¬ÿ“ŽVÞé?VêAó¯?äïAR}Q?VþAó­ûSý߃+Ç蛩ñœñ[…‚è2NçD@À9øTõâ, ÖäzàjÕxLµ±’âCYæýÈÆGʤ'öcêëzàÿ|cIC"{KðË Š>*ÑËI2úລÅÅš\})‡®*ü@ó8‡X¹ùR 8ÝxŸT°‡åO·•ÿúAü°—Wâ æÂæ(¯T³DyAFãnïÔüœÏô޲brT2Ÿc–+ ¨`òqEéýhPü«[ò%<’p‹A3’ˆ$õú£æ puКŠrgWJ㪢R¥J¼Ó¼T©R J•*T©R J•*T©R J•*T©R J•*T©R J•*üÏPxÑGœÖç×j¢ºQxË¿è‡ýÜ}õôZ{:í}•ßàÆÿSöWGbZ×£çy¸ËˆµˆšËPâ‚yP©'¯zd!xÕ°7äÆ(«ËÄ6–XP°ÅÌûw±û€÷Ьi€U£‰”ø`Ÿ†ÕÅ’¯c§ñØò1È_“'swëí®d»Â§gÊXÎmtöêÌYX6Ø$÷ïŸuGvÏhBò‘…RƒlõmBÜׂv™ÇœC¡#XÚYÚÍ9ew2däÿ%€û*Ê?*\O¹:E¡'Á¦þýy)ÓEsrñ‚|ÔݹûhøB }QìßqVqå’„Ú£_*œJ[F¶ö<¿Þ©ÑùI↴úYÑ"ìÀ'i_8ö絉UB`6ߥgCôÙR73Žž–Íg“SIy5éã—k‚›þVõ¢7Ñ”xâCýÚ÷þW5|ÌßýAýÊú6Ä´ÓikXÉåW4áá (¬âÌO5å˜ê^í<«ê×3ˆcЙœŒàL£Óþ®½ŸÊ¾¡hý•ƃ*¾3ürtÿ­ʦ‘c¦ÜiÑÛÁlåØò¨Ê?µU<¤Ù^K}qskÙQyÐ`TBœé=œ"°÷Êü€yú§?÷©ÿã¯G–%_­¡?¨ºpV¬ü5¡7]*Èÿ°_º£ÏÂ|:Q™´k/d*+oÓÇÛ9»±ôbâ÷¾»=²*Œñn™Œ5qßc'_uwøÝ£ô?M:ÙÈ?³[ÛôaDÝr.món±û2*E²óÛÄùÎP5QßqN‹-”ñ§ñ²ïm ë·…q¦q~‚šu¼s_ªH°„u(Û1áâ)9T‡M ”E¾ZèE‘‘êªoÆþgRº¬a×"œŠt…­{ˆóñèùP²X´¿E³)UÈ«o#Röw:Å‘?V^eŽfûÅ?h.ŒW²;®_]NòU}k/_-µÄsÇ4G ‚ “ÓÔk›­z±=+©ší*iˆYPs`o‘ž´íxǨ*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•*T©P¥J•|¯aåÒ1Í­ÙT«÷ÔÿùFàb05«/lÉ÷Ðà®aÿ2YŸæ ƒ®p‡ Ùiw¯¢ÚÆsæã &º$šVßàçØÍü j±kÜk¨^ÛyÖí1Xœªƒöf¡(PÆ ã¨'~•À™€p§ ñŽú–$ôaƒ‘õMyÒôz8ÒŠY`;¸#9ú¹ß»4Õ¯g'"†'žA±ãƽ¼ ¡åæS€( ï·Æ¼µMÔf9 匒 ƒÓÓÍ4†›Ôk¾OµîÓô$ŠïW²Šv‘™Ñ¦PÀçÍ€¢¤âÎ Æúí€ÿl´Ã|ÃRhÖ²Þi0Ë;Æݳ’Nÿ:±ÿ“Þ;í5êi—ø<ìŽ2›l¼Öx£…$ÓnËX²–á¢e@K1ï ½ k88Lk˘`…&Ï+…Qúž•+\à¾Ól>™i¤ÅÂ:vl ØäoîÍFá.±âÞ5µÓµ(öÂòÈ„pûq\òO¸•5G š7;~0áPŠi'þÙßO-áƒÓˆ4¯üÜ} È·‘ÿ2Eý6¯ÈŸ`ÿ™“Øí÷Ñ£ÿëñÿ§- [ʶ«eªëð>ò ¨a·úð¸uæ$œdwà k€ïl Ò¤][Ç#ÌĆp:U'pþÃE§höâÞÞ>Nd Hæ*wôî¨\7ä뇵M"=BþÖInn ;?lüú|)`‹Ôé9ê=AËÌÄ`Q‡ò-ú¦©ìðH‡òDæä÷.Q[ZÜjËy ›ky%;4@$í¹ÆÛoEIÄj6…hÀx^oŽ¿£C«4p^ÛÍ+„'¸xÑ:q&‡æÿœ­ñúØî®ŽšpŒ]œýBv©~âü]„ç¦/8þtu]o”g†3ޏ»Žœ^!ÑIÕmFsÖA·Zôkú1LRÌzå_Et÷!ïòaOѵMY‘ƒp´§ÕsùÕ‰užpÔ·JI!ùâÏ·ˆ"Š"Öô—Cþu²¹– h·Ö+bÀÝÛ©ÉË™ey‰ÕƒC”–ÿ‘­I=ˆM//åx6àú–#ýªgB½k($Žï‡õ&æ°å· €qàh•nì™W–îפƒÆžŠâܺqÎÛ8ª¸]ßäZUI­é=ž&Ð5U8ÿÙÎGØ T\êˆ/®.t”»°‘` ç[¼ ‘͸ÈÛ4k±íûEqdjÏ R2IÞžSò5–}2Ç%f˜M87^Öu*Òa¸Õ.åSu<Ò@,3 «éšùoÉ%“M;j¬$‚Aɜߡ¯¨¢`ñ«ƒÀùè'Lö6ðuJ•*°*T¨R¥J€*T¨R¥J€*T¨R¥J€*T¨R¥J€*T¨åHæFذϮ…<­ê"ÛƒçX¹uˆzºŸ°ÅÖòýÝXË(/æ¿-Á{½•ä’ÝM!®$’1ÜÎXãDó9*dG "ÖF‹•ÉÆÝv5é¸ç!¥‡Žv¦Ñ×* å9ߦFÔüåD]˜PPÀãá\íîuÖÇ *¹TU 7ç1«¾Ðõ[—úLZ|æU]P•#;œúÆ(zèƒ:G‘„ßïoí¤.oQGÑïÙ9NDI1OOM\;¦£èÛT@‘(ÀE à6§yÎpÍ|áΤO0¼ºÈËvøøz=T…þªHÅíØ‘z)Ÿr>êßõ2ôrvYºñXžkXbŠ7|É“Ê Øó5aäBÑ­x“T¾¾ÝV »““•óúê ÃR»Î&$á] S[b£ð•Ï//uÁ*zõÞ³î½NToQÇ¡p­õ‘ÿ­Bž+Æ¿²#k¨OóÅ|B5. 4£S¾ôƒÍÓ>êxêzêÜMZórǶ xøõÞ§¸ÌûlÕøê;›ÍoZºŽ ]žáÂáIÈ\¨>‘…C ÆÖº5œJ²Â™®pưˆµ}d¡+­ê±"sÍŠö=s_¤ß…¯×›Ì('bñë×lõ«Ç—B¤‹Êœâ£èúI¸ªn:•“…ïYTŸ0tðÈùV)&µÄJ]WXÔ‰Œýa9Áû|)K®ë²[:Ük¯ ‹ÊÈò’èG^˜ñª—På£àjVVEŸ!*Æ6#÷=k§XTä}>¾ÊzÛ³–'=§)æÀ#⼆4$–ä¸ëXYÕUÁß;8` Œm‚6ÅZy-F“4PÈ/Q‡LŒüªü©n@ncƒçdïW~F¢í¼¡h¼ `37~vÊœB[MÊpŒÝ1Y>‘ kwÖí4\Mwo9 f‡®:tÁµ=Aù,§“?V6;z5küZ4"=.È“ytû°ØÆ§>ºêþ¥I¹+8zÇ%¤‡¬¾£ô/ÆËÒ9yûEŽ?wO…Sñ]®£m'Ðm¸›P½™<ùA†>Hǧn¾Š•-ÝÕ”ZÎÑÈT°Á8 ÒMGO³áÙ­T_ÞÍÈX¹/ Ü“èöצž:i£†RžÔÎô‹mN[ÓcsÅ…”Œy  e ÈÁÇ…Ö#ŸŒ®×'šº÷•U¬êú}îo§Çr]ÄJ36CDGçïèÚª´ùoo/ úMÜÓròòs9 l \gl’ЙJw³ åáuafünº8àÛGUö–×R[ÆWR™<Áæ„R:cã½Xðç‰ÃéúΠ„“;8Ü{ö¨ºs¯J˨ptâ¨Û¤íHn[ç z£‰$`¨í„‘¾;ö©?ŠÜL>¯Û‘é°Þ§ã?ÂmÏ„‹ñh#Àß5§KI=Hž¢r‹TÀOÅž*n#²>»ýêóño‹Û[Ó›×fßÞ£ÎÄô¯{¹=Õ×ÚÅûN~ôÀÃÜ[õ-¶ï¶aó¨ñh|O+È‹&†Íò¿ uuW 9€?Tä{©8 ¶|ÿ¬È±S*õPÇùšö'Ò9N7õQÝÏkI%kXãRÄý%zuð¬ú6 ÎáK‚vÎ ®v©š-óÙF;QÏ͸äÎ|k™.QùTE"¨éÌs×ÛQæVQÉ"øg”fæŒÒ09Î6ÈðöVtlå| —3H"€AÀýýÑE c(##®[W«z•ÃvÇP¼ŽÍ`yy¸]ºõîèhÖn ˜Ä€éÒþL䤩9ëáZ(6g)¥ÈYû r¨Þ|bC€|k’ìN]Ç8Ü9¬<h‚ebs¦NKu?I_º¹~’nRtÙÇ/L\.>Ô=ÄÄža`wò9¥ÚR€f#œa·SÐì£ÁÁ3) é÷GÎÏñëîéKñ.@í‹ ÑÎ7üª}Ôô0Ö€<å‡;“ô¶!LJ»äòÅØ*Äá6Â8^•9XØ^’2ë·w…xüòDñ›ÑÎÁ˜…Lü6£¶Åì-ÎWe?[¹O8;QžU;69AqèöQ¤\ Ê„-¦ `‘Gí§ƒ%ä´Ô“êì§j41)«Ü ä ™¹NÅ1ÊBz¦¦pçÆC~qÀ%ŽÔo'KÙ¼DÔ1æ>`;Õ/èCI‰gx®cænQÛ §Lަ“ƒJÊSMÒ)!nXÕËÌÞ'­?Ì s^cù§&£Ç%ºÊ#æÈïÎA®£`’ê­|MêGlêD?F,Y‡›¶PQw¸Õü¢éå|ã2±À8þ,íP}ó9³rñßGŸäù<|Î ’–26Þ´?MpFï®]õ²F-äéú¦¾qâ_Êñ¦N!ìåS󯢸¹8züçǼ_6éz¦¯{ª¬Ou9ˆçú,e¶ÛÃÕ]m¶Ž.©ªA–®ÄYB çû§¢Ñã›I}RdÖïËg$±`1è$ûG…Q_G¨´òFufu^€Âƒ»ÕWö–ú«p|“uŠ5ÀüšÁ)>i$ù¹Ï·Â½8'm¿“‚Mm_¾#ÓÒÄéw(ˆÌEË­œnŽí”j.Œ9.bÏs¨ø {,u8´-2ñõ¶‘vXÑá‚3—~€o𢱋W[ Ÿ…£V Ä+žíúR”^²|rLÔãYFq‡|‘Ô`°Ï¾ˆôæþ ¸ ]XêË “PŽEwažÄdùÙöoFšc¡Ç““¾MFDÓVo‡†Xóñ·ƒV†FcWî+ò¬ÊåÛ°"6 ßšHÈüh–8ø Ä#å©QúV#ÕúU¿I{ÑŸR¸  Œô#5Ì€a€ïÁûqCDqSïø_O=ßèDn¼aÅ|¼ÿ„´Òmí[×úuÖ”ŽZùs‡åô~ʯ„Ä7)¯oý¬*µ‡'éÚYÀÆÖíýê­¼Ÿ‰­5ˆŸ´ÓäžhÄiæ0R'zäõ©›qVÊ„nÕ†äe—à|¾êw”e—ÓßÚ(;é|g°6úa+àXxú}5ÅÖ»ÅV˜–æÇN ìaÛ¯u'6•Ð(7Àd6P|SíáPµ˜ûM`$Âàzñ÷ÕH»â¬`Úé„z;ß­&ºâslc{ 5—|‘+ûºUïëû ÉKgÃwzιouFÖØб OîG}}äÎ1k¤Ï§)ôi*{² ³‰pލúlp»Ä€9€p0FÝýw¡pŸZ¦´m”Í=Ú– ®¤as¹=Ý@¯ŸÍ6{8äÞÆ±J™³›é±OÊW´@ܤ䌌➬ÍEJ•*T©R J•*T©R J•fžWøÛðM¬š>..- ?ŃݟÒ4Ôm‰º=òå$¾Ÿ¤:Ir2$›9Tôéî¬+WÖe–i^Fv%™ŽIôÔë³q;yÄŸIßöT>uaÊ 1À+JK‚ÝÍÁc¹'q¸®;U#äŸ5Icw0©2Éœr/Aû+ƒ:D{beÆÐ¹||…B¢S–'$ª95Ä’@0 Œ[Ð*F¤êwm#·†wÇû|jÞN)=Ö¡±;…ÇNáKR–Pý$0`$ø³)Î×´ [TaâÙ5sèи2E$ž%ÎÕ*OÀ0(^ÆÝqúl1S© ù×ñÏ‹/ƒYÝË‚E*ø€)ÁÛ¯uwkXÆ9_½>ú³â¹V4†=ÁbIoŽŸ:©¶|º¬g$ã¡Á÷f±È©Ò6ÂÕ]˜¢\]a»e6õuûk™Âlj vÐçÞ|i똮{4UUæ;yÌñÆs½5t×&ÝbuuL÷>G³ÑYÙ«HnmJÿI0Üéˆ#ºÎóÔ0Æã§¶¦'ñá0+ãgµ7e ¸ºä|¶  Îþš9E@bºpãRVÌ3½4ÀáÇ|yí£ÿÉšé| qÐåÖ:dÚ<§†tI¿ü•Çü«ñpé§ØZMÿä«ÛUnneUÇ3î}NåÛ­8aRŠbËP›Š•®+S–°Óóú³ÿ’¡ê\e¬ñ4Aoí`Š80ì¹ñÇçÝFílrÊ ôŒÐwòÇ{" D Œí¿@*2âPA©3„i£„G 2Á;×N9ù€c=æšvƒÌT`Çl›²¸Rá¹¹þ·vã¿Õ½`tÚ¿2¬%XžRq¶AÆEi¿äß +Ô%8!l9zîê³Y•ñ=’Œœ—çg¦õ©ÿ“¡äÔõ‰{'`!‰|Ì¥³êÕ>›ä×8¹ÀáÛÂNÅ1ï V!£i±¾`î¤e²¡AÏ»Ñ[ÝèÅàL§ÍÝ—ë-eÚ2I%Î6®Žh¶rõ tq5Ÿ4ŒÆâbǼ•ϧvL¶QZÇ=ÐLóº’9Xøô¦Ißi}w’Z¼O̱ƨÃ`ô®«ØÃJ jöúŒ–È.®nM¸É«2•co ¯ŽÙÄþ•77Žî¢N!p4›DëœNÃöÕyÎûS±4†µ #Ús‰l6áNþê¹´´í YÕÄ}G*>R*»Q,½œƒuäÁ«]1¿§§'í47|•G­fÑq{rývvt>Š™Á×’êÖ±[ÉŤC¬e!å;ã òoê¦ælÅBñAqÛöbD’)‹sl¹ÏMúZbž‡fy¢ä•‘ÑuBÞoêñ0CýÊ÷ðFµ¸¦ìM´'àµAâØ9Œz¨t €²¬NC wŒlsVÏÅ\=Ì Þ·QÖ ?»]±ê1µoûŽ^ÇK×p¤q<§›®m"?*­Ô4½mµ+T—^,ä?$ŸEPS=ÄgöUÇã6‚aP/w zÄý=Õó^Ò¥Ôlæ†íYb‘Œ‡‘‡*‘‚ztÍ9eÆÐEM>ΓĀ’8• þU–·LÜè|Gr«¼Ai"ç#6 ŒÿâÕÁâ-”ãRŒì?1ºû©#ÐJ©ü#`:GÊž¼/Ð.ç¢|Öú)ÁkÅÜ­þqј.ûYH6ëþ¶¤§h<Ä Nßïb?}©èuíœÂ¶ÀëÎð§ÜÇìš— rÖÊ[ˆ. ½hŒÑ™ÊGæ“’v8ØøÕ· hp÷ÙÝC38»9G~ãP4ÅÕœšíÔ‰q[ËÕÃ]Ј«[»ûw²°¸I£iHÛ·ÉþÑ®L‘Œ±M¿ÿN¨ÎK$¡½póöšE¹=@#ÜMXU'JLeÎyd8õ?m]×LT©RªR¥J€*T¨R¥J€øïˆaá¾–ùÈ30äO{žÿP¯–µíN}Bò[›‰Y™ä,ÌNI'âhïËï›Þ&:tO›{ÉŒ‹Ÿ¬~_ͬ™îј«0Qœ3w@ñ5«úË;’Fác'#ê.äÔf¼S)ŽVôH3Ê:e®œ×·lˆ­mlãùÃ9ùUWßǤéϦÚÃo!PÒ–#Ç¿>ªËVåiÚØÐâ$¶’WÓíåçú¡ãrW¯;TX¸ªâÚsvÖ÷+&@iO×õgöwU-´·V€Ákp`”á¦p~Ï`ùÒ‹[Ö%@$¼•”w2‚>š\{7ý)á’ä^¼ñlŽáßé§ï| -Ó¢\ËrÖêÁ„en7ÎÞÓáCãY¾ŒóB• Ÿ—¢šmVyäæš V`p3ú¾t©pŽãŽlî‹Ç}<…[¡axg¿×áM¯é"ÔE ŒÉÎGåÀ ì#=Ã×½ µê´¡äÓ¬äô˜±©Ù%¶”yúEÇ‚°ñ*6å\+k ^XÔ 18Ï_˜¦aídnh£y¶Ï>=äÿ2DjXù£ zœûêQ¥ÙoÃQ+ή›Î[¦:mñ¢Åð íLÕµè­4ëÕ²T‡™Ü§6ç|}´J¼ÄÿþåŒÿ»¾»±I¨ðsõ ä‘8L\iG¬Ó‰¼NGÿ©"ÿ˾šKÔ´»§‡QÔRõŠR±òr8cÓÒ–i=#é`»¨rß <Ï×p>:”5Y£h|A­Íyqc«Cen“r"´åˆï«QÁ¡áA––*Ò…#^mºãcó«”! i!NMYPµÖb›³]~å“—š_æÑ6›e<–¨Ý#ÃäŽNý6ªÞ#²ÍÄ’ $ˆåvßåWš+gN„Žõ®yÖ¦‘Õ ãgŸBž1“©ÝÈ?E‚cú´ÚŸ-ÔÖ㈧æBBoäcêøV)Ê{E^[ ‹›‰+,S>qàƯ»#,šJŽøNûˆõ}r->~&š&Á…¬DçÃêÖ„8?^Àåã)Ï®Â*Ïø^!oÄÖw'9/Ͱï9ùÖø°ƒŒn ç]¸!ŽIìräÉ4ù¸ ã>½>:jï‡8ŠÜDç‰ÒPÒÞÅ Û=w᧎ ‚GuWëÈRÁÛ¡ŽHÛþ5ùVÒÅKؘæ›iX/ø·Å ²ñ£~µ€þõz4+~ÒÛõ¬Ûûôr°–'mÀ®…¸#›ÕöÓíbô.ö@ðÿí ½v²íRüŧþ³¡öíQâÛ’Çz÷±=Fhìâôé]®­a$:“X–dWC7/R7¯u]I<é¥ö?)Dg›Í9ëž»xRâ1_Ú¾1•t>¿4SêÉ-ç–ÚÖ/#Àˬ,:€qõq'Ùé®,˜ä¦ã±Õ ÆIJ\ŸCù5¸éü¼Ù- 7´ ¶Œ+.ò+qÏaf[øÇ…•ýyæ­F¼L|S=&*T©V€*T©P¥J•*‡¬]¥†•w|ÿVÞ”úyA8û*eùh¼ú“]^PpZ5Œ{X†jñG\Ô_°>RâMJK½B{™dgy$,Ç©$þÚvÊÒÞÚÚ=CQ ¸–&>jé¨Z|pBÆöùÁl“yÇŽ´¬¸ <7é@—O©^M1í#„òÅžŒ4|ý‚­ø»Q絋N³EG—¤lHêÉ>8ª qqÀ«”M¶üæ=O¾¥ì‡É?Aµ7—Ad'‘ró7£®=¦¯5-=„Iqm¦Hy»ÕmáÖºáÛ3²À>»áå#Þ«¿ÝG\?Ig-«F®}Õš–åÑšö³!å{É çáOÛL<å}9¥p~e¢Æòóö uèw¨ÇHä̈‡8ÀÞ†Ç@Ðkv>v…Ç_8 õåÓFèìòd}?%¿O¨&ŸgVñ<ŠâCÎqâ:c¯O@«~%ÕôÞµö =ʦÄþ~}ÕI Ì‚ÕD3Ȫûã üö©pÚ£G—p21 >ýÆ*ºH©….6ÊsÒ¥Á,Ê¢1–Ü‘ù,ïRÑqkÑéŠD•Ø÷ý”Ôl\r2‚YŽ Îi˹®U;7ʳôÈÁÇ®¦ðΚúœ¤¤Ö°˜ŽOm(ǦzЕ‚tÿ&qîîue‰`­hW8ÈUoQ¡Ï'óiZ› Ú•—¶.ü“©ì(î*áÐ2u;mºùâ»a8¨Õœ}KrÈÚ)[HºMÌ/ìßáY÷¹YºVv\«¿Q€=äÖÀ¼UÃl¹]Nß'§ž+&â=>mOQÔn ¼°=´ò2fåå$‘ßàEcžJI$iн9— ‡É–•,¼+©€fw—s×||¨mlW>£Lðmþ•¤h6–7¶âhí²)Û“öš±ü5£€OÓ 8ðq]à¶³ ÎR›h†ð0ý!Yf½7Ÿ¨Ès$ z@$|1Zôº¶’Àâö þ¸¬£PÑ/®­%Ž9­ ±ó³r½Nιóµ&’:ºirrØ-á{3iÈÖèûzF~&­ÖÖB<Õcê¤iW:M¼vp5ä°Ä‹³ƒ²€ _¦»¡ Á¿€gmˆñéﮇ({8²996 ^Ù\%”òö2ˆÍ¸#`3_<Ý’Ú›sT¿zÓjúŸˆ5M6} þ[¨ži-¤Xט ±R÷×Ê’):›óyÊ c¾@ß5Í•§%GGOtìy²ryNq…$S†5d.T d䂆ÇÔVt-Ê•ÛbrièÙÙ±R2zc?áY Œj,xCs»ò<+}ÿ'(‚pMÜÄ’dÔÜÇ5€\…7<ªÇêþnÿ¸Ú¾Šò'“ÈØŒsÜÊÝ1ÞÊ”¾Ö/%Ï”†G·RsÍt£þ?*Ÿ ý.WncŸ`ûU¬yb¿M?C¶¸•\¢Üs7 ã”e¡i S}ÚúA!,IE΢»zJÎ.­YqxœÒ§¹1ò¢=l‡áý’Ü£ÕKqæçìÏ_ —X‰çY­Ð»gÇÆŠ5=aäÑtXK¾‰y¬Œ«ÊÙ ¿]‡JìŠz£–[ÍQwÅðÞÁÃ"êðH¬è0€yç=ý(gOŒ ‰ýÚ°•[ñ¶¹,ü=f%Ñu)U¹ÝPƒæ0ÆÍü¯²„ìµØ’á˜Ùݰeƒ;wõªÌ¿™²3‡†¹#[_ÙI‰¢äÀñÿ °Ñˆú[`rûª“WÕ–éÄmav Ô Îø ÕÆêöQ²©P@ ˆïÅa5õYÓ‰ìXIŽÏ>ªÇa©ÝJ?—*Aé‚Tãí¢æ9B(7RÔ¬!º¹Iuq>ä! ã—Ãõjk‚åDëHU5m.HÆP±#þ-¾ÊÛíI0Bçó–6÷ŠÀ´­nÍc€8¸aìV''›oø«[³â˜þ‡F¬qn-Æo×»ºfíìqeA0d˜ôü*»ˆm6øžèCû°~U xª 8:F®9³àß¶ êœI¶Q/Töì™6Çò‘šê½žÆ);A}—œËü¥øŒ×|¸Bv~ß•YñÆ•‰d·Ô9£UV"Ü‘$ñ‘R?42[1߀Xõ¶n†¡e‹¦SÇ.ÈÀ‡ÁñûûëÒ˜r¸ÏîE Ûq®4e#ŽýŸ<Ø[W'ëêÍI[¦v¤öˆ›)>ê¥$ø'K\œq”Abµ”wL=ÅX|jv‰%ÏéÛÆþß8€ª.(â-:÷MEÚ¸•9KÚÈ«õÇRFÛLéΑ܉%·–E1•ódï9ê1¶Õ”§§%ü¨9cÿcEòA0‚v„ìb¾t¢yGÙ[%`M®V-[PXÑ£NÕ%Ec’1ƒñ5¿w×…/õ&¾OZb´©R ¡R¥J€*T¨V=þTš¹´àË}-9sy73å°yScÒX{«]¸–8 y¥p‘Æ¥™˜à7&¾;ò‘Å—|m¯O-Ç(*ý•¼H,q‚OSéñ5p–¬k3q!+mm$ÐÉ…•»0w÷ï¨:ÜñGs„ˆmÔ“+™>¶ÃpO°xÖƒÃ÷vz7 ]\ÜœàeLzóY°n5=FMBç%æÉØáêÆ>”]«`Õp5~gM^âò䨖rD tTñ÷`{ü)Ý2ØJæá””M‘Oyý÷¢­kGúVj²ª¬ËÜ qŠ…Ãv}£‚ÃòPù£=çÆ³“µeÅQ¡Ùm‡9̯ç1=h‡De‹S‰3€Þiýýu[j9N{ë·vŠE‘NH;xõ¨[¡†:rHyÆzäT=ÕJ‚>ŠÁš(äG$0cè§Š?XŸmZ¦}«È-¯#ITœôUù>Šò³ÍkuosN¿HŒó1<À`ãîÛâ+Tâ­3´·y!Pe]Æ{ý ³[jI>—¨r¸G뜲°Û ý•¤i;%™te#uåÆàc*#ÅPíŽe;äïí¦‡0 µ²°;tlgß^Ã)Œ`” ô OÛë.MÇWÍ 1º:‚a¨Ò@YË^\ žP:íOJve&Uí#e'uæBvó<…öÊ“ÜF@ùж¯rò†"‰žLÈ|ãœWF7‰7D2oÍùSŒtð§ g’<Í Ç!Æÿ}{3¿çŒ?Lžú¢)É>dä#œü=>4õÄÇ$mÚNÄ—ÀõR ¤y*ògxÇš@ß>ÚôJòBŒ¸Øy o°¤4ÄVíÈ]•B–Ç!”çÇ=)ÎÀ´±·4f2áÈÇ]ŽÛšryÃ:f .1] ¬ˆ%ìdú òÆß,4¢!8‘[;~T’AïWk3‚¤1æ— ŸG¦»y!*& d\æ c¯Î…šâ.hã"Lýl í½?*VDh˜å•oç'Of+¾Ä²0ÄE@%Ojrqì§<ÎrÅ_¨í0Îö×HóÙ©+ù¹ ‘@©XÀ·çFb 0À|ûzt®`3+9”òàå€ÈÞ¥HçWí “ŒwïUqo¼’4ª[r…=>]h±é:‡’1ùLcaæ(õöÓÐB\v’@bàoï¦$9Pqׯ¾½‰È\ròà¹{¾t0^†&jràrޏ;äúñ_KyNÏɦ–pAs3õ\||Í#«_8;ì1‚ñù×Ô^IGäëFM†a-ïf?:SûAþ\fÑ-a,T3’p¤ì žìÖo¤,PE/3HKg%ar1¶;½¥y`r"ÓÔo“'ö(N`b“ƺúI8Ãc“qãÓÆ¤Ú]ˆ QØ\H)#öSRÈ~–ÈGpǺ§i/˜úGÀT96i¨ð7øH+ôKÑŸH?qsi­|Iy‚²­¼¬1±î\u4])“c¨'µºü%qqó|ÜaÞ’‹–È©4–å,vpÝò¥Ô¦7Ø£[M‘‚:ykWÒø‹OO‚?£j¬024ÉÈðý ¸³íYeæ+";àŽ ìk\ÑãoÁVÁ‰$Äý{ë¿§MlÙÖQ|kĶœ[êË¿æÉúCÑLÏÄ:kBÈ`ÔÀuÆúlþ¯Ð¢ˆQ¹åålLÊ)Æv®´ŸaiºAe§ˆM¥ô žneµ®þnõaøÝf …ð›gþíXðÄdééã(Ξæ5n°þUcÉ—¾²ÇŽ¢ª_ØÖsNO`+M×lS_šöEž(^ñR¬£U%@ÎÕSÀBÁ×,JöÌárHÜ>&®áR·8;Yp¨µÁ25Ç+óc»¦ŽV•²;5 [Õ Ó4ùo$<Á6D]Aï¬R¾Õä½{©onÒy³¢HÁT€x mUÚ°oÁ·è7–sÄóH 3`¼eIdîÆÝ<}˜ï£-¡ˆ·kI$_0G©ëùüž§¨.<.zo5;…hïoï¦S¹;~ÚªVJ³nâž/á; y ŸSíæ ŽÆØ?ã¹–Þë–orÓiz c#öT¨…¿ nRHÛÎéþ?¶› ˜¹qà?¶º\8Î{6Ç*°5š¡‰#s>T‚§¹ªâ ™þÓÏ0æÙÜ ñõzUI–8Œ’ÎK/†I8ñûsãGö~PøF;xãí ªú4Ÿu\R­È“§°<ºvkw¦…æÎÌÀÿV½ADP¿M²-Ôv÷t¢qå„þžßÛk'Ý](<[›é£ýÚOîÓ¤F¦ ~/¹P¢îÃïç»ÑN.…0…£í´âIúÆlwøQHòÁ‡cskÿ–“û´àãî #êÏÛk'ÖŠ@¤Ð Ü?$…„Ø/(=%ÎÛ\¯Î$Á»±*ÙÏå†~Ô`8ãÈɼ±îÒÿr—ãÏçkËŸöi¹E ÔÀé8vyQ®,)$¸œGïŠr.¹X»#uaÊC‰”ôÅþ<ð9øfŸŸM´¿Ü®ÿxŸô½;ÿ-/÷(Ø502>”ÄCÜiáü{eûëÔáÙÄj½‚gÀ\ý=hÈq¯ã&óM?îòrºüwà^ë½4»ÉýÊ6 LÕtyí¡íš{VŽ?ÍIƒ1ÎÞÚ®µ(¢B«ËƒŸª ŽôeÆ\UÃ:žözD¶²Ü³ `pÀœî£»ÓAºsHb‚äžñƒŒŸuK..É X)@¼ÝwìÆ?Mpæ<ëÉŽ›oû+§‘@>nÔSM†Üº€3± )"ÞÄ4fúTÄsc=s·Aá_Tù9†xxE¬d˜„Ôú×Ê6$™KˆîÍ}{ Øðž rXÀ¸ôˆÔQ“í" _•ÇqucËÂ3/]¼wú¢ƒ4÷DŠLÈ€ïù‰¼¸C ³¬²Ã™hË(!Ir;úÖMÃaoµ^Âx­Ìc¸[ =@ð𮾒-Á$ræi=Ã6‘HÙ×ØÂ§@mDL¯78Vã$}ù¡gJÓÒí¹mbjþhðˆƒ¦ŽÑî?Ø«Jíç¤;‘ç7«Õ]Âå³™åJTZkó@Yc†HÝX‰<Ö)À\}™ªèÝAúËëȦ|¥ðÞ‰§]Ú-Ž›Ebá‘Óº‡,4Í=¥U{H›~ôU< KM’³&®‚é$O¦sR õÈ©º\±˜oúCÀP Æ—§C®ÈÆ…¸$róAØt£ ÆÉ¬?¢ÂÑ©<€ 8±”yfК‘póDQ€–3±è£¯iÏ!ŽîÕUöåpIÏO\¾›`ÿ·Ïÿ PY@u÷“$aŽ3צ~Ê›w±n:•P~öó¶†Y±oªzŸm_ÁÄ:ÜPÇO¥•9G˜Ý?¥X†™¥ArèÈ‘DˆIÏ) gÓ[†•Áœ1&™lï¡Ù34JI1Œ’@9®¬8ç“ÍÙeލr>&׃9çÓ?_5¾úKÄ:àÀÿ6~½<¼‡c¡YB» ÂdÌVƒÔ t.Ÿ'î0îâý¤=;\Ö-Ñiì #s³ Ø’@ôTµâN!2¬‚(ŸÎ|xüêŸð»Þ^Å&nÂ'Pƒ4 ޾$ÔÏÄëø!êw:˜ôùûŠ–\wö$â"åû /|ôgÇ…8x›ˆ`ÚégÔò gñ …1¶žÉdÚ®?¸Oÿeê¹”j«ôù?p»Ø¿i1¸§]eå{0팉Ÿî¨zeåÌ6 DîÁ‹©”€˜lälsƒÝ¶ÕÚð ‘Á¯ìº›ûõÏJ²Ó/n4ÛhŠÛ,™DggÀ*S’wÍe—ñ¥&ìÓ¡;ŠTê3ß ½2êæÖÚ(⸠Y.ÏBq‚ƒ¿õ¼ð¼ú\±©.}„˜5óeÌqý$ VF$zÆ~ÌÖùä¶ù.aß”†9P€}9ïë^_Y=Y”¾Þš:1ÐsJ•*ÌÜT©R X¯ùRñSé¼9o ØÝ°_À¹PKÇo~U†/©³·:PÃäKôÂ?Ò/‰ýuþíuÿ%ºgO¤ßö‹ýÚÙâÓP‚y)K§Æ£<¸­i*lùóUàÛ-;S’Õ$–U§.rrsêðÞ…À–Ú«\Ë$òÅoÈ¡1¹ï¢Î(ÁâÌ`…`£Üί¸ÓŸFæå´ÛÙ°¬q­Rg~E§_9|•صÕç½~êå¼”Ù÷^]üߺ·ht•äÏgšöM)@ÉP1Ükm(àî3æŽ"áHxgSŒC3ÍÏ7å01“•D°çìPïá¿_myi œH" ¤-ºŒ|±÷àŠ ¶<‘¡]НvÇö×4ÙÕ.Fè\wôÈÆ›f‘™¹‡ÝMî[˜ÈøÈ?XàWrhÀæ#êœç×RŠnÈåO6Á²ûd÷gö6Ÿcco]’%_p¾;ÒмÑ'0Ä’žò+ì°N06õxQ—„LL«ËkáçºÉ:õÞV˜ðL!µf'>hÏδŸ,af¿¹V b—=àsçÃ݆§3(°^Zô:8½ GQ%«I'Ržè¶óWú´Wy‹†x}ý#öþÚœf]ûÀø ¿³¾ŠÃK’Kñ, ìcä²Î·¨÷W^95G,•Ïú’¼©Â¯s¦¶6%—ÞV…¬íPO0#d`6ðæÅq¥½üÄ_êñ‹åOdT{|j¢, ®OLŒÿÄ)ÎO¸ÈØUjÖJ·Ó(<ÜÛîz½ÕsÂÍþmOÕ*]™“ˆ®1 ¡N‡šj뇸À¡\ÒvÎÌ|îr¡&·Yõ¼ÜžÇìó¾-'lÕ¦]Ã,›(‹Îõgï"’ÝšJZUƒVq;˜Â/+7(ß~¸'äk|Ñ üfN3Ø'OP¬SZ€$V3!•œÑÇíû+fП:=§ÿ ~èô{¦yÙüJk ÔÇ>ØÍz»Žr5£òëwÊOÖHØ{ˆùUˆa޵N­Ž#~•ªŸs¾¬CÎÜr|—§R0F|MCæÉ«7Š69ª“ äÄlÝ1Cz´@ëá 2¬ÑÇ–S‚7aŸ^1EMºH¸ê3CO˜õ)€Ç4n= ©ùšçê7ÆÍpm2PÑx…ɶ»•í#wP¬É’«‘ïØ}µ¼ùº™^nÑaû–³ý9‘Òõ0 ‰võSñ&ˆüˆÜrA`ŒIh¦0ŸY|XוüGc¢qöz=G=I›u*T«ë*T¨ËO jœYÁSiš\ñÇ*¸—‘—&^Pp çn½}UòÞ—¦6•<‹| Ñs} 8ÁR6 øxWÛuògùIÒø×S†1Ê.yg$wåAǵƒ{ªš×¯[Ž<™'ßµåóàM‚êñÜŸiªù ¡zÿEp<æ,Ø NNkÜo°ßX½€rUUÝØÉÇGuÁŸŸn*H<ñ+g(â£\¸ä*§§ïñ©Llìà’Ãl1ômûü(ÚÁ-"Ü#R¹Üøï@Pùì@É,6žê3³•-¸j9]žEŽ<ä ŸWÊ”·’AÍFñ­íÚß wqæÄ¾¡cèÆš.•kg ªÄÒ_ÉçyÉ`:~¢+y~ƒe.»¨ŒÏ'› yßʯçC÷r+Aq¨^75ÄÛõè‡ËÔj¢ ¸±UbYOyϳ×RÖÙ˜`—•NOyï©rÀ×*n™ ±>dc®:çÕŒz²*N—Ÿ2ÜF¥²OR~B©²JÉ!Nלr…ë€Np6ø¶žŠ$,ê¶$÷ŸmX·Ð>‘ôqh9úmÓü3]{~ß²h°Ç|G¯¾“cØ«³ `)$ä°ÁöWHGfà ø€F7ùÔŽÆ2í‚vÇÕl]+¸ÔΜ g—r†Ô¼•[4ˆÚYq¹æeQ’:šÞô»¦µ·Ž5ä.ãÃjÁlínnÞÒÚc“Ìœn@éšÑ£à{†‰õ“èíî­±Þ—Ašª)š*ëS.ñþ5®MôY˜yJœá;¨xåG(âm\ê>USàë›m>âsÄš³£/Ê]pp3ƒµ7ªŒbÊk¦g…œ‘—É÷ÿl¼#e¾“j¸®}xãXެ&ú Å rÈÌN;ÉëZÞ—À¶ oI«êå‚€ynØ Öx­&vuµQA´ æýiD/.Äm“·¶¨ãà}((c«ëYÇuóÕv³ÂIm1‡YÖƒ‰½s½hìáQ^ÌçUɨÞÊ×7Øqò£_'ÌÑéúm¿"ì2Hßv?*Î¥ç‹J“2!óÛ©;îjëxfþöâÄÜñ¥È9Ù!~@£àxVx.Ýý[Kb}ó6PE1rœÃ!Fþ¿¦ƒ—­¹¢Ÿ‰¡$8E9±·N•qÆÐýˆïl–âK¡ÅVI¤%ÏA¹ïß5ý$Vulxï\Çj[l2”’¼Ç$ä`à× $„Ñ`c¹N|jpÊI—\ç?ToŠjìÆ‰ ìÎèOn:ИÚ8á¨MWKNCÊ×1JÁ`+ëÕ9Šù;TIÅA3›è§wZú¿›§/”c¾V/lãâËk‹ÛKyb*&”) }Ô'¥ê:d ókhSŒ¹RjO—XÚ~5$e‚ ÎOÔJ¢[˜ôFCÊ;okÒémâJÏ;¨¥+¢SêÚQu?…4ýý¥:c>5/ñ¡nû+GÕ,LѯbÄe†óºª·Ž1(f¶=ÿ7~*~•¡þ·¶Ô&@æåÎ  ÷œŸp=õ¶™U&bœ\­£‹ž&7ä.£­ØÏÙ0ìÛé¶ÏCèèÖ4€_üécç.?ÒSÄkˆ4øãÕ.nbÒM”Wš4`2ë°Øué“\*Â9mT6o2Šj[±=-pFׯô»^æxu;G€*°¹MÈÇ_E^p¼«-˜t’9Y0'$uCĶñM<Î,×·¯D;ƒ¾j׃&—²•!:tü欦©›ã¦¶³µ ëױܗ–ð ÊJ¨OB:õÝhƒ'¡1´’æîÈF+Úlgå4¼–ø³}¦¾[ßéò¼rsr‹˜ÇˆÏ^¸Á­Eã‡K·†]MY0ÊnW ûë(¸´º’Íp€ò>0S#â1÷VÁÂRÇ>jìn\GïÝ]ý/Ói3‹:T›GcxWÿÜiÿxZôq¯ ÷ñ›ÿ˜_¾¬ÿ#Ëù}ÐìqSì®ÍýœÛz(‹8qõ˜î£Ö설Ž.…9Ȭð¹ÿüƒMÿÌ­Câ˜á3YÈUHéÐòýÕ'°áìn-óÍaÜ’“V»qqN˜àãÆÜA¦oÿ¼¯ßVq§ GlN!Ó² r à޽zULÐpÿbü‚Ü7)Æç5ï›s§Ìd¬ìwàâŽäœ’´¸¨¹S-×øC·Èâm+cü):tñªˆô IìáÓµ‹ ¹Ä­æE:³c”ïXAÙÛüLCÃa몮)†ßèTŽ5x¥F;°4ò&àÕ‹Jka½*[hä¸íþžUÂ2òÍ ÉÆF*.òIt±Kr‘ó„‚ï´^rK`³œõ8¢»·Œ –xѹ!œ×öÕ÷“mB­ßC‰¯?˜r09Gß^7Y7,I? ôúx(͵äú”t¥íª;."ÒMŒ%ê+Àçc‘RhÀur:ïX¨¶®µ/e¦)b«F·¤…ô=3×»­tºÖ–Nô?ʧ¥†¥ì÷^Õ-4]ïU¿“³¶µŒÉ#wàwvzE|)å+Šîx¯Š¯5{¦þ9ÉD'"5èª=@ìÍkßå]å"Úç²àíéeH–õãl‚ýÉŸGSé#¾tncÌÀÇT¾ˆ×–RŽÄ… q·®œpQ0 Þ¼â¼9›©êr{ëÔ‘«0,{vk™±¡,ŒŠb]˜òwî¦%ˆž™øÓ…²¬äõ=çßñËÚô 6¡ sLå@¤°2ÈÜ€á°ÍiV¿FÓD3:º®FÛŒ~ûÖw²+H¬C)¸ÜÑ(ÔÌšu¬VìAçø;ç¨ÑÞjd›v •:ãj×ípêÉg› ²<}ãÝBœI¨vÒ³¦M²¶¥÷mÒ¯8ªYb¹]=—´gl¿n~Ô9|¿HŠ£'䱎FÀ<Ý ÷ü«T¨–GŠöíå€nÏ•‚§‡ºŠ´Fí#"0¤J|ÆcЧ;{(RÎ&­ÙOfT–!A¿@Ípåì0µ­ÅÒΑÇp²Al‚1íëÝßC$—'Óy¨Òª¥F1èõxTIR+{ವºýeæ@Àºç8øUî©s¡åãŽÇRfR´  Ÿæl7eQÉslé&-¯¼þöt'×õ<)5¹h¬³ ¨ÎwmpJ‰ˆ˜–¦E8Å•kÈÈ|úk˜|å*¼¸,v8Ütï©-"×Nžk ¸·¥…y×™r2MlZ5õÅÆ‡ í͹ŠfŒ»F6;g§†FþÚÇb½“O“骴¨Ê2ädoWöü_ÄÊÐ\< ‚$x8®Œoè¢zŸºƒÍ]·ÔçX’ ˆ¤ [Î\®=c¡¡þ"×õ)..¬ 0%±~Ë9%ˆÎ3Ÿ•þ¿³›²´˜ÅÍŽr dú=ƒ4“¦I$œœõ'üh›´g‰\Ò'i¶ßLâM&Ìà‰.ød}õô]®œ‚{ñ÷ÖÁdž:ÓÛ“Ÿ² øô€qöâ¾ÒYç´ä”’:ŒdoöšX©@߬w$Ž?Æù½ß÷P÷A®‰?NÎ>¾ÿºŒ§x¢òŽþŸ}gþTµKTáÅIÔ¼ìcAÉ+ûiÉìrÆ-º0ÍAy4Þ]ò@_€­oÉæœ}cø»|íÐlβMQ¤!Áäí8ã­kG¸†=KP¼e´eìc ’Ãõ/J:u³:úùp éȧDº°PoMžöb€¨ ¸é¿…@¼¿˜ÄÙå@õ}õmžblùcŽÈ~1ÕÎ /\t<¤oº váOqQ^ê×H×.d`Ç´œ·0aÔäæ“¨iCƒÔ0á½q®ž’gFPɺã˜t$¾[Ô[çU·‘ðÇ9Æ@©.ñÆ» ØggÃ¥G¾+Ø7)'Ÿ#N:xP‚MÑmäÖA7è ˆ›ÈÎpÀ û+ê¢#8¯—¼‘Æ%ò£!rBÌÌô#•}@†ª§/#ò ¸ã Æíg\8\G3 ÙTwž•OŒFL×Dÿó÷Õ¿ÊßrL„mèÈùT cü½uèbIcGI}MâÓâi£A%Ñˤ¿ßVvPè°NÕ@röÌËõ}uGdшa¸#®k¥’W1³9bÊēԞSZžå†µ¥Ù®™± Tó ÄÏœ}5MŸ?ZsþÝþúq$f\$uÆv§£;Šu¸¬‡cn—*9§ Ê:Nÿ}KÓ¬m¦‡±™LŠƒ#™É?Y»ûö¯5ã¢~ ¦*N’Sù›Ê:úÚ¥ÐãvuøNÉŸþ‘¡Þ/¶U6¤(i(r áTÜ/-å™U$$œ€ƒI•àŽ(ä´œfX¦S”c+vÏ.çþ´~Ó4 Í}oÒÆÍÏ)ôß®ã9 ‹ë …­Áú<¬{ee Èê‘e ÍÍ—4°:4r¬„l@=þœ×OM‘)nsg„œlÕ…¸qºXD}Nß}:8S‡öƒcþ“}õ–¦Fya7 þiaR Ôu¨7ŽêõGëµw¬‘94H=ÕxoE·{>ÊÂ5Y.9<æó”‚qצ@©ßŠš9üô›ï  ]kX’tÞO C΢MÇ0ξŸ“Š8‘ò>”ÃõbQò©S†§e8Êqø© cm9}|í÷Ó°ð—s§/²Gûë9}wˆ\o¨]oàq^ÙßêÎì'¼» ©ÈqMä…£;4¯Å^QçØ"õÜÌøþ·¢ªõý#„m¬¦{f´Šåž,\žna¾æß¦1A¬d–8ûGw!<ÌIÆwþ±¦§·<Ñòïʸ8éY¼‘{ÉnǦA¬iC! Zä¯8\œrs|V¬ø/L‡øµ-£“™.¢'tÆã˜‘ß·Õªî¹U²R킳@Ã'sÊ~Æ«íFTŠtYцîÑœ¿ k<#>–OÊ_öuⓎt¼,v72ÙöÈŒQŸÍ!ÈñÏç tÔšmÛ>BKçÒw'|lÕ'M¾Ó£Ó$ŠæØI0~pÞnHØcsãšrMCKì”­‘æ8a€½ÄŽãá\ø$Þ4Ñy"µ²Ñ.ù£n<äÁ"iOˆñð¡_(ºÔœ!ÃRj’É8™%²µÄ¸g9ß®àO²Ž î–SœY¾Îq…6>5”à›Îì~uÛGr$H QÍ’Ät=}U²“Rr>hži/.亞V’GnbÌrI9$ï×zz ™ÕrC€:ãî¦0wëžê÷ 2ªásð¯6NÎÔJUW“°1öÓ ‡µhã%¹sêÏ_&|H¼¤]s²;Ltß÷ÍACl²aQ¼Ô'zR°q"ªœÀõx|éÕ,O( ç®zSNñÅ$©ÀÏR|hL-\-«Ô|jÆéžÆ&¡ +‰zœ€ÞªîŨÞ{÷1ðõmDr a‰30¨ÙGJ®Š}rÞ][O*ªO^o#wùPu˜–yy™‰ÀÉÛlŒ`Vˆ"¾T½ž=ýô%¦LºÉ[b¸‘ƒ`Œ7Ϫ´ObXÔVàXùÊÍ›d¦sŒƒÓ|U–‘boîñ)"<Ù>>¿…NÒ4ô¾…f†KË(Îç®}]p)ûþÎ’+få·„sHÀd±ðýýT¹ÃÒ¥î•Yè¢åbü‘².qß¿]ˆÞ£jŸJŽ/âú¢©æÝã? ¦³¾Õ­toa¾(„ñ…Âàï·v1ߎ´…æ¥yhÒ*ÛÜF_”±8뾩½‹FqÛ:Œv®y»Éx{ªv‰›p’˧ÛÞà¤èZ?ãÇ5ZÏù2)æÛ'ç÷qM²±Ë‚*xeÝ…1q˜^vNÓ"sÔ,dQÒYu;®]¹ïçb@èÍQðÔh5p¨Å‚ÆùÏ)éb‹í¦pÍ­t\M®i ²3\‚ðgÆ}Õå¿iR E%Ãö`óbݼí5Q \Ì:yæ£ðîð]9Œ)åošM^Ÿ“5?‚Ê.!Ò‹y’\7ªÙ³OǯX9Rõ¢Ù¨[Li$rT^ƒz»³…ù×j¨CW’e=> šŸi¨!IâÔ"`9†m· ÷õéVF­ ©%Ä—®€„ÁŒÎç8ÏMúÐÏ(ü+n®*BªÝ|IøQÇvü‘–eßëuîÚ–HW’ñÊù, w°¾ìªÆêVW#“Ȧܱ~£º®óÜ(wе£2¡nY8ëÜÔ(ÛI–åI±±«p›œ.—)õXšðjÜ*W™t¹ŠçYœgÃ×U6×@!l« è³멪Ëqo˜Q@çÉæÛ|¶¶X=½Œ^‚OáNëø*sþç]&¯ÂÃÿSÌÜ…CHemùa¼ŸEv-f=ð(ô!?:¾Â~IýCôL]g‡»EX4‹ˆä$E˜Sž˜ôR]k‡þ¤º>«%ûê4VÒ«¬;b(5ìö³ “²#˜Ðçú;1°ïºà‘øw‡{´;³ê²OïRü7ÃýÞû,ãþõE—9Þ8ºøšôÚÝ b(·ôŸ ;öO~^‰?†ôÓA½?îqÿ~½ü5¡ãmøþR/ïÔQksŸââÎ5ïÑîà¤[ú͈û~^‚Í k{ë¦[e]Ñ'E [Ã$tl÷Ñüök=œÖúJZŒ‡·Âµ-kŒl`Ó®.î­ Šc.Ø Û|ÞOJø×Ê']q—Üê’Œ[«•‚0vUcÝûï[Ên·É8árø ܸhÔ þêhVØã»=ø¯fÇd¹úºô¦KŒtÎk„„Î;BÙ¤¤™rÛ(ÿdd&3’{‡w}(Ù˜9nRIÏCû)PÇÚPˆÀç›Ñ×5¶2Î!Œ„ ±l(é©«™ù#|m¿\õ?¾jËAÒæº˜6 »²Žïž> e¿ Ø‹¦(ȵ¼g,WbNÞüïöTëÅkxáK`gÆ;±ûüêÆ)#·ÓÄF±AÀ»Ÿé¨WrŽÎF Aœî?~µ›•²Ôv"H Ì"bIõà>Ú Õb¸RÙ@¯(@îôxújîg•£fb¡¶ 㑾j¾ò9om¿*݇!'W$‡ÛZÂ$›7x m?Maš>“pvÁéŒøÔkÿË£ØF¨ˆ(ʤ4‡}÷=6øT®c—ô³k-ÄaŠÇ :®Àã'ÃzJ«s§Ýê8P#¤¼¥!;ìÀ…nÁ•Z¾¦öGI®šH’>V„Þ7ÛÕPt-y šD1«Úª±†.cʄ쾱œ{©„½1 šæÚ7º¾«`¦:gÓÐý´Äw7RjpË Œóù«„ÁÛúÁàáù•בßvQÝ]¾~ÀmúC}´–U2€À¿Lžµqo¡ÌTJºŽ–y÷åkÀ0Ï*èÑ´Š¦03mAwæ;g}ü+¨ÄJ~D)ß%¿gY~.ÌdljZYmü-k¤áÛ€¸’ÿIp{¾š€øz(ÒÃYNå\!$*22NãÝ·JôÆÌ;CÙ¨n¹<;wÌ ÝéGרG·Û^Ž¿<½Ö˜ÈQƒcÑBrET(NVÑã+ÌçÐ+Èù—sÊ<îâNÕl¼9©Àæ²<¤à èFôükßÅÝXc‘¬Ç1Ç(Ô!z~½ 1©$U>[*0Ã8=¡-©´ó¹’7“>wåOÝW燵@W dyGýºïÓIÃú˜q"¥‘Èßðÿ~ÂÑO*‚¡TFßX™|3Ó¥zy‘[xùpqÊ䟅\7j„a#µoä Èqëúþ4Äú«oi$²ÁnŠ-Ëy8êv¿¨R RET+ù_1ÖNQÞ¸ßÿ=)åy”©Lî~p’¸ €p7ÜŽ¾ºïf¦riЮ˜ó$ØËFTgl…3vgܧ˜u' JÄØNNf›»bZ6Æ7àcüh¡6h¾@“Ù˜d²‘¶Û™Gηý±½`ÿäðŒü_}+6BØõ@2'Ý[¬§Ì8VYy(ùÛÊd¿_[ÌãVÚyHõÓ|6 YL ”~Ÿªirö,¼Ž9‚»ó]pìÍ&•4®açõZ´Ô«úékþFtECvÔ0ÑDq¨æ ±qí%¡]sj2±ˆÏ(P1áí5{6¨±™{%,Þn3°üÑó©Œâ˜J-ìqÅb3¬’ê ì«¶­øQbO2 ˜÷#>ͪÌšn«7Án¹ðŸ5ˆÆÙ©œ7jöRö0b9ŽW¦6¢NÕ¯f˜þBÖ¨øyí¦^n\Ÿ§*éºU.ºˆð̲Æã¸íó¤¹E>I Y!cu c!F¦l.aµ´§pª®§'Ó‘SmEʦX,ѸÈ‚@8ûÅÜþWN¾B:òÿX®˜Ïfr¸Û¢Þ=sKQƒt¨ïñƒJþO©M_Ú¡Y±ÐTIU£@C““X>¢qðl°F^CáÄV‰Ø“°ó Z~ÓÖâKyde‘\†óI3ð¬©]¹— ßE—Ÿ[”)úâ7÷Ä>u/©•Y_§ŠA”š¦™Ê¬.ØÁðÏΓêšo("åvÜíà~ãAû›N¹*@ßÃ¥7!",žô?ýÚ•ÕHžÂ dÔtåfévo¿î¦îuM0”?I\òƒÃü(>á™T>s̾?})¹–H‹tæe;m¸4¿U/@ºuìÒ8.òÚçQ¢a$]º‘¶ß âûˆ,8†K;[u&)9efAùÇ›èÆ>ÚïÉÕÃE,Ã;©WÍêÜÅ{Ä7×¶àˆæ™=#-ƒÿ Sž¬m¿f‘Ž™$½Kð,Ëu¢Ù‘!PCW®`:z¢¯¢æY¹`}™~G³¿$wŸnÒe ˜Êú}U?h¯ü¢EÂü;6¢éKÙr¾vK‘Œî7sìô×/DÞ–º…rFGþR|V-Êð¶ŸtÒ±Ã\°s€|: `|}ŠiêLªƒêŠçUÔ.µJãR¼•¤žwç%‰'z~Àr#;lHÛÇfÉ©šB:Uîʈ<®˜RBcŸ¿Â½g°ß¸CÌù!qÓÆ±4‘ŠÀò 8=Ýø¦ä­bVw$HœÛ좼¸nhÙKaF Àïð©ÑɨKk#np;ÏÝšÂg:”ú¤üç Éß8Ÿ],pÅl°Â¡bS»óãë¦l`ŠÛMŠÒß«žfÆ =çåNÏçÄa¹26~êÎS.1¹ÜIÈ€ÀéÔ fä+ÂU†ìFþŒ{éûu«@H2ãµ2X+ÉK3w¿¿¢§ÉLv bmØÈ °É,OwL~þ5E¨«ÛÞÃ*»0†dQõ†wERy˜"—Î6]y7úq’)¹Qž£¸|+h? Î@wq#Ë3¥š˜áå*êã'|Yß>³C°Üɘc²3—ì” 6øž»z¼jÇU²µ…­t7wfÛ~à*ŒÊê'UVäpØa•8ß‘Zp§à¶†æ}PÌX¢(”e³ß“Ó÷ð«Ø,áƒJ:…=¤2.E¨n‡ÓTü ¦ïUšæùÂÀdr~pïÜ ¼3FðÝD¤¦Ÿ§GäFyA;gcÝŸ]Cgp®ff1žU•;ü÷ükU²»á„´‰sdyP ›¨³áúU’©"ÚEQž`GL þ懤´’6 dE\_¾,ú/xd»ô.ƒþµ§ùUì—œ4À,·aÿZ‹ûՃ漑.F}Ì–ŽŽW$ãÑFäl}·<5Ð%¡ÿy‹ûÔ¢~dɎМŸúÌgÇùU‚E¥Nü¤¶9LoŠv]Tx> ¶7b‹§E¨6­pnÎ8l²¨ŽÓ¯ý¢?Oò«¡cø«Sêš?¾°t÷ŽS—8ðÑ´”Ÿì}\8Ì6çsÿJž>ºqãáÎhÇÑáÜ÷:xM`÷úX·´¶šBÞ饴q+†„°ÙgÔMuo¤M$+#63Ýè¥tTqêàÞ;Éü„'ÑΟ}+k^0§ðhÏš?9Oξx0NŽT}UÜ6Ó3o•ÀÎMR!ª>…œ:&`Ö«²Œc—¿>ŸETq‚hpè7OkkË/'˜p:ôî¬8Ç?ƒb¤éå¯UœeW9mÐÒ| -ö.­ä,òÃxç9§ÕÔ°Ctß|Ó6ÅÔ8Q±cŒ}Þ*/¤­×ôÆßmK-žU÷“Q/Jå²`7QÐÔÙårÏö8Ûí¨sô…Üàç¡M$j¿äÞs®ê­œâÙüYùVÜX ç¾¾~ò@ú•©Ô%Ò­.&‘¹BŽ€ç7Îù´6¿âÒ<ë Ì‘ß$xøVy"䯙“ñuÄŒm„LB21o­ŒTnÔåóH#¾?”¢´(´ ]U4«°LÜ ùWRh:Æ:]ÙÁß7I÷WJÊ‘ƒÆÛ³Öç  ÜïÝWÜ8Ÿz샂!—ú­G‡‚ ÈÎÜ0åŽç3¡ùS°ð¤ñE$Qðì‹ʰ( ƒ±üß ¨eŠL—‰º2Nr.Ø»çÍÛ¿aWrJ2ØßÍϸ­ÃÂrDÜÑpË/†.§ôiÃÃ7Y%´éßp?¡Q® ñ°&ùÀ²™Ys‡æÛŠ á7/ÈKFNN(«ÁÃ7Ó&Ú#zææ?ÿ; küðéóÃŒì·H:ÿ³ñ…• X™Þ²ª5xLâXr0ŸXûªùxkˆ‰ Ñ\ŒøÝ§ÿŠªxß@Õ4®šòìLªÄ o¤‚AÜ÷*þh³&ÕÄÒe$—–B@¡†bÉÚ¨^ C_Fc©”÷j7’+`¤Ó(æw ñ𧌖ò,Æ»€ÁäÞVæS×ÇzëÇ%½’rDÔí®$Ò¤ „Œæ‡>…~v³ŸR$s+ÙÈVi¹ùNhÝjº[]E îv#¯Ÿûk ‘n™¾9%±^º~¢NÉõFÔ_-ïá;yRÞr ¼DáŒzö¡ÁmzOŸ4¾×ý´Vö‘§ ZN–ðK8!¥Œ1Çœ~"³KÁm¦qôÞÊá ´äžžaëÎÇáŠòk Ãn¼¶ÓG/Õ9Üó¨Ð£»á­l?û²äTí>Î nÖ)­,™[˜y¶êCƒœuÍ-Ú#›ƱŒ˜% ÊT‚„ﺽ´œÁäInpÛuÀÛm3u¤Û=ÝÑhT–”°bO~øûjëE“JÓt SO:=­ì—¨K700?Yqßëñ¥£z I ð\rÛêRC¦Ù#÷î¨ÜKipó©‚U,®@È$çׂ>Úg…lÖÛˆÖp ¦ûUÖ²9n%Ÿxý•¤VÔ;4ï"·Lœ(й̑¨ÎNÄå‡À Ë|°ñd¼KÄ¿C„²éöC³D,I'rIôäý€wQ‡“ îÃNº„·)%»û¼ß¼ÖUĶb"½†3…33oÁ9ù×&98¹E ZL‰m %\‡øÔ¢vÛëzi¥óQAoMp$$2zЪÌ2 ïߊéN)$g}«›oÎnEyõŸíß@Ðü.ewy?ãWú¬ª‹$ÊUOS¿°âª4ËSs/1RbVï&ŠÕ‚¡`¼¬Ç>Ͼ²›**Ç Ê¼ÈŠG†:Ó–Îêùm˜úAÅG…O#òŸXÎÞú€P wxãÙꬹ,k™•¶ÅqÀ©°Ä±BÅñÍ× mЇ fr¤œówzë»·.Þ&,ª£-Ô9ðùÖ‰6K؉3\e#Á‰FÙï?:ëH@tùѶenqe6"&2<ìFI¼Wºwi ã–B-Ý9Kg>qÛï«‹8šÒ©ù³ÄìÇŠÄ‘÷¡ëÈÒ>uì9Ÿô‰è=o¯Ø[ÅsìÊW¹¹ìGAèõÕ¥$rÊÒ 4<ØÁ9zÚ÷ ƒÃsºê6ö»vr¸Î{JÚô»x#UÓ§qßãX”,!ºŠe‹—‘ÃìOmLáìÔƒŸ4Fÿ ÍýÀŒVr«ÌÀ8Á>5ò6…ÁøÔÛaç¤è0|+™Sžð¯\am\y.{c;‰9` ÓjoipKd-O•p› jÉ|ãµhsÙ2Î5i¶ÆÔíÒÝ>¨'á]éÉç±î¯n~»mà>&²{ÍñZz{(牚áÈÞ¸¿>y¤¼¨³0fÆôäRFz8>ÚÖŽ #${àŠ½XÂZBþÚ‚€1\`äÕ¬ã‡8î*Ë'£¿£V¤Ê ÑDŒmL„ŽØîÇ´íVró±À&£ÉËݾMi±Å)[!ªŒn)ø“3(ßÕš‘^üW!E¸êÍ)pV>Oté¡u\©'Î$¹ô…:å‹ù®¤AßQí [u O¨=>5Ø8Ç)>6ãí¬èÒÇ™p;Gp¥‘Ÿ}C˜~\e$äìN;½4ð@K““ÞAù×;½Ð2ÈÍ…ê1M Ѷÿ“mˆ“JÖelï$ô®äaŒ7ÄTˆ@e,¦††D’Ú$ä  ÷9?:Q"v„e­L¸L¬aN|ïoCLE´œÄqKÈ™ëÀ–8îzP–¨‡â?hŠ_ ”g c‘¨öhÉ•AŽêòÍü@”í´€à~« ­¬NèùÜH"!”NÙ2±ã÷öTi$· Ïco·îF*cöQN°»gÃ#¯ïš£¹œ EV2Oº´‹Iœû²Ö ¨Þ&ì­mwí?i¯VáŽÍöÝ{ûCýª‡ì –QÊë ÇJ[ûLo2û}u½&·fMµÂÈN›h}b_ïÕ”z†£ka† DV, Ý€Æé¬ˆ;̵aowm.«"”°Îp3€hÑcR—£ßÃ:˜8å±Ûþá‡ö«ØõQƒ`Ú)lMŸëzjTÒZsYcÜñßšæ&·ur2ys±µá‹¹/DnÖíÚ@ZØüQßo_…y ]´O‰`\ga©ÑöBQ‚€˜Ç…8$‰eUgEæ¡hù oÑ ÀÞ-ä2W—œÄ 6õú«Þ.¹k]^NÒK…Dn@ÎHÍ=ô‹~ÓUæ]}^j.9‚#s/z)ÛcÞº”¢’ØÓ¯’7’F©o;6”à¨Ì­“Œ1ûª›Ê œK$9Ð0Àö|¨£…ÛšöDYŒâ$Tläá¸Å7ÆÒÏe<.²‰9þ2$s·¬zk‰Åk{J_H#ÃúT:¬³‡!Š$˜ÍÊ wú®¾‹ÃÈp[T8ôÆ(ŸƒÀšîÖi¥"|ß“¥ MjÅ@*¼ÄùÀ’7­I{’{.053‘Œ‰#ѧítÝ"xšHmõWE8vúDx_Ió6õª×¶ù¥‡xÆ|¨H¸»Ót(´mÛ‰dƒ› |0sЉ:àÖoê%Ga¦i¶VíWN%‹œ¸\ƒ’1õ:äS¨l˳“Žû…Û¿ô)¥ã@²™”†‚Y"#»•‡Å©°Ø”d(Òj&÷[n‹–Æ<‹gÛnFr™Ö»‚8d’@m ·úFÇ8úž¨6sHïÊGU؃R4û‘øNrPÉË'†Í÷`ÓŠ^Pœ™Á1´l‘Ú0Sõˆ¹ö~…t«0`Y(ÆØúA'Çô}5Â+Ç+¡ ” õÛˆ§%"Hðä¨ÛÛûâªéÐ LA ØFÌËæ ²{ü=¹®e´ì/Ó»+V #dätÎ=;äTë'ŽKŽRŠÅW‘Reµ…ÚÞæP¤ByqË’H9ÜiZkotðô¶wZ ¿iÂ:\ÅA¦ ˆïo4ïéÛ®Ä)Eá TŒ}aýÊã†$/±ÁÈaŽàvùT¹à‘Ÿ!8é¶Õ¬[ª.Ošµ›NÆþxŒa JËÊqßO…pmÇi¥[Ü€ü*›Ê]˜´â«À &%Ýþx§8.b-$ˆªç£¿Ê§*ú¬¤ÛH©’Hܪ:“áÖ¥Ùßè«+H÷KÌwÝOÝPL"KE÷V|Ÿe1lc+é8¥M2}±L¿—TÑܳ§ôOÝ^èèˆyÄcù¹ùT…9v*=ƒhؾH@þMVæ?I}m5µÏ4¶Ì­Ø;ÿsL-å„7-ÍÌHÝÊÇ ×zlb;fÆ7=Ý;‡Ê©šÚ)/ZF@Í#“¹ÛšûÎì›`HžóiË›V$çóq^vºI8ÚNWâÞ.|4 ‘á°¦þ@>ÚÒ™ÁkÑ`’ÚU ¹µrNÁA÷TûçXíù•TÉ8ëT––±›¸ñRŒ÷U¦³Ï0È|ÖqÍž˜Ösåý>ØäÑZ%³'ý.ÌúÜSÆâÄ[r‹»sâµ;LÑtyÊÁœ—žòzŸWº»Ôôí* Û~XåsÕz½ý7©®-GK«/c-1{25º22IŒî¸#4Ü–¶üÇ Hð s<)¸ås“èÎÔ2¢Öô; óÅš[Íý< ûéØÈHÀó†<ýôÂc”ж9¯O.[½ô†J› A';¹Æ|zÓ%®-†rÙõÜxÀ Ù=Ø$ ò äFÝ:Žúh½“ÆcàëÇæ~žü¸RèÒ´øewrÔ°\œ¯«jͼƒ(ƒ‚$V zíãùª>U£ià4å”69@ÜŠÑ‘cŽg,ÀÈîÂ~ûÔVVg>y¿Wnê"Œ2‚Iñð4ÃE¾ë¬Ê6­†&fñQM­³6´až˜QSD`€r[}ÏutÊyAÆ1á@ b•'õQÓ¥%ƒl©ô Ô„ D{òNÕâÄŒ¡²Túè‰VE+™OˆØzH·SÐNà÷Œ^´Dü3NZ) àG_RR‹Ú¶çÍ7¡¿*ßð]ÜP»IÈ;B(ó@$žîíè’â@.#Mˆ'ï¨üPª8gR >‰/xý¦Ÿ5ÜéQ\M¯cvYé ¿Æ \pµ¬òsKµ?É‘GÌÑ Õmºò·ôãþõrukOÿÄûÕ²£) á¨"RÚìçô§Zhp…¦rÖ÷DŸ…LjF¯kžÿ‹÷é~´ÿbÛ§hTP´'ÎLz% ý¦Ÿ^‰,Î(åUí{@@NàŽ¸é諃«Zô{fûÕÏáKn~|ƒ¶?ûÔlJ¿Åæ*£•¼Ð×ÛøW±ðó!Ï!9^]å=ÕiøVÑÿj´†¨„dFóÅ*AE{h ÎŒcÁUå—»ÝN™”ö``cøÓ÷TσBûOÙ].¦{¡_éŸîѰè‚8yCó…PsÜýÕ£ðGÚqœWZž¦–v¼¬œÁ”ãØ3íÅ Pãxÿ´oîV§äbä]ðõìª;;“…,NÅTõÀïÏuLp5*ø³ƒôN»ÓçÒ5ÄÔàÈ’§h„¦ ù¤÷çì ¿(öìÖQJyXî=?áZ÷ðŽ¥¯Od4‹xäž ‹ËÌáG!éÜ ª¼œqèO-ÂÚÇXf=¨$Ÿ:ÉÅÊI¤VÉP䯅už(…ŸFŽúüòv’„Ù‘ÔÕæ¡ä;§¾¸xWNXÞghù®NyI$wliÏ#6óËÅÐXÁwuk¦4m0Jc32‚ÜÄŽ£#÷Ínc†!ïÔõfõÞ?ßWj‰àÃ4ÿ üe†IäÒy€Â݈ÇêÕ€ò!ņ{í4ÔvŽIÿ†¶ákLy׺‘õÞI÷ÔkN±~x¥šõ»'eÝI’ æñßf¦ñ!©­·‘Ýn 2[W¾±Ëº¸!˜Œ€Aîð#ÝQ.<ëÔ¬W­ñ[HVá½w2xxkEýÏ®g?:;1 LÇíüê«æ®·b§¼„lþÊu½nTxD~úц´,o§B}c5èá­mø.ÔúãŸisA©™Õ·’ño(fÖc xDqñ©ëäþÜ«óë1Œàî€Ýãû⛇ô1ø*Ðÿ²Z†4]-Ec]6ÔG2TD¸$`°µ.ÔRà56Sé\/c§KÏ&»nG/)ÉP>5*{ )ÄVún#:¹µg;M-äö² mòÈ@ÈÀû…Áua ëÚq –Ë ;¦X9=>yªÞ ¹MWA2Ç©ÜÜÜ"x‰<ª3œ†ûÿuÉm±ä«»£:u\ã”c­l8VûXnRh ³æäy%—`ruØôÍwm ^ÜÛ‹Ù$gôÜîïýµ¤y6‚Ñ£3§:$îÜ àÙæÖ-¦u$Ò°?ñ̪ƒÄmŸEƒƒñ¯-IÈâé›'ÇÆ¶Qw¦±É°/öW¿JÓ1ÿ7üC÷T¤#<lPíÿc|}µKyÃóÚêsGip·hyê;<cgoÚŸE;Í2àAŸ¦P„#—8®–QÇ«4PYۼǔò®KcëM:‚àÚv~ÌÔyX“æåà|jPlœõÁï¤2¤ÅÀ^ÏbóOq¨úë]ñDTÀüÛ~©©è;žüõ¦5X\DA!£eõä >oü5gžìú­£þõ{ønÓZ÷ˆ"þõ ¤ÃÅ:²‚6§©™„G\µéþpöEþÕ/Ãv¿ÿ°ÿËï¡þÑkÂëœs}˜Z¶;gQþ„Uçá¨F¾öˆ…™~°¯9Á?]}†LTn™½÷Ç÷W‡\‹=oñf‡‹úEpÒc¡jaH#:ì^‡ý²ì×'^ƒ;ÅxÞ@þÅ 4§ÄSÏœŠ51ÐS'Z.smvß?þµ¥ùÔ[SV6Âhhð^Ó'ÎߦÝÕ€<£…ÎA­¿üœfË} vˆÝþ52“ØÕîP‚3$w÷PÒ†ScÃ+ƒì Ï)’j|-wh5M»D\óÞÊÀŽarÛŒgo]êÍͧHÑàù¹ùÖÄk=Åʧš'øµ°ÙÉmßc¬è“ÚÆ½vÃy¿:ú;›ÃzùW„g6É®æ vþk~ÊúŠ9Ñ]*à ƒ¶*ñóFlyš¡@J_Ü(èÁ_Úr> O–¨lØÔ×sÄsì#ûÆ´d’]ÎqM9®ÈÉñ¥ë¦c$æ¢Ýù·?ˆdøìÔÜTSÍHäèRUödàý„Ó|Ùomp\Ólãi—”Ö„Hû>ýjórKo/èJ¾ãæüó]G1~L–’ª}nRW××ãOŒÞ›c½7¢XE;2†ÝëÂÞš´ ò¡cô­2þL™í˜¯ë·Ú|¿×$Àõ[ƾ³ãh‹ÚÃ(ÏšÅv;n3ò¯’õë6±â ÛAgUÏ€9fõ–eq6ÖŸÁ³YÎÒ[k/­‹qýêz~yœ¼ºª»¥­A?Ö¯›ª$k·Jº]7VÇüû9öŠçH§7äáx%@Çá(÷ë‹1ýêòN!Qª¾‹Qýê|iÚ±þœûpš~®X¯Oê¦ÃSŸ»X»3¬=»ÿ^œƒäB¼º´~oBlÆvþ}:ºv®S'\—~þE®E†³Ê¤krîqº/$«¼’|“Ž­tFqÿÊïÔK®¾¹¹YæÖÖIy®Ö{ŽñùõêiúÉÛðãŸæ'Ý]?[.?Ïí‰>ê©‘›‚î$˜M&²¬Ý?Ñ1ý½é³À’‹ƒ0Õ×%yJ›\Œuý:˜Ö:è q½°§Ý^ -{—mpõï‚?ºŠ\¹*«9:¹‹Oõë¦àËA:¤t?Bޮ͖¿Ì¸ÖÉ$úÆ6Ïuvºv¼ÚÑÿÀOºÉÔ3/ ꋎ=}‘:ò­¹Ã;5p}¡Óôï¢4½³FN\¦9‰%‰Æý橎Ÿ¯ôü3ÿÐOººŽÏˆ¹qøhåãû¨à›ä4#d\ú«Õ$~bæÐhµâ/ýµÿüé÷W‹kÄemoÙÓî¦ Ë˜çê©õŠãrÿM²ÄlÞd™åSüšŽm¸„ùðƒÿËÇ÷R– ‚Þ[–Ö¹„HÎA·ŒdN:mÒ”€Ñ¸HÇiùoÍfÀ#,ƯVx€+ÍÍŽ½v=h€.`»á]>âȲÃ$aÔÜrGØjò"Y]ÛŸp]‡Î©²‡ZXÿHgÛšmdO¤);/)ÎAññœ€F;û«¤Üó)$R°£‡ž5 KÃü*#ÝÄÎ@cìºÕ®VÓM¼¼™ G /!ž¾Y²ù`ÐÏЮ½i 4c2tPIô)¦Œ®Iœ› ggÊþ†»®Ÿv7ñÑgñDK¦Ï©Z@ñÆ“‚¾ È söŠ`_©lÆZ9 ?4Ô·˜`‚¬M”ב3V,GuwŒ©`@Lj©O@dîüÃ×¥q#ƒWÇ¡ 9'#G¶ý>úi•° $z:ŠÏ–K•O.ÛSɦÈw÷Q¼¶Iô‰|ÑõÛ»Òkƒj~@G QF`aÓ¤qQßOqp¿¶VÞê HªûË4¹cŸ•0ÛMp3Êi¨lÊÈ6ÇO°üèþK8ù9ˆô ¨ú(]EÔ3Ý@û©Pòiòe¬_ÀÑÉÓYÆê=ÕÃiðö/é¦%±`2Tš>m …y`¨`e‰FÝå[ÂÉ©ö* —FúÄãò¬ÊöIŸ ùÊ}ûV“ä…Ìͯv[ýª_ ®á.ͼˆ{0¥Hèz…ݰåúÙÏJ<•¶+€3Þ~ߣ–DPÛj¦R4&ìÚxOUçÖpOÚkén¸Iø{NŸ˜åí£'~þQöæ¾^ººK-VýæÂŽ~l É'#Ç¥Íå ^áÞЮ!´±hnb‘P8bT£`‚s¹ÜmTHÍ›¿j u¨—r¨ºµ`G×*}Dñ¾y-5)m­Æë¶Ú²69¹n\…Á Šë™Óf#¯Mµ¢ZŽ|Tuñ®žÖ×;ÛÅŸÔÐN£­4­ämjÇ–w\‚;˜ŠoñW³cüáPx¶‰õ$ªÝÊÝÌjªD•@óÁß¶QTs9» O¯ý‰¿¤)Í:éµR;x ì¦TfˆåÆTwzè`Ç1ÿ¥ÙD~LâÆØ»I9³ ˜ïSò¥(ª6ØN4=[þ ý6û¨o‰ÒmU¼º‰$bÊ #œnø$ÖÃØ t¬çËU¸ü Úò6XõÇöªZ-03ñÉ\a-‘HñýÔÅ×4!shŒOý騡C€ù jҪ΀°Q×Äïð¤4ÉÇzY¨ÿl¹Q&âÖ›*ÖÈ£õÉù i£=¢âºpLC+ÞÇaûMl&‚v¿3¯,|Ãî4mäþ_£ê¶ò1ÀIý¢ƒxf ò„î’_nÇåE|(C]FÄl7ôæ¡‚vnó\ÆÌ¬Ìçù¤mAÚË{8\ãœã=|hÁXIjù§|ã#Ƹ¢d‡U™Ia͆ÙIêW‚¬Íxª)#â¶œ3ÝFô(÷ 'Ô®b—É.Ÿs2—6šœ° c#ûšj›‹‚I{ÈÀH#ô‡Î§é¯’®"NÄÊl®í®UN3ç„a¢/ëFrô ý5äo2UQáÈI§¬µo{ ŒGW0¼§=ßn*‰õœ­‰ÄxîøÓ7××NÑ,ÑT!Ë!ÉÇ\ÕÚhŠ~Bï*—_Aã_°µ³’c:°êD€>}ÍAÏ®¾wiWÔ¢‹|¦J$Ö´yö¦iÒdôb«ÙŸ¶3@†4…wçÆ:â©ÉòM²p×Á¥oæŠî×X’iBˆ”)ÏœÊ T\œ7(##Ò+­4óNuj™y  7U»–^Ðncd äöÒŽQÑ‚H=C,õ˜ñJrjòc 6jÐ4gúg“­fÛë5•åµÐv<ÈOüjhŒSøLR~’{êÞð3% cš+Ód2ÚFÇÃöPˆ;у&mTœVfŒ=àöíô Óÿ8Û%Êzâu?Õf¥¢¨6Í(úÈûú¶4Ï“©qD®Ggx²Z¾zbDdk-HÐH·“bàõÛcO•ýÏìC.®Y–ÜÊ„‡‹)ôþ"­|­Û¦£ÃWw1¯2”K¸ýD~Æj©€,–à¼ê¹]ÁSŸ ¿j<gdƒm%£Žï0•þ©cQHÍÜó`ϧ踮Œw8óe°'ÿ˜4X,¢Æüçý£RúXÀçþ›TQV *]–{eÁÅ!ËlļÑSZFÙÿ¦ÕÒÙÄÙOÏ4 æ 0&±ÿÆ5×csÝ-—þ1¢gµˆ³Hשl¤yÄçÐN(BR+¬ý{/üÁ¤ñ]«%‘õ\%[tyO>Iýb=çÐâ'OOÒ4‚ÁtŽèŒö–Cýàצ;¾`[#ê¸4N,¡£Lâºú 8ú§úf˜®­‘ÿx4’;®ù,‡ûÁ¢eÞk{×BÊÇ+LÐ6 îæK/üÁ¯V;¶8 dIèÁ$š$žÂ€ÃÓ5ÄVª%G9$‘¶v ve½‰ÌnÖjÃràƒ^¡ºi,Iÿæ(Ška,ò8Ùƒrõô nK3呹À=ý1é¼ü+ü²iÑI„çʹé¸ÇÙN­²¶ž[³å%~¯\z(®ò%å™°?‰#ãU—1Ó›•qæž”!šgBbÒ­“aˆP`@«TÈMÛ§ª«¬d™-Q *9P®|=U*&šXù Qæîç»o ¤Q%Ÿ•yÆNzcsMÂé$/_çW .C‚cˆÿ´?ux¿I;˜b<À` ØÏ¢ÑŠ“ÿFuBÄ–sQ«ç ±ÉÄ·Ëã4ƒþ&ô_I?âæ£˜£³—¤„íÊÞŠù¿U¸‹ñ¦ð ‘s0 Ÿ¬ÕPäË!6<„õ´ùÊð9ØÊän>U…­äXþ23í¶ù–Fàøž>̯;œ–=yØV™x'ÜIŽÈ€¿œ:ŒwŠö,ê…ˆ=ÕÔ x@È9çÇÛ^Æ× çš2FÃÍ?}bŽ‚l¢<áºü+“._—¡õïP'žtV ÆÜ Ÿ¨sñ¯byØ挟Ô9øÐ+1>1·ñV¤Ëô—9‘ÔžµMy‰3#(ôŒQ7ësYñ-ü-ibܳ9‘²{óõª–ë‰btåšËLaàQ¿½[«£™­È;ãj!òjôÊÕs»#ýŠOÊ©GÚ¨Úf–ê7ßDOuØnø¶Â(ì4ø¹Ë¯w‰ ¶0qßT»šVþVÞ®Ÿ #¶‘Bò¦‡õùD9Û=Õ˜ÑTÀòÕΘØ9Ü÷UQPW©>Ê´ÑÑÚܨS€{ÆÛB </>¥f1æže$øò·Î‹4ìïQ@Ƭlh3…ØÅ©Y‚@Äê§=N>te 4:Œª›°•±á¹&¤·éS+é6åˆ'‘~¡.3ˆ AXe£*Û‡9[C¥rÞidõŒVú+§*åHnã¿z~ xž"R2:ƒŸ`"¬¸S½šË‰mä«&˜óDÊŠ ˜Ù[ÃsŠc^(ö˜¹¶Á¸Ÿ•säè+ñÄ–‡-õ¤ðúÑ“ñ)&Ód¶ÓØÖø‰®`z†«y,.wBÁW¯£º¹¶Ò´äXbææX¹;P޼ \¨\’26¢ŽI"Ó#íùÊéZFƒÓDM¶­†œMmü)Ã×]š³D“Ûs’pà{¥¡),bt1ò¤wm¿uI,sy8,N~‹©)>$d|b ùõ(„nÐáùAôÑ}¨-ƒ¥£ZÞ„d&<ç#qвÐã¶1ò¤—Èøc׊«Ôndžåœ¶s¸ÛÆá£Ÿ¼+zzzk8µgFX=+Ù©ð*dÖtÌä]é³_LH?ûtÅb.Â)%Glm…`>F‹<›^©â*yOšòˆ_ÔþaûÐç[rž´uªÉÍ>©“=„<çÅ£&6þ¨÷м“"lQìÊz?ί8NNmQ´;ýåf\÷\cÞ¿mSÈ Ë"އ÷û* k7Ű.¬Ý@þRÃìæ£†LY_n«ïè|Ÿ¬£Ú+K]D‘›¦öLiï ê'¥Ì‡ý¹¤¸7ƒ¿ç)ô+²6eÑX+Új1Âò½Ì  í´ýP@’‹ù2Àš–Á³7WÃë Ǧºm̸õŠÁ¦¬úlŸøæœ†ÏVg ôÉ7=׋AFí…$—RÇÓÝá]ç|åO¶±§êöËê¹?uyø?Rk«üÇì¢ÐQ¹smùžúèzòÿJ°/‹È¢öà$qPšëQV \ÏŒ÷ÈÔÕGdcb¾Ö¯9ð7ß_8›­K?é3ÿâçéz—ýªüCL(úBReNPê»ä޵â'åÐó©éŸoʾr7:—désä’?Œ5­ù2ÒTYiÚŒòI$ìd$³’1ç @ÐUsop·rM‘o­’FwÏqßá^‹[¹¤Fšh#U9äF$±ôŸ úWoci5ÄŒÊ9³“˱ù¯ÂÖ;˜È\72 Éê7ÇÎ"^¢9bœgþ¾«®k,cr1V:‘”ý?4|*ª;4ÄP€Òa]Æm±ûjD$„Âã“™ºzÍ0¬NRsßOÛàAÊW1øš gP–W dç¦kÙоi ú+ÈÈ õ†~ÊñÜc Œúè@âl· jq‘g/N¹Õó¤ü¬Üñþ¡ö½Äòȹsa˜‘ÿG×¾Š×ÊÔ@uÞÚNÿäšóH*ªÆÀ ¨ÆÈ™ó)òaÄ1Žf¹´Ç¡.ÿÅ[Ç‘[IôžŽÂ~V– X…`2X·çNÌ;¨Âí‡dp@Ò¤‹žâ7•#Ëç0ä© .Ùqó 1RØÜ WŒÃ”ŽR3·¢¡¯d0º…—¿=ÛDhÏ©ÅA£ÀÄR` ©ëLYÜÀ:®·JW3CÙ²ó©ÃzbÝÇe,uö hGÎX5 ¡ò«DW˜ PÏz)ùШÔYŠƒßÓD^\@SµR½ ˆôÿ¹JÎ1·}U³6‘>úýÖå” Ûmè—Éì­åG @V¸ ·¤ó í@ ߸Uÿ’ù\{¡·þÿ÷¸:M…#ë’þhª=‹·á U_¡ÌvôFÇâ*ÒIÕ@\Ôm–ãF¼„oÚ[̘ïÞ6:Õˆù—õV’E‰]Œ© ÐŒÿ…X˜¥gÂFíêRi»Ý3Q–ÙÄz}Û‘¸å…£ÃÓXÚ(úDå@íÛ»jwJvíYÉæñ554uÇ›¡jmê²ü©Ø8gˆÃ‚¼?ª)ôÚ¸ùQh Ú$”ÑÈNé(oqÍhwèTø°?` í;@×ÙŒšEÚ³~”DFš7Ócff‰çǧʑ£ð“si!qžV#à~tß@Æ&8<²}X4ßÉ$ÖSEåWXƒÓáµMâ Y–ÆY^D(P§#»¯·Âš{@N§úªÈ EUðÄ¿Dãíà`sM'Ð|ß^^€ðH0TÐpÔ ƒQ±¸QÚÉnÊÜŠØÜ6FOp¨|%¸)ÅÖfʵks ä±íÔä|=¤ÜªÛª;e¼IÚŠü¤k|9§ñž¡§Áb{Öu’YF© G.¡²7ƇãâÞR«oÀúxð\JûÿHfµ“wf®¥¢ïFæ¸à~'µŒèÜ Û¢J Ÿt†³HÑûwc# ÷¡µ¾âxo¯/,£áÛµ°¸ócI ¬lá[.r¤ ÈõP™ãKxåe+ÃñúVØŸ‹I¦ŒwH »‚7ja#ÏvM^ñÝâGÍk¤èˆGŽŸøƒQWʼT‡HõtØGöiiùþæ‘nC<%usìeQ‰F »½GÚ(‹Ê}«ZH£nIfíã!N1 ?­TéåŠ/-ä1 ¿‹¶vö $ò‘ÅÜKge¡^Xê÷-Õ‚90u,Œ}y\ûjáêÌ瑘G¦Ý»a-®\ÿ&&5>ÏCÖ»U’-#R“}[W?*“'ñ|Ÿ[ˆ/ªLTwâÞ'“w×µê…M/c žÛ‡õö&¦<3jãåF–ÚµyÂÚtcOn-.%FGfáXñùÜÕÙkZ¬ñ+I©Þ?®v?:(áÉ¥»Ð5›y¥yY+•æb~£òŸ²O²…Șj4]L^h¢»>W渌`ÿKÄWz}”¶Zµä·z|K £Ÿšò0yAüï@ÓöÒF°bRwT°wÜ÷ÔçÁŸ Ž?<)!˜ääoIªŒXßΧ¨§–ñÉæDùë”Þ©‹1—'*7b68ÅÙ¢à^K5¬¨Ø  ôb•î­:"€H5&ae1;’TgíùT-IÎTgz"Íuy 3ÉJãÎËz©ÛM^v”à(ÀîÍ døš—`O3žêT0˜j·ÆWÝ]Ç©Nî©•Üâ¨ÕØlw©V Íuëç ( )!¹Ô.%X`Üì\€Nûu>e;}¤Å7%«3·œ"7@º×Ž£ Ï‹Ue¦¢ÖPÎÂ(åe‘ràûòîj3ñ=é]Äf^l™y;n|G6øõxTé:ðåÇu%¹}e§i—lÆH£·^HÕšàòÈù!¹q’ÇÀï$f¼] –Æ9¥Š`yƒÈù<ª¼¬Ü¾¼*äúqÝC–ìÖq˜áŽ&Á×¹XwŒô®#Ö'>sƒõ—”ý”ôüš.£ +Žå÷iŸƒl­\£Yƒ9>k‘Ç£<Ø>€k\à8_ð6š±¡$B_±ÉùÖo¤¸¶†$„óS¦Ã9Ǽ“_Sy±I¢UtW)¥¨@ÙÀfåßì5qŽÔqçœe;ФAm:Iˆilä';„MbÐËŠÒEɇ$än|húýŸšú1oœ©lÂ9 ¨æÝsÞØæÛãÆ®ì`Ó\[ÛÍapf’ç,®ž\àï±ÛûªbÓtÃ(+ÿ=™¦Šu ‚F\íQJ†’mÃH£í3^—µ¼¼“cÏrO½³QáRu 1¶óÇýaB24Há·À oþhÅv"·åÚ8³èAÖ¹ r剻ͿšÜ˜8ë¿…PëE®D1ïßÊ3^[Õ›³B@ušq°FFÃÕ\)ü£÷Š "ë艠ê*¡Gði:¾©¦´æÅ=¯¯kÃÚ„hÀ³[H Ð•"ƒ4Æ×àrs4‡Ä¢•Tf£Éœ•†÷/æc5Ižá° ÊôëßT7']–.QpAôDŸuOá8nã·¸7³v’v›aÆ1ï¢SRÙcNËãçy͹аÛ;U¡‰ N0JœÄ•Â>Ú“C¢œÅFi§!”¢œ×LìN¼`§lñ ˜<½@”›Ö2F¥’#¾süZ•¼(¤GìÎhóü¢Ó“Ê,§ô­âo°•glO/R2|’îá…¥%®£S±V=­¸%aƒŠt¹Öò&ìï!|r°;:ŸEPßȧù+OèRö:¼½9$V÷04 ÁötVüÀóÝN7è9@øSWq¹{;™É,ÎaÎ<=5Ø|K"ø9¦§}ÐõéÿˆV”¨HùêN6âæ<­¯Þ‚< ‡'ñK6ê£ÕvãçUú´fJæ?Ñ•—ÜH¨-‘ŠÍ¶PܼaÄò²q&´ø$y×Ò\ðÖ·¨ÜðÇ4÷×—E §k;1™AÆzlƃ%@·Slç4KäîÞkã¯iÖñf¹ÓcAùÌX^V»»IÍÞŸÛH ,[ë1&´(¼ý;Lvïµ@}kñ4#¥ð—ÛX˜îô© !²9¤A·¾--å‹H±ŠUãWS† LJ¢¥»¼ž8HåP2 ©ÛÑŸ¾ˆuð'Ò.P1SÊvÆûoò¡N‘"¹å‘ÀR„nF3±¢íBêÕ­e^Þ]ÝÇx¤h¸3;èÝC)w*GqÅgif-m™W#’f^§÷î­Bíy—”·…ëüx }IƒméÿH‰ø ùoŒMÄZmö?Ó4›i‰ñ8*ª( ?&ãÑáZ•b&ᮾÆIµ–ÜŸÍÆßñVs!'êì|jŸÕ}–ù+»Tã­09ÂÉ0ˆúŸÌ?cÖmÚÞö{~…ô‚GÊžák™lõÛK¢Ç1ʬ1â0~5må"Ùm8÷X@å7²H¾¦<Ãìj˜ªLÇÉSÂúÖ±uÙGÌ ¸Fq!ï>¯ºŠSÉÚ¼q å~pX²ÄpŸT{vbqü“W^B.†ê–jp¯rº‚ÁíG³ÊÊJ½Ôq¸‹”ýP9¹qÍÝ8I¢1r½Íc‘-«ƒ*¿òkmd'‚Iîææ ØÅlÙÁÎþžƒß\q¼2ÉäÛHyce–Âî{YU† “ÊØ>ÖjÖ#º‰LŒo ™2@Ô2uð;sÝÐxï@¼`°_ðÏ[Ã4r$°Ý‡S‘–æWûYG²µÇ wbË“U*àÆ³ï¯U=ØBZåO¨è%²þ{7¤ ’,·Ñš_ß÷Ú¸Ãëg®à–ëdlÄ«@š1O;³æÛzQ? Ý-jÒèvR«ûà)=‰a.š¶íÍב©ðh²q‚)¡´×ï-ÕYä}Gqöbº‰Â‚A?Μˆ[3çëhLñI(ÁØwÓ€ªNzøU„ºc[\F±73òÜ»2I? ¦’V‰Ìn„0ñëI–Ck,ù>U_~¥ÆÃÆ¥ÇÍ%µ¸¯3…@»Vk†ÀqL8±ýí2Æ2 çÕL€Œ1©V£€*lg}ù"¥é¨Âé[¬Ùör0úq™Ai ¡W錟ˆ÷TÏ£˜S*Ù#*½wôú»½´_lRЩ&ªO1üÓî4u¦ÂÆÉ+m*á‹€RéI|Ôlr7é¿Jêkk‰m¥¶ü¡3KEª m’¤ór탓Ô}RFÙª¢é€ñHˉثs€9™I+Ðäxtø× 6>«{¨¯LàNî6‘µ8×nVW. fÄT]kƒõ .ÚIžòÚpƒ%bg|î¡zzi=ŠÔ™]b¤…X°éŒ.wÎ}•õ“»ÝCOˆ}Ù¤ŽTŽ)$W N0s×쯗t¸Ëß[®ç%kìo%äÛðÆ¡w»Ü4e™bQç9UΤô«ŽÊÉ—Û_$®I¥p@Àz¶ÕÞ¯5…·mco-Ô¼ùegdpwÉR:wcÓÝAë.ÜI!’-bÚÎI䶸I’4,A:)øÄš>PMK…$»+wßòð«†0¹\•>;b†è7jÑ“]ö«$‰2•MÊÃÀŒä{Å;7á 2£,'LNA¦ïç3¹œàg.}g˜Ÿ;¦:ÍŽHÇn§Ý¿Ê³CAèk¦Qˆc$uü¡Ûì¥ Ü2«£ßq—9øSÀ³'˜ÀèÀÇu7nÿÁc#¨9î¢Íä³ÏÉ… ð|)˜ç™»GƼǩøEFŸQ’RËmfÒqÎÇ•~ò=žÚƒ"jóü)-”÷GOS÷SØE¦¡{-­“Lmà) bAq×6ȪFò !8—×7짤áøfEk»ËÛ–;á®ýSCGÑÖQcî¹f#Û«)9xE*9O*7dÄñÕ–­_kB[·Ó-ôÓ²ˆ”“ÍÔç®Ý~Êo éjœ¶ù#¯f?|×Kúc)æ†D'§$®Ÿ1D\›Ý t[ö“àÈçÏ!ÏÆŸ†k£¾a>µ?}PE¥OnÇèz­êЕûP=vOÛS-åÔà–8®ô“(ß:Ð’Õå»ÁoÉ ^Å-ÃD ?¢´Ý¼œàd2’:62=ÜA„Y @ÙóçùG+~<ÄÏ‚Íeéü§*ÍÙ“!IªÔ¿Ê&~,´½Š àçøÇ¬äÄÆ Õ½JqE¤C{‘nÁæ\ƒõ+BDÙ"æ*‡–Sæ‹]YÂýªþJSè+‘F¤J>½íƒ7h×½ø?:æw挰îßÝU¶—\Úe‹àåíaNñ©®ŒîñH¡åHÙMlª„`\ecÅz´8ú—³/°; ¦|‘€(ÏômR^3Õd¶Ó/¦I.]Õ¢·vû†ýj‘xkˆŸêðþ¬ÜdÇõk-H Bênä-*®H>ž•äåq öë)o¤X\ÅÜð±ø]\p?Mw$‰ÃúˆSŒs@ûӊ¼à> â};‹,¯/´‰¡µ\¬®Î€*G¦–¤‚Á½;{gVÁÁÎØ>Š:ágÿѨÀä¸qïùÐî™Á|QkÚ-Õ„q1–º‹ßõ¨«F±¸±Ò&†qnØ8 "·\ìâ›vÀ&à±#jðo4‚0=F´ `R2N¬û…ÉŠñãfwδeR`PNN=´ Õì— ;§aÌFîGÊ…5¡'Ó.••C2+àFÛ|¨×ZN]Bu=Î{¿âKÎË^KnBZ[~§¦# B’±Ž5…钅.öš”áFN|V-ô»Ù+cr|15»ù.K‰ío 7##ò"(ägpOæøÑ§àô{ÛÁú³²ü1M'%°Ÿ|½g¡ë_HŽXô«ÒÁÚñõxQO”®Öõ!†þÓJ»˜ÜÙ[¼œ‘1È•Xzò§jÝšÂ"1ôËöôÉþµF6qËow™Œe“yíÌHωà èÐП´ãK B;û^¾FA^ks#Ç•—´M$DHå%£EÛ9ï>9÷ŸÖZu0ë®……²ô¶_èSPh­M*2˜ì¼¦Iˆék|õš?Îñ©\/¼Aô}r ]¬ƒê6²(å¹C™<Öã8^µ§­”_›jó+™-»)`•mˆåg ÐØM:k{ܹ0eòQ­°óµM?Ö¹r~Ä5&$šŽ?+®i#ÿ‡Ú¿öo ar~¥£‘èM«¿ÁšéfÀzp(Ò½ižKã¶æíx‘wÆÉa#}ÕooÀtNµ›Éqܺy_‹ÖštÛ¿ÎXSõ¥Qó®$±uuŨ>‰”šzQ œÚ¤×‰~£+IÉJ€¹9m‰+’+£¡ÁÌ̶šÉÏžñöf‰-Û£A+ƒ†,¥T‘‚sá×$ÓÆHHúÎÙµ*A§ÍeÏ Kôy ANÈbí9Xàž\dp<å5Ý«Ï;2©8àï«OâFêËN¼ì¤‘ X‘“¿«§ZN2Ûpk(4Õ¢ô´Ä£²‰íËÏÆª$oÊ™yÍZÝŽc";í°¨¢Ö.\…fôªŠ4Þ¹½Òἆò#Ú(.…c'˜€q’r«@ï#»5c}Á7Ö6\=Ä mŸ³™w9P0{÷=øéBÖŽa`Ñ– :eúw|*ãFíuÃm=Ñ‚,s3ªdíèÛ>ú§Fu+ä!á{(ÿ)š%f7~Gu9¯ÁòB‚>Rìë1‘ŸP©|?E–pγÇ~B¬s“¸ÉǾ–¥:¢Œ–op'â+™Éê£ZUdk­2ÜÛ[%¿-ë8`]ç(»8ö1ÍU‹4œÃs FHCÄ¿KP($É ãmÈé¾k8æW7PDGœ‘a€8ß'ühr171Æpòc}og-çÒ&µ‡ƒ;`mŸHñ£F×ôeúúž–=R©ùšù²=gLš5–[ņpïçÛ^6³¢.sv‡Ô ªŽËqG?pêýmfÅ}Dcñ¿…âbFµnsÔ*3߈4EØL[Ô÷S ÄÚJô·©)ØQôƒñß ']YêÄÆš(ü,£kÛ§õBkçÅ:rŒ‹k‚4Ûq}˜ú–rŸY…/QôT¾S¸ms…Ô$õ :‡qåCA# a¨IúÅ@øšùñøÂ?̲#Öãî¦H3Ëh¾×¢þ 7÷ò©§Äz5ËåNø‰7•(Î{.LJ5γXCqÖ0¶‘Y4Óq~ ~¬Pa4&ý¸Må>øíj¿¬Ì~ê‡/”½u¾­Žž¾¤r­X£ñN¨ûsD¾¤¦ˆuFé8¤í´K刋e~ЇÑ?Ô9¼£ñ/mmq†`¼Â$gÙXùÖµ6ØÝ0õ*ÿAž[íé¦s$¸9=q×äj[h½[†x’K6kù-šóÏ3€;ú üßX=¹ê±ð­'‹ïÖùfÓÒÝcx_”K-ÀC‰ó{ÆØÍWG(‡¤Óa;i 'ÒÔ®ÍͰÎÛm_?Óu¹Þ5)rßàöeÑb½½7‚µ­W•ôý%o9³üSç8©ö~N¸.˜^ðÍñ‚#ùa’Àc8ôw|kVò?¨XXØIgywmm'dÑþQÁlìAÛl Ñãñ„ïyw·GÈܱs¨*pëéŸUzÍ7“÷ÿn—Lê+cå›þÕôøDÚ‡ÜZ¡óʬ †};‘EÚ?hñÙYÜ´÷QÏqn’0I( Çœ<»û¨ËË6µg}ÃMe’•YÉRXóƒ¼Åyn¶vº4MwnÓövð„8a–=Ã2}&´èó<ú¯„èéÅÙKÙE ØYÅ5Ôwš„qžS+™ w œmR®8RÛîogÔ#h yƒÈÑì‹€qʾ )ÉÒ[»‡úD$I!(¨²ÄN2Ûm° T’zÙÅ[ÝZܧ ]ÙÜ]À4Ù¢I]üÔY »È 2{ñ]Ž ¬áÖÀóÁ\3¬˜.o/.¢–ãhæE‰åª”Ü`õ¦“¾ R¿ç%-"–E[ä˾ÞnûU÷âÔ·—7Z5ͬö1Cö½»1猻69™{öÁ¨×\sŪI§¤`#@Ò²“,jåˆyÙÔç×µ7è]Éz*¢àh—µÔ»&(²ò=òPÀO›àG¿ÓVšo’¾»¶[›Ifž2Òä8Ûô7éI¸3Uš÷èª#Æ´’`. H剱>Ú=á+Ò´{ ‰"iÈÎcbWÎvoFØjzg&Ìëˆ<žh<1`ºÅªÎ.#š0…¤d°»5²p=ÝÝéO¹ž6ŠG‘UIbyÔ zp[oEy\”~,ÛªVK¸ÆÛŽŒ~TwÂv’Ñ †àÙ°FpKnAá–Sœüj$š‹HßýA&¨j—*'³h£æF d¬wð¦øâC‡!HõƒŸ•TZ$­`ê­ È_Ësl×~œ¾wéxל[q\ ²$æâ™¹˜¶Ä¶O\½••ª5êq(½HËn/çl•LáÕÏZs€ÿÔaP¦9ž 柕Ná×Uâ8²pÐg»hÁrFƒ!›5ÑØõ4Ô³ÇË’$ 2sÊkߤÄà¹ÇòM=”ŸÇF˜‘ Tz g*ŒwÌÞÅ¥ùz^2g%9Š?«zÏ– ÔÝ矺’j‰C&;br= ^öRc—ùµ#èó¶×ùÿ²½ú,‡o¢N}n>êb#öwGr}”» ?ÔÜ‘ôGÇú$¾ÙÝ^7ÿ²Ÿl¢€#4üDãÖeXð’4|S¥¹G\]Ź9üáQ£ú°¹Lá¸> ±s Œ\!È|ž¢š(û6Û?뜰Ǫ«ÍÓ…TK“ú¿}u ̲)ØŒXuROÆú¾›§Ëh·×ëjd˘݋c—?TuúüeáòÛë™õZKýÚ¸ã­8j2éææ%“— ž¼¿pª$áûl•ä ¤ö%òJN&áÑÿ®&>«9)äâÞMÿ ^7ªÍ¾ún.µ+üX¤ü?h"%ÊzŸ¢v%ÅÇœ1ؼ+y}Ím+bÏr¼ÝÃ=rÀTQå ‡Oœ’j¯þâG·§Ó-íx¦ØeѶ۪Ÿ•A¢X¬!Qµ5'è6"Iå G(;mM°?Ôó¨ÇVNOg¦j¯ƒçWhöj¬D “èzW–Ze°‰±Œ6:z¤!ã8ÛêèÚ‰ýiS2ñ|‡êhsŸÖ¸åD¯§À"5÷S/a~ ÷Qõ‚—Y¨0!8xK]V™ÒµÛûÝb;K½:+xÙ[ ®IÎ3V(šâÖ=ÀAUW6ëí¼¨"Mð;аùÔ» %hÎK¢üÑï­N¹ŒÙDÌ@ ‰õ|ë7Ò“òçÏ#Ïa¶À‘F6PÃØÄyuÎwñ©)2…”ÛKÀäx~u“ùK·’ã‡dXл$¨À(Éë­c‰!SnŒS€ÙAÚ ’7I >Œ R|•àùéÆŠæ¦êð}Tºƒìæu÷*&6«Å𦇠ͼšž qkpÀã¼ú(wUå¿<<:ÚKZFÙÈW'lúwœÒjÄËI/,õM+SHm;{xÿ&Øç»níê¾]Þχ&–àzÜ…AüÌœëÀ&­tkUµÒôë @ê dSבwÇØ>ÚòîdÔ¸º->f‚ ËÊHúÎ6Éô þ4—±wšU¶ŸÃs5†¼b›ž¨Nü£ù»ûj”éò,j,Ê#/È ÉÇ\Q.¨­®q(ÒàG[x¥nÔ÷ç¡?f²ž–Â×Uâtë[sžVR£ˆê=ãóG`h‚cœC!ˆå<¹ðÏL°Ó ݃ΓÛ´Å{“û ]_>´­¢Xiæ U”+Èv €vÿu?©ÚO6µi¦XÀö–¶dsL2NÇ¿ÃÛE°l¤ºá‰,ô)nî˜ … ò† töš"Œ8¶-J{ËÃ$’Ccn^ry\à`ÞIÎô%¤4s 'à$»»³n“C=#öCX«ž ŸèÜGfÌ|Ö~Cê#Ràô”ú[jÖsÚħò‰ÊYqÌ3ßT£‚õ˜4™4Ñôa žs!„—Ç_G_]bvº–ª¤©NÞ¹œT‹S]ŠSjó¡RAÄÎw÷ׇøL±GJ—ÉëKø„dø6‰øö(¬ÿö‘Ý[‚Fˆž`I9ÇqÎGøTgà›˜Ÿ–Ýä[9#U¸,„±Æ ÷t’Yk¡-ެÉ纪ä’;úù¦­—Ê'¬E—U€*àmhŸ¿uvô;é±h“¶ÙÃÕåŽyÚàÓímaÓẶµº‚å3v×é‰  uÛn_†žÖíæºàÛûKViä¶·GŽÙÄ 9‘š@ëõ‰¬†O*œh‘uhÙ»€µAò§ãò™ÆNùéAïÕ:û«ºþN.×É¥jÖzÅÝÖ=­ž Ý•³¤",LÎyÌYQ° ʧù«eáÝRêÊ×±Ò®á1F~¼˜&B`RØîÈW8ôA-å#Œ1ÿ=ãýÙ)¶ò—Åào­·²ÝißÈžìÐ¥Ðõë¹®düšò³Ë$®Œ2µÃÄàdï¹ÂŒxb¨|£C<1¥£‹?6î\äs9É9$õ÷Ó¯¡é—¥´–·«Ò‰˜ö˜U<¤m¾ÃŠ©â­&ÓHÐ…¶že]änÑË’{.N§ÑQ¡-ÒÉ9lØÛ]"“Ÿ3ï«>¸„ g9ëê:¬‘¿†ÿèÇά¸Y±¯HÛ[·_e¤Zä,’@:Ä#yã·Ûz‡p? ì:zÔƒ!NÝæ‚‘ùTÐγÅrbª±ÇÐïœC°ð7çÈZ7²!‹*婸זì€g´O麥"$òx¤àöÞÆ}:<žÅЭÁõcï­ <}t?Ïu9ÎÅóÇÝUB3µòym8\D}õèò}gÄþÔýµ¢^åSüàkþý˜>ÊTÀÎdàE#{AÌ%•ì7! †É'¸çáZ$àõäØ~ú©¾(¡‰*0§¯«×N†,s’}8®í_ÀŸÜ|w®%G”åAPR)Y!ë6][|ú¦ÙD}tå°wo•Vò&@ª›Ä²¢·b®räyªXø÷U@»Û& ƒêþêqà—Éc/.1^¿+l* w,G›ktÙð³ð§U®Îë§]œÝ‘V kˆ'é­â]á'û4YlpŠr77­Xj—Z„±é³ªE+gåŒ<}"¯cç;D¤ùT|é&¬D™›"™´ủžðuGº¹§hÏn#'—™®c=q¹ëŽê‹©iÒ4·Ч—ºŒžÿM´:eÃMFvgµM |3SæÔ,ÈódvõBçåUZÌR@è¸ÏCôgîß“Û/6ñǃŸ·éšß#¾¢‘RòBÌ>°>ž€|¨»DºW‰¹UÛ”Žƒ¾³)ë0M-³$h d6çlô¡Û'QpybB§À“EÏv“=Ä2e¹W'ÒñN†‡Í°Ô\&Ɠܤ–| YÉcÅú„2ÆQ»^lâÏ«z Çu}/åNáŽ-Hî[B½p ,¬Ýš²ø1Èïœ ¤«¥ÛÖ¹‘¾êz‰{Ö›§ÇhL‚IŠŒ´¤o‚|=}ÍÃ0µöž¸ýxÁûA®[UáhŽ ÐD¢ß ¯€ÿ‰onncšÊÁ-J¸‘Äi“#Ò=þªwSÖxƒPž m4Éà?8X b¼NÛú¨Þ׈49ïà¶³¾¹žgp¨½¡ IÛÀxÕcp—4Òõ¨ãCõylÍR~/Õ¡X›HºÉÛ:>$žµ"â.:Ô¿=“/`ÊëžDæ#½²Fj|¼«~“Åúrzñ‰÷WpD]º#ñ~$ŒÀr©ç9;xøÑl,‰«èü_¬2›ô¶Ty©ô˜Âƒã³uªÿĽD ½ö“5â“öf¯´ËAesc4 ›iY ;A#>­³MOÙv®’pGL~ÿ ÍÍêÒt,Ë×eT|1ŠIdÖ4ÕHñÎÊìás°è=Ô:ŸiMáb—ŽpNçW\Ehª¬Ã äøzé<ŽØÛöXÊ·óo©@AèÈ«MŒ8£^‘—T½ÛªTF¨ŸF‚)U¥R©ÍÊç˜B{ðÍ¢Á§3. 8ÜÍïä†[‡-sœôQó«I­Jb•€õ>•ª•ȸl÷WÏøZè©Á\„×äŽ@#þQõSÊ.(V=ˆÜäŒ×hAP[_>„‘‚qãŠE#ò™{¨Ûql‘Û\¼@ ÈG!vÇÛƒT±êzÎ7Õ'Ñ;UÏ”Èù¸¶LØå?£@sk×q]M [ÀBHÊ2‡8=hMþÕñ“ªÎ?Û½xou2|íVSë‘G®ê 6·€0׆uNè¢̧¿°²ÎûR½‰C˨»q’ç¯]WË­ k§sèlš“ÆvùÓávOúLÿÚrA8Í °ä'}jÕ¤>ÑRldQÓ˜€ûsz(4æ£~…¥Ñ&p>«·ßC°>’QpQJÌ@; §#ƒä1f>vÀx•qi´îIåjBäò6¤hg¾[¯u+†-nlµ«gkÀ…á¡ £œdc½FÕ‹IÅZó€_^Ô›ιsó­“ü ×›á?£|‡þ:ùèdÄ2:´ö!ò]K­j“Içê7LéJÆ¢Ü^ÏÎCÌ[¼’jÊ.)^ LÄwÓ·ìL×¼‰L·=¨#¨~K´8##uaŸ²´.X±´H6îQY‡©àÝa1ŒI{ûAZXlŠh–Sñe´w:Z£ å[”nž*ãä(],£‰Š¬a½Ô_­‚öÜñŸëQÁµ;iÒ8Ù&r‚ÎWàH¥¦ÝPå%eün­/h¿U‘õoEü.y–Lc ;Ї I•T¡1ìûè—…Û'Oºº|™ Šñs\5OºóùÊ æ­¦¢ÀÁ¨¾–”ÈšóKiÃú„Ñ*sÁH¹POÊ ‹)d .¦ŠÀ@sƒßè«»è~‘§][•µ…ÓÞ¬Wñ¦~Í cnÌdª1-Ý“–ë½ÔZŠÜÛM.¢Uj#H•·mBsŸÑU*ÉxÚâúûFâ;¹ÌÇJÔÓ²b æQÓê7©“qô‘4K•Q†0¨Ç«>Ÿ°{(ôùßP‹‹!”ó4öQÏõ@Ú&_ ‡ÂšÉ²nƒ&ê“3ø#’i–5Éf8uÏ…LM>0X\Jc` à²Æ3“šâH»̤†]ù‡\׈ °Îýþ>4³ áùZÛZ·•N9${G‰øúϗÅ!óžr†ùæ†-À[¸LZ'Ãmu©éS ý'O‰‰þXOÚµQ|Ýî£YÜö+ àÃ¥s¦Ön­ÕÙ¢pr^+¼xóÙΉp¸ðeSŸ~j²¥p@#ÚÔCÇöËo&‘|à´MdÖ§«GÌõî=Ô3o&K(錮OCJIò‹Œ¬´áhø†Ü°ÌfNÉÏv+ðcPõéÇ\1Ö6Åsk3Ãp$F!²´n>Ð*ÃØë·£ÌæTÁÛ †ùÖLèÑM RäŽE噽…ËŽÕ+S~kÇð\(ömQ i æîMˆtÍ7'Ö»î¦ØùÙª$逯¤ uÀ zw®IØmHu42ÓxØ(Æ]G³sVOüy P´ÈÙÚ£<Ò“ì}õ0g´æ œæ‚Xak;Ùðý¢Ýeæó~Ú ç=F:ÔWÕyäoó»±q`=¥P'ÕÒâÊÒÎ5`иË*o YFÒîæ{V•b”.>’# c¦1¹Î7¦e%J؆´¿ÆVsÊz‹%ÎGó©Ž0’CaÉ;NÒ”~v@§IwlE1jÈe¸†Dfn@cÅÐURqƒéؽtç7-½ªA¿òT/å¾KT¶“|ä“ç¨û ê_Òá@$Ÿ7ߺƒ¼™®8råçKò£.ušFˆ!‘¹°1××›×êN4cÕo¥šÞ«Nbóã•.ûnzdùߵਮ`[›K™ ˜*àä`ò‘ìÁ«m^ tžXp«pƒê,Þp8ÎvîÁÍ@àëW¶K€ùó¥zôº\’oL!‘9iòY¿úl£ÃVÜÌ5Â7ó}­÷UC§OëV¼#Ú‹›ÆG~L®J½t.Bˆdʼëæ}µ5YvÆÿmVÜ™DhDÙæe6ÉáN0 ™ùy{”Ó,θÎ/Lýw*Äõ+…]Ví|á‰Üw~‘­×_BÜC1/Íçu x×ÏúÉÿ<^ïÿXëQ!Òå{Ë{éØd¾m·ëéªÃÉÙä[oJÑÝ^Y÷S¡ùSŒÁ¤iå6æœÌVpU™È““Ò´ï,c6—³r?ûb³b¥ŠäaJ B*Žu#Ö+Gò{ËÄ´Ž?áSYõ—e#*–Ç‹b´o&ņµÏ!{y1ž¿Å­ ÚÎQôXv*;êXpW"ƒoµÓ!µQm$¿‘W‘ƒ}AæŒúzôôhñ1ÉrѰv9 ‰ 8B=s´Ô¶#ùz*x ŽF×1Ÿë|ï ­×Ê…Âj>Mï%ku†hnR7Qƒ‚½ýsí¬!Î õÎ*¢íù;]¤_]=<Н‚‰¹·†Yï`¶… K+„EÈ$à}HÔì.m®)Ó‘ãr¸##ohÏ};WB§VhE&jÑ… ˜âm½ GδµcŠÊü‹ùšŽ¢…æ´æÛÑ"ýõ§¡ÛcµTD7©oapA#[Üê>t<ÎÌÌ=#¥^‚Ö— o˜OOÊ~T>°ÈįfÇ#ôk‹©_Q¶. >á·¶y’3îb?µU!UÙgr¿*²áä’ I„‘ºƒ 9*@ÙÔü3P5De»œm+úú“YäÿI2àþ¦UO 5v\ø×P§Ñš9Ža"7¸ƒRb%Ûe5åÚGw;c¹£à(¸-Û¯"‚NF矕\pïn.AºU˱=ÞjÓEp·qï8W§ääAkÅr¸G~*/¸± •»²¸µ>¾R³E Û¥ŠÈl'žF\,R™p˜ÉØÇú|hjÚQmå NžH„¡"²‘–óNëæœ’zmÝXÅ(½Žî¦RÉÓÊüÓ3Û²ÁÜ08=+ÙQíØ,êc,Žm†;Äá­5«U {)Þ=úŒ>Tÿ_\ßè<“¥ XmÄ(c`\…ÊŽo ‡O¾µ“jIxœ²´Üe-Ê­zÝmgQ…–0véãó¦xR籺úƒθn0G£p¾¬nIÂÖ3“”'Þ>B¨´ë¤ƒ‰QÜ€§•ztýÍS9Öé ¿Ê‹'Á!Œÿfo¨JsgÓÞ=´ls˃ÐV“Æ–°ÍÁš¨†áe+ØÜ Ã`ý†²èä Žý┸5ÇÂ,—$†]ñV¼K—·Òî†áíUI(J|UVœlÙd[«‹ˆ'0h‘[¿æ¦Ë;M§Gdìdú3‡ŽNB ¤£›w`¯·š¡ÁÕk2r¯€væ•Øï–4Ӻפ“½sßTŒOsµrYÏ;`W¬1·…7ÎôÀéºájÎÃM’hZ^Á™WÍÍ€µWѺî<+Rò%ÃÒq–§ŒÇ y×3Iééb~oà6òÀû£^,lsÈ&Þ¸¢~ òÅ\UÞéšk}é1ZµÜ§–%’GTQžóÌËÓ5¬yGò1ioÄZqá'-guÉc:1$ÂädÏzà’}#ÓZô_CÓuNà}–+*¾š#ÂÆOòŒÏŸäß[âëvr÷µpe9ÀÉ''z ÐÝáHÑìF$žrÄmŒb¸ú•oo冪bC$±\M\Ê0F1ÁžýN‚%ˆŒ s>výý?azÊ›U\çdçz ¶~Ñb çüXW'O©ç¹°Œ¿Qmø" î®O׫Ž!#¾v8^eûj™ÒnþðÕÿk[ÂwÄ¿!^¡è®K«™•mùCs1#>pi³)daH¦d ¡Š‚ÀûzÓná  èïÛz"ÆÁ}Hók‘·ž>&¾{ÕÎu[³ž³?ÄÖýy)›œg2…û[²¾~Ô›:Éñ•¾&šfØu©Ú þ!#>oΤÛèfm õ/¤¢•Râ2„ä.Ç~îÿE7ÃB¼ä¸sg«“㊘dŒÛ¯f‘åœÿ™4¿þeûb²ùz¶ÿœkHò¡¡Z·–fKö"B{(] Y•ˆ]*ôùÙÚ5V‰D8ä8í¹ðÞ´_%ÄǺ‡0Á1ÿh:߆µ²ñ³iw£'|ÂÃ[¢Û_iœª‰b’ÞL–^aƒŽP3öQhwf£«Ê :ÞHß’nW‘• ªÑ–å÷§Z‹¡kwo)Žº2¤NeÇŽÇ>Ê áÙ£¸á­-åuf6‘’[sžAVVÒÛ£¸.‡ÍH鸬šm–€3²’ÛÉ%ßkÌ&gIœ1%²Ó)ǧãÙXª‚¨K(Éïïñ¯¢¼¡E£Â7–+ykiÉùIœ\:ÏwJÈäá{bN'ÑAy·üªÖÉlD®Á»Ÿ£j—Ý’¿dà·2’?Ǿµ¸¸ ëŒx~êù\ÛÝÁÎñ Ã ;ñשÇ_NhxsGXÙ%âÍ9Pœ¨í¿º´ŽÖ£Ñ4%†×Q[ƉÂ2‰6z¼=•çÿÉ—5,{;ô59(8¯ ’x8†î96r!oÊqöV¤‡j¦‚=21½åVòóžáa·FNfß§ÖæÛÑVñ}ZôpdîAOÚ3åÉ+E² ó„NW>!IùT¹½’”63‘Ö§3*YI\6@ëŽVªÅ6˜Ó.ÖÊ>9•ðÍ I±žàß…™åndyÄàmŸ•GÖ¯¦U’Ý!WBßX #}ë½;\†ÿT·€éÒCÎX2änì ø{iÍJKV’FPË7›Ì ¶Øç;ôÝþŠÆq}º³H:žè¬˜(NÉœ+>Ù=B’7€”eïï§æ(\309ô÷TYäbņqÝêé\HÝ—¶³‚Gœ"}¸ý´Ý·éPk1é9[†~UÊžR|3㟶¼°éÑIŒ7f#®Ùs÷“ñźH9cGúJÈbFsÓq^¦­¬åK’׎x͵+Ñ´ ¬`l±Þ»½4-wôi&Y%œIj‰™ÌßÍ>½ª£]µ¹³ÖïmäR&`3Ѓ¸>ÐA¨–„‰»7$R¤gl©TË,\tiØúsü›užÖ4+ÛK6×PÔÃ³Ý½Ú Õ˜… Ov06ÇÛ@œ^öcÊŒ—QL-í.!íQÁ)” œï……|‰qŸ jÃT¸³3öE~VÃAÎýø8õU§ös þ wvnPã”>G«fyf§‹Ó2è1éêo”Ë»FÉ Êê‰8dDýš†wÌ¿)åóÂþ|x–.׈ìnt§–òC43žSÌÜÙÉwçlzª‚V!Œns¶Êz×I©uj&Zd°#bÀ°šâY-£ÞÍÒFgOÃ|¨@ö¼{«Aœærøê<àûT>e¼žÙmZI¤†<˜Ð±*¤îp;·Þ|¦ZC6·i|ò’óO·Ÿ$õó9~+ARÉJ ’Tï¶q]Lùtù*‘àÕå¶$+ Ær6ùÑþ—kgCdý¢Âö«;„°ì¥`HÍf<ËFË2·:ïÎzü«WÓ¤â¹-óo-&€ã˜ÃãÞI¡rCä{½+DÃjÍoª (Í7qiÃæÖ}Hi·r4L„©¸Áó²Øx®=µ]<€Ù2ä¬}Yi޳é—ÐmK{Q•¾¢¨„· 4°ÔtI£f[‹vˆBË•ÜsnsÓÍÇJΧâ ‰mÃ:IHܪ³£’@Û?[ÛG>N®‘í!C$Q—•y‰9#ÑcöVeÄP‹ Ô¬‡ÕK†clgáTÖÃÇÁ:.%¸Ôc©¥i–üí˘`Áñë½i04™'íÞþã^DR®`#mQÏôYRÏP‚ãf "±R6>ŠÐu[û›éc)1@P¯)hÛÛÒ,z\¦¸2Îæå¦ã)¬xM’#-á•]ذD}w ÷š”<Ÿh#áùõÔ¼mü ò?–)¿ÇHŽÂÉÏ­Åx—3ï# Uiçྀ»J'å_7¬Ó]†5{¨mTˆQÊ ''¨\ÞK©Ú5ØSK0o’s÷Ê/œËy4‡~iýµ¯OªÞ£Êþ3ØZc†44:àVñþNêÚLöbHŒw•Êò9ÿUŒd{kk^á½FSm£ÝÚßðBŠª­ç© ËÓØw®¥-;ž ‹“I¯qTü?¡©ÛªÉ%œFåc“<¬Áå>ÑmUyâ9ø»Vâ>+»‰a¸Ÿé¹!#P¤íß>$Ðgk‰¨ð}呞[­JéÂ29œ zQï‘n„xlÄd繞"÷>üÀ{°@®ŽžNOàÁÃBqaÇÈ-⹸u8P»dà`¡χš}õó½ÄrñFªšŒÖÛ‘ıÇÍ€vÜœœ“_VkÂÎ{+è®<ØÞÖDžáŒçç_XfÜ©ÐöjÛä§àMí4…†XÛG$×b5uFc€síñ¯akl® È'AÀÜ{?sMZ³½Á,q²IÆ52žGyˆÛ?ecà¿!­Ì|ú›`3µ²¹ ß°÷- YèðKα\â .ðúÔY¤öÂÚÍý½¯%ºbI2ôè<6?a«>Y›¯XÕ¶†Hjf”?QÈ-ã|à(Á?ÒðÚ‰´dž8"IЩßñ×âjH‰ŽçŠmÿ›h3^–T¾¿ô²:Fmƒîèk8bQv‰PIÙ#çÎÞ27ÄÕ×Âe´¸a,Š ì0§ê­ ®¹¦[ #¸Ÿ‘ùÛ#òh·&Š}IbbQæb=;ñ«àÒ%¼ºz2ÚHG‡9ëÝ^<æv±î~”ëHê02[Óµ:b„A#?,TÀI“üã.w<ÃÓúUóåärÉ›—¬‡ã_B˾£6OVþõ`RÈÆáŽóÍiÒK¨¥‘³[‡7TÏ·¬÷Tþ…­ïZfŠ9 hΨs‚AÈ;ž”ÎOèý¦¬t¡ŠéÌR<,…\#€Ø;lH89ôP£O`aO”¹µ‹»;Ë[éaŠUHÙ"r¤Ÿ9ºAÙAsëZË»¨ÝÿÖ>ò™lÍô+оk0Œ!ß`¤ç׃@ÏcȽOAM6+#þ¿$¼¸m»ä=hã’MW†5H%g%É@X’FW¯¾ƒD,7=Õ y/R4ûÅaÊïEÀиua=§Ãæó¥´hÄ®ù K˜EyÇôÀÛükÍüdÈrL)ÌLàS·Æ@ Ÿ«¹Î}U"ìã剸+PÑïóGQ‚~ÊÂÉó°3ÔWМeiâf¤Èð–È×Ï.Yeažú´Kçqü‘ÊIÏZÓ´ØÓðŠ¢ŽÜÇcÑæ’}}Mg°<Å?9Ÿ`\žêÒôˆbµžÖÖs'2F‡”à׸g5Ãש<J¶R’Œe/éÿ%åì:zñN‡t ‰|ñH›}Y–Aì`qï«XúU>±K¯ðÅüE ++BåH8,6ŒŽoq«ØÓ *ÿ†¦ºxÙ íGŠ¼Î‹×,¿o@¤B&NÝE(Ä‘·O=~"…šÑVWNvb+N§Ã4Æq§ž]FÐò€Lè6Pç}µ7Z€,Í1xùZ×Ç78;íÔl:Ôhí£ŠâÞ^Õ²“FØ=6`~#‰ Åän¸B=ÌÕ”_ò™i}h«h“²ç~]w}A¸%œ:ššû© T7ÞlxW*7/4•Θ«ž…ÇÚOάµk }C…äƒN³T¼—“¶¹RCg9]ü3¶=½Ùª½ ¹­%£1bš¿áߥÜZµ²•pc„R@¤wÏM«ØétºRôsÃîf+­jöîÜ^r¤°[ y J³oî {*¶v¶Šâ)‘–NS–R6ï÷ŒU¿• i!⛢PÇÎÀœ¶w¡y ܨ }´š§F½ÊZZ.#²p—vÖÎ#æ~Öè;îÅq;_i\1¦%Ê›§Ê"†åT„‘%Œ8÷•*ÃC6²ÀÉbˆH•bhÜž™æ$qû*ÿD{½GGÖø2ñC\"­Ý–Û—]üßKË=”%»‹7ËcÇ,ûÿÑOê Œ(ÇŠ‚j¥ÄÚØ äó/B;ˆÇJ§L£†/œRØ’rwð«ÓG3ê²µÉwåiõá^æC$³ZI 9êLoŒÅA1·åÁ8Åk+ôŸ$Úl§¡j’ÛÿMCü¨.ÃJª[}WƒÁ?‡n„:í£U¨^þý«d†cè“ g@O¤’§Ù‚+ „˜¯REü×ݽl—“Áú]Ø rL}'”ÿdÐLŠ]rÝ-uMBÔƒˆ¦‘=Ì@§ø\£_E0&FˆçùJWâE[qÝ•×ã-÷Ñ£&ÊJ0¹æÊ‚~Òj»J±{F[ÉÌ‘¼R#*rì@ çѵSÜÅÉ&.¸¸Iimg$²v…ÀSÐà }•m¯Ûð½¿ßI«G4ÏvŠÈyª9ñÏ}H†9tÝRâ8 É äïUH⋾²Óæˆ*ÈЈår œ) Šj”“»†./u÷¶Òm¥·å´r¯§Ãz'Ñìß[–ki® ÝBòD sƒ¾þ=*E•¿Ñ%V˜R™Î\øÔ="õtÍråæp†HÆÝAaÛZ,ZñM®Rÿ²±f¬‘^ÿøgæ»ã¥qŠéFH^ó\'ºƒÍ6‹ÉÖ£u!å+ÊAÁ ìÜŸ³Æ±‚rw­k_6¼ÿYb’#ž˜l°{×>ÃY8Z¼\ÿÌ£œú+YàÍ ÅÂV·\d—šWr7Æpª=ßÛY\Q—‘QFKé­¿Bµš6{yß4U' Œf–g±ÉŠ“¶SñÖ³%¶‰xŒÒ2°hÓ çߊ¨Ó<¨ñΟŠ×\`ª?) rQÝ–RqµWqÕи֘Fy£‰™Ô6Ï¿5K•ÜðM=äT²¢9ÁT=iÁ69‡6OÙQ››êöÓwbÉ$„Sälê3oùßÞ¬ä¾r:üëv™Ôjœç'Í÷1¬0@ßë{j‘™#˜ŸÎê‘fÇ™°ÃÝP…³ŸúU§íS±$´ŠsáT¥å;#LÓù6ü°ÿíÖy!~ry»ÍhV04{X¨Ÿ©Y£\FK[¯…$œùø£Ï&ø%à Íç¯Â³¡qè®}”}ä¦Pö÷øVdëíû¨`iš‘jøÛ±_ Ÿ%̹Qs °>Úƒ¡¨5› ÿ øTÔ ’ŒãÑQe¤CâÐ[„õÙê’g¿ï_7I½Éz«èþ!~×D½M÷¶qæšùîÎÏ€j¢LŽô»–´½BŒUÐåXkXÒå–XìÕ¹d`H$¹9nïFõ“OnVá\xƒµja­,ÖÙ£ G€Ò<¡W;÷éé✬Ã4Þ>ÖÚºÅÅV¶Í42É iÊÙö§ ë°÷Žú>žêÊ£Óïlµ=5î/ ÈsÔ2s‚ñ’Ûú«fX $Þk<‘Ó6iŽzà—¢¶HñîÆô9w„¼¸‡›+Œ½M]@D|Ц¡g+j7NœÈÄaI;ï\B´b諹/Ù¼Ì1Ê2«z·âTÄÖûgyAþ’Ÿ¨76ª¬žr‘²³×ᾸµŠK+3q0=9Âç`¬£á$V¥©޼¬À¢¢<ùÆ*Ö3\’OáO`˜úËr®IðÆØõæš¹Òõ†ø6IÜÓÝ_èªüë†^X‹E‘PL­·œžó‘òª%â=WEÕÛè¨?“اœrÄì7õUö“¦jVÆâMQ­?' ·-€T“ßë¡Þ4áë‹û‰5+)9š[3´·i¼˜kðaôk»{•È#ë™ýühÆùÎ+ë> ዽc‡o4´¶‚¹—N@9ƒ;YÄ~Bu?•Õ£ÑÏ»4î‚èÄÌnNpkUŽH¦ò}„âHÚ7=zØ[ÝDöÞAÆGm¬JR0>ú*Ó<–ÚÛi-¦½ÄòÂÛïðéÔÒÕdÝø Mg{}i§ÝÚY›Öq«°u#nò*Ö…¬ÏA¦ªço:Uýµ iqag¬Z½êÀƒc8q’¹>ú²†ÇI/îØú]GÀ ¥-ŒÞ+wFi6‡­»/-½±<£%¥#p1áãRnôíU4¸aX­ŒË#l\òòü=iÝ bø2¶ÑµÇëô‚Æ‚¸ÎÎæÏRì®9]Ê” ¾5ôKÅ¥ Ú{p† ùZÐ4ûûHµ+K fƒ꣪îsïÅut™Ö·.3ËÓ¹ªŠÜÀôíº“2H¯¢æ¥éö²½Ú ]úîkÎiÑïãœu+eŸêWš—[éMÊ#„'rw÷ЈÒlH‹îì„j9س¶:t¨Ëk8*ÇšÓinruÙc—-‚ÏN]E1*y6M·£­Bk…¸œÑ$æeÎ 9 ES[}‡fÇÃsVw1Ï• ¯:¯h ã®Â§,[ª2Ã(¤õGgmeu(bJOiÍ×9?*«Ðd‰¯eYÊ qÍ€zxb®¬Cë—Kks4Vó"`M Ç>ÙŸꤱ²‘&š;B’²å7½µWtF•ôy¡%±–ánV7‰Y¹—#9ë ªON€xz«Í2ÞGYžä” yœoLŸ˜ùÙÕK‚eVJYUFKduÚŸk˜ÚÐ p ™ßÒ}«ÒŒíŸU%…Êaõ±°§dQ¢éZ·<Îü°¡#‘I$ãæzoV#T²Æ× ì„-à™Çäã’NâU $Z]ç&ÒèÊS¦mÁ­Âc«ÙãiÁö¨jöi I9Ÿ òª1kwœ IÉýC]¶•©ÌŒ±é×EˆÛµ'1Ô=‘¢ÖcrˆÛ¦3‘FÜ#t‡mØ smúýv ˆ8GˆÌ[isì;ð h¼#¦ÜYpõ¬–2,¨qƒÕ‰ùâš•Šã಄¡‰8>=i«øÚD`w†žÊÀbÚM³Œ{ExÐ]:¬o0zЛ 6xÕõc2¬‚>„£òlXï©D?ÙŸ¾µH¸jÓ´ynäá ÅK@ÓSýa?ü3NÈÓfO“0[ÎÔãåôFsñ©ù2µÎ[UϪ1Z¯à‹1ÿf)øôû?ô1i`/èm®[Gl“¢v2Ë.GÕÇΨG“æZú/d¶µÅ´±( vò ï WÒÙ³˜''»£pÒd§#C½è>¤«=IF3"Ìdí'+€1þ5¢Iam•ü„¡‰ÀÜzþTÔÚLr7õ’)XÔJý š%Ÿ6yL@ž¨‘ "ñÐw êÖÂæV$™B®yA@}>5ËZêHÀ\Æ1Ü6#Ûé¤YáRi¤…·WX:T~ЗuÒò”Í\ .^×´k­œý`}=1è«3}$ ±´ÛÅÿjšV'8·Eд>º¿}"Êœ±s|ó²ú÷øPÆ™§bæH[’WE˜9útï"Š¸çˆšý?=¡#ó‡ŠSl¶ ÀÁª-´ÓµËKÄvìÄ ;(\ãf3ì®Îš´Ê¹9ºˆi”~Fm5-GIÔñF.ÆOÉÈÃ!¸ƒÜöV«¡2êqrÛ\ÚÉ*=R@ÀgQšãCk¨Û ¥¼io#Úx“ 22§dzé®Y¡»tdžÉб¢:o¾ùÛcÀƒßJyc“ÕÊ*e íÆvÃwŒzÁ$W+¡\­2ŸRˆ%ºOã®nÙK··zs±Y^I[ÒÒ±®Z³}(vMPpY°z¸è³ý1”6<ܨ+§¶‹ô‡ô©“*yXGèèh¡é=›GP kð=r¨¨éºx8mQ?÷œÔÇHÀxÆ|1QäH°BÎG«¥4^ÇBÆ%½z‹9¨7º0Mtîymä#áVocŽf>ªŽð2J²G$ˆêARTúô9ÝE&*ø2+½tèõÙ’ câF¶•‘È’¸ô…Á Ý)¡’ÊîÒ]žSEáÌ9‡Áˆ­ë‹­¤Öté­îï÷xÊ/3ª"“¾yFsè  ôëid:µæŸv­€Š·;žãê«t•!T¯€+‡äú%Ýżªža*OyV }a¹O²·~ º·‹‡m#}1å–$¿åH9]³Œmï M7†øwOâ”Ô®5 -¢”H–Ý«9ìr2:gÑG£‰øj çšcnÓÉÚH–Ñ2'1ï|t¥(ê§EÂ2¦¨Ö,üªÇÅnžÂ -„R7*Àød0}f´I8†öôóI¦ÛÛÐ,j}‡z—Ž´Tl 9½Qšmx÷M©+¯  T¸‡aøÕ/¿5"¥®ZþüãzVq7”PýIØz9@¨SùF¼ËiO®@(¦~ME¯5 opši¯¤Ý½ä€ú…dÓùEœý[!üéI®#ãùd¯lªÞ9$QAKÙ¬É<„ÒîCërj,’Û©Ë ‘g-ä)q´±Œ¸ÜäŽÃóVc¸†VeŽTfV(@`pèúŒ×4ÑiW:Ì’Z^M0fYE!MÅ<¶ÀÇ9\N)RÑlÍ­–£ÙT ÙnXº67gw$’ ç®j¬+£ªÞTÏnÕX ªNïR›aŽ{švÑ994ØYvàõX4íÕGç@I†Ýª£íQa]M7­B¾jöR½²úÔàòqïª,%ÒŽ* ò÷þúÿëRo—û‹÷¿úÔX9‰g¸¤yIÆÅÿ¾¿úÔ4’?*ß_ýj,ĹëJ¥A¾_î§ýõÿÖ¥ß ùv¯ýõÿÖ¢ÁÌKÔÒàg­BQ“µ?ïª7Ëž‰Ÿ÷¿úÔX9‹§ZiéLÝ)þúÿëSI” ß_ýjvbAëK’9¨wKމÿ}õ©CKÜ ÿð¢ÁÌL0y’F®r1ÈÁÅ5]z?:S"gïΑWC<‘êß÷Ѥh†Üdþtÿ1s€Ãó¤,§ø‡çE˜®†$lr‰ °' ÃqÏ­C>¥chÁ..áˆèÌüªíÛ5³7îBóv69'©Æã­-Bæ†Ö òE.qQEwoq M ñÉŒ«#â)|Ôþòþtõ ¢NÔ½©‚UîÀ~4y©ýñùѨ] N 4Š<Äù—ó È€d²þtjBàv(ïM çrþty‰ÇÌ?:,Âè}!ÀlâH‡«Αå9gP=X@] gæ8Œ¬¯(P€ÆXpOçR•j•¶£f" ÜÃÃ7ñŽ›Y0ȹY‡û'4j tÀ£hÇJoš™ûÃó§ù©ýåüè ¢4…6Q*w‘ç`¥Sž)ÌÛŸJ.]ˆŒá•Tº%¤[K@¬7I ò—×ê{~}ªYµâ¶–vìRv÷'°üzSm6ÁšB^Võc×ü°\9Q%½•½¢l† ¹ê{±õ'©¦€>×ß} ‘æ*•fVäœuëMVX€#i ý(¸X¤,m,u$l7‰ŽwméžqŸz¾ L´~TÇ!®O¢'_¯ÿª¤Y(ÉàQp°¢þèãÚ†‰=ü*@r8ïLr0Gµ*ì4Æ£Óò¦€¤´qíC8ÙœóŠ­Öñ2”‘B™e#wÊ#ÔsÀÑp²ì[XÑ”0Ÿjc#…Àö¤…²™õæ¤è98÷¢ádVº™mÕP4ò±®8õ$úÜý=E6+(ß.&”ò]Æ!Ð †ÕEÀ}AŽLÃîÅÔ~xýG¥]WQÜWÛx‚«  íÆ=óýhšÖͼ8#ñ蜒1¿ŽÙ×4JÙÚ¹ûçzwÿ>ôî Óm^ EI¦y›s6é~ð’úáVñƒž0xP¦œýSÓ4\VEtI°>eÿ¾úô³,þS|ËÓû¿ýz™œHÇ4\9L›¨_°å@’uÏËýÐ_žÙýjß•&ìüŸ÷Í6áö…˜ìKÿè?þº·Žô\9Jf ZBK8è½Z_.Dš!¸tnJÕ¼àU=FS° 6ébFJï`¹ü3š.£a¥C6ð|Ó»;{vïèJ 2á†û?ýzG»hmSΑ~RáTûŸéÖ˜-žä«]K½qþ¥Ôúíúj.¨¤@É*²žAQZiŠRìK§ýž¿­A£Á¦˜¶ñ(X¢–TEQ#°­úÑpå)ù)'p Œ}Úz£…wþïÿ^§ašL`Qp²"ÚåHW ÿ»T5U˜ií™÷ÎËÚ¼üÌ?€$þ¦=ª•ÙߪéðÿL~ªýEÆ’&, b ( Òš¶åyߟ¨éV‡¸踬Š6öüÍ—ÏïxïM,Ò:Jv¡1®Gpyýxü*V™¢KÖŒâ@[»\~¦§Ž%ŠŒ…ÉïïEÂÄX›,ƒ=ò)V9— eÝíŠqR .FiZìÜ}®írò•þO˰¸G¨\©$œþ•¥i^0̧¦(Ð~÷sïí1ižòGòçQÄJ8`S==XUÆi]\nÏ`þUrêÝ.me·b@‘ äu m¤=²3æýÙ1Ð0á±øŠ4zÅUóFÕ7'’@ÿ ‹Q…îÑ`ûmÔhX3yj`:®qœÕÚ§¨¨ÙíQ)Àçõ_ñ£@÷ŠQ¥ÄQ,q:ÇŒŒ(öÆ)È÷j<Å$äçÊÿëÖŽÕþíW½"+)ŠðÅJ§ûÇú‘O@÷Š6>ØÑÞà€ìÒ±âbÃùÖ‚JÁpÅØú”Å:ÐDˆ£åU¥Nih'ÌD$ª±ÿ€Õ ZïPŠšm“M3äob¡c÷ °'è+T¨¦•âÒ($÷L@0¢®9%‰9ú^õ^Cruht-¼€þèõ-mÞÕ¦Ê8ÅT:Ñç…¶}[ÿ±§ í!ᥠfWÏû1õüé~—3OÇ_sÇÒ­m`fiw"í/LÐÜ9Š9åC$‚¸Èúuü+DÉsü/ã0·ôj|5ÕÏ e_ütëEº²+@äæ3…$õ^ßáøRÐ-!‚[Õco eÿQqvÿFŒžÿ½?üMXÀõ§ Œ1£@´†FçZ”äôªHŒXbGý*Ç”ÄÞ¿éþh={í9;ƒsŒç¥R3ý“Pmî>ÍrFÖþä1ì=Áõ«BÜŒâFœñŽMDÖ¼lŽ7!à†ä,…¯bÃ0R3Þ«½Â-ì@ž NUªjÆÒu´º™„lGÙåv?ûÿx~£Ü°Öj/"lísœû­½‹‰*È>Z©~ìÓÙÛ  ZA#‚ØùS?+N¸h­#3Ïqä êXã?ãU죒y¤¿œIp߆3É‹œzžhÐ5ì^Y%bNt©¼ÅÝŒóUþÎ ÉfàƒÖœm”œå²zœÑdö')}œçéNc€qUÖÜ©ÀûÔ¦<÷lÿ½EkØV<â©DßñPÜ'o²Dñù*×’G?6ÞªBšã1ÝûÛe xØÇ?ú0Q 'äjR3íPù`6Ð_8Éù'•“Õÿï£O@»ìÄy÷xÄ£ñù›x|™a¸þÛ$ÿt÷ü?Zm¼cκûüJ?‹ý„©%%Gƒ”`A"•_È›Í8Önžï5¹Žv?j„ì— y#£}ÁüjâÄ2>ÿýôhÐ5ì9©zUdíÎä7Sý(°î‰sÍ¿5 •[~•(XØ‘êÔX\Èžhb¸‰ãš5’6à« ƒY£Ú ¨bî¢RŽÁa»‘åzÜu«’É'+.:Ž9ªË$ÿÚ1±7Sž¥øš,5"h´»;gó’ óÏIÈß›f­É÷:w]f¹,Œúâ”™X°1ð:`Ñ`æEµ^Ô¸öªÐùªîÄÏO˜Säg(@BÔQa]ãž¼SW‡qpI%Ošk½Äg!2[{Q`º/â©ê¢H®‘Ì-– 2JÏðèæ•ò<­ p~aJòJW">r?ˆQ`æB‡Whäƒ+¯ AA©F=+ÛÞÃ>û"Š»²`›˜þªG*1íS½þ ‡æÓ7ÔÃ:ŸÈ,ÇtZ¶ÿ‹±ÄÃÿ@J³ÓšÄ²¿»fºh´É[tçïÈ‹ÑU}}ªfþظ[ÚFz´R$#Ðd¿^­Ù®OÛ­ÚÁ‰Ô£uPd4DüË!èO9g‘[`zÕX"ÑlŠQœžycê}MJOî΋25g½M—9¢ŠWb“QL,E*#Øý)Ë™9ÜT)ú“EW!§=(¢‹€­òíÇN”Œ(¢ “L9ã½PmQŸ—“J¤ÔQLSBAE€«§ 0ÌqÖâ_ý …^À4Q@ØÃ0 uì&ý„ØÎ;âŠ)Ü,ÿÙÿàJFIFKKÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ”"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷dà` š2ÊFHà÷æµí&çW»ÓÝ&…ì¡YÖ²]KnØ®É7G˰§æÎAª°øVÓ¼;¦ÛYëèš…Ä®÷&2É:JÏ»znùŸç ’~òúUfw;A5ÍÜØÞYhñC¤\ÝÜ´W1Í?›r·JØðN:eGà؆öI ûD°=¨ç÷2²ÿÇXÖ‹1]yÈ¥ÍQŽñœgjõþ÷J‘.HU/°9³E˜®‹TÂ{Ô2ݪuê Fo# e€ÏAšv ¢wFúRÅŒöª²N1½W>ã4ß9cT " õ,h³ £Bðj¢Ýf5eaÃ|Ã<â¤[¨Ùˆ,¬(³Ñ6sIÉæ£FsûÅüé|豟1:,Ùw$£9úTbh»H¿|X?¼\¼(³dKHG¸‡ŸÞ/çGŸ_1ïª,ÙwTšNAéM7ÏEÿ¾¨ó¢ÿžŠGûÔY‡2îH(?Z§„‰ó¦ý¢~uãÞ‹0æ]É©sÏ óâí"þtñ´ìÙw%t¥¨¾Ñ÷×ó¤1p<Åüè³eÜ›vÚO3Ú£Äz84¾t~¿¥+0æ]ÌË-ÅûÝÿjj±+›x®ŠÄpÈéžçš›ûÍ€]@1Σp?“ÖŠ±*)À硤UŒy¼;¦ìcäÝHqŒÙŽGâþÔYi:|í=½µÚ³Ç°«ÜÉ"c9áYˆÜ ÖÏÃÍ;…ˆ2>C}) â>¸«¤â‹±Y9Æ?vqߥF‚<œÇŒœ–¬·'Þ.;Qp²û¯l})ߺöüª@ƒñ¦¬'’]îKª‚¥²£äÙÏéEÂÈLÅÐýÐ6m£ ÿ»ScÛŠn(¸Y Ø£ÿÕJG§åKšN”\,„¹íùR•Óò§AÍ !¾X?þªBŸçò1Þœ}h¸Y l}(#é¥. 攊."d%x#ò§m'Óò§cš3@XhLz~T›I=p~”ò8ã4£Ž¿ ³§O­íÇåNëÍ'O­a¥X1HÕ%ˆ “ŠyéH„‡éšÃ-¦ŽîÚ+˜$Ia™‘ºôe# Â¥#éUt”Ž-.Þ•V8”ƪ§€ªH©ì*æ9¢áa„˜¤ÚG@*N”ÑEÂÃJœsƒõ¤Ç°§sN€°Ï˜×™>Ÿ­IŒúѶ‹…ˆÈ?å¢ÿßB¤ÅÞDüé‘F¤gh©<µm•¼5®!òÑ?:O´BxóW>™§y)»A…=)è/x`¸ˆŸõ‹Ÿ÷¨óâäyˆqèÔãz U…Iû£4h/xg›8.~µÖ«§Xm[‹¸c‘¹X÷nwÿuFXþª™ui^-9Ì6hvÉ|&CÝaÏÝù ÉÎ.ÚiÖšz°µc,rïÕÜú³Xû“KAëÔ¬|Ad>ì“úcNœ~¥DÚÓIU-®ünìPĪÎÛ†ÌÀŒF;îö­9XG<Õ{’ »±<þúF„àñÊ3ƒù¦?,ƒÞ+7Štˆ®b¶¼¹63Jv¢ÞFЫ·¢¹û5¤ó­†uÈç­$¶ñO Á4i,.6¼n¡•‡¡ƒYVVvZ&¢4û8¦H.£’çÊóKE‹„S÷Cy/SLÜÅÞTÀ÷ ]B媟ø§,a¹Ó„bž‚÷†‰ãÏ2!ú5/ÚaÇúÕüéBƒŠpLQ {Äi„œùˆ>Ó é"ÿßU# Å&ÎÙ£@÷† ˜qŸ1qõ \Eÿ=Wó§`ÿ{éM.Ú[Ÿ¥¼5®ay‹Ÿ­i‡ëSzyÂ)$ð9&•T:†ƒÓŠ4x`º‹§˜¿x‡ñ®~µ!SŽ þ…X21ô£@÷†}¢æ/çN|Sðr?«ÞßC`"W;眕‚ÆùXr@öÉàw£@÷‰LÑžŒ¹úÕy5KÇ%ì Ød¿.½©Ÿc–謗ón#‘m ‘ûÁýxö«QE ²HvBÒ–ƒÔϱÕì–ß|¯ûé@" ûì@ÎßB*×öŘ#tŽ3ÎL2×¼S­ƒ n”3q6pAQOãÎjÐÜ;Ñ jWKûYKî#¯P® ¦æ.~p=³Kq s³E€só¨<þ5—u¦ÌÚ¾Ÿ%¥ýͬq9–摊J˜ÀR ÀËc¦8ž©¦.bÀù×󧋈¿¾)ʧ=³JÛ³€@£A{ÃEÄmÑÇáKæ§÷83tÏ4¿?¥-QŠqÀ¥êj²ÜFåªÿßU*ÜEõ‹­es.äÀ€)¦E’3L70“þµ:¡3Ç,ÄLå‡Y‹™w4‡'Þ²æZíÕÏölR}§þ>dS#ø£zŸ—  Å©]›-"âX¥ rBÅq+‰Ç|3}…Moo …œV¶ó.ÈPFŸ7,r{“ÔŸSE˜ù—sEJ®(@T`éFìæ©«(ÎnäsƒLicˆü’/ÎÝäñE˜¹£Ü¼Ã(Aî* Ø,Vä®ïßG·Ø“Œþ¦¡7”!Àô<š&™<»Þ¶dÏ>ýè³eÜÐÇåU,šŒ²í?"²{ÿÇâJuÅìp[¼¡ƒ²•3Äœø’W·"#xŒ€e˜ N?E˜s.åØÎÜç×Rg'&¨Ç? —wËf•fŽF9”m,Ú=ËàŸJ…gˆ<À_´E¾1E˜sG¹!85ðì3Ö¡ûT~iRàú`ÓLÀ>K/J,Ùw,ž3UÄʹÜÀ;W=Î Çèi±Ü+—ËŽ8ªÍges-¼— ¹ígóâ;ÈÃá—<xcÁ¢Ì9—ró¸hÂdnÈȧÄOÌ;n8ªì#qŸ9˜ ]Fĸú|¦‹0æB_ß >Ñ® O3’(SïJç¢ñì2{UkKm„×—rùú„Ãçq÷c^¢8ý~ly>Ôìn“UÖ®5Ù´³-iièÎï¤äulî·­j¼é·+ÍcæKKA·1É©=j‡Ú .ÞO§*Ìz—öY‹™w$…ÿâeuâqOŒcîû(«DY6÷Œ÷W=1ò8ëÁ⬙äÈn1èauܲÎYÛ€MG`»ÜaœäOAùUinRyÒ&ÈŽ•!âŒÐ!¾X¨nbßí, Ëp}gô©ó“MeÜôù—<ûŠÅvÌ×ëí1À7ÉÏ;Î6Œ}2*µ°V&•¨¥¦ž¯ª²ê7sK3Zg|¿|€®KaUFG¦jù–úåw Ú)þ+ÿï€p?ü(EÀ›­RþдI»5ÔéÖ+l;s€Np½?ˆŠbiñ±)u,÷Xè%“ä#Ý jôH‘D±D‹j0¨ *ìÐÏÐõOí­-o ´¶“ $Š[iˆ/ £*Øã<Çb+Hž§5¥¨Kíh7ûºzÁ ?©­wP "ç’OsNòéÔžÔ ¿=ižMIÆ8  }h¤Ìy¤‡ñyãÞšO§Ò€¹9É&ªjׯ¦iW‰“$qâ$þüò¢þ,@üjàâ±ü@¦k»–MQ ØH¥À 4 nZÒ´ã¥iV–{JÖñiÁvþ&üNM]¿½×­(äÑÖ ÚAÎhÚIþ¦ŸŠ3í@`VÚœclL8öaý)÷· ijÒ"«Ì~Xc'ä?u?Ó5GÝÈ+Ö±G¨yþb‘U®uFŸsyÊcyÃH~ó{à|£êÔ€}½³[@¸’SóI&0]ÏSùôôªŒ '©<š°qM¹æ•&º•N.¹=1ãô­/,uÉÏÖªjÎðé7Ia4Š!ˆ¯Pîv)ü gð£@÷Œí)n%¶šéõ ÝÌó.ÈPü¿u9+ýÅZÐ)m·×-»ˆÓŽwÜ~Uj£‚á‡"(Ð" ÿõˆ+:ž¾ôh˜…'`É#ŸR€vöœ&RrIÿ¾MOåóÔšp\w?B÷ˆDéŽÿ|šFèÜÿ²j|{šnxÑ {Ç/¨ê~!¸¸6úv‘-¤)6×»œÃ!t“y£«zô­v»»lùv± ©8–b>˜TaùÐ+îi¥0:Ñ ý⨖à…ù¡SÆvïÛžëÞ³5u.¹¢ –±îù Æ#Ù‘óÓP1[aO¯åY²ZNÈ´éËBòÅý¨Ð1a}ê^ä¶ØÏêirÅS7— Ž¥bO›ë”«›yïFÒ{Ñ ½âªà6ZâèüÙÆÐÓ…éMDDÜ~ÓzrAù˜œ}8÷«¤u4›r=¨Ð=îæ-Ü2I©¯‘¨^A$–“q¾Ãº<{g4ÍÞZÛ »©ͺ(Ü` ’¯@êp8äH'©'E¹×a\䥤‡8é—Oþ&¥»‚Y"Y-È1ñnèOu>ÄqíÁíKAûÄM%Èc¶xv“ÀkW$ zïõÍ'›v1™mÈÿ¯i§û_Z±o:^[¥ÄDì~Ì0ÊG؃Á R3OA{Å_´\q sÀ׌ý ur³oH•ùuù8ïVˆ=3úR…o_ÒÞ*ý²ï+›47ï[ û|ƒ?;ísÿÏ·þ>­.îøü©yõ¥ ýâ=ûTÀ{ñéT…Ä`¬_Î¥K¨qþ±E˜ù—rÁÀëLgÇcMûL=|Åüꋽ¶ìÖÂ)%uÊ+sÏ qžÔr±sG¹2‚y?­QÕÙLZ¬q¼’[)IQ9/ »¹\¯µq®a q 8>µ¾ÄÄ :E˜s.å¨äŽX’XY^92:œ†SЃéF9éXq‰t© Óadijث°õ&#À?Âp9àŽúPjV—–þd2äUƒ¬ÝXA†‹0æ]ËyÁª×L¿i± É3¶ßcåIý3Q‹±‘X£‚ R¾¹v¸²‘Q—mÇ\zÇ'éœQf˹·ü¨ª"Y2ÏÝÅIÊ}×q»·¸§fÑîZö¬Ûƒö­~ÚÛƒ¤FêNå£|‘ËÌ?—µZšúÚÖÚ[‰åXà‰ ’9èªIü«+G…Nö[ë—i²ÉóĬTö!÷•˜s.æ´Gid'¡ì*Ȫ"uYrXÂ’’Ó;»á¼“ü¨³h÷43ŠKíNK÷\ðÄãŠx½\†"ŽV˹o¨£‘Táœ+È­+1##µNnÔþFŽV˸öÅ0÷¦5Âïß&˜Ó©¯'øUàzVdR¨Öï-͵¸Æ÷¦ÿ½ç¯£ÿß&•˜9.åk™ÊÜ i˜$Øuι>œ?PjÙ½ª½ÏÙï-e¶ ™ r)SÊ‘‚* >ñÊImtÌ×í´¶ÃûÄ9Øý;Î:h³eܾ>´áÅBg_Fÿ¾M'ž¾ÿ|švaÌ»–íÚ—Ò¡[…ÏÝoûäÓ¼õôoÈÒ³eÜ­Œõ©‘~”νªP=)<€Ýy¤ØƒÅ.h ؾ™ ¦}:\ÑŸZbPvëõ¬ëÝ:St·Ö­½èÂÈ~îá» ñÙ‡#ÜdLƒÒ“©  U׬`"=Q_I˜òVð…¿Ý”eéœúW%1Ïö)`™dŒÜ­™ånààÕàH8°õF’âÅeÒ4ç2Ým;íPîýÛžxöÍÐØ”¬™&”FŠ2Yßh‰¬ÏøH4™>[;í ÀK3óèJü«õbI†ô+g߇¦DÇø’Î5? ­'fBçÀ CìÚ¼¨ú¤ik§£]=_{ÊÃfaÆþÈÏRzV»>Ö\îËg4å$¨Èæ™&wÇþ÷o¥ÝÁ9õ§t8$æœ)ØãšaޤŠ6çø?‡ЛImÜž´„í 9=­8.;“L˜‡P€©9äIåàu§Ò‱–¼qY—pý“Ä–Àána{‹>ddÂAÿ±ŒuªúªÞéóÛd.‡lŠ9Fê¬=ÁÁü(Jާš¹npUˆªÚv¢×jÐ\Çäjöˆ éþÚŸâCØ¡Á ÇËp@þ!š.$ ç­{æœ=Å(>´F,ÿmÞGÖøÿ¾¥«ÜúƒTb,5ëå8Ú-­È㟽.jøéÍa˜bzÖn§apnmµ;% {jLY .bo½>¹Ã)<;kW‰éŽ§Ò€)Øjº¬/%¬ÛŒgl±8+$-Œíu<©úÕï\®·äë–·zžMfÞE {l¸ƒaå’g8W 08 fºÄ Qwí»iÈÏ|gµhU íNù½ç@ǯ¿/­±I&NÇ¿LT‚xÇ9çèiªàt©Dy99£@Ô` #KöˆÇsÿ|š—hî1I´zqOA{Ä_hOSÿ|šÖ6vc+Œó€§pF=) ÚÞ+ÆñD[F'¾ æJ…ƒv; ÅM°S]Îh/x©ö—†o˜r0„äUK‹§ûv–¥Y€šI ØsÄL¿û=_ S  îÇ­$–…õ;k‚Å2¡9ÜÆªE4È­µÆñ’26Ÿð«Q¨* ë@P~P(Ð=â§›!¸\³ìñæ­™Ðg;ý~é§ì ¹äŸLÒ©dK@÷ˆÌéŒüß÷Áÿ ¨÷M71'´Õâ=ÏçMÙ¸óÍ=Þ*Ç;¹mņ?Ø?áL’á¥‰Š†ã9]¬ò«á= Å#`›¹ëŠZ¼Qká¸(F)Žr§¿áR-üg…I tÆÃS˜S ãžÙ¤Xˆ•œ1£@ÔO´ UÿïƒHn‚vÉÿ|SšP£Í=ïw^MÜ0¼Ë(š#˜åJ¼dõÁÇ~ã¡ïUëX·t-:¢®~h·”u`Q¾åúVñÑŽ)»ç&ïN¶±®gÓ5HFqÅ©—ñýÙj„ø›KFijË;GÚ-f‡'þ‚´ö“üDSÆïùèÃñ¥ õ9ËOé'\Ô¥Šêc·ˆFl°ß‘À?Þ¢|Anã÷z¬ì;%„ªк¨ýhÒ|Ã}­¾öÃ_àsÙ`‰˜5¦7ËF€Ì“«êRá`ðýÔ-¿{4q§þCgoüwñ¤&ðÕÜÞñÂÉéüï霱<ô¶9ëI¶ž‚÷ˆüЪ–áT`„@›=OûàÓ‡$㎸§m'½ Þ&íå¸ú¡¥óG÷þù§o_Ò­ëFƒÔ…*UázÔKR¯Ý5%ߌ iªwrh=GÒ„è(@*œçÚœb•Š‘»SH¤"”ô¢ úÓ€Á4ƒ¨¥ ðqMsü©çïToý ýÅ0 ?tTâDœ9QÒ¦ô¨GúÃ@=)šSH)€®ÅA#°¨›ï¡îsRI÷éQ·ÞŽÀ&Œ ZZ`1¾îi敾á¤JJ: i§‚šÝin9Å-ÄhíL Ý@Ž÷Õ¯frO©jÕDzô_õw_õõ/þ…Z½…bc¤4§½#JB!ŒŸ=ÇÐÓ®¥0ZÍ*€Y˜g¡ Scÿ‡ú n¡ÿ û¯úäßÈÓi—Oy¥ÚÜÈ<±+°^™ µšÏпäaÿ^ñÿè"¯Ò¹ÿÙlibimager-perl-1.004+dfsg.orig/JPEG/testimg/exiftest.jpg0000755000175000017500000002711112031434614022322 0ustar gregoagregoaÿØÿáßExifII* ’«±1Â×ß(2ç; ûi‡]Imager Development NotesCanonCanoScan LiDE 35CanoScan Toolbox 4.5KK2005:12:06 15:25:39Tony Cookš‚û‚'ˆd0221 ‘’ 3’; ’†’C 0100   ”£¤¤¤ K< 2005:11:25 00:00:002005:12:06 15:25:39‚^ÄPart of notes from reworking i_arc() and friends.R98P‡ÿØÿàJFIF+=ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀx "ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ö©5m> ‘g-ä)q´±Œ¸ÜäŽÃóVc¸†VeŽTfV(@`pèúŒ×4ÑiW:Ì’Z^M0fYE!MÅ<¶ÀÇ9\N)RÑlÍ­–£ÙT ÙnXº67gw$’ ç®j¬+£ªÞTÏnÕX ªNïR›aŽ{švÑ994ØYvàõX4íÕGç@I†Ýª£íQa]M7­B¾jöR½²úÔàòqïª,%ÒŽ* ò÷þúÿëRo—û‹÷¿úÔX9‰g¸¤yIÆÅÿ¾¿úÔ4’?*ß_ýj,ĹëJ¥A¾_î§ýõÿÖ¥ß ùv¯ýõÿÖ¢ÁÌKÔÒàg­BQ“µ?ïª7Ëž‰Ÿ÷¿úÔX9‹§ZiéLÝ)þúÿëSI” ß_ýjvbAëK’9¨wKމÿ}õ©CKÜ ÿð¢ÁÌL0y’F®r1ÈÁÅ5]z?:S"gïΑWC<‘êß÷Ѥh†Üdþtÿ1s€Ãó¤,§ø‡çE˜®†$lr‰ °' ÃqÏ­C>¥chÁ..áˆèÌüªíÛ5³7îBóv69'©Æã­-Bæ†Ö òE.qQEwoq M ñÉŒ«#â)|Ôþòþtõ ¢NÔ½©‚UîÀ~4y©ýñùѨ] N 4Š<Äù—ó È€d²þtjBàv(ïM çrþty‰ÇÌ?:,Âè}!ÀlâH‡«Αå9gP=X@] gæ8Œ¬¯(P€ÆXpOçR•j•¶£f" ÜÃÃ7ñŽ›Y0ȹY‡û'4j tÀ£hÇJoš™ûÃó§ù©ýåüè ¢4…6Q*w‘ç`¥Sž)ÌÛŸJ.]ˆŒá•Tº%¤[K@¬7I ò—×ê{~}ªYµâ¶–vìRv÷'°üzSm6ÁšB^Võc×ü°\9Q%½•½¢l† ¹ê{±õ'©¦€>×ß} ‘æ*•fVäœuëMVX€#i ý(¸X¤,m,u$l7‰ŽwméžqŸz¾ L´~TÇ!®O¢'_¯ÿª¤Y(ÉàQp°¢þèãÚ†‰=ü*@r8ïLr0Gµ*ì4Æ£Óò¦€¤´qíC8ÙœóŠ­Öñ2”‘B™e#wÊ#ÔsÀÑp²ì[XÑ”0Ÿjc#…Àö¤…²™õæ¤è98÷¢ádVº™mÕP4ò±®8õ$úÜý=E6+(ß.&”ò]Æ!Ð †ÕEÀ}AŽLÃîÅÔ~xýG¥]WQÜWÛx‚«  íÆ=óýhšÖͼ8#ñ蜒1¿ŽÙ×4JÙÚ¹ûçzwÿ>ôî Óm^ EI¦y›s6é~ð’úáVñƒž0xP¦œýSÓ4\VEtI°>eÿ¾úô³,þS|ËÓû¿ýz™œHÇ4\9L›¨_°å@’uÏËýÐ_žÙýjß•&ìüŸ÷Í6áö…˜ìKÿè?þº·Žô\9Jf ZBK8è½Z_.Dš!¸tnJÕ¼àU=FS° 6ébFJï`¹ü3š.£a¥C6ð|Ó»;{vïèJ 2á†û?ýzG»hmSΑ~RáTûŸéÖ˜-žä«]K½qþ¥Ôúíúj.¨¤@É*²žAQZiŠRìK§ýž¿­A£Á¦˜¶ñ(X¢–TEQ#°­úÑpå)ù)'p Œ}Úz£…wþïÿ^§ašL`Qp²"ÚåHW ÿ»T5U˜ií™÷ÎËÚ¼üÌ?€$þ¦=ª•ÙߪéðÿL~ªýEÆ’&, b ( Òš¶åyߟ¨éV‡¸踬Š6öüÍ—ÏïxïM,Ò:Jv¡1®Gpyýxü*V™¢KÖŒâ@[»\~¦§Ž%ŠŒ…ÉïïEÂÄX›,ƒ=ò)V9— eÝíŠqR .FiZìÜ}®írò•þO˰¸G¨\©$œþ•¥i^0̧¦(Ð~÷sïí1ižòGòçQÄJ8`S==XUÆi]\nÏ`þUrêÝ.me·b@‘ äu m¤=²3æýÙ1Ð0á±øŠ4zÅUóFÕ7'’@ÿ ‹Q…îÑ`ûmÔhX3yj`:®qœÕÚ§¨¨ÙíQ)Àçõ_ñ£@÷ŠQ¥ÄQ,q:ÇŒŒ(öÆ)È÷j<Å$äçÊÿëÖŽÕþíW½"+)ŠðÅJ§ûÇú‘O@÷Š6>ØÑÞà€ìÒ±âbÃùÖ‚JÁpÅØú”Å:ÐDˆ£åU¥Nih'ÌD$ª±ÿ€Õ ZïPŠšm“M3äob¡c÷ °'è+T¨¦•âÒ($÷L@0¢®9%‰9ú^õ^Cruht-¼€þèõ-mÞÕ¦Ê8ÅT:Ñç…¶}[ÿ±§ í!ᥠfWÏû1õüé~—3OÇ_sÇÒ­m`fiw"í/LÐÜ9Š9åC$‚¸Èúuü+DÉsü/ã0·ôj|5ÕÏ e_ütëEº²+@äæ3…$õ^ßáøRÐ-!‚[Õco eÿQqvÿFŒžÿ½?üMXÀõ§ Œ1£@´†FçZ”äôªHŒXbGý*Ç”ÄÞ¿éþh={í9;ƒsŒç¥R3ý“Pmî>ÍrFÖþä1ì=Áõ«BÜŒâFœñŽMDÖ¼lŽ7!à†ä,…¯bÃ0R3Þ«½Â-ì@ž NUªjÆÒu´º™„lGÙåv?ûÿx~£Ü°Öj/"lísœû­½‹‰*È>Z©~ìÓÙÛ  ZA#‚ØùS?+N¸h­#3Ïqä êXã?ãU죒y¤¿œIp߆3É‹œzžhÐ5ì^Y%bNt©¼ÅÝŒóUþÎ ÉfàƒÖœm”œå²zœÑdö')}œçéNc€qUÖÜ©ÀûÔ¦<÷lÿ½EkØV<â©DßñPÜ'o²Dñù*×’G?6ÞªBšã1ÝûÛe xØÇ?ú0Q 'äjR3íPù`6Ð_8Éù'•“Õÿï£O@»ìÄy÷xÄ£ñù›x|™a¸þÛ$ÿt÷ü?Zm¼cκûüJ?‹ý„©%%Gƒ”`A"•_È›Í8Önžï5¹Žv?j„ì— y#£}ÁüjâÄ2>ÿýôhÐ5ì9©zUdíÎä7Sý(°î‰sÍ¿5 •[~•(XØ‘êÔX\Èžhb¸‰ãš5’6à« ƒY£Ú ¨bî¢RŽÁa»‘åzÜu«’É'+.:Ž9ªË$ÿÚ1±7Sž¥øš,5"h´»;gó’ óÏIÈß›f­É÷:w]f¹,Œúâ”™X°1ð:`Ñ`æEµ^Ô¸öªÐùªîÄÏO˜Säg(@BÔQa]ãž¼SW‡qpI%Ošk½Äg!2[{Q`º/â©ê¢H®‘Ì-– 2JÏðèæ•ò<­ p~aJòJW">r?ˆQ`æB‡Whäƒ+¯ AA©F=+ÛÞÃ>û"Š»²`›˜þªG*1íS½þ ‡æÓ7ÔÃ:ŸÈ,ÇtZ¶ÿ‹±ÄÃÿ@J³ÓšÄ²¿»fºh´É[tçïÈ‹ÑU}}ªfþظ[ÚFz´R$#Ðd¿^­Ù®OÛ­ÚÁ‰Ô£uPd4DüË!èO9g‘[`zÕX"ÑlŠQœžycê}MJOî΋25g½M—9¢ŠWb“QL,E*#Øý)Ë™9ÜT)ú“EW!§=(¢‹€­òíÇN”Œ(¢ “L9ã½PmQŸ—“J¤ÔQLSBAE€«§ 0ÌqÖâ_ý …^À4Q@ØÃ0 uì&ý„ØÎ;âŠ)Ü,ÿÙÿàJFIFKKÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ”"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷dà` š2ÊFHà÷æµí&çW»ÓÝ&…ì¡YÖ²]KnØ®É7G˰§æÎAª°øVÓ¼;¦ÛYëèš…Ä®÷&2É:JÏ»znùŸç ’~òúUfw;A5ÍÜØÞYhñC¤\ÝÜ´W1Í?›r·JØðN:eGà؆öI ûD°=¨ç÷2²ÿÇXÖ‹1]yÈ¥ÍQŽñœgjõþ÷J‘.HU/°9³E˜®‹TÂ{Ô2ݪuê Fo# e€ÏAšv ¢wFúRÅŒöª²N1½W>ã4ß9cT " õ,h³ £Bðj¢Ýf5eaÃ|Ã<â¤[¨Ùˆ,¬(³Ñ6sIÉæ£FsûÅüé|豟1:,Ùw$£9úTbh»H¿|X?¼\¼(³dKHG¸‡ŸÞ/çGŸ_1ïª,ÙwTšNAéM7ÏEÿ¾¨ó¢ÿžŠGûÔY‡2îH(?Z§„‰ó¦ý¢~uãÞ‹0æ]É©sÏ óâí"þtñ´ìÙw%t¥¨¾Ñ÷×ó¤1p<Åüè³eÜ›vÚO3Ú£Äz84¾t~¿¥+0æ]ÌË-ÅûÝÿjj±+›x®ŠÄpÈéžçš›ûÍ€]@1Σp?“ÖŠ±*)À硤UŒy¼;¦ìcäÝHqŒÙŽGâþÔYi:|í=½µÚ³Ç°«ÜÉ"c9áYˆÜ ÖÏÃÍ;…ˆ2>C}) â>¸«¤â‹±Y9Æ?vqߥF‚<œÇŒœ–¬·'Þ.;Qp²û¯l})ߺöüª@ƒñ¦¬'’]îKª‚¥²£äÙÏéEÂÈLÅÐýÐ6m£ ÿ»ScÛŠn(¸Y Ø£ÿÕJG§åKšN”\,„¹íùR•Óò§AÍ !¾X?þªBŸçò1Þœ}h¸Y l}(#é¥. 攊."d%x#ò§m'Óò§cš3@XhLz~T›I=p~”ò8ã4£Ž¿ ³§O­íÇåNëÍ'O­a¥X1HÕ%ˆ “ŠyéH„‡éšÃ-¦ŽîÚ+˜$Ia™‘ºôe# Â¥#éUt”Ž-.Þ•V8”ƪ§€ªH©ì*æ9¢áa„˜¤ÚG@*N”ÑEÂÃJœsƒõ¤Ç°§sN€°Ï˜×™>Ÿ­IŒúѶ‹…ˆÈ?å¢ÿßB¤ÅÞDüé‘F¤gh©<µm•¼5®!òÑ?:O´BxóW>™§y)»A…=)è/x`¸ˆŸõ‹Ÿ÷¨óâäyˆqèÔãz U…Iû£4h/xg›8.~µÖ«§Xm[‹¸c‘¹X÷nwÿuFXþª™ui^-9Ì6hvÉ|&CÝaÏÝù ÉÎ.ÚiÖšz°µc,rïÕÜú³Xû“KAëÔ¬|Ad>ì“úcNœ~¥DÚÓIU-®ünìPĪÎÛ†ÌÀŒF;îö­9XG<Õ{’ »±<þúF„àñÊ3ƒù¦?,ƒÞ+7Štˆ®b¶¼¹63Jv¢ÞFЫ·¢¹û5¤ó­†uÈç­$¶ñO Á4i,.6¼n¡•‡¡ƒYVVvZ&¢4û8¦H.£’çÊóKE‹„S÷Cy/SLÜÅÞTÀ÷ ]B媟ø§,a¹Ó„bž‚÷†‰ãÏ2!ú5/ÚaÇúÕüéBƒŠpLQ {Äi„œùˆ>Ó é"ÿßU# Å&ÎÙ£@÷† ˜qŸ1qõ \Eÿ=Wó§`ÿ{éM.Ú[Ÿ¥¼5®ay‹Ÿ­i‡ëSzyÂ)$ð9&•T:†ƒÓŠ4x`º‹§˜¿x‡ñ®~µ!SŽ þ…X21ô£@÷†}¢æ/çN|Sðr?«ÞßC`"W;眕‚ÆùXr@öÉàw£@÷‰LÑžŒ¹úÕy5KÇ%ì Ød¿.½©Ÿc–謗ón#‘m ‘ûÁýxö«QE ²HvBÒ–ƒÔϱÕì–ß|¯ûé@" ûì@ÎßB*×öŘ#tŽ3ÎL2×¼S­ƒ n”3q6pAQOãÎjÐÜ;Ñ jWKûYKî#¯P® ¦æ.~p=³Kq s³E€só¨<þ5—u¦ÌÚ¾Ÿ%¥ýͬq9–摊J˜ÀR ÀËc¦8ž©¦.bÀù×󧋈¿¾)ʧ=³JÛ³€@£A{ÃEÄmÑÇáKæ§÷83tÏ4¿?¥-QŠqÀ¥êj²ÜFåªÿßU*ÜEõ‹­es.äÀ€)¦E’3L70“þµ:¡3Ç,ÄLå‡Y‹™w4‡'Þ²æZíÕÏölR}§þ>dS#ø£zŸ—  Å©]›-"âX¥ rBÅq+‰Ç|3}…Moo …œV¶ó.ÈPFŸ7,r{“ÔŸSE˜ù—sEJ®(@T`éFìæ©«(ÎnäsƒLicˆü’/ÎÝäñE˜¹£Ü¼Ã(Aî* Ø,Vä®ïßG·Ø“Œþ¦¡7”!Àô<š&™<»Þ¶dÏ>ýè³eÜÐÇåU,šŒ²í?"²{ÿÇâJuÅìp[¼¡ƒ²•3Äœø’W·"#xŒ€e˜ N?E˜s.åØÎÜç×Rg'&¨Ç? —wËf•fŽF9”m,Ú=ËàŸJ…gˆ<À_´E¾1E˜sG¹!85ðì3Ö¡ûT~iRàú`ÓLÀ>K/J,Ùw,ž3UÄʹÜÀ;W=Î Çèi±Ü+—ËŽ8ªÍges-¼— ¹ígóâ;ÈÃá—<xcÁ¢Ì9—ró¸hÂdnÈȧÄOÌ;n8ªì#qŸ9˜ ]Fĸú|¦‹0æB_ß >Ñ® O3’(SïJç¢ñì2{UkKm„×—rùú„Ãçq÷c^¢8ý~ly>Ôìn“UÖ®5Ù´³-iièÎï¤äulî·­j¼é·+ÍcæKKA·1É©=j‡Ú .ÞO§*Ìz—öY‹™w$…ÿâeuâqOŒcîû(«DY6÷Œ÷W=1ò8ëÁ⬙äÈn1èauܲÎYÛ€MG`»ÜaœäOAùUinRyÒ&ÈŽ•!âŒÐ!¾X¨nbßí, Ëp}gô©ó“MeÜôù—<ûŠÅvÌ×ëí1À7ÉÏ;Î6Œ}2*µ°V&•¨¥¦ž¯ª²ê7sK3Zg|¿|€®KaUFG¦jù–úåw Ú)þ+ÿï€p?ü(EÀ›­RþдI»5ÔéÖ+l;s€Np½?ˆŠbiñ±)u,÷Xè%“ä#Ý jôH‘D±D‹j0¨ *ìÐÏÐõOí­-o ´¶“ $Š[iˆ/ £*Øã<Çb+Hž§5¥¨Kíh7ûºzÁ ?©­wP "ç’OsNòéÔžÔ ¿=ižMIÆ8  }h¤Ìy¤‡ñyãÞšO§Ò€¹9É&ªjׯ¦iW‰“$qâ$þüò¢þ,@üjàâ±ü@¦k»–MQ ØH¥À 4 nZÒ´ã¥iV–{JÖñiÁvþ&üNM]¿½×­(äÑÖ ÚAÎhÚIþ¦ŸŠ3í@`VÚœclL8öaý)÷· ijÒ"«Ì~Xc'ä?u?Ó5GÝÈ+Ö±G¨yþb‘U®uFŸsyÊcyÃH~ó{à|£êÔ€}½³[@¸’SóI&0]ÏSùôôªŒ '©<š°qM¹æ•&º•N.¹=1ãô­/,uÉÏÖªjÎðé7Ia4Š!ˆ¯Pîv)ü gð£@÷Œí)n%¶šéõ ÝÌó.ÈPü¿u9+ýÅZÐ)m·×-»ˆÓŽwÜ~Uj£‚á‡"(Ð" ÿõˆ+:ž¾ôh˜…'`É#ŸR€vöœ&RrIÿ¾MOåóÔšp\w?B÷ˆDéŽÿ|šFèÜÿ²j|{šnxÑ {Ç/¨ê~!¸¸6úv‘-¤)6×»œÃ!t“y£«zô­v»»lùv± ©8–b>˜TaùÐ+îi¥0:Ñ ý⨖à…ù¡SÆvïÛžëÞ³5u.¹¢ –±îù Æ#Ù‘óÓP1[aO¯åY²ZNÈ´éËBòÅý¨Ð1a}ê^ä¶ØÏêirÅS7— Ž¥bO›ë”«›yïFÒ{Ñ ½âªà6ZâèüÙÆÐÓ…éMDDÜ~ÓzrAù˜œ}8÷«¤u4›r=¨Ð=îæ-Ü2I©¯‘¨^A$–“q¾Ãº<{g4ÍÞZÛ »©ͺ(Ü` ’¯@êp8äH'©'E¹×a\䥤‡8é—Oþ&¥»‚Y"Y-È1ñnèOu>ÄqíÁíKAûÄM%Èc¶xv“ÀkW$ zïõÍ'›v1™mÈÿ¯i§û_Z±o:^[¥ÄDì~Ì0ÊG؃Á R3OA{Å_´\q sÀ׌ý ur³oH•ùuù8ïVˆ=3úR…o_ÒÞ*ý²ï+›47ï[ û|ƒ?;ísÿÏ·þ>­.îøü©yõ¥ ýâ=ûTÀ{ñéT…Ä`¬_Î¥K¨qþ±E˜ù—rÁÀëLgÇcMûL=|Åüꋽ¶ìÖÂ)%uÊ+sÏ qžÔr±sG¹2‚y?­QÕÙLZ¬q¼’[)IQ9/ »¹\¯µq®a q 8>µ¾ÄÄ :E˜s.å¨äŽX’XY^92:œ†SЃéF9éXq‰t© Óadijث°õ&#À?Âp9àŽúPjV—–þd2äUƒ¬ÝXA†‹0æ]ËyÁª×L¿i± É3¶ßcåIý3Q‹±‘X£‚ R¾¹v¸²‘Q—mÇ\zÇ'éœQf˹·ü¨ª"Y2ÏÝÅIÊ}×q»·¸§fÑîZö¬Ûƒö­~ÚÛƒ¤FêNå£|‘ËÌ?—µZšúÚÖÚ[‰åXà‰ ’9èªIü«+G…Nö[ë—i²ÉóĬTö!÷•˜s.æ´Gid'¡ì*Ȫ"uYrXÂ’’Ó;»á¼“ü¨³h÷43ŠKíNK÷\ðÄãŠx½\†"ŽV˹o¨£‘Táœ+È­+1##µNnÔþFŽV˸öÅ0÷¦5Âïß&˜Ó©¯'øUàzVdR¨Öï-͵¸Æ÷¦ÿ½ç¯£ÿß&•˜9.åk™ÊÜ i˜$Øuι>œ?PjÙ½ª½ÏÙï-e¶ ™ r)SÊ‘‚* >ñÊImtÌ×í´¶ÃûÄ9Øý;Î:h³eܾ>´áÅBg_Fÿ¾M'ž¾ÿ|švaÌ»–íÚ—Ò¡[…ÏÝoûäÓ¼õôoÈÒ³eÜ­Œõ©‘~”νªP=)<€Ýy¤ØƒÅ.h ؾ™ ¦}:\ÑŸZbPvëõ¬ëÝ:St·Ö­½èÂÈ~îá» ñÙ‡#ÜdLƒÒ“©  U׬`"=Q_I˜òVð…¿Ý”eéœúW%1Ïö)`™dŒÜ­™ånààÕàH8°õF’âÅeÒ4ç2Ým;íPîýÛžxöÍÐØ”¬™&”FŠ2Yßh‰¬ÏøH4™>[;í ÀK3óèJü«õbI†ô+g߇¦DÇø’Î5? ­'fBçÀ CìÚ¼¨ú¤ik§£]=_{ÊÃfaÆþÈÏRzV»>Ö\îËg4å$¨Èæ™&wÇþ÷o¥ÝÁ9õ§t8$æœ)ØãšaޤŠ6çø?‡ЛImÜž´„í 9=­8.;“L˜‡P€©9äIåàu§Ò‱–¼qY—pý“Ä–Àána{‹>ddÂAÿ±ŒuªúªÞéóÛd.‡lŠ9Fê¬=ÁÁü(Jާš¹npUˆªÚv¢×jÐ\Çäjöˆ éþÚŸâCØ¡Á ÇËp@þ!š.$ ç­{æœ=Å(>´F,ÿmÞGÖøÿ¾¥«ÜúƒTb,5ëå8Ú-­È㟽.jøéÍa˜bzÖn§apnmµ;% {jLY .bo½>¹Ã)<;kW‰éŽ§Ò€)Øjº¬/%¬ÛŒgl±8+$-Œíu<©úÕï\®·äë–·zžMfÞE {l¸ƒaå’g8W 08 fºÄ Qwí»iÈÏ|gµhU íNù½ç@ǯ¿/­±I&NÇ¿LT‚xÇ9çèiªàt©Dy99£@Ô` #KöˆÇsÿ|š—hî1I´zqOA{Ä_hOSÿ|šÖ6vc+Œó€§pF=) ÚÞ+ÆñD[F'¾ æJ…ƒv; ÅM°S]Îh/x©ö—†o˜r0„äUK‹§ûv–¥Y€šI ØsÄL¿û=_ S  îÇ­$–…õ;k‚Å2¡9ÜÆªE4È­µÆñ’26Ÿð«Q¨* ë@P~P(Ð=â§›!¸\³ìñæ­™Ðg;ý~é§ì ¹äŸLÒ©dK@÷ˆÌéŒüß÷Áÿ ¨÷M71'´Õâ=ÏçMÙ¸óÍ=Þ*Ç;¹mņ?Ø?áL’á¥‰Š†ã9]¬ò«á= Å#`›¹ëŠZ¼Qká¸(F)Žr§¿áR-üg…I tÆÃS˜S ãžÙ¤Xˆ•œ1£@ÔO´ UÿïƒHn‚vÉÿ|SšP£Í=ïw^MÜ0¼Ë(š#˜åJ¼dõÁÇ~ã¡ïUëX·t-:¢®~h·”u`Q¾åúVñÑŽ)»ç&ïN¶±®gÓ5HFqÅ©—ñýÙj„ø›KFijË;GÚ-f‡'þ‚´ö“üDSÆïùèÃñ¥ õ9ËOé'\Ô¥Šêc·ˆFl°ß‘À?Þ¢|Anã÷z¬ì;%„ªк¨ýhÒ|Ã}­¾öÃ_àsÙ`‰˜5¦7ËF€Ì“«êRá`ðýÔ-¿{4q§þCgoüwñ¤&ðÕÜÞñÂÉéüï霱<ô¶9ëI¶ž‚÷ˆüЪ–áT`„@›=OûàÓ‡$㎸§m'½ Þ&íå¸ú¡¥óG÷þù§o_Ò­ëFƒÔ…*UázÔKR¯Ý5%ߌ iªwrh=GÒ„è(@*œçÚœb•Š‘»SH¤"”ô¢ úÓ€Á4ƒ¨¥ ðqMsü©çïToý ýÅ0 ?tTâDœ9QÒ¦ô¨GúÃ@=)šSH)€®ÅA#°¨›ï¡îsRI÷éQ·ÞŽÀ&Œ ZZ`1¾îi敾á¤JJ: i§‚šÝin9Å-ÄhíL Ý@Ž÷Õ¯frO©jÕDzô_õw_õõ/þ…Z½…bc¤4§½#JB!ŒŸ=ÇÐÓ®¥0ZÍ*€Y˜g¡ Scÿ‡ú n¡ÿ û¯úäßÈÓi—Oy¥ÚÜÈ<±+°^™ µšÏпäaÿ^ñÿè"¯Ò¹ÿÙlibimager-perl-1.004+dfsg.orig/JPEG/imjpeg.h0000644000175000017500000000043012263740600017727 0ustar gregoagregoa#ifndef IMAGER_IMJPEG_H #define IMAGER_IMJPEG_H #include "imdatatypes.h" i_img* i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength); undef_int i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor); extern const char * i_libjpeg_version(void); #endif libimager-perl-1.004+dfsg.orig/JPEG/imexif.h0000644000175000017500000000037512031434614017743 0ustar gregoagregoa/* imexif.h - interface to Exif handling */ #ifndef IMAGER_IMEXIF_H #define IMAGER_IMEXIF_H #include #include "imdatatypes.h" extern int i_int_decode_exif(i_img *im, unsigned char *data, size_t length); #endif /* ifndef IMAGER_IMEXIF_H */ libimager-perl-1.004+dfsg.orig/JPEG/README0000644000175000017500000000075712263740600017177 0ustar gregoagregoaImager::File::JPEG provides JPEG file format support for Imager. It requires libjpeg to be installed, any version from jpeg6b or later. libjpeg-turbo is also supported. For Linux distributions this typically requires installation of the associated -dev or -devel package. See Imager::Install for more information. This is currently shipped as part of Imager, but Imager may install with out installing Imager::File::JPEG, so if you need JPEG support, add a dependency on Imager::File::JPEG. libimager-perl-1.004+dfsg.orig/JPEG/t/0000755000175000017500000000000012617614576016570 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/JPEG/t/t00load.t0000644000175000017500000000011712031434614020176 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use_ok("Imager::File::JPEG"); libimager-perl-1.004+dfsg.orig/JPEG/t/t20limit.t0000644000175000017500000000317512263740600020410 0ustar gregoagregoa#!perl -w use strict; use Imager; use Test::More tests => 12; my $max_dim = 65500; { # JPEG files are limited to 0xFFFF x 0xFFFF pixels # but libjpeg sets the limit lower to avoid overflows { my $im = Imager->new(xsize => 1+$max_dim, ysize => 1); my $data = ''; ok(!$im->write(data => \$data, type => "jpeg"), "fail to write too wide an image"); is($im->errstr, "image too large for JPEG", "check error message"); } SKIP: { my $im = Imager->new(xsize => $max_dim, ysize => 1); $im->box(fill => { hatch => "check4x4" }); my $data = ''; ok($im->write(data => \$data, type => "jpeg"), "write image at width limit") or print "# ", $im->errstr, "\n"; my $im2 = Imager->new(data => $data, ftype => "jpeg"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is($im->getwidth, $max_dim, "check width"); is($im->getheight, 1, "check height"); } { my $im = Imager->new(xsize => 1, ysize => 1+$max_dim); my $data = ''; ok(!$im->write(data => \$data, type => "jpeg"), "fail to write too tall an image"); is($im->errstr, "image too large for JPEG", "check error message"); } SKIP: { my $im = Imager->new(xsize => 1, ysize => $max_dim); $im->box(fill => { hatch => "check2x2" }); my $data = ''; ok($im->write(data => \$data, type => "jpeg"), "write image at width limit"); my $im2 = Imager->new(data => $data, ftype => "jpeg"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is($im->getwidth, 1, "check width"); is($im->getheight, $max_dim, "check height"); } } libimager-perl-1.004+dfsg.orig/JPEG/t/t10jpeg.t0000644000175000017500000003474412322335072020223 0ustar gregoagregoa#!perl -w use strict; use Imager qw(:all); use Test::More; use Imager::Test qw(is_color_close3 test_image_raw test_image is_image); -d "testout" or mkdir "testout"; init_log("testout/t101jpeg.log",1); $Imager::formats{"jpeg"} or plan skip_all => "no jpeg support"; plan tests => 109; print STDERR "libjpeg version: ", Imager::File::JPEG::i_libjpeg_version(), "\n"; my $green=i_color_new(0,255,0,255); my $blue=i_color_new(0,0,255,255); my $red=i_color_new(255,0,0,255); my $img=test_image_raw(); my $cmpimg=Imager::ImgRaw::new(150,150,3); open(FH,">testout/t101.jpg") || die "cannot open testout/t101.jpg for writing\n"; binmode(FH); my $IO = Imager::io_new_fd(fileno(FH)); ok(Imager::File::JPEG::i_writejpeg_wiol($img,$IO,30), "write jpeg low level"); close(FH); open(FH, "testout/t101.jpg") || die "cannot open testout/t101.jpg\n"; binmode(FH); $IO = Imager::io_new_fd(fileno(FH)); ($cmpimg,undef) = Imager::File::JPEG::i_readjpeg_wiol($IO); close(FH); my $diff = sqrt(i_img_diff($img,$cmpimg))/150*150; print "# jpeg average mean square pixel difference: ",$diff,"\n"; ok($cmpimg, "read jpeg low level"); ok($diff < 10000, "difference between original and jpeg within bounds"); Imager::i_log_entry("Starting 4\n", 1); my $imoo = Imager->new; ok($imoo->read(file=>'testout/t101.jpg'), "read jpeg OO"); ok($imoo->write(file=>'testout/t101_oo.jpg'), "write jpeg OO"); Imager::i_log_entry("Starting 5\n", 1); my $oocmp = Imager->new; ok($oocmp->read(file=>'testout/t101_oo.jpg'), "read jpeg OO for comparison"); $diff = sqrt(i_img_diff($imoo->{IMG},$oocmp->{IMG}))/150*150; print "# OO image difference $diff\n"; ok($diff < 10000, "difference between original and jpeg within bounds"); # write failure test open FH, "< testout/t101.jpg" or die "Cannot open testout/t101.jpg: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); $io->set_buffered(0); ok(!$imoo->write(io => $io, type=>'jpeg'), 'failure handling'); close FH; print "# ",$imoo->errstr,"\n"; # check that the i_format tag is set my @fmt = $imoo->tags(name=>'i_format'); is($fmt[0], 'jpeg', 'i_format tag'); { # check file limits are checked my $limit_file = "testout/t101.jpg"; ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149"); my $im = Imager->new; ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image width/, "check message"); ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image height/, "check message"); ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside width limit"); ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside height limit"); # 150 x 150 x 3 channel image uses 67500 bytes ok(Imager->set_file_limits(reset=>1, bytes=>67499), "set bytes limit 67499"); ok(!$im->read(file=>$limit_file), "should fail - too many bytes"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/storage size/, "check error message"); ok(Imager->set_file_limits(reset=>1, bytes=>67500), "set bytes limit 67500"); ok($im->read(file=>$limit_file), "should succeed - just inside bytes limit"); Imager->set_file_limits(reset=>1); } SKIP: { # we don't test them all my %expected_tags = ( exif_date_time_original => "2005:11:25 00:00:00", exif_flash => 0, exif_image_description => "Imager Development Notes", exif_make => "Canon", exif_model => "CanoScan LiDE 35", exif_resolution_unit => 2, exif_resolution_unit_name => "inches", exif_user_comment => " Part of notes from reworking i_arc() and friends.", exif_white_balance => 0, exif_white_balance_name => "Auto white balance", ); my $im = Imager->new; $im->read(file=>"testimg/exiftest.jpg") or skip("Could not read test image:".$im->errstr, scalar keys %expected_tags); for my $key (keys %expected_tags) { is($expected_tags{$key}, $im->tags(name => $key), "test value of exif tag $key"); } } { # tests that the density values are set and read correctly # tests jpeg_comment too my @density_tests = ( [ 't101cm100.jpg', { jpeg_density_unit => 2, i_xres => 254, i_yres => 254 }, { jpeg_density_unit => 2, i_xres => 254, i_yres => 254, i_aspect_only => undef, }, ], [ 't101xonly.jpg', { i_xres => 100, }, { i_xres => 100, i_yres => 100, jpeg_density_unit => 1, i_aspect_only => undef, }, ], [ 't101yonly.jpg', { i_yres => 100, }, { i_xres => 100, i_yres => 100, jpeg_density_unit => 1, i_aspect_only => undef, }, ], [ 't101asponly.jpg', { i_xres => 50, i_yres => 100, i_aspect_only => 1, }, { i_xres => 50, i_yres => 100, i_aspect_only => 1, jpeg_density_unit => 0, }, ], [ 't101com.jpg', { jpeg_comment => 'test comment' }, ], ); print "# test density tags\n"; # I don't care about the content my $base_im = Imager->new(xsize => 10, ysize => 10); for my $test (@density_tests) { my ($filename, $out_tags, $expect_tags) = @$test; $expect_tags ||= $out_tags; my $work = $base_im->copy; for my $key (keys %$out_tags) { $work->addtag(name => $key, value => $out_tags->{$key}); } ok($work->write(file=>"testout/$filename", type=>'jpeg'), "save $filename"); my $check = Imager->new; ok($check->read(file=> "testout/$filename"), "read $filename"); my %tags; for my $key (keys %$expect_tags) { $tags{$key} = $check->tags(name=>$key); } is_deeply($expect_tags, \%tags, "check tags for $filename"); } } { # Issue # 17981 # the test image has a zero-length user_comment field # the code would originally attempt to convert '\0' to ' ' # for the first 8 bytes, even if the string was less than # 8 bytes long my $im = Imager->new; ok($im->read(file => 'testimg/209_yonge.jpg', type=>'jpeg'), "test read of image with invalid exif_user_comment"); is($im->tags(name=>'exif_user_comment'), '', "check exif_user_comment set correctly"); } { # test parseiptc handling no IPTC data correctly my $saw_warn; local $SIG{__WARN__} = sub { ++$saw_warn; print "# @_\n"; }; my $im = Imager->new; ok($im->read(file => 'testout/t101.jpg', type=>'jpeg'), "read jpeg with no IPTC data"); ok(!defined $im->{IPTCRAW}, "no iptc data"); my %iptc = $im->parseiptc; ok(!$saw_warn, "should be no warnings"); } { # Issue # 18397 # attempting to write a 4 channel image to a bufchain would # cause a seg fault. # it should fail still # overridden by # 29876 # give 4/2 channel images a background color when saving to JPEG my $im = Imager->new(xsize => 16, ysize => 16, channels => 4); $im->box(filled => 1, xmin => 8, color => '#FFE0C0'); my $data; ok($im->write(data => \$data, type => 'jpeg'), "should write with a black background"); my $imread = Imager->new; ok($imread->read(data => $data, type => 'jpeg'), 'read it back'); is_color_close3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0, 4, "check it's black"); is_color_close3($imread->getpixel('x' => 15, 'y' => 9), 255, 224, 192, 4, "check filled area filled"); # write with a red background $data = ''; ok($im->write(data => \$data, type => 'jpeg', i_background => '#FF0000'), "write with red background"); ok($imread->read(data => $data, type => 'jpeg'), "read it back"); is_color_close3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0, 4, "check it's red"); is_color_close3($imread->getpixel('x' => 15, 'y' => 9), 255, 224, 192, 4, "check filled area filled"); } SKIP: { # Issue # 18496 # If a jpeg with EXIF data containing an (invalid) IFD entry with a # type of zero is read then Imager crashes with a Floating point # exception # testimg/zerojpeg.jpg was manually modified from exiftest.jpg to # reproduce the problem. my $im = Imager->new; ok($im->read(file=>'testimg/zerotype.jpg'), "shouldn't crash"); } SKIP: { # code coverage - make sure wiol_skip_input_data is called open BASEDATA, "< testimg/exiftest.jpg" or skip "can't open base data", 1; binmode BASEDATA; my $data = do { local $/; }; close BASEDATA; substr($data, 3, 1) eq "\xE1" or skip "base data isn't as expected", 1; # inserting a lot of marker data here means we take the branch in # wiol_skip_input_data that refills the buffer my $marker = "\xFF\xE9"; # APP9 marker $marker .= pack("n", 8192) . "x" x 8190; $marker x= 10; # make it take up a lot of space substr($data, 2, 0) = $marker; my $im = Imager->new; ok($im->read(data => $data), "read with a skip of data"); } SKIP: { # code coverage - take the branch that provides a fake EOI open BASEDATA, "< testimg/exiftest.jpg" or skip "can't open base data", 1; binmode BASEDATA; my $data = do { local $/; }; close BASEDATA; substr($data, -1000) = ''; my $im = Imager->new; ok($im->read(data => $data), "read with image data truncated"); } { # code coverage - make sure wiol_empty_output_buffer is called my $im = Imager->new(xsize => 1000, ysize => 1000); for my $x (0 .. 999) { $im->line(x1 => $x, y1 => 0, x2 => $x, y2 => 999, color => Imager::Color->new(rand 256, rand 256, rand 256)); } my $data; ok($im->write(data => \$data, type=>'jpeg', jpegquality => 100), "write big file to ensure wiol_empty_output_buffer is called") or print "# ", $im->errstr, "\n"; # code coverage - write failure path in wiol_empty_output_buffer ok(!$im->write(callback => sub { return }, type => 'jpeg', jpegquality => 100), "fail to write") and print "# ", $im->errstr, "\n"; } { # code coverage - virtual image branch in i_writejpeg_wiol() my $im = $imoo->copy; my $immask = $im->masked; ok($immask, "made a virtual image (via masked)"); ok($immask->virtual, "check it's virtual"); my $mask_data; ok($immask->write(data => \$mask_data, type => 'jpeg'), "write masked version"); my $base_data; ok($im->write(data => \$base_data, type=>'jpeg'), "write normal version"); is($base_data, $mask_data, "check the data written matches"); } SKIP: { # code coverage - IPTC data # this is dummy data my $iptc = "\x04\x04" . "\034\002x My Caption" . "\034\002P Tony Cook" . "\034\002i Dummy Headline!" . "\034\002n No Credit Given"; my $app13 = "\xFF\xED" . pack("n", 2 + length $iptc) . $iptc; open BASEDATA, "< testimg/exiftest.jpg" or skip "can't open base data", 1; binmode BASEDATA; my $data = do { local $/; }; close BASEDATA; substr($data, 2, 0) = $app13; my $im = Imager->new; ok($im->read(data => $data), "read with app13 data"); my %iptc = $im->parseiptc; is($iptc{caption}, 'My Caption', 'check iptc caption'); is($iptc{photogr}, 'Tony Cook', 'check iptc photogr'); is($iptc{headln}, 'Dummy Headline!', 'check iptc headln'); is($iptc{credit}, 'No Credit Given', 'check iptc credit'); } { # handling of CMYK jpeg # http://rt.cpan.org/Ticket/Display.html?id=20416 my $im = Imager->new; ok($im->read(file => 'testimg/scmyk.jpg'), 'read a CMYK jpeg'); is($im->getchannels, 3, "check channel count"); my $col = $im->getpixel(x => 0, 'y' => 0); ok($col, "got the 'black' pixel"); # this is jpeg, so we can't compare colors exactly # older versions returned this pixel at a light color, but # it's black in the image my ($r, $g, $b) = $col->rgba; cmp_ok($r, '<', 10, 'black - red low'); cmp_ok($g, '<', 10, 'black - green low'); cmp_ok($b, '<', 10, 'black - blue low'); $col = $im->getpixel(x => 15, 'y' => 0); ok($col, "got the dark blue"); ($r, $g, $b) = $col->rgba; cmp_ok($r, '<', 10, 'dark blue - red low'); cmp_ok($g, '<', 10, 'dark blue - green low'); cmp_ok($b, '>', 110, 'dark blue - blue middle (bottom)'); cmp_ok($b, '<', 130, 'dark blue - blue middle (top)'); $col = $im->getpixel(x => 0, 'y' => 15); ok($col, "got the red"); ($r, $g, $b) = $col->rgba; cmp_ok($r, '>', 245, 'red - red high'); cmp_ok($g, '<', 10, 'red - green low'); cmp_ok($b, '<', 10, 'red - blue low'); } { ok(grep($_ eq 'jpeg', Imager->read_types), "check jpeg in read types"); ok(grep($_ eq 'jpeg', Imager->write_types), "check jpeg in write types"); } { # progressive JPEG # https://rt.cpan.org/Ticket/Display.html?id=68691 my $im = test_image(); my $progim = $im->copy; ok($progim->write(file => "testout/t10prog.jpg", type => "jpeg", jpeg_progressive => 1), "write progressive jpeg"); my $rdprog = Imager->new(file => "testout/t10prog.jpg"); ok($rdprog, "read progressive jpeg"); my @prog = $rdprog->tags(name => "jpeg_progressive"); is($prog[0], 1, "check progressive flag set on read"); my $data; ok($im->write(data => \$data, type => "jpeg"), "save as non-progressive to compare"); my $norm = Imager->new(data => $data); ok($norm, "read non-progressive file"); my @nonprog = $norm->tags(name => "jpeg_progressive"); is($nonprog[0], 0, "check progressive flag 0 for non prog file"); is_image($rdprog, $norm, "prog vs norm should be the same image"); } SKIP: { # optimize coding my $im = test_image(); my $base; ok($im->write(data => \$base, type => "jpeg"), "save without optimize"); my $opt; ok($im->write(data => \$opt, type => "jpeg", jpeg_optimize => 1), "save with optimize"); cmp_ok(length $opt, '<', length $base, "check optimized is smaller"); my $im_base = Imager->new(data => $base, filetype => "jpeg"); ok($im_base, "read unoptimized back"); my $im_opt = Imager->new(data => $opt, filetype => "jpeg"); ok($im_opt, "read optimized back"); $im_base && $im_opt or skip "couldn't read one back", 1; is_image($im_opt, $im_base, "optimization should only change huffman compression, not quality"); } { # check close failures are handled correctly my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; ok(!$im->write(type => "jpeg", callback => sub { 1 }, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } libimager-perl-1.004+dfsg.orig/JPEG/Makefile.PL0000644000175000017500000000466512567572530020307 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Getopt::Long; use Config; my $verbose = $ENV{IM_VERBOSE}; my @libpaths; my @incpaths; GetOptions("incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$verbose); our $BUILDING_IMAGER; our %IMAGER_LIBS; my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; my %opts = ( NAME => 'Imager::File::JPEG', VERSION_FROM => 'JPEG.pm', OBJECT => 'JPEG.o imjpeg.o imexif.o', clean => { FILES => 'testout' }, ); my @inc; if ($BUILDING_IMAGER) { push @inc, "-I.."; unshift @INC, "../lib"; } else { unshift @INC, "inc"; print "JPEG: building independently\n"; require Imager::ExtUtils; push @inc, Imager::ExtUtils->includes; $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ]; # Imager required configure through use my @Imager_req = ( Imager => "0.86" ); if ($MM_ver >= 6.46) { $opts{META_MERGE} = { configure_requires => { @Imager_req, }, build_requires => { @Imager_req, "Test::More" => "0.47", }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; $opts{PREREQ_PM} = { @Imager_req, XSLoader => 0, }; } } require Imager::Probe; my %probe = ( name => "JPEG", inccheck => sub { -e File::Spec->catfile($_[0], "jpeglib.h") }, libbase => "jpeg", testcode => _jpeg_test_code(), testcodeheaders => [ "stdio.h", "stddef.h", "jpeglib.h" ], incpath => \@incpaths, libpath => \@libpaths, verbose => $verbose, ); my $probe_res = Imager::Probe->probe(\%probe); if ($probe_res) { $IMAGER_LIBS{JPEG} = 1; push @inc, $probe_res->{INC}; $opts{LIBS} = $probe_res->{LIBS}; $opts{DEFINE} = $probe_res->{DEFINE}; $opts{INC} = "@inc"; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'JPEG Image file support'; } WriteMakefile(%opts); } else { $IMAGER_LIBS{JPEG} = 0; if ($BUILDING_IMAGER) { ExtUtils::MakeMaker::WriteEmptyMakefile(%opts); } else { # fail in good way die "OS unsupported: JPEG libraries or headers not found\n"; } } sub _jpeg_test_code { return <<'CODE'; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); return 0; CODE } libimager-perl-1.004+dfsg.orig/JPEG/imjpeg.c0000644000175000017500000004763112322335072017737 0ustar gregoagregoa/* =head1 NAME jpeg.c - implement saving and loading JPEG images =head1 SYNOPSIS io_glue *ig; if (!i_writejpeg_wiol(im, ig, quality)) { .. error .. } im = i_readjpeg_wiol(ig, length, iptc_text, itlength); =head1 DESCRIPTION Reads and writes JPEG images =over =cut */ #include "imjpeg.h" #include "imext.h" #include #include #ifndef _MSC_VER #include #endif #include #include #include "jpeglib.h" #include "jerror.h" #include #include #include "imexif.h" #define JPEG_APP13 0xED /* APP13 marker code */ #define JPEG_APP1 (JPEG_APP0 + 1) #define JPGS 16384 #define JPEG_DIM_MAX JPEG_MAX_DIMENSION #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) static unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI}; /* Source and Destination managers */ typedef struct { struct jpeg_source_mgr pub; /* public fields */ io_glue *data; JOCTET *buffer; /* start of buffer */ int length; /* Do I need this? */ boolean start_of_file; /* have we gotten any data yet? */ } wiol_source_mgr; typedef struct { struct jpeg_destination_mgr pub; /* public fields */ io_glue *data; JOCTET *buffer; /* start of buffer */ boolean start_of_file; /* have we gotten any data yet? */ } wiol_destination_mgr; typedef wiol_source_mgr *wiol_src_ptr; typedef wiol_destination_mgr *wiol_dest_ptr; /* * Methods for io manager objects * * Methods for source managers: * * init_source (j_decompress_ptr cinfo); * skip_input_data (j_decompress_ptr cinfo, long num_bytes); * fill_input_buffer (j_decompress_ptr cinfo); * term_source (j_decompress_ptr cinfo); */ static void wiol_init_source (j_decompress_ptr cinfo) { wiol_src_ptr src = (wiol_src_ptr) cinfo->src; /* We reset the empty-input-file flag for each image, but we don't clear * the input buffer. This is correct behavior for reading a series of * images from one source. */ src->start_of_file = TRUE; } static boolean wiol_fill_input_buffer(j_decompress_ptr cinfo) { wiol_src_ptr src = (wiol_src_ptr) cinfo->src; ssize_t nbytes; /* We assume that reads are "small" */ mm_log((1,"wiol_fill_input_buffer(cinfo %p)\n", cinfo)); nbytes = i_io_read(src->data, src->buffer, JPGS); if (nbytes <= 0) { /* Insert a fake EOI marker */ src->pub.next_input_byte = fake_eoi; src->pub.bytes_in_buffer = 2; } else { src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = nbytes; } src->start_of_file = FALSE; return TRUE; } static void wiol_skip_input_data (j_decompress_ptr cinfo, long num_bytes) { wiol_src_ptr src = (wiol_src_ptr) cinfo->src; /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway --- large skips are infrequent. */ if (num_bytes > 0) { while (num_bytes > (long) src->pub.bytes_in_buffer) { num_bytes -= (long) src->pub.bytes_in_buffer; (void) wiol_fill_input_buffer(cinfo); /* note we assume that fill_input_buffer will never return FALSE, * so suspension need not be handled. */ } src->pub.next_input_byte += (size_t) num_bytes; src->pub.bytes_in_buffer -= (size_t) num_bytes; } } static void wiol_term_source (j_decompress_ptr cinfo) { /* no work necessary here */ wiol_src_ptr src; if (cinfo->src != NULL) { src = (wiol_src_ptr) cinfo->src; myfree(src->buffer); } } /* Source manager Constructor */ static void jpeg_wiol_src(j_decompress_ptr cinfo, io_glue *ig, int length) { wiol_src_ptr src; if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(wiol_source_mgr)); src = (wiol_src_ptr) cinfo->src; } /* put the request method call in here later */ src = (wiol_src_ptr) cinfo->src; src->data = ig; src->buffer = mymalloc( JPGS ); src->length = length; src->pub.init_source = wiol_init_source; src->pub.fill_input_buffer = wiol_fill_input_buffer; src->pub.skip_input_data = wiol_skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = wiol_term_source; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ src->pub.next_input_byte = NULL; /* until buffer loaded */ } /* * Methods for destination managers: * * init_destination (j_compress_ptr cinfo); * empty_output_buffer (j_compress_ptr cinfo); * term_destination (j_compress_ptr cinfo); * */ static void wiol_init_destination (j_compress_ptr cinfo) { wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest; /* We reset the empty-input-file flag for each image, but we don't clear * the input buffer. This is correct behavior for reading a series of * images from one source. */ dest->start_of_file = TRUE; } static boolean wiol_empty_output_buffer(j_compress_ptr cinfo) { wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest; ssize_t rc; /* Previously this code was checking free_in_buffer to see how much needed to be written. This does not follow the documentation: "In typical applications, it should write out the *entire* buffer (use the saved start address and buffer length; ignore the current state of next_output_byte and free_in_buffer)." ssize_t nbytes = JPGS - dest->pub.free_in_buffer; */ mm_log((1,"wiol_empty_output_buffer(cinfo %p)\n", cinfo)); rc = i_io_write(dest->data, dest->buffer, JPGS); if (rc != JPGS) { /* XXX: Should raise some jpeg error */ myfree(dest->buffer); mm_log((1, "wiol_empty_output_buffer: Error: nbytes = %d != rc = %d\n", JPGS, (int)rc)); ERREXIT(cinfo, JERR_FILE_WRITE); } dest->pub.free_in_buffer = JPGS; dest->pub.next_output_byte = dest->buffer; return TRUE; } static void wiol_term_destination (j_compress_ptr cinfo) { wiol_dest_ptr dest = (wiol_dest_ptr) cinfo->dest; size_t nbytes = JPGS - dest->pub.free_in_buffer; /* yes, this needs to flush the buffer */ /* needs error handling */ if (i_io_write(dest->data, dest->buffer, nbytes) != nbytes) { myfree(dest->buffer); ERREXIT(cinfo, JERR_FILE_WRITE); } if (dest != NULL) myfree(dest->buffer); } /* Destination manager Constructor */ static void jpeg_wiol_dest(j_compress_ptr cinfo, io_glue *ig) { wiol_dest_ptr dest; if (cinfo->dest == NULL) { /* first time for this JPEG object? */ cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(wiol_destination_mgr)); } dest = (wiol_dest_ptr) cinfo->dest; dest->data = ig; dest->buffer = mymalloc( JPGS ); dest->pub.init_destination = wiol_init_destination; dest->pub.empty_output_buffer = wiol_empty_output_buffer; dest->pub.term_destination = wiol_term_destination; dest->pub.free_in_buffer = JPGS; dest->pub.next_output_byte = dest->buffer; } METHODDEF(void) my_output_message (j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (*cinfo->err->format_message) (cinfo, buffer); i_push_error(0, buffer); /* Send it to stderr, adding a newline */ mm_log((1, "%s\n", buffer)); } struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr * my_error_ptr; /* Here's the routine that will replace the standard error_exit method */ METHODDEF(void) my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ (*cinfo->err->output_message) (cinfo); /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); } static void transfer_cmyk_inverted(i_color *out, JSAMPARRAY in, int width) { JSAMPROW inrow = *in; while (width--) { /* extract and convert to real CMYK */ /* horribly enough this is correct given cmyk values are inverted */ int c = *inrow++; int m = *inrow++; int y = *inrow++; int k = *inrow++; out->rgba.r = (c * k) / MAXJSAMPLE; out->rgba.g = (m * k) / MAXJSAMPLE; out->rgba.b = (y * k) / MAXJSAMPLE; ++out; } } static void transfer_rgb(i_color *out, JSAMPARRAY in, int width) { JSAMPROW inrow = *in; while (width--) { out->rgba.r = *inrow++; out->rgba.g = *inrow++; out->rgba.b = *inrow++; ++out; } } static void transfer_gray(i_color *out, JSAMPARRAY in, int width) { JSAMPROW inrow = *in; while (width--) { out->gray.gray_color = *inrow++; ++out; } } typedef void (*transfer_function_t)(i_color *out, JSAMPARRAY in, int width); static const char version_string[] = #ifdef LIBJPEG_TURBO_VERSION "libjpeg-turbo " STRINGIFY(LIBJPEG_TURBO_VERSION) " api " STRINGIFY(JPEG_LIB_VERSION) #else "libjpeg " STRINGIFY(JPEG_LIB_VERSION) #endif ; /* =item i_libjpeg_version() =cut */ const char * i_libjpeg_version(void) { return version_string; } /* =item i_readjpeg_wiol(data, length, iptc_itext, itlength) =cut */ i_img* i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) { i_img * volatile im = NULL; int seen_exif = 0; i_color * volatile line_buffer = NULL; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ jpeg_saved_marker_ptr markerp; transfer_function_t transfer_f; int channels; volatile int src_set = 0; mm_log((1,"i_readjpeg_wiol(data %p, length %d,iptc_itext %p)\n", data, length, iptc_itext)); i_clear_error(); *iptc_itext = NULL; *itlength = 0; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; /* Set error handler */ if (setjmp(jerr.setjmp_buffer)) { if (src_set) wiol_term_source(&cinfo); jpeg_destroy_decompress(&cinfo); if (line_buffer) myfree(line_buffer); if (im) i_img_destroy(im); return NULL; } jpeg_create_decompress(&cinfo); jpeg_save_markers(&cinfo, JPEG_APP13, 0xFFFF); jpeg_save_markers(&cinfo, JPEG_APP1, 0xFFFF); jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF); jpeg_wiol_src(&cinfo, data, length); src_set = 1; (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); channels = cinfo.output_components; switch (cinfo.out_color_space) { case JCS_GRAYSCALE: if (cinfo.output_components != 1) { mm_log((1, "i_readjpeg: grayscale image with %d channels\n", cinfo.output_components)); i_push_errorf(0, "grayscale image with invalid components %d", cinfo.output_components); wiol_term_source(&cinfo); jpeg_destroy_decompress(&cinfo); return NULL; } transfer_f = transfer_gray; break; case JCS_RGB: transfer_f = transfer_rgb; if (cinfo.output_components != 3) { mm_log((1, "i_readjpeg: RGB image with %d channels\n", cinfo.output_components)); i_push_errorf(0, "RGB image with invalid components %d", cinfo.output_components); wiol_term_source(&cinfo); jpeg_destroy_decompress(&cinfo); return NULL; } break; case JCS_CMYK: if (cinfo.output_components == 4) { /* we treat the CMYK values as inverted, because that's what that buggy photoshop does, and everyone has to follow the gorilla. Is there any app that still produces correct CMYK JPEGs? */ transfer_f = transfer_cmyk_inverted; channels = 3; } else { mm_log((1, "i_readjpeg: cmyk image with %d channels\n", cinfo.output_components)); i_push_errorf(0, "CMYK image with invalid components %d", cinfo.output_components); wiol_term_source(&cinfo); jpeg_destroy_decompress(&cinfo); return NULL; } break; default: mm_log((1, "i_readjpeg: unknown color space %d\n", cinfo.out_color_space)); i_push_errorf(0, "Unknown color space %d", cinfo.out_color_space); wiol_term_source(&cinfo); jpeg_destroy_decompress(&cinfo); return NULL; } if (!i_int_check_image_file_limits(cinfo.output_width, cinfo.output_height, channels, sizeof(i_sample_t))) { mm_log((1, "i_readjpeg: image size exceeds limits\n")); wiol_term_source(&cinfo); jpeg_destroy_decompress(&cinfo); return NULL; } im = i_img_8_new(cinfo.output_width, cinfo.output_height, channels); if (!im) { wiol_term_source(&cinfo); jpeg_destroy_decompress(&cinfo); return NULL; } row_stride = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); line_buffer = mymalloc(sizeof(i_color) * cinfo.output_width); while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); transfer_f(line_buffer, buffer, cinfo.output_width); i_plin(im, 0, cinfo.output_width, cinfo.output_scanline-1, line_buffer); } myfree(line_buffer); line_buffer = NULL; /* check for APP1 marker and save */ markerp = cinfo.marker_list; while (markerp != NULL) { if (markerp->marker == JPEG_COM) { i_tags_set(&im->tags, "jpeg_comment", (const char *)markerp->data, markerp->data_length); } else if (markerp->marker == JPEG_APP1 && !seen_exif) { seen_exif = i_int_decode_exif(im, markerp->data, markerp->data_length); } else if (markerp->marker == JPEG_APP13) { *iptc_itext = mymalloc(markerp->data_length); memcpy(*iptc_itext, markerp->data, markerp->data_length); *itlength = markerp->data_length; } markerp = markerp->next; } i_tags_setn(&im->tags, "jpeg_out_color_space", cinfo.out_color_space); i_tags_setn(&im->tags, "jpeg_color_space", cinfo.jpeg_color_space); if (cinfo.saw_JFIF_marker) { double xres = cinfo.X_density; double yres = cinfo.Y_density; i_tags_setn(&im->tags, "jpeg_density_unit", cinfo.density_unit); switch (cinfo.density_unit) { case 0: /* values are just the aspect ratio */ i_tags_setn(&im->tags, "i_aspect_only", 1); i_tags_set(&im->tags, "jpeg_density_unit_name", "none", -1); break; case 1: /* per inch */ i_tags_set(&im->tags, "jpeg_density_unit_name", "inch", -1); break; case 2: /* per cm */ i_tags_set(&im->tags, "jpeg_density_unit_name", "centimeter", -1); xres *= 2.54; yres *= 2.54; break; } i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6); i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6); } /* I originally used jpeg_has_multiple_scans() here, but that can * return true for non-progressive files too. The progressive_mode * member is available at least as far back as 6b and does the right * thing. */ i_tags_setn(&im->tags, "jpeg_progressive", cinfo.progressive_mode ? 1 : 0); (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); i_tags_set(&im->tags, "i_format", "jpeg", 4); mm_log((1,"i_readjpeg_wiol -> (%p)\n",im)); return im; } /* =item i_writejpeg_wiol(im, ig, qfactor) =cut */ undef_int i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) { JSAMPLE *image_buffer; int quality; int got_xres, got_yres, aspect_only, resunit; double xres, yres; int comment_entry; int want_channels = im->channels; int progressive = 0; int optimize = 0; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ unsigned char * data = NULL; i_color *line_buf = NULL; mm_log((1,"i_writejpeg(im %p, ig %p, qfactor %d)\n", im, ig, qfactor)); i_clear_error(); if (im->xsize > JPEG_DIM_MAX || im->ysize > JPEG_DIM_MAX) { i_push_error(0, "image too large for JPEG"); return 0; } if (!(im->channels==1 || im->channels==3)) { want_channels = im->channels - 1; } quality = qfactor; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; jpeg_create_compress(&cinfo); if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); if (data) myfree(data); if (line_buf) myfree(line_buf); return 0; } jpeg_wiol_dest(&cinfo, ig); cinfo.image_width = im -> xsize; /* image width and height, in pixels */ cinfo.image_height = im -> ysize; if (want_channels==3) { cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ } if (want_channels==1) { cinfo.input_components = 1; /* # of color components per pixel */ cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ } jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */ if (!i_tags_get_int(&im->tags, "jpeg_progressive", 0, &progressive)) progressive = 0; if (progressive) { jpeg_simple_progression(&cinfo); } if (!i_tags_get_int(&im->tags, "jpeg_optimize", 0, &optimize)) optimize = 0; cinfo.optimize_coding = optimize; got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres); got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres); if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only)) aspect_only = 0; if (!i_tags_get_int(&im->tags, "jpeg_density_unit", 0, &resunit)) resunit = 1; /* per inch */ if (resunit < 0 || resunit > 2) /* default to inch if invalid */ resunit = 1; if (got_xres || got_yres) { if (!got_xres) xres = yres; else if (!got_yres) yres = xres; if (aspect_only) resunit = 0; /* standard tags override format tags */ if (resunit == 2) { /* convert to per cm */ xres /= 2.54; yres /= 2.54; } cinfo.density_unit = resunit; cinfo.X_density = (int)(xres + 0.5); cinfo.Y_density = (int)(yres + 0.5); } jpeg_start_compress(&cinfo, TRUE); if (i_tags_find(&im->tags, "jpeg_comment", 0, &comment_entry)) { jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)im->tags.tags[comment_entry].data, im->tags.tags[comment_entry].size); } row_stride = im->xsize * im->channels; /* JSAMPLEs per row in image_buffer */ if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits && im->channels == want_channels) { image_buffer=im->idata; while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } } else { i_color bg; i_get_file_background(im, &bg); data = mymalloc(im->xsize * im->channels); if (data) { while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ i_gsamp_bg(im, 0, im->xsize, cinfo.next_scanline, data, want_channels, &bg); row_pointer[0] = data; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } myfree(data); } else { jpeg_destroy_compress(&cinfo); i_push_error(0, "out of memory"); return 0; /* out of memory? */ } } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); if (i_io_close(ig)) return 0; return(1); } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson, addi@umich.edu =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/JPEG/JPEG.xs0000644000175000017500000000217312263740600017412 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "imjpeg.h" DEFINE_IMAGER_CALLBACKS; MODULE = Imager::File::JPEG PACKAGE = Imager::File::JPEG const char * i_libjpeg_version() undef_int i_writejpeg_wiol(im, ig, qfactor) Imager::ImgRaw im Imager::IO ig int qfactor void i_readjpeg_wiol(ig) Imager::IO ig PREINIT: char* iptc_itext; int tlength; i_img* rimg; SV* r; PPCODE: iptc_itext = NULL; rimg = i_readjpeg_wiol(ig,-1,&iptc_itext,&tlength); if (iptc_itext == NULL) { r = sv_newmortal(); EXTEND(SP,1); sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg); PUSHs(r); } else { r = sv_newmortal(); EXTEND(SP,2); sv_setref_pv(r, "Imager::ImgRaw", (void*)rimg); PUSHs(r); PUSHs(sv_2mortal(newSVpv(iptc_itext,tlength))); myfree(iptc_itext); } BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/W32/0000755000175000017500000000000012617614576016153 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/W32/win32.c0000644000175000017500000003545012263740600017251 0ustar gregoagregoa#define _WIN32_WINNT 0x500 #include "imw32.h" #define STRICT #include #include "imext.h" /* =head1 NAME win32.c - implements some win32 specific code, specifically Win32 font support. =head1 SYNOPSIS i_img_dim bbox[6]; if (i_wf_bbox(facename, size, text, text_len, bbox)) { // we have the bbox } i_wf_text(face, im, tx, ty, cl, size, text, len, align, aa, utf8); i_wf_cp(face, im, tx, ty, channel, size, text, len, align, aa, utf8) =head1 DESCRIPTION An Imager interface to font output using the Win32 GDI. =over =cut */ #define fixed(x) ((x).value + ((x).fract) / 65536.0) static void set_logfont(const char *face, int size, LOGFONT *lf); static unsigned char *render_text(const char *face, int size, const char *text, size_t length, int aa, SIZE *psz, TEXTMETRIC *tm, size_t *bytes_per_line, i_img_dim *bbox, int utf8); static LPWSTR utf8_to_wide_string(char const *text, int text_len, int *wide_chars); static LPWSTR latin1_to_wide_string(char const *text, int text_len, int *wide_chars); /* =item i_wf_bbox(face, size, text, length, bbox, utf8) Calculate a bounding box for the text. =cut */ int i_wf_bbox(const char *face, i_img_dim size, const char *text, size_t length, i_img_dim *bbox, int utf8) { LOGFONT lf; HFONT font, oldFont; HDC dc; SIZE sz; TEXTMETRIC tm; ABC first, last; GLYPHMETRICS gm; MAT2 mat; int ascent, descent, max_ascent = -size, min_descent = size; const char *workp; size_t work_len; int got_first_ch = 0; unsigned long first_ch, last_ch; i_clear_error(); mm_log((1, "i_wf_bbox(face %s, size %d, text %p, length %d, bbox %p, utf8 %d)\n", face, size, text, length, bbox, utf8)); set_logfont(face, size, &lf); font = CreateFontIndirect(&lf); if (!font) return 0; dc = GetDC(NULL); oldFont = (HFONT)SelectObject(dc, font); { char facename[100]; if (GetTextFace(dc, sizeof(facename), facename)) { mm_log((1, " face: %s\n", facename)); } } workp = text; work_len = length; while (work_len > 0) { unsigned long c; unsigned char cp; if (utf8) { c = i_utf8_advance(&workp, &work_len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { c = (unsigned char)*workp++; --work_len; } if (!got_first_ch) { first_ch = c; ++got_first_ch; } last_ch = c; cp = c > '~' ? '.' : c < ' ' ? '.' : c; memset(&mat, 0, sizeof(mat)); mat.eM11.value = 1; mat.eM22.value = 1; if (GetGlyphOutline(dc, (UINT)c, GGO_METRICS, &gm, 0, NULL, &mat) != GDI_ERROR) { mm_log((2, " glyph '%c' (%02x): bbx (%u,%u) org (%d,%d) inc(%d,%d)\n", cp, c, gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY)); ascent = gm.gmptGlyphOrigin.y; descent = ascent - gm.gmBlackBoxY; if (ascent > max_ascent) max_ascent = ascent; if (descent < min_descent) min_descent = descent; } else { mm_log((1, " glyph '%c' (%02x): error %d\n", cp, c, GetLastError())); } } if (utf8) { int wide_chars; LPWSTR wide_text = utf8_to_wide_string(text, length, &wide_chars); if (!wide_text) return 0; if (!GetTextExtentPoint32W(dc, wide_text, wide_chars, &sz) || !GetTextMetrics(dc, &tm)) { SelectObject(dc, oldFont); ReleaseDC(NULL, dc); DeleteObject(font); return 0; } myfree(wide_text); } else { if (!GetTextExtentPoint32(dc, text, length, &sz) || !GetTextMetrics(dc, &tm)) { SelectObject(dc, oldFont); ReleaseDC(NULL, dc); DeleteObject(font); return 0; } } bbox[BBOX_GLOBAL_DESCENT] = -tm.tmDescent; bbox[BBOX_DESCENT] = min_descent == size ? -tm.tmDescent : min_descent; bbox[BBOX_POS_WIDTH] = sz.cx; bbox[BBOX_ADVANCE_WIDTH] = sz.cx; bbox[BBOX_GLOBAL_ASCENT] = tm.tmAscent; bbox[BBOX_ASCENT] = max_ascent == -size ? tm.tmAscent : max_ascent; if (length && GetCharABCWidths(dc, first_ch, first_ch, &first) && GetCharABCWidths(dc, last_ch, last_ch, &last)) { mm_log((1, "first: %d A: %d B: %d C: %d\n", first_ch, first.abcA, first.abcB, first.abcC)); mm_log((1, "last: %d A: %d B: %d C: %d\n", last_ch, last.abcA, last.abcB, last.abcC)); bbox[BBOX_NEG_WIDTH] = first.abcA; bbox[BBOX_RIGHT_BEARING] = last.abcC; if (last.abcC < 0) bbox[BBOX_POS_WIDTH] -= last.abcC; } else { bbox[BBOX_NEG_WIDTH] = 0; bbox[BBOX_RIGHT_BEARING] = 0; } SelectObject(dc, oldFont); ReleaseDC(NULL, dc); DeleteObject(font); mm_log((1, " bbox=> negw=%" i_DF " glob_desc=%" i_DF " pos_wid=%" i_DF " glob_asc=%" i_DF " desc=%" i_DF " asc=%" i_DF " adv_width=%" i_DF " rightb=%" i_DF "\n", i_DFc(bbox[0]), i_DFc(bbox[1]), i_DFc(bbox[2]), i_DFc(bbox[3]), i_DFc(bbox[4]), i_DFc(bbox[5]), i_DFc(bbox[6]), i_DFc(bbox[7]))); return BBOX_RIGHT_BEARING + 1; } /* =item i_wf_text(face, im, tx, ty, cl, size, text, len, align, aa) Draws the text in the given color. =cut */ int i_wf_text(const char *face, i_img *im, i_img_dim tx, i_img_dim ty, const i_color *cl, i_img_dim size, const char *text, size_t len, int align, int aa, int utf8) { unsigned char *bits; SIZE sz; size_t line_width; i_img_dim x, y; int ch; TEXTMETRIC tm; int top; i_img_dim bbox[BOUNDING_BOX_COUNT]; i_render *r; unsigned char *outp; i_clear_error(); mm_log((1, "i_wf_text(face %s, im %p, tx %" i_DF ", ty %" i_DF ", cl %p, size %" i_DF ", text %p, length %lu, align %d, aa %d, utf8 %d)\n", face, im, i_DFcp(tx, ty), cl, i_DFc(size), text, (unsigned long)len, align, aa, aa, utf8)); if (!i_wf_bbox(face, size, text, len, bbox, utf8)) return 0; bits = render_text(face, size, text, len, aa, &sz, &tm, &line_width, bbox, utf8); if (!bits) return 0; tx += bbox[BBOX_NEG_WIDTH]; top = ty; if (align) { top -= tm.tmAscent; } else { top -= tm.tmAscent - bbox[BBOX_ASCENT]; } r = i_render_new(im, sz.cx); outp = bits; for (y = 0; y < sz.cy; ++y) { i_render_color(r, tx, top + sz.cy - y - 1, sz.cx, outp, cl); outp += line_width; } i_render_delete(r); myfree(bits); return 1; } /* =item i_wf_cp(face, im, tx, ty, channel, size, text, len, align, aa) Draws the text in the given channel. =cut */ int i_wf_cp(const char *face, i_img *im, i_img_dim tx, i_img_dim ty, int channel, i_img_dim size, const char *text, size_t len, int align, int aa, int utf8) { unsigned char *bits; SIZE sz; size_t line_width; i_img_dim x, y; TEXTMETRIC tm; i_img_dim top; i_img_dim bbox[BOUNDING_BOX_COUNT]; unsigned char *outp; i_clear_error(); mm_log((1, "i_wf_cp(face %s, im %p, tx %" i_DF ", ty %" i_DF ", channel %d, size %" i_DF ", text %p, length %lu, align %d, aa %d, utf8 %d)\n", face, im, i_DFcp(tx, ty), channel, i_DFc(size), text, (unsigned long)len, align, aa, aa, utf8)); if (!i_wf_bbox(face, size, text, len, bbox, utf8)) return 0; bits = render_text(face, size, text, len, aa, &sz, &tm, &line_width, bbox, utf8); if (!bits) return 0; top = ty; if (align) { top -= tm.tmAscent; } else { top -= tm.tmAscent - bbox[BBOX_ASCENT]; } outp = bits; for (y = 0; y < sz.cy; ++y) { for (x = 0; x < sz.cx; ++x) { i_color pel; int scale = outp[x]; i_gpix(im, tx+x, top+sz.cy-y-1, &pel); pel.channel[channel] = scale; i_ppix(im, tx+x, top+sz.cy-y-1, &pel); } outp += line_width; } myfree(bits); return 1; } static HMODULE gdi_dll; typedef BOOL (CALLBACK *AddFontResourceExA_t)(LPCSTR, DWORD, PVOID); static AddFontResourceExA_t AddFontResourceExAp; typedef BOOL (CALLBACK *RemoveFontResourceExA_t)(LPCSTR, DWORD, PVOID); static RemoveFontResourceExA_t RemoveFontResourceExAp; /* =item i_wf_addfont(char const *filename, char const *resource_file) Adds a TTF font file as usable by the application. Where possible the font is added as private to the application. Under Windows 95/98/ME the font is added globally, since we don't have any choice. In either case call i_wf_delfont() to remove it. =cut */ int i_wf_addfont(char const *filename) { i_clear_error(); mm_log((1, "i_wf_addfont(%s)\n", filename)); if (!gdi_dll) { gdi_dll = GetModuleHandle("GDI32"); if (gdi_dll) { AddFontResourceExAp = (AddFontResourceExA_t)GetProcAddress(gdi_dll, "AddFontResourceExA"); RemoveFontResourceExAp = (RemoveFontResourceExA_t)GetProcAddress(gdi_dll, "RemoveFontResourceExA"); mm_log((1, "i_wf_addfont: AddFontResourceExA %p RemoveFontResourceExA %p\n", AddFontResourceExAp, RemoveFontResourceExAp)); } } if (AddFontResourceExAp && RemoveFontResourceExAp) { mm_log((1, "i_wf_addfont: adding via AddFontResourceEx()\n")); if (AddFontResourceExAp(filename, FR_PRIVATE, 0)) { return 1; } } else { mm_log((1, "i_wf_addfont: adding via AddFontResource()\n")); if (AddFontResource(filename)) { return 1; } } mm_log((1, "i_wf_addfont failed: %ld\n", GetLastError())); i_push_errorf(0, "Could not add resource: %ld", GetLastError()); return 0; } /* =item i_wf_delfont(char const *filename, char const *resource_file) Deletes a TTF font file as usable by the application. =cut */ int i_wf_delfont(char const *filename) { i_clear_error(); mm_log((1, "i_wf_delfont(%s)\n", filename)); if (AddFontResourceExAp && RemoveFontResourceExAp) { mm_log((1, "i_wf_delfont: removing via RemoveFontResourceEx()\n")); if (RemoveFontResourceExAp(filename, FR_PRIVATE, 0)) return 1; } else { mm_log((1, "i_wf_delfont: adding via RemoveFontResourceEx()\n")); if (RemoveFontResource(filename)) return 1; } mm_log((1, "i_wf_delfont failed: %ld\n", GetLastError())); i_push_errorf(0, "Could not remove resource: %ld", GetLastError()); return 0; } /* =back =head1 INTERNAL FUNCTIONS =over =item set_logfont(face, size, lf) Fills in a LOGFONT structure with reasonable defaults. =cut */ static void set_logfont(const char *face, int size, LOGFONT *lf) { memset(lf, 0, sizeof(LOGFONT)); lf->lfHeight = -size; /* character height rather than cell height */ lf->lfCharSet = DEFAULT_CHARSET; lf->lfOutPrecision = OUT_TT_PRECIS; lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; lf->lfQuality = PROOF_QUALITY; strncpy(lf->lfFaceName, face, sizeof(lf->lfFaceName)-1); /* NUL terminated by the memset at the top */ } /* =item render_text(face, size, text, length, aa, pbm, psz, tm) renders the text to an in-memory RGB bitmap It would be nice to render to greyscale, but Windows doesn't have native greyscale bitmaps. =cut */ static unsigned char * render_text(const char *face, int size, const char *text, size_t length, int aa, SIZE *psz, TEXTMETRIC *tm, size_t *bytes_per_line, i_img_dim *bbox, int utf8) { BITMAPINFO bmi; BITMAPINFOHEADER *bmih = &bmi.bmiHeader; HDC dc, bmpDc; LOGFONT lf; HFONT font, oldFont; SIZE sz; HBITMAP bm, oldBm; LPVOID bits; int wide_count; LPWSTR wide_text; unsigned char *result; dc = GetDC(NULL); set_logfont(face, size, &lf); #ifdef ANTIALIASED_QUALITY /* See KB article Q197076 "INFO: Controlling Anti-aliased Text via the LOGFONT Structure" */ lf.lfQuality = aa ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY; #endif if (utf8) { wide_text = utf8_to_wide_string(text, length, &wide_count); } else { wide_text = latin1_to_wide_string(text, length, &wide_count); } bmpDc = CreateCompatibleDC(dc); if (bmpDc) { font = CreateFontIndirect(&lf); if (font) { oldFont = SelectObject(bmpDc, font); GetTextMetrics(bmpDc, tm); sz.cx = bbox[BBOX_ADVANCE_WIDTH] - bbox[BBOX_NEG_WIDTH] + bbox[BBOX_POS_WIDTH]; sz.cy = bbox[BBOX_GLOBAL_ASCENT] - bbox[BBOX_GLOBAL_DESCENT]; memset(&bmi, 0, sizeof(bmi)); bmih->biSize = sizeof(*bmih); bmih->biWidth = sz.cx; bmih->biHeight = sz.cy; bmih->biPlanes = 1; bmih->biBitCount = 24; bmih->biCompression = BI_RGB; bmih->biSizeImage = 0; bmih->biXPelsPerMeter = (LONG)(72 / 2.54 * 100); bmih->biYPelsPerMeter = bmih->biXPelsPerMeter; bmih->biClrUsed = 0; bmih->biClrImportant = 0; bm = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); if (bm) { oldBm = SelectObject(bmpDc, bm); SetTextColor(bmpDc, RGB(255, 255, 255)); SetBkColor(bmpDc, RGB(0, 0, 0)); TextOutW(bmpDc, -bbox[BBOX_NEG_WIDTH], 0, wide_text, wide_count); SelectObject(bmpDc, oldBm); } else { i_push_errorf(0, "Could not create DIB section for render: %ld", GetLastError()); SelectObject(bmpDc, oldFont); DeleteObject(font); DeleteDC(bmpDc); ReleaseDC(NULL, dc); myfree(wide_text); return NULL; } SelectObject(bmpDc, oldFont); DeleteObject(font); } else { myfree(wide_text); i_push_errorf(0, "Could not create logical font: %ld", GetLastError()); DeleteDC(bmpDc); ReleaseDC(NULL, dc); return NULL; } DeleteDC(bmpDc); } else { myfree(wide_text); i_push_errorf(0, "Could not create rendering DC: %ld", GetLastError()); ReleaseDC(NULL, dc); return NULL; } myfree(wide_text); ReleaseDC(NULL, dc); *psz = sz; /* convert into a map we can just pass to i_render_color() */ { i_img_dim x, y; unsigned char *outp, *ucbits; size_t bits_line_width; *bytes_per_line = sz.cx; result = mymalloc(sz.cx * sz.cy); outp = result; ucbits = bits; bits_line_width = sz.cx * 3; bits_line_width = (bits_line_width + 3) / 4 * 4; for (y = 0; y < sz.cy; ++y) { for (x = 0; x < sz.cx; ++x) { *outp++ = ucbits[3 * x]; } ucbits += bits_line_width; } } DeleteObject(bm); return result; } /* =item utf8_to_wide_string(text, text_len, wide_chars) =cut */ static LPWSTR utf8_to_wide_string(char const *text, int text_len, int *wide_chars) { int wide_count = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, text_len, NULL, 0); LPWSTR result; if (wide_count < 0) { i_push_errorf(0, "Could not convert utf8: %ld", GetLastError()); return NULL; } ++wide_count; result = mymalloc(sizeof(WCHAR) * wide_count); if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, text_len, result, wide_count) < 0) { i_push_errorf(0, "Could not convert utf8: %ld", GetLastError()); return NULL; } result[wide_count-1] = (WCHAR)'\0'; *wide_chars = wide_count - 1; return result; } static LPWSTR latin1_to_wide_string(char const *text, int text_len, int *wide_chars) { LPWSTR result = mymalloc(sizeof(WCHAR) * (text_len + 1)); size_t i; for (i = 0; i < text_len; ++i) { result[i] = (unsigned char)text[i]; } result[i] = 0; *wide_chars = text_len; return result; } /* =back =head1 BUGS Should really use a structure so we can set more attributes. Should support UTF8 =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/W32/imw32.h0000644000175000017500000000117312263740600017250 0ustar gregoagregoa#ifndef IMAGER_IMW32_H #define IMAGER_IMW32_H #include "imdatatypes.h" extern int i_wf_bbox(const char *face, i_img_dim size, const char *text, size_t length, i_img_dim *bbox, int utf8); extern int i_wf_text(const char *face, i_img *im, i_img_dim tx, i_img_dim ty, const i_color *cl, i_img_dim size, const char *text, size_t len, int align, int aa, int utf8); extern int i_wf_cp(const char *face, i_img *im, i_img_dim tx, i_img_dim ty, int channel, i_img_dim size, const char *text, size_t len, int align, int aa, int utf8); extern int i_wf_addfont(char const *file); extern int i_wf_delfont(char const *file); #endif libimager-perl-1.004+dfsg.orig/W32/README0000644000175000017500000000062112263740600017013 0ustar gregoagregoaImager::Font::W32 provides font support to Imager via the Win32 GDI API functions.. It requires Win32 header files and libraries to be available. This is currently shipped as part of Imager, but may not be installed as part of Imager if headers or libraries aren't found at build time., if your module or application requires Win32 font support support then add Imager::Font::W32 as a prerequisite. libimager-perl-1.004+dfsg.orig/W32/W32.xs0000644000175000017500000000366612263740600017076 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "imw32.h" DEFINE_IMAGER_CALLBACKS; MODULE = Imager::Font::W32 PACKAGE = Imager::Font::W32 void i_wf_bbox(face, size, text_sv, utf8=0) const char *face i_img_dim size SV *text_sv int utf8 PREINIT: i_img_dim cords[BOUNDING_BOX_COUNT]; int rc, i; char const *text; STRLEN text_len; PPCODE: text = SvPV(text_sv, text_len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif if (rc = i_wf_bbox(face, size, text, text_len, cords, utf8)) { EXTEND(SP, rc); for (i = 0; i < rc; ++i) PUSHs(sv_2mortal(newSViv(cords[i]))); } undef_int i_wf_text(face, im, tx, ty, cl, size, text_sv, align, aa, utf8 = 0) const char *face Imager::ImgRaw im i_img_dim tx i_img_dim ty Imager::Color cl i_img_dim size SV *text_sv int align int aa int utf8 PREINIT: char const *text; STRLEN text_len; CODE: text = SvPV(text_sv, text_len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, text_len, align, aa, utf8); OUTPUT: RETVAL undef_int i_wf_cp(face, im, tx, ty, channel, size, text_sv, align, aa, utf8 = 0) const char *face Imager::ImgRaw im i_img_dim tx i_img_dim ty int channel i_img_dim size SV *text_sv int align int aa int utf8 PREINIT: char const *text; STRLEN text_len; CODE: text = SvPV(text_sv, text_len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, text_len, align, aa, utf8); OUTPUT: RETVAL undef_int i_wf_addfont(font) char *font undef_int i_wf_delfont(font) char *font BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/W32/t/0000755000175000017500000000000012617614576016416 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/W32/t/t10win32.t0000644000175000017500000002301512263740600020054 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 59; use Imager qw(:all); use Imager::Test qw(diff_text_with_nul isnt_image); ++$|; ok(-d "testout" or mkdir("testout"), "testout directory"); ok($Imager::formats{w32}, "\$formats{w32} populated"); init_log("testout/t10w32font.log",1); SKIP: { print "# has w32\n"; my $fontname=$ENV{'TTFONTTEST'} || 'Times New Roman Bold'; # i_init_fonts(); # unnecessary for Win32 font support my $bgcolor=i_color_new(255,0,0,0); my $overlay=Imager::ImgRaw::new(200,70,3); my @bbox=Imager::Font::W32::i_wf_bbox($fontname, 50.0,'XMCLH'); print "#bbox: ($bbox[0], $bbox[1]) - ($bbox[2], $bbox[3])\n"; ok(Imager::Font::W32::i_wf_cp($fontname,$overlay,5,50,1,50.0,'XMCLH',1,1), "i_wf_cp smoke test"); i_line($overlay,0,50,100,50,$bgcolor, 1); if (open(FH,">testout/t10font.ppm")) { binmode(FH); my $io = Imager::io_new_fd(fileno(FH)); i_writeppm_wiol($overlay,$io); close(FH); } else { diag "cannot open testout/t10font.ppm: $!"; } $bgcolor=i_color_set($bgcolor,200,200,200,255); my $backgr=Imager::ImgRaw::new(500,300,3); ok(Imager::Font::W32::i_wf_text($fontname,$backgr,100,100,$bgcolor,100,'MAW.',1, 1), "i_wf_text smoke test"); i_line($backgr,0, 100, 499, 100, NC(0, 0, 255), 1); if (open(FH,">testout/t10font2.ppm")) { binmode(FH); my $io = Imager::io_new_fd(fileno(FH)); i_writeppm_wiol($backgr,$io); close(FH); } else { diag "cannot open testout/t10font2.ppm: $!"; } my $img = Imager->new(xsize=>200, ysize=>200); my $font = Imager::Font->new(face=>$fontname, size=>20); ok($img->string('x'=>30, 'y'=>30, string=>"Imager", color=>NC(255, 0, 0), font=>$font), "string with win32 smoke test") or diag "simple string output: ",$img->errstr; $img->write(file=>'testout/t10_oo.ppm') or diag "Cannot save t10_oo.ppm: ", $img->errstr; my @bbox2 = $font->bounding_box(string=>'Imager'); is(@bbox2, 8, "got 8 values from bounding_box"); # this only applies while the Win32 driver returns 6 values # at this point we don't return the advance width from the low level # bounding box function, so the Imager::Font::BBox advance method should # return end_offset, check it does my $bbox = $font->bounding_box(string=>"some text"); ok($bbox, "got the bounding box object"); is($bbox->advance_width, $bbox->end_offset, "check advance_width fallback correct"); SKIP: { $^O eq 'cygwin' and skip("Too hard to get correct directory for test font on cygwin", 13); my $extra_font = "fontfiles/ExistenceTest.ttf"; unless (ok(Imager::Font::W32::i_wf_addfont($extra_font), "add test font")) { diag "adding font resource: ",Imager::_error_as_msg(); skip("Could not add font resource", 12); } my $namefont = Imager::Font->new(face=>"ExistenceTest"); ok($namefont, "create font based on added font"); # the test font is known to have a shorter advance width for that char @bbox = $namefont->bounding_box(string=>"/", size=>100); print "# / box: @bbox\n"; is(@bbox, 8, "should be 8 entries"); isnt($bbox[6], $bbox[2], "different advance width"); $bbox = $namefont->bounding_box(string=>"/", size=>100); isnt($bbox->pos_width, $bbox->advance_width, "OO check"); cmp_ok($bbox->right_bearing, '<', 0, "check right bearing"); cmp_ok($bbox->display_width, '>', $bbox->advance_width, "check display width (roughly)"); my $im = Imager->new(xsize=>200, ysize=>200); $im->box(filled => 1, color => '#202020'); $im->box(box => [ 20 + $bbox->neg_width, 100-$bbox->ascent, 20+$bbox->advance_width-$bbox->right_bearing, 100-$bbox->descent ], color => '#101010', filled => 1); $im->line(color=>'blue', x1=>20, y1=>0, x2=>20, y2=>199); my $right = 20 + $bbox->advance_width; $im->line(color=>'blue', x1=>$right, y1=>0, x2=>$right, y2=>199); $im->line(color=>'blue', x1=>0, y1 => 100, x2=>199, y2 => 100); ok($im->string(font=>$namefont, text=>"/", x=>20, y=>100, color=>'white', size=>100), "draw / from ExistenceText") or diag "draw / from ExistenceTest:", $im->errstr; $im->setpixel(x => 20+$bbox->neg_width, y => 100-$bbox->ascent, color => 'red'); $im->setpixel(x => 20+$bbox->advance_width - $bbox->right_bearing, y => 100-$bbox->descent, color => 'red'); $im->write(file=>'testout/t10_slash.ppm'); # check with a char that fits inside the box $bbox = $namefont->bounding_box(string=>"!", size=>100); print "# pos width ", $bbox->pos_width, "\n"; print "# ! box: @$bbox\n"; is($bbox->pos_width, $bbox->advance_width, "check backwards compatibility"); cmp_ok($bbox->left_bearing, '>', 0, "left bearing positive"); cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive"); cmp_ok($bbox->display_width, '<', $bbox->advance_width, "display smaller than advance"); $im = Imager->new(xsize=>200, ysize=>200); $im->box(filled => 1, color => '#202020'); $im->box(box => [ 20 + $bbox->neg_width, 100-$bbox->ascent, 20+$bbox->advance_width-$bbox->right_bearing, 100-$bbox->descent ], color => '#101010', filled => 1); $im->line(color=>'blue', x1=>20, y1=>0, x2=>20, y2=>199); $right = 20 + $bbox->advance_width; $im->line(color=>'blue', x1=>$right, y1=>0, x2=>$right, y2=>199); $im->line(color=>'blue', x1=>0, y1 => 100, x2=>199, y2 => 100); ok($im->string(font=>$namefont, text=>"!", x=>20, y=>100, color=>'white', size=>100), "draw / from ExistenceText") or diag "draw / from ExistenceTest: ", $im->errstr; $im->setpixel(x => 20+$bbox->neg_width, y => 100-$bbox->ascent, color => 'red'); $im->setpixel(x => 20+$bbox->advance_width - $bbox->right_bearing, y => 100-$bbox->descent, color => 'red'); $im->write(file=>'testout/t10_bang.ppm'); Imager::Font::W32::i_wf_delfont("fontfiles/ExistenceTest.ttf"); } SKIP: { print "# alignment tests\n"; my $font = Imager::Font->new(face=>"Arial"); ok($font, "loaded Arial OO") or skip("could not load font:".Imager->errstr, 4); my $im = Imager->new(xsize=>140, ysize=>150); my %common = ( font=>$font, size=>40, aa=>1, ); $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue'); $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue'); $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); for my $args ([ x=>5, text=>"A", color=>"white" ], [ x=>40, text=>"y", color=>"white" ], [ x=>75, text=>"A", channel=>1 ], [ x=>110, text=>"y", channel=>1 ]) { print "# ", join(",", @$args), "\n"; ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); } ok($im->write(file=>'testout/t10align.ppm'), "save align image"); } { print "# utf 8 support\n"; my $font = Imager::Font->new(face => "Arial"); ok($font, "created font"); my $im = Imager->new(xsize => 100, ysize => 100); ok($im->string(string => "\xE2\x98\xBA", size => 80, aa => 1, utf8 => 1, color => "white", font => $font, x => 5, y => 80), "draw in utf8 (hand encoded)") or diag "draw utf8 hand-encoded ", $im->errstr; ok($im->write(file=>'testout/t10utf8.ppm'), "save utf8 image") or diag "save t10utf8.ppm: ", $im->errstr; # native perl utf8 # Win32 only supported on 5.6+ # since this gets compiled even on older perls we need to be careful # creating the string my $text; eval q{$text = "\x{263A}"}; # A, HYPHEN, A in our test font my $im2 = Imager->new(xsize => 100, ysize => 100); ok($im2->string(string => $text, size => 80, aa => 1, color => 'white', font => $font, x => 5, y => 80), "draw in utf8 (perl utf8)") or diag "draw in utf8: ", $im->errstr; ok($im2->write(file=>'testout/t10utf8b.ppm'), "save utf8 image"); is(Imager::i_img_diff($im->{IMG}, $im2->{IMG}), 0, "check result is the same"); # bounding box cmp_ok($font->bounding_box(string=>$text, size => 80)->advance_width, '<', 100, "check we only get width of single char rather than 3"); } { # string output cut off at NUL ('\0') # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd my $font = Imager::Font->new(face=>'Arial', type=>'w32'); ok($font, "loaded Arial"); diff_text_with_nul("a\\0b vs a", "a\0b - color", "a", font => $font, color => '#FFFFFF'); diff_text_with_nul("a\\0b vs a", "a\0b - channel", "a", font => $font, channel => 1); # UTF8 encoded \x{2010} my $dash = pack("C*", 0xE2, 0x80, 0x90); diff_text_with_nul("utf8 dash\0dash vs dash - color", "$dash\0$dash", $dash, font => $font, color => '#FFFFFF', utf8 => 1); diff_text_with_nul("utf8 dash\0dash vs dash - channel", "$dash\0$dash", $dash, font => $font, channel => 1, utf8 => 1); } { # RT 71469 my $font1 = Imager::Font->new(face => $fontname, type => "w32"); my $font2 = Imager::Font::W32->new(face => $fontname ); for my $font ($font1, $font2) { print "# ", join(",", $font->{color}->rgba), "\n"; my $im = Imager->new(xsize => 20, ysize => 20, channels => 4); ok($im->string(text => "T", font => $font, y => 15), "draw with default color") or diag "draw with default color: ", $im->errstr; my $work = Imager->new(xsize => 20, ysize => 20); my $cmp = $work->copy; $work->rubthrough(src => $im); isnt_image($work, $cmp, "make sure something was drawn"); } } } libimager-perl-1.004+dfsg.orig/W32/t/t90std.t0000644000175000017500000000106112263740600017711 0ustar gregoagregoa#!perl -w use strict; use Imager::Test qw(std_font_tests std_font_test_count); use Imager::Font; use Test::More tests => std_font_test_count(); Imager->open_log(log => "testout/t90std.log"); my $font = Imager::Font->new(face => "Times New Roman Bold", type => "w32"); SKIP: { $font or skip "Cannot load font", std_font_test_count(); std_font_tests ({ font => $font, #has_chars => [ 1, 1, 1 ], #files => 1, #glyph_name_font => $name_font, #glyph_names => [ "A", "uni2010", "A" ], }); } Imager->close_log;libimager-perl-1.004+dfsg.orig/W32/lib/0000755000175000017500000000000012617614576016721 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/W32/lib/Imager/0000755000175000017500000000000012617614576020125 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/W32/lib/Imager/Font/0000755000175000017500000000000012617614576021033 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/W32/lib/Imager/Font/Win32.pm0000644000175000017500000000060312263740600022253 0ustar gregoagregoapackage Imager::Font::Win32; use strict; use vars qw(@ISA); @ISA = qw(Imager::Font::W32); require Imager::Font::W32; 1; __END__ =head1 NAME =for stopwords GDI Imager::Font::Win32 - uses Win32 GDI services for text output =head1 SYNOPSIS my $font = Imager::Font->new(face=>"Arial"); =head1 DESCRIPTION This module is obsolete. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/W32/Makefile.PL0000644000175000017500000000462312567572530020127 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Getopt::Long; use Config; my $verbose = $ENV{IM_VERBOSE}; my @libpaths; my @incpaths; GetOptions("incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$verbose); our $BUILDING_IMAGER; our %IMAGER_LIBS; my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; my %opts = ( NAME => 'Imager::Font::W32', VERSION_FROM => 'W32.pm', OBJECT => 'W32.o win32.o', clean => { FILES => 'testout' }, ); my @inc; if ($BUILDING_IMAGER) { push @inc, "-I.."; unshift @INC, "../lib"; } else { unshift @INC, "inc"; print "Win32: building independently\n"; require Imager::ExtUtils; push @inc, Imager::ExtUtils->includes; $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ]; # Imager required configure through use my @Imager_req = ( Imager => "0.95" ); if ($MM_ver >= 6.46) { $opts{META_MERGE} = { configure_requires => { @Imager_req, }, build_requires => { @Imager_req, "Test::More" => "0.47", }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; $opts{PREREQ_PM} = { @Imager_req, XSLoader => 0, }; } } require Imager::Probe; my %probe = ( name => "Win32", inccheck => sub { -e File::Spec->catfile($_[0], "windows.h") }, libbase => "gdi32", testcode => _win32_test_code(), testcodeheaders => [ "stdio.h", "string.h", "windows.h" ], incpath => \@incpaths, libpath => \@libpaths, verbose => $verbose, ); my $probe_res = Imager::Probe->probe(\%probe); if ($probe_res) { $IMAGER_LIBS{Win32} = 1; push @inc, $probe_res->{INC}; $opts{LIBS} = $probe_res->{LIBS}; $opts{DEFINE} = $probe_res->{DEFINE}; $opts{INC} = "@inc"; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'Win32 font file support for Imager'; } WriteMakefile(%opts); } else { $IMAGER_LIBS{Win32} = 0; if ($BUILDING_IMAGER) { ExtUtils::MakeMaker::WriteEmptyMakefile(%opts); } else { # fail in good way die "OS unsupported: Win32 libraries or headers not found\n"; } } sub _win32_test_code { return <<'CODE'; HDC dc = GetDC(NULL); HDC bmpDc = CreateCompatibleDC(dc); DeleteDC(bmpDc); ReleaseDC(NULL, dc); return 0; CODE } libimager-perl-1.004+dfsg.orig/W32/fontfiles/0000755000175000017500000000000012617614576020144 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/W32/fontfiles/ExistenceTest.ttf0000644000175000017500000000363412031434614023437 0ustar gregoagregoa €0OS/2QB_¥¼VcmapVÕJcvt å‡`glyfT{0Òp~headÖƒ#ð6hheatþ($hmtx-LlocaÖ` maxpI´l nameIôôŒâpostÿ¨Fp,èô ÈÈÈÈÈÈ1PfEd@ ~ÿÉZ7D(!/ÿÿ!/ÿÿÿâÿÕ!y~.–!nš.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!!MþÔ þõšýf!X3Ïâ*†± ?° 3° 3° 3±í±í±í±í°°Þ° 2°!2°"2±í±í±í±*í°$/°%3°&3°'3°(3±í±í±í°/°3°3°3°3°#3±í±í±í±í±í±,Ì01732+"'&=47632+"'&=476k2!  2!  ,!  ,!  ~ !  ! dþ6!  Ê! ÿÄÿÉ3 °/°/01;K"üµ$üè÷Å¡ƒ_<õèº2ïåº2ïåÿÄÿÉ3 ÿ8ZùÿÄÿÇ3°!M63ùÿÅ+++«¿+@†@ AO$W |Š ’€ ">HN˜´Ä €  " > HN ˜ ´ ÄCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ExistenceTestRegularPfaEdit : ExistenceTest : 28-11-2072ExistenceTest001.000ExistenceTestCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ExistenceTestRegularPfaEdit : ExistenceTest : 28-11-2072ExistenceTest001.000ExistenceTestÿœ2libimager-perl-1.004+dfsg.orig/W32/W32.pm0000644000175000017500000000357612460670607017070 0ustar gregoagregoapackage Imager::Font::W32; use strict; use Imager; use vars qw($VERSION @ISA); @ISA = qw(Imager::Font); BEGIN { $VERSION = "0.89"; require XSLoader; XSLoader::load('Imager::Font::W32', $VERSION); } # called by Imager::Font::new() # since Win32's HFONTs include the size information this # is just a stub sub new { my $class = shift; my %opts = ( color => Imager::Color->new(255, 0, 0), size => 15, @_, ); return bless \%opts, $class; } sub _bounding_box { my ($self, %opts) = @_; my @bbox = i_wf_bbox($self->{face}, $opts{size}, $opts{string}, $opts{utf8}); unless (@bbox) { Imager->_set_error(Imager->_error_as_msg); return; } return @bbox; } sub _draw { my $self = shift; my %input = @_; if (exists $input{channel}) { return i_wf_cp($self->{face}, $input{image}{IMG}, $input{x}, $input{'y'}, $input{channel}, $input{size}, $input{string}, $input{align}, $input{aa}, $input{utf8}); } else { return i_wf_text($self->{face}, $input{image}{IMG}, $input{x}, $input{'y'}, $input{color}, $input{size}, $input{string}, $input{align}, $input{aa}, $input{utf8}); } } sub utf8 { return 1; } sub can_glyph_names { return; } 1; __END__ =head1 NAME Imager::Font::W32 - font support using C on Win32 =head1 SYNOPSIS use Imager; my $img = Imager->new; my $font = Imager::Font->new(face => "Arial", type => "w32"); $img->string(... font => $font); =head1 DESCRIPTION This provides font support on Win32. =head1 CAVEATS Unfortunately, older versions of Imager would install Imager::Font::Win32 even if Win32 wasn't available, and if no font was created would succeed in loading the module. This means that an existing Win32.pm could cause a probe success for Win32 fonts, so I've renamed it. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Font. =cut libimager-perl-1.004+dfsg.orig/typemap.local0000644000175000017500000000777512614520110020264 0ustar gregoagregoa# definitions we don't want to make visible to the world # because they're intended for use specifically by Imager.xs # internal types used in Imager.xs i_channel_list T_IM_CHANNEL_LIST i_sample_list T_IM_SAMPLE_LIST i_fsample_list T_IM_FSAMPLE_LIST i_polygon_list T_IM_POLYGON_LIST off_t T_OFF_T Imager::Internal::Hlines T_PTROBJ Imager::Context T_PTROBJ i_palidx T_IV double * T_AVARRAY int * T_AVARRAY i_img_dim * T_AVARRAY i_color * T_AVARRAY i_poly_fill_mode_t T_I_POLY_FILL_MODE_T ############################################################################# INPUT T_OFF_T $var = i_sv_off_t(aTHX_ $arg); T_IM_CHANNEL_LIST SvGETMAGIC($arg); if (SvOK($arg)) { AV *channels_av; int i; if (!SvROK($arg) || SvTYPE(SvRV($arg)) != SVt_PVAV) { croak(\"$var is not an array ref\"); } channels_av = (AV *)SvRV($arg); $var.count = av_len(channels_av) + 1; if ($var.count < 1) { croak(\"$pname: no channels provided\"); } $var.channels = malloc_temp(aTHX_ sizeof(int) * $var.count); for (i = 0; i < $var.count; ++i) { SV **entry = av_fetch(channels_av, i, 0); $var.channels[i] = entry ? SvIV(*entry) : 0; } } else { /* assumes we have an image */ $var.count = im->channels; $var.channels = NULL; } T_IM_SAMPLE_LIST SvGETMAGIC($arg); if (!SvOK($arg)) croak(\"$var must be a scalar or an arrayref\"); if (SvROK($arg)) { i_img_dim i; AV *av; i_sample_t *s; if (SvTYPE(SvRV($arg)) != SVt_PVAV) croak(\"$var must be a scalar or an arrayref\"); av = (AV *)SvRV($arg); $var.count = av_len(av) + 1; if ($var.count < 1) croak(\"$pname: no samples provided in $var\"); s = malloc_temp(aTHX_ sizeof(i_sample_t) * $var.count); for (i = 0; i < $var.count; ++i) { SV **entry = av_fetch(av, i, 0); s[i] = entry ? SvIV(*entry) : 0; } $var.samples = s; } else { /* non-magic would be preferable here */ $var.samples = (const i_sample_t *)SvPVbyte($arg, $var.count); if ($var.count == 0) croak(\"$pname: no samples provided in $var\"); } T_IM_FSAMPLE_LIST SvGETMAGIC($arg); if (!SvOK($arg)) croak(\"$var must be a scalar or an arrayref\"); if (SvROK($arg)) { i_img_dim i; AV *av; i_fsample_t *s; if (SvTYPE(SvRV($arg)) != SVt_PVAV) croak(\"$var must be a scalar or an arrayref\"); av = (AV *)SvRV($arg); $var.count = av_len(av) + 1; if ($var.count < 1) croak(\"$pname: no samples provided in $var\"); s = malloc_temp(aTHX_ sizeof(i_fsample_t) * $var.count); for (i = 0; i < $var.count; ++i) { SV **entry = av_fetch(av, i, 0); s[i] = entry ? SvNV(*entry) : 0; } $var.samples = s; } else { /* non-magic would be preferable here */ $var.samples = (const i_fsample_t *)SvPVbyte($arg, $var.count); if ($var.count % sizeof(double)) croak(\"$pname: $var doesn't not contain a integer number of samples\"); $var.count /= sizeof(double); if ($var.count == 0) croak(\"$pname: no samples provided in $var\"); } T_IM_POLYGON_LIST S_get_polygon_list(aTHX_ &$var, $arg); T_AVARRAY STMT_START { SV* const xsub_tmp_sv = $arg; SvGETMAGIC(xsub_tmp_sv); if (SvROK(xsub_tmp_sv) && SvTYPE(SvRV(xsub_tmp_sv)) == SVt_PVAV){ AV *xsub_tmp_av = (AV*)SvRV(xsub_tmp_sv); STRLEN xsub_index; size_$var = av_len(xsub_tmp_av) + 1; $var = $ntype(size_$var); for (xsub_index = 0; xsub_index < size_$var; ++xsub_index) { SV **sv = av_fetch(xsub_tmp_av, xsub_index, 0); if (sv) { ${var}[xsub_index] = Sv${(my $ntt = $ntype) =~ s/Ptr$//; \(ucfirst $ntt)}(*sv, \"$pname\"); } } } else{ Perl_croak(aTHX_ \"%s: %s is not an ARRAY reference\", ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\"); } } STMT_END T_I_POLY_FILL_MODE_T $var = S_get_poly_fill_mode(aTHX_ $arg); ############################################################################# OUTPUT T_OFF_T $arg = i_new_sv_off_t(aTHX_ $var); libimager-perl-1.004+dfsg.orig/imextpltypes.h0000644000175000017500000000143112031434615020477 0ustar gregoagregoa#ifndef IMAGER_IMEXTPLTYPES_H_ #define IMAGER_IMEXTPLTYPES_H_ #ifndef PERL_NO_GET_CONTEXT #error Sorry, you need to build with PERL_NO_GET_CONTEXT #endif #define IMAGER_PL_API_VERSION 1 /* This file provides functions useful for external code in interfacing with perl - these functions aren't part of the core Imager API. */ #define IMAGER_PL_API_LEVEL 1 typedef struct { int version; int level; /* IMAGER_PL_API_LEVEL 1 functions */ void (*f_ip_handle_quant_opts)(pTHX_ i_quantize *quant, HV *hv); void (*f_ip_cleanup_quant_opts)(pTHX_ i_quantize *quant); void (*f_ip_copy_colors_back)(pTHX_ HV *hv, i_quantize *quant); /* IMAGER_PL_API_LEVEL 2 functions will go here */ } im_pl_ext_funcs; #define PERL_PL_FUNCTION_TABLE_NAME "Imager::__ext_pl_func_table" #endif libimager-perl-1.004+dfsg.orig/filters.im0000644000175000017500000016270612322335072017573 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" #include #include /* =head1 NAME filters.im - implements filters that operate on images =head1 SYNOPSIS i_contrast(im, 0.8); i_hardinvert(im); i_hardinvertall(im); i_unsharp_mask(im, 2.0, 1.0); ... and more =head1 DESCRIPTION filters.c implements basic filters for Imager. These filters should be accessible from the filter interface as defined in the pod for Imager. =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ /* =item saturate(in) Clamps the input value between 0 and 255. (internal) in - input integer =cut */ static unsigned char saturate(int in) { if (in>255) { return 255; } else if (in>0) return in; return 0; } /* =item i_contrast(im, intensity) Scales the pixel values by the amount specified. im - image object intensity - scalefactor =cut */ void i_contrast(i_img *im, float intensity) { i_img_dim x, y; unsigned char ch; unsigned int new_color; i_color rcolor; dIMCTXim(im); im_log((aIMCTX, 1,"i_contrast(im %p, intensity %f)\n", im, intensity)); if(intensity < 0) return; for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { i_gpix(im, x, y, &rcolor); for(ch = 0; ch < im->channels; ch++) { new_color = (unsigned int) rcolor.channel[ch]; new_color *= intensity; if(new_color > 255) { new_color = 255; } rcolor.channel[ch] = (unsigned char) new_color; } i_ppix(im, x, y, &rcolor); } } static int s_hardinvert_low(i_img *im, int all) { i_img_dim x, y; int ch; int invert_channels = all ? im->channels : i_img_color_channels(im); dIMCTXim(im); im_log((aIMCTX,1,"i_hardinvert)low(im %p, all %d)\n", im, all)); #code im->bits <= 8 IM_COLOR *row, *entry; /* always rooms to allocate a single line of i_color */ row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */ for(y = 0; y < im->ysize; y++) { IM_GLIN(im, 0, im->xsize, y, row); entry = row; for(x = 0; x < im->xsize; x++) { for(ch = 0; ch < invert_channels; ch++) { entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch]; } ++entry; } IM_PLIN(im, 0, im->xsize, y, row); } myfree(row); #/code return 1; } /* =item i_hardinvert(im) Inverts the color channels of the input image. im - image object =cut */ void i_hardinvert(i_img *im) { s_hardinvert_low(im, 0); } /* =item i_hardinvertall(im) Inverts all channels of the input image. im - image object =cut */ void i_hardinvertall(i_img *im) { s_hardinvert_low(im, 1); } /* =item i_noise(im, amount, type) Adjusts the sample values randomly by the amount specified. If type is 0, adjust all channels in a pixel by the same (random) amount amount, if non-zero adjust each sample independently. im - image object amount - deviation in pixel values type - noise individual for each channel if true =cut */ #ifdef WIN32 /* random() is non-ASCII, even if it is better than rand() */ #define random() rand() #endif void i_noise(i_img *im, float amount, unsigned char type) { i_img_dim x, y; unsigned char ch; int new_color; float damount = amount * 2; i_color rcolor; int color_inc = 0; dIMCTXim(im); im_log((aIMCTX, 1,"i_noise(im %p, intensity %.2f\n", im, amount)); if(amount < 0) return; for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { i_gpix(im, x, y, &rcolor); if(type == 0) { color_inc = (amount - (damount * ((float)random() / RAND_MAX))); } for(ch = 0; ch < im->channels; ch++) { new_color = (int) rcolor.channel[ch]; if(type != 0) { new_color += (amount - (damount * ((float)random() / RAND_MAX))); } else { new_color += color_inc; } if(new_color < 0) { new_color = 0; } if(new_color > 255) { new_color = 255; } rcolor.channel[ch] = (unsigned char) new_color; } i_ppix(im, x, y, &rcolor); } } /* =item i_bumpmap(im, bump, channel, light_x, light_y, st) Makes a bumpmap on image im using the bump image as the elevation map. im - target image bump - image that contains the elevation info channel - to take the elevation information from light_x - x coordinate of light source light_y - y coordinate of light source st - length of shadow =cut */ void i_bumpmap(i_img *im, i_img *bump, int channel, i_img_dim light_x, i_img_dim light_y, i_img_dim st) { i_img_dim x, y; int ch; i_img_dim mx, my; i_color x1_color, y1_color, x2_color, y2_color, dst_color; double nX, nY; double tX, tY, tZ; double aX, aY, aL; double fZ; unsigned char px1, px2, py1, py2; dIMCTXim(im); i_img new_im; im_log((aIMCTX, 1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n", im, bump, channel, i_DFcp(light_x, light_y), i_DFc(st))); if(channel >= bump->channels) { im_log((aIMCTX, 1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels)); return; } mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize; my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize; i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels); aX = (light_x > (mx >> 1)) ? light_x : mx - light_x; aY = (light_y > (my >> 1)) ? light_y : my - light_y; aL = sqrt((aX * aX) + (aY * aY)); for(y = 1; y < my - 1; y++) { for(x = 1; x < mx - 1; x++) { i_gpix(bump, x + st, y, &x1_color); i_gpix(bump, x, y + st, &y1_color); i_gpix(bump, x - st, y, &x2_color); i_gpix(bump, x, y - st, &y2_color); i_gpix(im, x, y, &dst_color); px1 = x1_color.channel[channel]; py1 = y1_color.channel[channel]; px2 = x2_color.channel[channel]; py2 = y2_color.channel[channel]; nX = px1 - px2; nY = py1 - py2; nX += 128; nY += 128; fZ = (sqrt((nX * nX) + (nY * nY)) / aL); tX = i_abs(x - light_x) / aL; tY = i_abs(y - light_y) / aL; tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ); if(tZ < 0) tZ = 0; if(tZ > 2) tZ = 2; for(ch = 0; ch < im->channels; ch++) dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ); i_ppix(&new_im, x, y, &dst_color); } } i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0); i_img_exorcise(&new_im); } typedef struct { double x,y,z; } fvec; static float dotp(fvec *a, fvec *b) { return a->x*b->x+a->y*b->y+a->z*b->z; } static void normalize(fvec *a) { double d = sqrt(dotp(a,a)); a->x /= d; a->y /= d; a->z /= d; } /* positive directions: x - right, y - down z - out of the plane I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n ) Here, the variables are: * Ia - ambient colour * Ip - intensity of the point light source * cd - diffuse coefficient * Scol - surface colour * cs - specular coefficient * n - objects shinyness * N - normal vector * L - lighting vector * R - reflection vector * V - vision vector static void fvec_dump(fvec *x) { printf("(%.2f %.2f %.2f)", x->x, x->y, x->z); } */ /* XXX: Should these return a code for success? */ /* =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is) Makes a bumpmap on image im using the bump image as the elevation map. im - target image bump - image that contains the elevation info channel - to take the elevation information from tx - shift in x direction of where to start applying bumpmap ty - shift in y direction of where to start applying bumpmap Lx - x position/direction of light Ly - y position/direction of light Lz - z position/direction of light Ip - light intensity cd - diffuse coefficient cs - specular coefficient n - surface shinyness Ia - ambient colour Il - light colour Is - specular colour if z<0 then the L is taken to be the direction the light is shining in. Otherwise the L is taken to be the position of the Light, Relative to the image. =cut */ void i_bumpmap_complex(i_img *im, i_img *bump, int channel, i_img_dim tx, i_img_dim ty, double Lx, double Ly, double Lz, float cd, float cs, float n, i_color *Ia, i_color *Il, i_color *Is) { i_img new_im; i_img_dim x, y; int ch; i_img_dim mx, Mx, my, My; float cdc[MAXCHANNELS]; float csc[MAXCHANNELS]; i_color x1_color, y1_color, x2_color, y2_color; i_color Scol; /* Surface colour */ fvec L; /* Light vector */ fvec N; /* surface normal */ fvec R; /* Reflection vector */ fvec V; /* Vision vector */ dIMCTXim(im); im_log((aIMCTX, 1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp "), Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n", im, bump, channel, i_DFcp(tx, ty), Lx, Ly, Lz, cd, cs, n, Ia, Il, Is)); if (channel >= bump->channels) { im_log((aIMCTX, 1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels)); return; } for(ch=0; chchannels; ch++) { cdc[ch] = (float)Il->channel[ch]*cd/255.f; csc[ch] = (float)Is->channel[ch]*cs/255.f; } mx = 1; my = 1; Mx = bump->xsize-1; My = bump->ysize-1; V.x = 0; V.y = 0; V.z = 1; if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */ L.x = -Lx; L.y = -Ly; L.z = -Lz; normalize(&L); } else { /* Light is the position of the light source */ L.x = -0.2; L.y = -0.4; L.z = 1; normalize(&L); } i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels); for(y = 0; y < im->ysize; y++) { for(x = 0; x < im->xsize; x++) { double dp1, dp2; double dx = 0, dy = 0; /* Calculate surface normal */ if (mx=0) { L.x = Lx - x; L.y = Ly - y; L.z = Lz; normalize(&L); } dp1 = dotp(&L,&N); R.x = -L.x + 2*dp1*N.x; R.y = -L.y + 2*dp1*N.y; R.z = -L.z + 2*dp1*N.z; dp2 = dotp(&R,&V); dp1 = dp1<0 ?0 : dp1; dp2 = pow(dp2<0 ?0 : dp2,n); i_gpix(im, x, y, &Scol); for(ch = 0; ch < im->channels; ch++) Scol.channel[ch] = saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 ); i_ppix(&new_im, x, y, &Scol); } } i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0); i_img_exorcise(&new_im); } /* =item i_postlevels(im, levels) Quantizes Images to fewer levels. im - target image levels - number of levels =cut */ void i_postlevels(i_img *im, int levels) { i_img_dim x, y; int ch; float pv; int rv; float av; i_color rcolor; rv = (int) ((float)(256 / levels)); av = (float)levels; for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { i_gpix(im, x, y, &rcolor); for(ch = 0; ch < im->channels; ch++) { pv = (((float)rcolor.channel[ch] / 255)) * av; pv = (int) ((int)pv * rv); if(pv < 0) pv = 0; else if(pv > 255) pv = 255; rcolor.channel[ch] = (unsigned char) pv; } i_ppix(im, x, y, &rcolor); } } /* =item i_mosaic(im, size) Makes an image looks like a mosaic with tilesize of size im - target image size - size of tiles =cut */ void i_mosaic(i_img *im, i_img_dim size) { i_img_dim x, y; int ch, z; i_img_dim lx, ly; long sqrsize; i_color rcolor; long col[256]; sqrsize = size * size; for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) { for(z = 0; z < 256; z++) col[z] = 0; for(lx = 0; lx < size; lx++) { for(ly = 0; ly < size; ly++) { i_gpix(im, (x + lx), (y + ly), &rcolor); for(ch = 0; ch < im->channels; ch++) { col[ch] += rcolor.channel[ch]; } } } for(ch = 0; ch < im->channels; ch++) rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize); for(lx = 0; lx < size; lx++) for(ly = 0; ly < size; ly++) i_ppix(im, (x + lx), (y + ly), &rcolor); } } /* =item i_watermark(im, wmark, tx, ty, pixdiff) Applies a watermark to the target image im - target image wmark - watermark image tx - x coordinate of where watermark should be applied ty - y coordinate of where watermark should be applied pixdiff - the magnitude of the watermark, controls how visible it is =cut */ void i_watermark(i_img *im, i_img *wmark, i_img_dim tx, i_img_dim ty, int pixdiff) { i_img_dim vx, vy; int ch; i_color val, wval; i_img_dim mx = wmark->xsize; i_img_dim my = wmark->ysize; for(vx=0;vxchannels;ch++) val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 ); i_ppix(im,tx+vx,ty+vy,&val); } } /* =item i_autolevels_mono(im, lsat, usat) Do autolevels, but monochromatically. =cut */ void i_autolevels_mono(i_img *im, float lsat, float usat) { i_color val; i_img_dim i, x, y, hist[256]; i_img_dim sum_lum, min_lum, max_lum; i_img_dim upper_accum, lower_accum; i_color *row; dIMCTXim(im); int adapt_channels = im->channels == 4 ? 2 : 1; int color_channels = i_img_color_channels(im); i_img_dim color_samples = im->xsize * color_channels; im_log((aIMCTX, 1,"i_autolevels_mono(im %p, lsat %f,usat %f)\n", im, lsat,usat)); /* build the histogram in 8-bits, unless the image has a very small range it should make little difference to the result */ sum_lum = 0; for (i = 0; i < 256; i++) hist[i] = 0; row = mymalloc(im->xsize * sizeof(i_color)); /* create histogram for each channel */ for (y = 0; y < im->ysize; y++) { i_color *p = row; i_glin(im, 0, im->xsize, y, row); if (im->channels > 2) i_adapt_colors(adapt_channels, im->channels, row, im->xsize); for (x = 0; x < im->xsize; x++) { hist[p->channel[0]]++; ++p; } } myfree(row); for(i = 0; i < 256; i++) { sum_lum += hist[i]; } min_lum = 0; max_lum = 255; lower_accum = upper_accum = 0; for(i=0; i<256; i++) { lower_accum += hist[i]; if (lower_accum < sum_lum * lsat) min_lum = i; upper_accum += hist[255-i]; if (upper_accum < sum_lum * usat) max_lum = 255-i; } #code im->bits <= 8 IM_SAMPLE_T *srow = mymalloc(color_samples * sizeof(IM_SAMPLE_T)); #ifdef IM_EIGHT_BIT IM_WORK_T low = min_lum; #else IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX; #endif IM_WORK_T scale = 255.0 / (max_lum - min_lum); for(y = 0; y < im->ysize; y++) { IM_GSAMP(im, 0, im->xsize, y, srow, NULL, color_channels); for(i = 0; i < color_samples; ++i) { IM_WORK_T tmp = (srow[i] - low) * scale; srow[i] = IM_LIMIT(tmp); } IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels); } myfree(srow); #/code } /* =item i_autolevels(im, lsat, usat, skew) Scales and translates each color such that it fills the range completely. Skew is not implemented yet - purpose is to control the color skew that can occur when changing the contrast. im - target image lsat - fraction of pixels that will be truncated at the lower end of the spectrum usat - fraction of pixels that will be truncated at the higher end of the spectrum skew - not used yet Note: this code calculates levels and adjusts each channel separately, which will typically cause a color shift. =cut */ void i_autolevels(i_img *im, float lsat, float usat, float skew) { i_color val; i_img_dim i, x, y, rhist[256], ghist[256], bhist[256]; i_img_dim rsum, rmin, rmax; i_img_dim gsum, gmin, gmax; i_img_dim bsum, bmin, bmax; i_img_dim rcl, rcu, gcl, gcu, bcl, bcu; dIMCTXim(im); im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew)); rsum=gsum=bsum=0; for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0; /* create histogram for each channel */ for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { i_gpix(im, x, y, &val); rhist[val.channel[0]]++; ghist[val.channel[1]]++; bhist[val.channel[2]]++; } for(i=0;i<256;i++) { rsum+=rhist[i]; gsum+=ghist[i]; bsum+=bhist[i]; } rmin = gmin = bmin = 0; rmax = gmax = bmax = 255; rcu = rcl = gcu = gcl = bcu = bcl = 0; for(i=0; i<256; i++) { rcl += rhist[i]; if ( (rclysize; y++) for(x = 0; x < im->xsize; x++) { i_gpix(im, x, y, &val); val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin)); val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin)); val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin)); i_ppix(im, x, y, &val); } } /* =item Noise(x,y) Pseudo noise utility function used to generate perlin noise. (internal) x - x coordinate y - y coordinate =cut */ static double Noise(i_img_dim x, i_img_dim y) { i_img_dim n = x + y * 57; n = (n<<13) ^ n; return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0); } /* =item SmoothedNoise1(x,y) Pseudo noise utility function used to generate perlin noise. (internal) x - x coordinate y - y coordinate =cut */ static double SmoothedNoise1(double x, double y) { double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16; double sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8; double center = Noise(x, y) / 4; return corners + sides + center; } /* =item G_Interpolate(a, b, x) Utility function used to generate perlin noise. (internal) =cut */ static double C_Interpolate(double a, double b, double x) { /* float ft = x * 3.1415927; */ double ft = x * PI; double f = (1 - cos(ft)) * .5; return a*(1-f) + b*f; } /* =item InterpolatedNoise(x, y) Utility function used to generate perlin noise. (internal) =cut */ static double InterpolatedNoise(double x, double y) { i_img_dim integer_X = x; double fractional_X = x - integer_X; i_img_dim integer_Y = y; double fractional_Y = y - integer_Y; double v1 = SmoothedNoise1(integer_X, integer_Y); double v2 = SmoothedNoise1(integer_X + 1, integer_Y); double v3 = SmoothedNoise1(integer_X, integer_Y + 1); double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1); double i1 = C_Interpolate(v1 , v2 , fractional_X); double i2 = C_Interpolate(v3 , v4 , fractional_X); return C_Interpolate(i1 , i2 , fractional_Y); } /* =item PerlinNoise_2D(x, y) Utility function used to generate perlin noise. (internal) =cut */ static float PerlinNoise_2D(float x, float y) { int i,frequency; double amplitude; double total = 0; int Number_Of_Octaves=6; int n = Number_Of_Octaves - 1; for(i=0;iysize; y++) for(x = 0; x < im->xsize; x++) { xc = (double)x-xo+0.5; yc = (double)y-yo+0.5; r = rscale*sqrt(xc*xc+yc*yc)+1.2; a = (PI+atan2(yc,xc))*ascale; v = saturate(128+100*(PerlinNoise_2D(a,r))); /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */ for(ch=0; chchannels; ch++) val.channel[ch]=v; i_ppix(im, x, y, &val); } } /* =item i_turbnoise(im, xo, yo, scale) Perlin-like 2d noise noise. im - target image xo - x coordinate translation yo - y coordinate translation scale - scale of noise =cut */ void i_turbnoise(i_img *im, double xo, double yo, double scale) { i_img_dim x,y; int ch; unsigned char v; i_color val; for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */ v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale)))); for(ch=0; chchannels; ch++) val.channel[ch] = v; i_ppix(im, x, y, &val); } } /* =item i_gradgen(im, num, xo, yo, ival, dmeasure) Gradient generating function. im - target image num - number of points given xo - array of x coordinates yo - array of y coordinates ival - array of i_color objects dmeasure - distance measure to be used. 0 = Euclidean 1 = Euclidean squared 2 = Manhattan distance =cut */ void i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) { i_color val; int p, ch; i_img_dim x, y; int channels = im->channels; i_img_dim xsize = im->xsize; i_img_dim ysize = im->ysize; size_t bytes; double *fdist; dIMCTXim(im); im_log((aIMCTX, 1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure)); for(p = 0; pxsize; i_img_dim ysize = im->ysize; dIMCTXim(im); im_log((aIMCTX,1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure)); for(p = 0; p x positions =item * i_img_dim *yo - array of I y positions =item * i_color *oval - array of I colors xo, yo, oval correspond to each other, the point xo[i], yo[i] has a color something like oval[i], at least closer to that color than other points. =item * int dmeasure - how we measure the distance from some point P(x,y) to any (xo[i], yo[i]). Valid values are: =over =item 0 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2) =item 1 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2) =item 2 manhattan distance: max((y2-y1)**2, (x2-x1)**2) =back An invalid value causes an error exit (the program is aborted). =back =cut */ int i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) { i_color *ival; float *tval; double c1, c2; i_color val; int p, ch; i_img_dim x, y; i_img_dim xsize = im->xsize; i_img_dim ysize = im->ysize; int *cmatch; size_t ival_bytes, tval_bytes; dIMCTXim(im); im_log((aIMCTX, 1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure)); i_clear_error(); if (num <= 0) { i_push_error(0, "no points supplied to nearest_color filter"); return 0; } if (dmeasure < 0 || dmeasure > i_dmeasure_limit) { i_push_error(0, "distance measure invalid"); return 0; } tval_bytes = sizeof(float)*num*im->channels; if (tval_bytes / num != sizeof(float) * im->channels) { i_push_error(0, "integer overflow calculating memory allocation"); return 0; } ival_bytes = sizeof(i_color) * num; if (ival_bytes / sizeof(i_color) != num) { i_push_error(0, "integer overflow calculating memory allocation"); return 0; } tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */ ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */ cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */ for(p = 0; pchannels; ch++) tval[ p * im->channels + ch] = 0; cmatch[p] = 0; } for(y = 0; ychannels; ch++) tval[midx*im->channels + ch] = c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch]; } for(p = 0; pchannels; ch++) ival[p].channel[ch] = tval[p*im->channels + ch]; /* avoid uninitialized value messages from valgrind */ while (ch < MAXCHANNELS) ival[p].channel[ch++] = 0; } i_nearest_color_foo(im, num, xo, yo, ival, dmeasure); return 1; } /* =item i_unsharp_mask(im, stddev, scale) Perform an usharp mask, which is defined as subtracting the blurred image from double the original. =cut */ void i_unsharp_mask(i_img *im, double stddev, double scale) { i_img *copy; i_img_dim x, y; int ch; if (scale < 0) return; /* it really shouldn't ever be more than 1.0, but maybe ... */ if (scale > 100) scale = 100; copy = i_copy(im); i_gaussian(copy, stddev); if (im->bits == i_8_bits) { i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */ i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */ for (y = 0; y < im->ysize; ++y) { i_glin(copy, 0, copy->xsize, y, blur); i_glin(im, 0, im->xsize, y, out); for (x = 0; x < im->xsize; ++x) { for (ch = 0; ch < im->channels; ++ch) { /*int temp = out[x].channel[ch] + scale * (out[x].channel[ch] - blur[x].channel[ch]);*/ int temp = out[x].channel[ch] * 2 - blur[x].channel[ch]; if (temp < 0) temp = 0; else if (temp > 255) temp = 255; out[x].channel[ch] = temp; } } i_plin(im, 0, im->xsize, y, out); } myfree(blur); myfree(out); } else { i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */ i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */ for (y = 0; y < im->ysize; ++y) { i_glinf(copy, 0, copy->xsize, y, blur); i_glinf(im, 0, im->xsize, y, out); for (x = 0; x < im->xsize; ++x) { for (ch = 0; ch < im->channels; ++ch) { double temp = out[x].channel[ch] + scale * (out[x].channel[ch] - blur[x].channel[ch]); if (temp < 0) temp = 0; else if (temp > 1.0) temp = 1.0; out[x].channel[ch] = temp; } } i_plinf(im, 0, im->xsize, y, out); } myfree(blur); myfree(out); } i_img_destroy(copy); } /* =item i_diff_image(im1, im2, mindist) Creates a new image that is transparent, except where the pixel in im2 is different from im1, where it is the pixel from im2. The samples must differ by at least mindiff to be considered different. =cut */ i_img * i_diff_image(i_img *im1, i_img *im2, double mindist) { i_img *out; int outchans, diffchans; i_img_dim xsize, ysize; dIMCTXim(im1); i_clear_error(); if (im1->channels != im2->channels) { i_push_error(0, "different number of channels"); return NULL; } outchans = diffchans = im1->channels; if (outchans == 1 || outchans == 3) ++outchans; xsize = i_min(im1->xsize, im2->xsize); ysize = i_min(im1->ysize, im2->ysize); out = i_sametype_chans(im1, xsize, ysize, outchans); if (im1->bits == i_8_bits && im2->bits == i_8_bits) { i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ i_color empty; i_img_dim x, y; int ch; int imindist = (int)mindist; for (ch = 0; ch < MAXCHANNELS; ++ch) empty.channel[ch] = 0; for (y = 0; y < ysize; ++y) { i_glin(im1, 0, xsize, y, line1); i_glin(im2, 0, xsize, y, line2); if (outchans != diffchans) { /* give the output an alpha channel since it doesn't have one */ for (x = 0; x < xsize; ++x) line2[x].channel[diffchans] = 255; } for (x = 0; x < xsize; ++x) { int diff = 0; for (ch = 0; ch < diffchans; ++ch) { if (line1[x].channel[ch] != line2[x].channel[ch] && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) { diff = 1; break; } } if (!diff) line2[x] = empty; } i_plin(out, 0, xsize, y, line2); } myfree(line1); myfree(line2); } else { i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */ i_fcolor empty; i_img_dim x, y; int ch; double dist = mindist / 255.0; for (ch = 0; ch < MAXCHANNELS; ++ch) empty.channel[ch] = 0; for (y = 0; y < ysize; ++y) { i_glinf(im1, 0, xsize, y, line1); i_glinf(im2, 0, xsize, y, line2); if (outchans != diffchans) { /* give the output an alpha channel since it doesn't have one */ for (x = 0; x < xsize; ++x) line2[x].channel[diffchans] = 1.0; } for (x = 0; x < xsize; ++x) { int diff = 0; for (ch = 0; ch < diffchans; ++ch) { if (line1[x].channel[ch] != line2[x].channel[ch] && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) { diff = 1; break; } } if (!diff) line2[x] = empty; } i_plinf(out, 0, xsize, y, line2); } myfree(line1); myfree(line2); } return out; } struct fount_state; static double linear_fount_f(double x, double y, struct fount_state *state); static double bilinear_fount_f(double x, double y, struct fount_state *state); static double radial_fount_f(double x, double y, struct fount_state *state); static double square_fount_f(double x, double y, struct fount_state *state); static double revolution_fount_f(double x, double y, struct fount_state *state); static double conical_fount_f(double x, double y, struct fount_state *state); typedef double (*fount_func)(double, double, struct fount_state *); static fount_func fount_funcs[] = { linear_fount_f, bilinear_fount_f, radial_fount_f, square_fount_f, revolution_fount_f, conical_fount_f, }; static double linear_interp(double pos, i_fountain_seg *seg); static double sine_interp(double pos, i_fountain_seg *seg); static double sphereup_interp(double pos, i_fountain_seg *seg); static double spheredown_interp(double pos, i_fountain_seg *seg); typedef double (*fount_interp)(double pos, i_fountain_seg *seg); static fount_interp fount_interps[] = { linear_interp, linear_interp, sine_interp, sphereup_interp, spheredown_interp, }; static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg); static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg); static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg); typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg); static fount_cinterp fount_cinterps[] = { direct_cinterp, hue_up_cinterp, hue_down_cinterp, }; typedef double (*fount_repeat)(double v); static double fount_r_none(double v); static double fount_r_sawtooth(double v); static double fount_r_triangle(double v); static double fount_r_saw_both(double v); static double fount_r_tri_both(double v); static fount_repeat fount_repeats[] = { fount_r_none, fount_r_sawtooth, fount_r_triangle, fount_r_saw_both, fount_r_tri_both, }; static int simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state); static int random_ssample(i_fcolor *out, double x, double y, struct fount_state *state); static int circle_ssample(i_fcolor *out, double x, double y, struct fount_state *state); typedef int (*fount_ssample)(i_fcolor *out, double x, double y, struct fount_state *state); static fount_ssample fount_ssamples[] = { NULL, simple_ssample, random_ssample, circle_ssample, }; static int fount_getat(i_fcolor *out, double x, double y, struct fount_state *state); /* Keep state information used by each type of fountain fill */ struct fount_state { /* precalculated for the equation of the line perpendicular to the line AB */ double lA, lB, lC; double AB; double sqrtA2B2; double mult; double cos; double sin; double theta; i_img_dim xa, ya; void *ssample_data; fount_func ffunc; fount_repeat rpfunc; fount_ssample ssfunc; double parm; i_fountain_seg *segs; int count; }; static void fount_init_state(struct fount_state *state, double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, int combine, int super_sample, double ssample_param, int count, i_fountain_seg *segs); static void fount_finish_state(struct fount_state *state); #define EPSILON (1e-6) /* =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs) Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points. I controls how the reference points are used: =over =item i_ft_linear linear, where A is 0 and B is 1. =item i_ft_bilinear linear in both directions from A. =item i_ft_radial circular, where A is the centre of the fill, and B is a point on the radius. =item i_ft_radial_square where A is the centre of the fill and B is the centre of one side of the square. =item i_ft_revolution where A is the centre of the fill and B defines the 0/1.0 angle of the fill. =item i_ft_conical similar to i_ft_revolution, except that the revolution goes in both directions =back I can be one of: =over =item i_fr_none values < 0 are treated as zero, values > 1 are treated as 1. =item i_fr_sawtooth negative values are treated as 0, positive values are modulo 1.0 =item i_fr_triangle negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value mod 1.0), otherwise the same as for sawtooth. =item i_fr_saw_both like i_fr_sawtooth, except that the sawtooth pattern repeats into negative values. =item i_fr_tri_both Like i_fr_triangle, except that negative values are handled as their absolute values. =back If combine is non-zero then non-opaque values are combined with the underlying color. I controls super sampling, if any. At some point I'll probably add a adaptive super-sampler. Current possible values are: =over =item i_fts_none No super-sampling is done. =item i_fts_grid A square grid of points withing the pixel are sampled. =item i_fts_random Random points within the pixel are sampled. =item i_fts_circle Points on the radius of a circle are sampled. This produces fairly good results, but is fairly slow since sin() and cos() are evaluated for each point. =back I is intended to be roughly the number of points sampled within the pixel. I and I define the segments of the fill. =cut */ int i_fountain(i_img *im, double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, int combine, int super_sample, double ssample_param, int count, i_fountain_seg *segs) { struct fount_state state; i_img_dim x, y; i_fcolor *line = NULL; i_fcolor *work = NULL; size_t line_bytes; i_fill_combine_f combine_func = NULL; i_fill_combinef_f combinef_func = NULL; dIMCTXim(im); i_clear_error(); /* i_fountain() allocates floating colors even for 8-bit images, so we need to do this check */ line_bytes = sizeof(i_fcolor) * im->xsize; if (line_bytes / sizeof(i_fcolor) != im->xsize) { i_push_error(0, "integer overflow calculating memory allocation"); return 0; } line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */ i_get_combine(combine, &combine_func, &combinef_func); if (combinef_func) work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */ fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs); for (y = 0; y < im->ysize; ++y) { i_glinf(im, 0, im->xsize, y, line); for (x = 0; x < im->xsize; ++x) { i_fcolor c; int got_one; if (super_sample == i_fts_none) got_one = fount_getat(&c, x, y, &state); else got_one = state.ssfunc(&c, x, y, &state); if (got_one) { if (combine) work[x] = c; else line[x] = c; } } if (combine) combinef_func(line, work, im->channels, im->xsize); i_plinf(im, 0, im->xsize, y, line); } fount_finish_state(&state); if (work) myfree(work); myfree(line); return 1; } typedef struct { i_fill_t base; struct fount_state state; } i_fill_fountain_t; static void fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data); static void fount_fill_destroy(i_fill_t *fill); static i_fill_fountain_t fount_fill_proto = { { NULL, fill_fountf, fount_fill_destroy } }; /* =item i_new_fill_fount(C, C, C, C, C, C, C, C, C, C, C) =category Fills =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear, =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs); Creates a new general fill which fills with a fountain fill. =cut */ i_fill_t * i_new_fill_fount(double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, int combine, int super_sample, double ssample_param, int count, i_fountain_seg *segs) { i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t)); *fill = fount_fill_proto; if (combine) i_get_combine(combine, &fill->base.combine, &fill->base.combinef); else { fill->base.combine = NULL; fill->base.combinef = NULL; } fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs); return &fill->base; } /* =back =head1 INTERNAL FUNCTIONS =over =item fount_init_state(...) Used by both the fountain fill filter and the fountain fill. =cut */ static void fount_init_state(struct fount_state *state, double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, int combine, int super_sample, double ssample_param, int count, i_fountain_seg *segs) { int i, j; size_t bytes; i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */ /*int have_alpha = im->channels == 2 || im->channels == 4;*/ memset(state, 0, sizeof(*state)); /* we keep a local copy that we can adjust for speed */ for (i = 0; i < count; ++i) { i_fountain_seg *seg = my_segs + i; *seg = segs[i]; if (seg->type < 0 || seg->type >= i_fst_end) seg->type = i_fst_linear; if (seg->color < 0 || seg->color >= i_fc_end) seg->color = i_fc_direct; if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) { /* so we don't have to translate to HSV on each request, do it here */ for (j = 0; j < 2; ++j) { i_rgb_to_hsvf(seg->c+j); } if (seg->color == i_fc_hue_up) { if (seg->c[1].channel[0] <= seg->c[0].channel[0]) seg->c[1].channel[0] += 1.0; } else { if (seg->c[0].channel[0] <= seg->c[0].channel[1]) seg->c[0].channel[0] += 1.0; } } /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n", seg->start, seg->middle, seg->end, seg->c[0].channel[0], seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3], seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2], seg->c[1].channel[3], seg->type, seg->color);*/ } /* initialize each engine */ /* these are so common ... */ state->lA = xb - xa; state->lB = yb - ya; state->AB = sqrt(state->lA * state->lA + state->lB * state->lB); state->xa = xa; state->ya = ya; switch (type) { default: type = i_ft_linear; /* make the invalid value valid */ case i_ft_linear: case i_ft_bilinear: state->lC = ya * ya - ya * yb + xa * xa - xa * xb; state->mult = 1; state->mult = 1/linear_fount_f(xb, yb, state); break; case i_ft_radial: state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa) + (double)(yb-ya)*(yb-ya)); break; case i_ft_radial_square: state->cos = state->lA / state->AB; state->sin = state->lB / state->AB; state->mult = 1.0 / state->AB; break; case i_ft_revolution: state->theta = atan2(yb-ya, xb-xa); state->mult = 1.0 / (PI * 2); break; case i_ft_conical: state->theta = atan2(yb-ya, xb-xa); state->mult = 1.0 / PI; break; } state->ffunc = fount_funcs[type]; if (super_sample < 0 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) { super_sample = 0; } state->ssample_data = NULL; switch (super_sample) { case i_fts_grid: ssample_param = floor(0.5 + sqrt(ssample_param)); bytes = ssample_param * ssample_param * sizeof(i_fcolor); if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) { state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */ } else { super_sample = i_fts_none; } break; case i_fts_random: case i_fts_circle: ssample_param = floor(0.5+ssample_param); bytes = sizeof(i_fcolor) * ssample_param; if (bytes / sizeof(i_fcolor) == ssample_param) { state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param); } else { super_sample = i_fts_none; } break; } state->parm = ssample_param; state->ssfunc = fount_ssamples[super_sample]; if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats))) repeat = 0; state->rpfunc = fount_repeats[repeat]; state->segs = my_segs; state->count = count; } static void fount_finish_state(struct fount_state *state) { if (state->ssample_data) myfree(state->ssample_data); myfree(state->segs); } /* =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count) Evaluates the fountain fill at the given point. This is called by both the non-super-sampling and super-sampling code. You might think that it would make sense to sample the fill parameter instead, and combine those, but this breaks badly. =cut */ static int fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) { double v = (state->rpfunc)((state->ffunc)(x, y, state)); int i; i = 0; while (i < state->count && (v < state->segs[i].start || v > state->segs[i].end)) { ++i; } if (i < state->count) { v = (fount_interps[state->segs[i].type])(v, state->segs+i); (fount_cinterps[state->segs[i].color])(out, v, state->segs+i); return 1; } else return 0; } /* =item linear_fount_f(x, y, state) Calculate the fill parameter for a linear fountain fill. Uses the point to line distance function, with some precalculation done in i_fountain(). =cut */ static double linear_fount_f(double x, double y, struct fount_state *state) { return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult; } /* =item bilinear_fount_f(x, y, state) Calculate the fill parameter for a bi-linear fountain fill. =cut */ static double bilinear_fount_f(double x, double y, struct fount_state *state) { return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult); } /* =item radial_fount_f(x, y, state) Calculate the fill parameter for a radial fountain fill. Simply uses the distance function. =cut */ static double radial_fount_f(double x, double y, struct fount_state *state) { return sqrt((double)(state->xa-x)*(state->xa-x) + (double)(state->ya-y)*(state->ya-y)) * state->mult; } /* =item square_fount_f(x, y, state) Calculate the fill parameter for a square fountain fill. Works by rotating the reference co-ordinate around the centre of the square. =cut */ static double square_fount_f(double x, double y, struct fount_state *state) { i_img_dim xc, yc; /* centred on A */ double xt, yt; /* rotated by theta */ xc = x - state->xa; yc = y - state->ya; xt = fabs(xc * state->cos + yc * state->sin); yt = fabs(-xc * state->sin + yc * state->cos); return (xt > yt ? xt : yt) * state->mult; } /* =item revolution_fount_f(x, y, state) Calculates the fill parameter for the revolution fountain fill. =cut */ static double revolution_fount_f(double x, double y, struct fount_state *state) { double angle = atan2(y - state->ya, x - state->xa); angle -= state->theta; if (angle < 0) { angle = fmod(angle+ PI * 4, PI*2); } return angle * state->mult; } /* =item conical_fount_f(x, y, state) Calculates the fill parameter for the conical fountain fill. =cut */ static double conical_fount_f(double x, double y, struct fount_state *state) { double angle = atan2(y - state->ya, x - state->xa); angle -= state->theta; if (angle < -PI) angle += PI * 2; else if (angle > PI) angle -= PI * 2; return fabs(angle) * state->mult; } /* =item linear_interp(pos, seg) Calculates linear interpolation on the fill parameter. Breaks the segment into 2 regions based in the I value. =cut */ static double linear_interp(double pos, i_fountain_seg *seg) { if (pos < seg->middle) { double len = seg->middle - seg->start; if (len < EPSILON) return 0.0; else return (pos - seg->start) / len / 2; } else { double len = seg->end - seg->middle; if (len < EPSILON) return 1.0; else return 0.5 + (pos - seg->middle) / len / 2; } } /* =item sine_interp(pos, seg) Calculates sine function interpolation on the fill parameter. =cut */ static double sine_interp(double pos, i_fountain_seg *seg) { /* I wonder if there's a simple way to smooth the transition for this */ double work = linear_interp(pos, seg); return (1-cos(work * PI))/2; } /* =item sphereup_interp(pos, seg) Calculates spherical interpolation on the fill parameter, with the cusp at the low-end. =cut */ static double sphereup_interp(double pos, i_fountain_seg *seg) { double work = linear_interp(pos, seg); return sqrt(1.0 - (1-work) * (1-work)); } /* =item spheredown_interp(pos, seg) Calculates spherical interpolation on the fill parameter, with the cusp at the high-end. =cut */ static double spheredown_interp(double pos, i_fountain_seg *seg) { double work = linear_interp(pos, seg); return 1-sqrt(1.0 - work * work); } /* =item direct_cinterp(out, pos, seg) Calculates the fountain color based on direct scaling of the channels of the color channels. =cut */ static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) { int ch; for (ch = 0; ch < MAXCHANNELS; ++ch) { out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) + seg->c[1].channel[ch] * pos; } } /* =item hue_up_cinterp(put, pos, seg) Calculates the fountain color based on scaling a HSV value. The hue increases as the fill parameter increases. =cut */ static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) { int ch; for (ch = 0; ch < MAXCHANNELS; ++ch) { out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) + seg->c[1].channel[ch] * pos; } i_hsv_to_rgbf(out); } /* =item hue_down_cinterp(put, pos, seg) Calculates the fountain color based on scaling a HSV value. The hue decreases as the fill parameter increases. =cut */ static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) { int ch; for (ch = 0; ch < MAXCHANNELS; ++ch) { out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) + seg->c[1].channel[ch] * pos; } i_hsv_to_rgbf(out); } /* =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count) Simple grid-based super-sampling. =cut */ static int simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) { i_fcolor *work = state->ssample_data; i_img_dim dx, dy; int grid = state->parm; double base = -0.5 + 0.5 / grid; double step = 1.0 / grid; int ch, i; int samp_count = 0; for (dx = 0; dx < grid; ++dx) { for (dy = 0; dy < grid; ++dy) { if (fount_getat(work+samp_count, x + base + step * dx, y + base + step * dy, state)) { ++samp_count; } } } for (ch = 0; ch < MAXCHANNELS; ++ch) { out->channel[ch] = 0; for (i = 0; i < samp_count; ++i) { out->channel[ch] += work[i].channel[ch]; } /* we divide by 4 rather than samp_count since if there's only one valid sample it should be mostly transparent */ out->channel[ch] /= grid * grid; } return samp_count; } /* =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count) Random super-sampling. =cut */ static int random_ssample(i_fcolor *out, double x, double y, struct fount_state *state) { i_fcolor *work = state->ssample_data; int i, ch; int maxsamples = state->parm; double rand_scale = 1.0 / RAND_MAX; int samp_count = 0; for (i = 0; i < maxsamples; ++i) { if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale, y - 0.5 + rand() * rand_scale, state)) { ++samp_count; } } for (ch = 0; ch < MAXCHANNELS; ++ch) { out->channel[ch] = 0; for (i = 0; i < samp_count; ++i) { out->channel[ch] += work[i].channel[ch]; } /* we divide by maxsamples rather than samp_count since if there's only one valid sample it should be mostly transparent */ out->channel[ch] /= maxsamples; } return samp_count; } /* =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count) Super-sampling around the circumference of a circle. I considered saving the sin()/cos() values and transforming step-size around the circle, but that's inaccurate, though it may not matter much. =cut */ static int circle_ssample(i_fcolor *out, double x, double y, struct fount_state *state) { i_fcolor *work = state->ssample_data; int i, ch; int maxsamples = state->parm; double angle = 2 * PI / maxsamples; double radius = 0.3; /* semi-random */ int samp_count = 0; for (i = 0; i < maxsamples; ++i) { if (fount_getat(work+samp_count, x + radius * cos(angle * i), y + radius * sin(angle * i), state)) { ++samp_count; } } for (ch = 0; ch < MAXCHANNELS; ++ch) { out->channel[ch] = 0; for (i = 0; i < samp_count; ++i) { out->channel[ch] += work[i].channel[ch]; } /* we divide by maxsamples rather than samp_count since if there's only one valid sample it should be mostly transparent */ out->channel[ch] /= maxsamples; } return samp_count; } /* =item fount_r_none(v) Implements no repeats. Simply clamps the fill value. =cut */ static double fount_r_none(double v) { return v < 0 ? 0 : v > 1 ? 1 : v; } /* =item fount_r_sawtooth(v) Implements sawtooth repeats. Clamps negative values and uses fmod() on others. =cut */ static double fount_r_sawtooth(double v) { return v < 0 ? 0 : fmod(v, 1.0); } /* =item fount_r_triangle(v) Implements triangle repeats. Clamps negative values, uses fmod to get a range 0 through 2 and then adjusts values > 1. =cut */ static double fount_r_triangle(double v) { if (v < 0) return 0; else { v = fmod(v, 2.0); return v > 1.0 ? 2.0 - v : v; } } /* =item fount_r_saw_both(v) Implements sawtooth repeats in the both postive and negative directions. Adjusts the value to be postive and then just uses fmod(). =cut */ static double fount_r_saw_both(double v) { if (v < 0) v += 1+(int)(-v); return fmod(v, 1.0); } /* =item fount_r_tri_both(v) Implements triangle repeats in the both postive and negative directions. Uses fmod on the absolute value, and then adjusts values > 1. =cut */ static double fount_r_tri_both(double v) { v = fmod(fabs(v), 2.0); return v > 1.0 ? 2.0 - v : v; } /* =item fill_fountf(fill, x, y, width, channels, data) The fill function for fountain fills. =cut */ static void fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data) { i_fill_fountain_t *f = (i_fill_fountain_t *)fill; while (width--) { i_fcolor c; int got_one; if (f->state.ssfunc) got_one = f->state.ssfunc(&c, x, y, &f->state); else got_one = fount_getat(&c, x, y, &f->state); if (got_one) *data++ = c; ++x; } } /* =item fount_fill_destroy(fill) =cut */ static void fount_fill_destroy(i_fill_t *fill) { i_fill_fountain_t *f = (i_fill_fountain_t *)fill; fount_finish_state(&f->state); } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson Tony Cook (i_fountain()) =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/imager.h0000644000175000017500000004504012614520110017171 0ustar gregoagregoa#ifndef _IMAGE_H_ #define _IMAGE_H_ #include "imconfig.h" #include "immacros.h" #include "imio.h" #include "iolayer.h" #include "stackmach.h" #ifndef _MSC_VER #include #endif #include #include #include #include #ifdef SUNOS #include #endif #ifndef PI #define PI 3.14159265358979323846 #endif #include "imdatatypes.h" undef_int i_has_format(char *frmt); /* constructors and destructors */ i_color *ICL_new_internal( unsigned char r,unsigned char g,unsigned char b,unsigned char a); i_color *ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a); void ICL_info (const i_color *cl); void ICL_DESTROY (i_color *cl); void ICL_add (i_color *dst, i_color *src, int ch); extern i_fcolor *i_fcolor_new(double r, double g, double b, double a); extern void i_fcolor_destroy(i_fcolor *cl); extern void i_rgb_to_hsvf(i_fcolor *color); extern void i_hsv_to_rgbf(i_fcolor *color); extern void i_rgb_to_hsv(i_color *color); extern void i_hsv_to_rgb(i_color *color); i_img *im_img_8_new(pIMCTX, i_img_dim x,i_img_dim y,int ch); #define i_img_empty(im, x, y) i_img_empty_ch((im), (x), (y), 3) i_img *im_img_empty_ch(pIMCTX, i_img *im,i_img_dim x,i_img_dim y,int ch); #define i_img_empty_ch(im, x, y, ch) im_img_empty_ch(aIMCTX, (im), (x), (y), (ch)) void i_img_exorcise(i_img *im); void i_img_destroy(i_img *im); i_img *im_img_alloc(pIMCTX); void im_img_init(pIMCTX, i_img *im); void i_img_info(i_img *im,i_img_dim *info); extern i_img *i_sametype(i_img *im, i_img_dim xsize, i_img_dim ysize); extern i_img *i_sametype_chans(i_img *im, i_img_dim xsize, i_img_dim ysize, int channels); /* Image feature settings */ void i_img_setmask (i_img *im,int ch_mask); int i_img_getmask (i_img *im); int i_img_getchannels(i_img *im); i_img_dim i_img_get_width(i_img *im); i_img_dim i_img_get_height(i_img *im); i_color_model_t i_img_color_model(i_img *im); int i_img_alpha_channel(i_img *im, int *channel); int i_img_color_channels(i_img *im); /* Base functions */ extern int (i_ppix)(i_img *im,i_img_dim x,i_img_dim y, const i_color *val); extern int (i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val); extern int (i_ppixf)(i_img *im,i_img_dim x,i_img_dim y, const i_fcolor *val); extern int (i_gpixf)(i_img *im,i_img_dim x,i_img_dim y,i_fcolor *val); extern i_img_dim (i_plin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals); extern i_img_dim (i_glin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals); extern i_img_dim (i_plinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals); extern i_img_dim (i_glinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals); extern i_img_dim (i_gsamp)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp, const int *chans, int chan_count); extern i_img_dim (i_gsampf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, const int *chans, int chan_count); extern i_img_dim (i_gpal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals); extern i_img_dim (i_ppal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals); extern int (i_addcolors)(i_img *im, const i_color *colors, int count); extern int (i_getcolors)(i_img *im, int i, i_color *, int count); extern int (i_colorcount)(i_img *im); extern int (i_maxcolors)(i_img *im); extern int (i_findcolor)(i_img *im, const i_color *color, i_palidx *entry); extern int (i_setcolors)(i_img *im, int index, const i_color *colors, int count); extern i_fill_t *i_new_fill_solidf(const i_fcolor *c, int combine); extern i_fill_t *i_new_fill_solid(const i_color *c, int combine); extern i_fill_t * i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy); extern i_fill_t * i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy); extern i_fill_t * i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine); extern i_fill_t *i_new_fill_opacity(i_fill_t *, double alpha_mult); extern void i_fill_destroy(i_fill_t *fill); float i_gpix_pch(i_img *im,i_img_dim x,i_img_dim y,int ch); /* functions for drawing primitives */ void i_box (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val); void i_box_filled (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val); int i_box_filledf (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_fcolor *val); void i_box_cfill(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_fill_t *fill); void i_line (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val, int endp); void i_line_aa (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val, int endp); void i_arc (i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,const i_color *val); int i_arc_out(i_img *im,i_img_dim x,i_img_dim y,i_img_dim rad,double d1,double d2,const i_color *val); int i_arc_out_aa(i_img *im,i_img_dim x,i_img_dim y,i_img_dim rad,double d1,double d2,const i_color *val); void i_arc_aa (i_img *im, double x, double y, double rad, double d1, double d2, const i_color *val); void i_arc_cfill(i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,i_fill_t *fill); void i_arc_aa_cfill(i_img *im,double x,double y,double rad,double d1,double d2,i_fill_t *fill); void i_circle_aa (i_img *im,double x, double y,double rad,const i_color *val); void i_circle_aa_fill(i_img *im,double x, double y,double rad,i_fill_t *fill); int i_circle_out (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val); int i_circle_out_aa (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val); void i_copyto (i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty); void i_copyto_trans(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans); i_img* i_copy (i_img *src); int i_rubthru (i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy); extern int i_compose_mask(i_img *out, i_img *src, i_img *mask, i_img_dim out_left, i_img_dim out_top, i_img_dim src_left, i_img_dim src_top, i_img_dim mask_left, i_img_dim mask_top, i_img_dim width, i_img_dim height, int combine, double opacity); extern int i_compose(i_img *out, i_img *src, i_img_dim out_left, i_img_dim out_top, i_img_dim src_left, i_img_dim src_top, i_img_dim width, i_img_dim height, int combine, double opacity); extern i_img * i_combine(i_img **src, const int *channels, int in_count); undef_int i_flipxy (i_img *im, int direction); extern i_img *i_rotate90(i_img *im, int degrees); extern i_img *i_rotate_exact(i_img *im, double amount); extern i_img *i_rotate_exact_bg(i_img *im, double amount, const i_color *backp, const i_fcolor *fbackp); extern i_img *i_matrix_transform(i_img *im, i_img_dim xsize, i_img_dim ysize, const double *matrix); extern i_img *i_matrix_transform_bg(i_img *im, i_img_dim xsize, i_img_dim ysize, const double *matrix, const i_color *backp, const i_fcolor *fbackp); void i_bezier_multi(i_img *im,int l,const double *x,const double *y,const i_color *val); int i_poly_aa (i_img *im,int l,const double *x,const double *y,const i_color *val); int i_poly_aa_cfill(i_img *im,int l,const double *x,const double *y,i_fill_t *fill); int i_poly_aa_m (i_img *im,int l,const double *x,const double *y, i_poly_fill_mode_t mode, const i_color *val); int i_poly_aa_cfill_m(i_img *im,int l,const double *x,const double *y, i_poly_fill_mode_t mode, i_fill_t *fill); extern int i_poly_poly_aa(i_img *im, int count, const i_polygon_t *polys, i_poly_fill_mode_t mode, const i_color *val); extern int i_poly_poly_aa_cfill(i_img *im, int count, const i_polygon_t *polys, i_poly_fill_mode_t mode, i_fill_t *fill); undef_int i_flood_fill (i_img *im,i_img_dim seedx,i_img_dim seedy, const i_color *dcol); undef_int i_flood_cfill(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill); undef_int i_flood_fill_border (i_img *im,i_img_dim seedx,i_img_dim seedy, const i_color *dcol, const i_color *border); undef_int i_flood_cfill_border(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill, const i_color *border); /* image processing functions */ int i_gaussian (i_img *im, double stdev); int i_conv (i_img *im,const double *coeff,int len); void i_unsharp_mask(i_img *im, double stddev, double scale); /* colour manipulation */ extern i_img *i_convert(i_img *src, const double *coeff, int outchan, int inchan); extern void i_map(i_img *im, unsigned char (*maps)[256], unsigned int mask); float i_img_diff (i_img *im1,i_img *im2); double i_img_diffd(i_img *im1,i_img *im2); int i_img_samef(i_img *im1,i_img *im2, double epsilon, const char *what); /* font routines */ #ifdef HAVE_LIBTT extern void i_tt_start(void); TT_Fonthandle* i_tt_new(const char *fontname); void i_tt_destroy( TT_Fonthandle *handle ); undef_int i_tt_cp( TT_Fonthandle *handle,i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char const* txt,size_t len,int smooth, int utf8, int align); undef_int i_tt_text( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, const i_color *cl, double points, char const* txt, size_t len, int smooth, int utf8, int align); undef_int i_tt_bbox( TT_Fonthandle *handle, double points,const char *txt,size_t len,i_img_dim cords[6], int utf8); size_t i_tt_has_chars(TT_Fonthandle *handle, char const *text, size_t len, int utf8, char *out); void i_tt_dump_names(TT_Fonthandle *handle); size_t i_tt_face_name(TT_Fonthandle *handle, char *name_buf, size_t name_buf_size); size_t i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf, size_t name_buf_size); #endif /* End of freetype headers */ extern void i_quant_makemap(i_quantize *quant, i_img **imgs, int count); extern i_palidx *i_quant_translate(i_quantize *quant, i_img *img); extern void i_quant_transparent(i_quantize *quant, i_palidx *indices, i_img *img, i_palidx trans_index); i_img *im_img_pal_new(pIMCTX, i_img_dim x, i_img_dim y, int ch, int maxpal); extern i_img *i_img_to_pal(i_img *src, i_quantize *quant); extern i_img *i_img_to_rgb(i_img *src); extern i_img *i_img_masked_new(i_img *targ, i_img *mask, i_img_dim x, i_img_dim y, i_img_dim w, i_img_dim h); extern i_img *im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch); extern i_img *i_img_to_rgb16(i_img *im); extern i_img *im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch); extern i_img *i_img_to_drgb(i_img *im); extern int i_img_is_monochrome(i_img *im, int *zero_is_white); extern int i_get_file_background(i_img *im, i_color *bg); extern int i_get_file_backgroundf(i_img *im, i_fcolor *bg); const char * i_test_format_probe(io_glue *data, int length); i_img * i_readraw_wiol(io_glue *ig, i_img_dim x, i_img_dim y, int datachannels, int storechannels, int intrl); undef_int i_writeraw_wiol(i_img* im, io_glue *ig); i_img * i_readpnm_wiol(io_glue *ig, int allow_incomplete); i_img ** i_readpnm_multi_wiol(io_glue *ig, int *count, int allow_incomplete); undef_int i_writeppm_wiol(i_img *im, io_glue *ig); extern int i_writebmp_wiol(i_img *im, io_glue *ig); extern i_img *i_readbmp_wiol(io_glue *ig, int allow_incomplete); int tga_header_verify(unsigned char headbuf[18]); i_img * i_readtga_wiol(io_glue *ig, int length); undef_int i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen); i_img * i_readrgb_wiol(io_glue *ig, int length); undef_int i_writergb_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen); i_img * i_scaleaxis(i_img *im, double Value, int Axis); i_img * i_scale_nn(i_img *im, double scx, double scy); i_img * i_scale_mixing(i_img *src, i_img_dim width, i_img_dim height); i_img * i_haar(i_img *im); int i_count_colors(i_img *im,int maxc); int i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc); i_img * i_transform(i_img *im, int *opx, int opxl, int *opy,int opyl,double parm[],int parmlen); struct rm_op; i_img * i_transform2(i_img_dim width, i_img_dim height, int channels, struct rm_op *ops, int ops_count, double *n_regs, int n_regs_count, i_color *c_regs, int c_regs_count, i_img **in_imgs, int in_imgs_count); /* filters */ void i_contrast(i_img *im, float intensity); void i_hardinvert(i_img *im); void i_hardinvertall(i_img *im); void i_noise(i_img *im, float amount, unsigned char type); void i_bumpmap(i_img *im,i_img *bump,int channel,i_img_dim light_x,i_img_dim light_y,i_img_dim strength); void i_bumpmap_complex(i_img *im, i_img *bump, int channel, i_img_dim tx, i_img_dim ty, double Lx, double Ly, double Lz, float cd, float cs, float n, i_color *Ia, i_color *Il, i_color *Is); void i_postlevels(i_img *im,int levels); void i_mosaic(i_img *im,i_img_dim size); void i_watermark(i_img *im,i_img *wmark,i_img_dim tx,i_img_dim ty,int pixdiff); void i_autolevels(i_img *im,float lsat,float usat,float skew); void i_autolevels_mono(i_img *im,float lsat,float usat); void i_radnoise(i_img *im,i_img_dim xo,i_img_dim yo,double rscale,double ascale); void i_turbnoise(i_img *im,double xo,double yo,double scale); void i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure); int i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure); i_img *i_diff_image(i_img *im, i_img *im2, double mindist); int i_fountain(i_img *im, double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, int combine, int super_sample, double ssample_param, int count, i_fountain_seg *segs); extern i_fill_t * i_new_fill_fount(double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, int combine, int super_sample, double ssample_param, int count, i_fountain_seg *segs); /* Debug only functions */ void malloc_state( void ); #include "imerror.h" /* image tag processing */ extern void i_tags_new(i_img_tags *tags); extern int i_tags_addn(i_img_tags *tags, char const *name, int code, int idata); extern int i_tags_add(i_img_tags *tags, char const *name, int code, char const *data, int size, int idata); extern int i_tags_set(i_img_tags *tags, char const *name, char const *data, int size); extern int i_tags_setn(i_img_tags *tags, char const *name, int idata); extern void i_tags_destroy(i_img_tags *tags); extern int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry); extern int i_tags_findn(i_img_tags *tags, int code, int start, int *entry); extern int i_tags_delete(i_img_tags *tags, int entry); extern int i_tags_delbyname(i_img_tags *tags, char const *name); extern int i_tags_delbycode(i_img_tags *tags, int code); extern int i_tags_get_float(i_img_tags *tags, char const *name, int code, double *value); extern int i_tags_set_float(i_img_tags *tags, char const *name, int code, double value); extern int i_tags_set_float2(i_img_tags *tags, char const *name, int code, double value, int places); extern int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value); extern int i_tags_get_string(i_img_tags *tags, char const *name, int code, char *value, size_t value_size); extern int i_tags_get_color(i_img_tags *tags, char const *name, int code, i_color *value); extern int i_tags_set_color(i_img_tags *tags, char const *name, int code, i_color const *value); extern void i_tags_print(i_img_tags *tags); /* image file limits */ extern int im_set_image_file_limits(im_context_t ctx, i_img_dim width, i_img_dim height, size_t bytes); extern int im_get_image_file_limits(im_context_t ctx, i_img_dim *width, i_img_dim *height, size_t *bytes); extern int im_int_check_image_file_limits(im_context_t ctx, i_img_dim width, i_img_dim height, int channels, size_t sample_size); /* memory allocation */ void* mymalloc(size_t size); void myfree(void *p); void* myrealloc(void *p, size_t newsize); void* mymalloc_file_line (size_t size, char* file, int line); void myfree_file_line (void *p, char*file, int line); void* myrealloc_file_line(void *p, size_t newsize, char* file,int line); #ifdef IMAGER_DEBUG_MALLOC #define mymalloc(x) (mymalloc_file_line((x), __FILE__, __LINE__)) #define myrealloc(x,y) (myrealloc_file_line((x),(y), __FILE__, __LINE__)) #define myfree(x) (myfree_file_line((x), __FILE__, __LINE__)) void malloc_state (void); void bndcheck_all (void); #else void malloc_state(void); #endif /* IMAGER_MALLOC_DEBUG */ #include "imrender.h" extern void i_adapt_colors(int dest_channels, int src_channels, i_color *colors, size_t count); extern void i_adapt_fcolors(int dest_channels, int src_channels, i_fcolor *colors, size_t count); extern void i_adapt_colors_bg(int dest_channels, int src_channels, i_color *colors, size_t count, i_color const *bg); extern void i_adapt_fcolors_bg(int dest_channels, int src_channels, i_fcolor *colors, size_t count, i_fcolor const *bg); extern int i_gsamp_bg(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samples, int out_channels, i_color const *bg); extern int i_gsampf_bg(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samples, int out_channels, i_fcolor const *bg); /* context object management */ extern im_context_t im_context_new(void); extern void im_context_refinc(im_context_t ctx, const char *where); extern void im_context_refdec(im_context_t ctx, const char *where); extern im_context_t im_context_clone(im_context_t ctx, const char *where); extern im_slot_t im_context_slot_new(im_slot_destroy_t); extern void *im_context_slot_get(im_context_t ctx, im_slot_t slot); extern int im_context_slot_set(im_context_t ctx, im_slot_t slot, void *); extern im_context_t (*im_get_context)(void); /* mutex API */ extern i_mutex_t i_mutex_new(void); extern void i_mutex_destroy(i_mutex_t m); extern void i_mutex_lock(i_mutex_t m); extern void i_mutex_unlock(i_mutex_t m); #include "imio.h" #endif libimager-perl-1.004+dfsg.orig/imrender.h0000644000175000017500000000155212031434615017541 0ustar gregoagregoa#ifndef IMAGER_IMRENDER_H #define IMAGER_IMRENDER_H #include "rendert.h" extern void i_render_init(i_render *r, i_img *im, i_img_dim width); extern void i_render_done(i_render *r); extern void i_render_color(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color); extern void i_render_fill(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_fill_t *fill); extern void i_render_line(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, const i_sample_t *src, i_color *line, i_fill_combine_f combine); extern void i_render_linef(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, const double *src, i_fcolor *line, i_fill_combinef_f combine); extern i_render * i_render_new(i_img *im, i_img_dim width); extern void i_render_delete(i_render *r); #endif libimager-perl-1.004+dfsg.orig/rotate.im0000644000175000017500000003064312263740601017415 0ustar gregoagregoa/* =head1 NAME rotate.im - implements image rotations =head1 SYNOPSIS i_img *i_rotate90(i_img *src, int degrees) =head1 DESCRIPTION Implements basic 90 degree rotations of an image. Other rotations will be added as tuits become available. =cut */ #include "imager.h" #include "imageri.h" #include /* for floor() */ #define ROT_DEBUG(x) i_img *i_rotate90(i_img *src, int degrees) { i_img *targ; i_img_dim x, y; i_clear_error(); if (degrees == 180) { /* essentially the same as flipxy(..., 2) except that it's not done in place */ targ = i_sametype(src, src->xsize, src->ysize); if (src->type == i_direct_type) { #code src->bits <= 8 IM_COLOR *vals = mymalloc(src->xsize * sizeof(IM_COLOR)); for (y = 0; y < src->ysize; ++y) { IM_COLOR tmp; IM_GLIN(src, 0, src->xsize, y, vals); for (x = 0; x < src->xsize/2; ++x) { tmp = vals[x]; vals[x] = vals[src->xsize - x - 1]; vals[src->xsize - x - 1] = tmp; } IM_PLIN(targ, 0, src->xsize, src->ysize - y - 1, vals); } myfree(vals); #/code } else { i_palidx *vals = mymalloc(src->xsize * sizeof(i_palidx)); for (y = 0; y < src->ysize; ++y) { i_palidx tmp; i_gpal(src, 0, src->xsize, y, vals); for (x = 0; x < src->xsize/2; ++x) { tmp = vals[x]; vals[x] = vals[src->xsize - x - 1]; vals[src->xsize - x - 1] = tmp; } i_ppal(targ, 0, src->xsize, src->ysize - y - 1, vals); } myfree(vals); } return targ; } else if (degrees == 270 || degrees == 90) { i_img_dim tx, txstart, txinc; i_img_dim ty, tystart, tyinc; if (degrees == 270) { txstart = 0; txinc = 1; tystart = src->xsize-1; tyinc = -1; } else { txstart = src->ysize-1; txinc = -1; tystart = 0; tyinc = 1; } targ = i_sametype(src, src->ysize, src->xsize); if (src->type == i_direct_type) { #code src->bits <= 8 IM_COLOR *vals = mymalloc(src->xsize * sizeof(IM_COLOR)); tx = txstart; for (y = 0; y < src->ysize; ++y) { IM_GLIN(src, 0, src->xsize, y, vals); ty = tystart; for (x = 0; x < src->xsize; ++x) { IM_PPIX(targ, tx, ty, vals+x); ty += tyinc; } tx += txinc; } myfree(vals); #/code } else { i_palidx *vals = mymalloc(src->xsize * sizeof(i_palidx)); tx = txstart; for (y = 0; y < src->ysize; ++y) { i_gpal(src, 0, src->xsize, y, vals); ty = tystart; for (x = 0; x < src->xsize; ++x) { i_ppal(targ, tx, tx+1, ty, vals+x); ty += tyinc; } tx += txinc; } myfree(vals); } return targ; } else { i_push_error(0, "i_rotate90() only rotates at 90, 180, or 270 degrees"); return NULL; } } /* linear interpolation */ static i_color interp_i_color(i_color before, i_color after, double pos, int channels) { i_color out; int ch; pos -= floor(pos); if (channels == 1 || channels == 3) { for (ch = 0; ch < channels; ++ch) out.channel[ch] = ((1-pos) * before.channel[ch] + pos * after.channel[ch]) + 0.5; } else { int total_cover = (1-pos) * before.channel[channels-1] + pos * after.channel[channels-1]; total_cover = I_LIMIT_8(total_cover); if (total_cover) { double before_alpha = before.channel[channels-1] / 255.0; double after_alpha = after.channel[channels-1] / 255.0; double total_alpha = before_alpha * (1-pos) + after_alpha * pos; for (ch = 0; ch < channels-1; ++ch) { int out_level = ((1-pos) * before.channel[ch] * before_alpha + pos * after.channel[ch] * after_alpha) / total_alpha + 0.5; out.channel[ch] = I_LIMIT_8(out_level); } } out.channel[channels-1] = total_cover; } return out; } /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */ /* linear interpolation */ static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos, int channels) { i_fcolor out; int ch; pos -= floor(pos); if (channels == 1 || channels == 3) { for (ch = 0; ch < channels; ++ch) out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch]; } else { double total_cover = (1-pos) * before.channel[channels-1] + pos * after.channel[channels-1]; total_cover = I_LIMIT_DOUBLE(total_cover); if (total_cover) { double before_alpha = before.channel[channels-1]; double after_alpha = after.channel[channels-1]; double total_alpha = before_alpha * (1-pos) + after_alpha * pos; for (ch = 0; ch < channels-1; ++ch) { double out_level = ((1-pos) * before.channel[ch] * before_alpha + pos * after.channel[ch] * after_alpha) / total_alpha; out.channel[ch] = I_LIMIT_DOUBLE(out_level); } } out.channel[channels-1] = total_cover; } return out; } i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const double *matrix, const i_color *backp, const i_fcolor *fbackp) { i_img *result = i_sametype(src, xsize, ysize); i_img_dim x, y; int ch; i_img_dim i, j; double sx, sy, sz; if (src->type == i_direct_type) { #code src->bits <= 8 IM_COLOR *vals = mymalloc(xsize * sizeof(IM_COLOR)); IM_COLOR back; #ifdef IM_EIGHT_BIT if (backp) { back = *backp; } else if (fbackp) { for (ch = 0; ch < src->channels; ++ch) { i_fsample_t fsamp; fsamp = fbackp->channel[ch]; back.channel[ch] = fsamp < 0 ? 0 : fsamp > 1 ? 255 : fsamp * 255; } } #else #define interp_i_color interp_i_fcolor if (fbackp) { back = *fbackp; } else if (backp) { for (ch = 0; ch < src->channels; ++ch) back.channel[ch] = backp->channel[ch] / 255.0; } #endif else { for (ch = 0; ch < src->channels; ++ch) back.channel[ch] = 0; } for (y = 0; y < ysize; ++y) { for (x = 0; x < xsize; ++x) { /* dividing by sz gives us the ability to do perspective transforms */ sz = x * matrix[6] + y * matrix[7] + matrix[8]; if (fabs(sz) > 0.0000001) { sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz; sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz; } else { sx = sy = 0; } /* anything outside these ranges is either a broken co-ordinate or outside the source */ if (fabs(sz) > 0.0000001 && sx >= -1 && sx < src->xsize && sy >= -1 && sy < src->ysize) { i_img_dim bx = floor(sx); i_img_dim by = floor(sy); ROT_DEBUG(fprintf(stderr, "map " i_DFp " to %g,%g\n", i_DFcp(x, y), sx, sy)); if (sx != bx) { if (sy != by) { IM_COLOR c[2][2]; IM_COLOR ci2[2]; ROT_DEBUG(fprintf(stderr, " both non-int\n")); for (i = 0; i < 2; ++i) for (j = 0; j < 2; ++j) if (IM_GPIX(src, bx+i, by+j, &c[j][i])) c[j][i] = back; for (j = 0; j < 2; ++j) ci2[j] = interp_i_color(c[j][0], c[j][1], sx, src->channels); vals[x] = interp_i_color(ci2[0], ci2[1], sy, src->channels); } else { IM_COLOR ci2[2]; ROT_DEBUG(fprintf(stderr, " y int, x non-int\n")); for (i = 0; i < 2; ++i) if (IM_GPIX(src, bx+i, sy, ci2+i)) ci2[i] = back; vals[x] = interp_i_color(ci2[0], ci2[1], sx, src->channels); } } else { if (sy != (i_img_dim)sy) { IM_COLOR ci2[2]; ROT_DEBUG(fprintf(stderr, " x int, y non-int\n")); for (i = 0; i < 2; ++i) if (IM_GPIX(src, bx, by+i, ci2+i)) ci2[i] = back; vals[x] = interp_i_color(ci2[0], ci2[1], sy, src->channels); } else { ROT_DEBUG(fprintf(stderr, " both int\n")); /* all the world's an integer */ if (IM_GPIX(src, sx, sy, vals+x)) vals[x] = back; } } } else { vals[x] = back; } } IM_PLIN(result, 0, xsize, y, vals); } myfree(vals); #undef interp_i_color #/code } else { /* don't interpolate for a palette based image */ i_palidx *vals = mymalloc(xsize * sizeof(i_palidx)); i_palidx back = 0; int minval = 256 * 4; i_img_dim ix, iy; i_color want_back; i_fsample_t fsamp; if (backp) { want_back = *backp; } else if (fbackp) { for (ch = 0; ch < src->channels; ++ch) { fsamp = fbackp->channel[ch]; want_back.channel[ch] = fsamp < 0 ? 0 : fsamp > 1 ? 255 : fsamp * 255; } } else { for (ch = 0; ch < src->channels; ++ch) want_back.channel[ch] = 0; } /* find the closest color */ for (i = 0; i < i_colorcount(src); ++i) { i_color temp; int tempval; i_getcolors(src, i, &temp, 1); tempval = 0; for (ch = 0; ch < src->channels; ++ch) { tempval += abs(want_back.channel[ch] - temp.channel[ch]); } if (tempval < minval) { back = i; minval = tempval; } } for (y = 0; y < ysize; ++y) { for (x = 0; x < xsize; ++x) { /* dividing by sz gives us the ability to do perspective transforms */ sz = x * matrix[6] + y * matrix[7] + matrix[8]; if (abs(sz) > 0.0000001) { sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz; sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz; } else { sx = sy = 0; } /* anything outside these ranges is either a broken co-ordinate or outside the source */ if (abs(sz) > 0.0000001 && sx >= -0.5 && sx < src->xsize-0.5 && sy >= -0.5 && sy < src->ysize-0.5) { /* all the world's an integer */ ix = (i_img_dim)(sx+0.5); iy = (i_img_dim)(sy+0.5); if (!i_gpal(src, ix, ix+1, iy, vals+x)) vals[i] = back; } else { vals[x] = back; } } i_ppal(result, 0, xsize, y, vals); } myfree(vals); } return result; } i_img *i_matrix_transform(i_img *src, i_img_dim xsize, i_img_dim ysize, const double *matrix) { return i_matrix_transform_bg(src, xsize, ysize, matrix, NULL, NULL); } static void i_matrix_mult(double *dest, const double *left, const double *right) { int i, j, k; double accum; for (i = 0; i < 3; ++i) { for (j = 0; j < 3; ++j) { accum = 0.0; for (k = 0; k < 3; ++k) { accum += left[3*i+k] * right[3*k+j]; } dest[3*i+j] = accum; } } } #define numfmt "%23g" ROT_DEBUG(static void dump_mat(const char *name, double *f) { fprintf(stderr, "%s:\n " numfmt " " numfmt " " numfmt "\n" " " numfmt " " numfmt " " numfmt "\n" " " numfmt " " numfmt " " numfmt "\n", name, f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8]); }) i_img *i_rotate_exact_bg(i_img *src, double amount, const i_color *backp, const i_fcolor *fbackp) { double xlate1[9] = { 0 }; double rotate[9]; double xlate2[9] = { 0 }; double temp[9], matrix[9]; i_img_dim x1, x2, y1, y2, newxsize, newysize; ROT_DEBUG(fprintf(stderr, "rotate angle %.20g\n", amount)); /* first translate the centre of the image to (0,0) */ xlate1[0] = 1; xlate1[2] = (src->xsize-1)/2.0; xlate1[4] = 1; xlate1[5] = (src->ysize-1)/2.0; xlate1[8] = 1; ROT_DEBUG(dump_mat("xlate1", xlate1)); /* rotate around (0.0) */ rotate[0] = cos(amount); rotate[1] = sin(amount); rotate[2] = 0; rotate[3] = -rotate[1]; rotate[4] = rotate[0]; rotate[5] = 0; rotate[6] = 0; rotate[7] = 0; rotate[8] = 1; ROT_DEBUG(dump_mat("rotate", rotate)); ROT_DEBUG(fprintf(stderr, "cos %g sin %g\n", rotate[0], rotate[1])); x1 = ceil(fabs(src->xsize * rotate[0] + src->ysize * rotate[1]) - 0.0001); x2 = ceil(fabs(src->xsize * rotate[0] - src->ysize * rotate[1]) - 0.0001); y1 = ceil(fabs(src->xsize * rotate[3] + src->ysize * rotate[4]) - 0.0001); y2 = ceil(fabs(src->xsize * rotate[3] - src->ysize * rotate[4]) - 0.0001); ROT_DEBUG(fprintf(stderr, "x1 y1 " i_DFp " x2 y2 " i_DFp "\n", i_DFcp(x1, y1), i_DFcp(x2, y2))); newxsize = x1 > x2 ? x1 : x2; newysize = y1 > y2 ? y1 : y2; /* translate the centre back to the center of the image */ xlate2[0] = 1; xlate2[2] = -(newxsize-1)/2.0; xlate2[4] = 1; xlate2[5] = -(newysize-1)/2.0; xlate2[8] = 1; ROT_DEBUG(dump_mat("xlate2", xlate2)); i_matrix_mult(temp, xlate1, rotate); i_matrix_mult(matrix, temp, xlate2); ROT_DEBUG(dump_mat("matrxi", matrix)); return i_matrix_transform_bg(src, newxsize, newysize, matrix, backp, fbackp); } i_img *i_rotate_exact(i_img *src, double amount) { return i_rotate_exact_bg(src, amount, NULL, NULL); } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/draw.c0000644000175000017500000014336512524332021016670 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "draw.h" #include "log.h" #include "imageri.h" #include "imrender.h" #include #define NDEBUG #include int i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) { i_color src; i_color work; int dest_alpha; int remains; if (!col->channel[3]) return 0; switch (im->channels) { case 1: work = *col; i_adapt_colors(2, 4, &work, 1); i_gpix(im, x, y, &src); remains = 255 - work.channel[1]; src.channel[0] = (src.channel[0] * remains + work.channel[0] * work.channel[1]) / 255; return i_ppix(im, x, y, &src); case 2: work = *col; i_adapt_colors(2, 4, &work, 1); i_gpix(im, x, y, &src); remains = 255 - work.channel[1]; dest_alpha = work.channel[1] + remains * src.channel[1] / 255; if (work.channel[1] == 255) { return i_ppix(im, x, y, &work); } else { src.channel[0] = (work.channel[1] * work.channel[0] + remains * src.channel[0] * src.channel[1] / 255) / dest_alpha; src.channel[1] = dest_alpha; return i_ppix(im, x, y, &src); } case 3: work = *col; i_gpix(im, x, y, &src); remains = 255 - work.channel[3]; src.channel[0] = (src.channel[0] * remains + work.channel[0] * work.channel[3]) / 255; src.channel[1] = (src.channel[1] * remains + work.channel[1] * work.channel[3]) / 255; src.channel[2] = (src.channel[2] * remains + work.channel[2] * work.channel[3]) / 255; return i_ppix(im, x, y, &src); case 4: work = *col; i_gpix(im, x, y, &src); remains = 255 - work.channel[3]; dest_alpha = work.channel[3] + remains * src.channel[3] / 255; if (work.channel[3] == 255) { return i_ppix(im, x, y, &work); } else { src.channel[0] = (work.channel[3] * work.channel[0] + remains * src.channel[0] * src.channel[3] / 255) / dest_alpha; src.channel[1] = (work.channel[3] * work.channel[1] + remains * src.channel[1] * src.channel[3] / 255) / dest_alpha; src.channel[2] = (work.channel[3] * work.channel[2] + remains * src.channel[2] * src.channel[3] / 255) / dest_alpha; src.channel[3] = dest_alpha; return i_ppix(im, x, y, &src); } } return 0; } static void cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm, i_img_dim bxmin, i_img_dim bxmax, i_img_dim bymin, i_img_dim bymax); void i_mmarray_cr(i_mmarray *ar,i_img_dim l) { i_img_dim i; size_t alloc_size; ar->lines=l; alloc_size = sizeof(minmax) * l; /* check for overflow */ if (alloc_size / l != sizeof(minmax)) { fprintf(stderr, "overflow calculating memory allocation"); exit(3); } ar->data=mymalloc(alloc_size); /* checked 5jul05 tonyc */ for(i=0;idata[i].max = -1; ar->data[i].min = i_img_dim_MAX; } } void i_mmarray_dst(i_mmarray *ar) { ar->lines=0; if (ar->data != NULL) { myfree(ar->data); ar->data=NULL; } } void i_mmarray_add(i_mmarray *ar,i_img_dim x,i_img_dim y) { if (y>-1 && ylines) { if (xdata[y].min) ar->data[y].min=x; if (x>ar->data[y].max) ar->data[y].max=x; } } i_img_dim i_mmarray_gmin(i_mmarray *ar,i_img_dim y) { if (y>-1 && ylines) return ar->data[y].min; else return -1; } i_img_dim i_mmarray_getm(i_mmarray *ar,i_img_dim y) { if (y>-1 && ylines) return ar->data[y].max; else return i_img_dim_MAX; } #if 0 /* unused? */ void i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val) { i_img_dim i,x; for(i=0;ilines;i++) if (ar->data[i].max!=-1) for(x=ar->data[i].min;xdata[i].max;x++) i_ppix(im,x,i,val); } #endif static void i_arcdraw(i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_mmarray *ar) { double alpha; double dsec; i_img_dim temp; alpha=(double)(y2-y1)/(double)(x2-x1); if (fabs(alpha) <= 1) { if (x2lines;i++) if (ar->data[i].max!=-1) printf("line %"i_DF ": min=%" i_DF ", max=%" i_DF ".\n", i_DFc(i), i_DFc(ar->data[i].min), i_DFc(ar->data[i].max)); } static void i_arc_minmax(i_int_hlines *hlines,i_img_dim x,i_img_dim y, double rad,float d1,float d2) { i_mmarray dot; double f; i_img_dim x1,y1; i_mmarray_cr(&dot, hlines->limit_y); x1=(i_img_dim)(x+0.5+rad*cos(d1*PI/180.0)); y1=(i_img_dim)(y+0.5+rad*sin(d1*PI/180.0)); /* printf("x1: %d.\ny1: %d.\n",x1,y1); */ i_arcdraw(x, y, x1, y1, &dot); x1=(i_img_dim)(x+0.5+rad*cos(d2*PI/180.0)); y1=(i_img_dim)(y+0.5+rad*sin(d2*PI/180.0)); for(f=d1;f<=d2;f+=0.01) i_mmarray_add(&dot,(i_img_dim)(x+0.5+rad*cos(f*PI/180.0)),(i_img_dim)(y+0.5+rad*sin(f*PI/180.0))); /* printf("x1: %d.\ny1: %d.\n",x1,y1); */ i_arcdraw(x, y, x1, y1, &dot); /* render the minmax values onto the hlines */ for (y = 0; y < dot.lines; y++) { if (dot.data[y].max!=-1) { i_img_dim minx, width; minx = dot.data[y].min; width = dot.data[y].max - dot.data[y].min + 1; i_int_hlines_add(hlines, y, minx, width); } } /* dot.info(); */ i_mmarray_dst(&dot); } static void i_arc_hlines(i_int_hlines *hlines,i_img_dim x,i_img_dim y,double rad,float d1,float d2) { if (d1 <= d2) { i_arc_minmax(hlines, x, y, rad, d1, d2); } else { i_arc_minmax(hlines, x, y, rad, d1, 360); i_arc_minmax(hlines, x, y, rad, 0, d2); } } /* =item i_arc(im, x, y, rad, d1, d2, color) =category Drawing =synopsis i_arc(im, 50, 50, 20, 45, 135, &color); Fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the color. =cut */ void i_arc(i_img *im, i_img_dim x, i_img_dim y,double rad,double d1,double d2,const i_color *val) { i_int_hlines hlines; dIMCTXim(im); im_log((aIMCTX,1,"i_arc(im %p,(x,y)=(" i_DFp "), rad %f, d1 %f, d2 %f, col %p)", im, i_DFcp(x, y), rad, d1, d2, val)); i_int_init_hlines_img(&hlines, im); i_arc_hlines(&hlines, x, y, rad, d1, d2); i_int_hlines_fill_color(im, &hlines, val); i_int_hlines_destroy(&hlines); } /* =item i_arc_cfill(im, x, y, rad, d1, d2, fill) =category Drawing =synopsis i_arc_cfill(im, 50, 50, 35, 90, 135, fill); Fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the fill object. =cut */ #define MIN_CIRCLE_STEPS 8 #define MAX_CIRCLE_STEPS 360 void i_arc_cfill(i_img *im, i_img_dim x, i_img_dim y,double rad,double d1,double d2,i_fill_t *fill) { i_int_hlines hlines; dIMCTXim(im); im_log((aIMCTX,1,"i_arc_cfill(im %p,(x,y)=(" i_DFp "), rad %f, d1 %f, d2 %f, fill %p)", im, i_DFcp(x, y), rad, d1, d2, fill)); i_int_init_hlines_img(&hlines, im); i_arc_hlines(&hlines, x, y, rad, d1, d2); i_int_hlines_fill_fill(im, &hlines, fill); i_int_hlines_destroy(&hlines); } static void arc_poly(int *count, double **xvals, double **yvals, double x, double y, double rad, double d1, double d2) { double d1_rad, d2_rad; double circum; i_img_dim steps, point_count; double angle_inc; /* normalize the angles */ d1 = fmod(d1, 360); if (d1 == 0) { if (d2 >= 360) { /* default is 361 */ d2 = 360; } else { d2 = fmod(d2, 360); if (d2 < d1) d2 += 360; } } else { d2 = fmod(d2, 360); if (d2 < d1) d2 += 360; } d1_rad = d1 * PI / 180; d2_rad = d2 * PI / 180; /* how many segments for the curved part? we do a maximum of one per degree, with a minimum of 8/circle we try to aim at having about one segment per 2 pixels Work it out per circle to get a step size. I was originally making steps = circum/2 but that looked horrible. I think there might be an issue in the polygon filler. */ circum = 2 * PI * rad; steps = circum; if (steps > MAX_CIRCLE_STEPS) steps = MAX_CIRCLE_STEPS; else if (steps < MIN_CIRCLE_STEPS) steps = MIN_CIRCLE_STEPS; angle_inc = 2 * PI / steps; point_count = steps + 5; /* rough */ /* point_count is always relatively small, so allocation won't overflow */ *xvals = mymalloc(point_count * sizeof(double)); /* checked 17feb2005 tonyc */ *yvals = mymalloc(point_count * sizeof(double)); /* checked 17feb2005 tonyc */ /* from centre to edge at d1 */ (*xvals)[0] = x; (*yvals)[0] = y; (*xvals)[1] = x + rad * cos(d1_rad); (*yvals)[1] = y + rad * sin(d1_rad); *count = 2; /* step around the curve */ while (d1_rad < d2_rad) { (*xvals)[*count] = x + rad * cos(d1_rad); (*yvals)[*count] = y + rad * sin(d1_rad); ++*count; d1_rad += angle_inc; } /* finish off the curve */ (*xvals)[*count] = x + rad * cos(d2_rad); (*yvals)[*count] = y + rad * sin(d2_rad); ++*count; } /* =item i_arc_aa(im, x, y, rad, d1, d2, color) =category Drawing =synopsis i_arc_aa(im, 50, 50, 35, 90, 135, &color); Anti-alias fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the color. =cut */ void i_arc_aa(i_img *im, double x, double y, double rad, double d1, double d2, const i_color *val) { double *xvals, *yvals; int count; dIMCTXim(im); im_log((aIMCTX,1,"i_arc_aa(im %p,(x,y)=(%f,%f), rad %f, d1 %f, d2 %f, col %p)", im, x, y, rad, d1, d2, val)); arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2); i_poly_aa(im, count, xvals, yvals, val); myfree(xvals); myfree(yvals); } /* =item i_arc_aa_cfill(im, x, y, rad, d1, d2, fill) =category Drawing =synopsis i_arc_aa_cfill(im, 50, 50, 35, 90, 135, fill); Anti-alias fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the fill object. =cut */ void i_arc_aa_cfill(i_img *im, double x, double y, double rad, double d1, double d2, i_fill_t *fill) { double *xvals, *yvals; int count; dIMCTXim(im); im_log((aIMCTX,1,"i_arc_aa_cfill(im %p,(x,y)=(%f,%f), rad %f, d1 %f, d2 %f, fill %p)", im, x, y, rad, d1, d2, fill)); arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2); i_poly_aa_cfill(im, count, xvals, yvals, fill); myfree(xvals); myfree(yvals); } typedef i_img_dim frac; static frac float_to_frac(double x) { return (frac)(0.5+x*16.0); } typedef void (*flush_render_t)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *cover, void *ctx); static void i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r, void *ctx); static void scanline_flush_color(i_img *im, i_img_dim l, i_img_dim y, i_img_dim width, const i_sample_t *cover, void *ctx); static void scanline_flush_fill(i_img *im, i_img_dim l, i_img_dim y, i_img_dim width, const i_sample_t *cover, void *ctx); typedef struct { i_render r; i_color c; } flush_color_t; typedef struct { i_render r; i_fill_t *fill; } flush_fill_t; /* =item i_circle_aa(im, x, y, rad, color) =category Drawing =synopsis i_circle_aa(im, 50, 50, 45, &color); Anti-alias fills a circle centered at (x,y) for radius I with color. =cut */ void i_circle_aa(i_img *im, double x, double y, double rad, const i_color *val) { flush_color_t fc; fc.c = *val; i_render_init(&fc.r, im, rad * 2 + 1); i_circle_aa_low(im, x, y, rad, scanline_flush_color, &fc); i_render_done(&fc.r); } /* =item i_circle_aa_fill(im, x, y, rad, fill) =category Drawing =synopsis i_circle_aa_fill(im, 50, 50, 45, fill); Anti-alias fills a circle centered at (x,y) for radius I with fill. =cut */ void i_circle_aa_fill(i_img *im, double x, double y, double rad, i_fill_t *fill) { flush_fill_t ff; ff.fill = fill; i_render_init(&ff.r, im, rad * 2 + 1); i_circle_aa_low(im, x, y, rad, scanline_flush_fill, &ff); i_render_done(&ff.r); } static void i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r, void *ctx) { i_color temp; i_img_dim ly; dIMCTXim(im); i_img_dim first_row = floor(y) - ceil(rad); i_img_dim last_row = ceil(y) + ceil(rad); double r_sqr = rad * rad; i_img_dim max_width = 2 * ceil(rad) + 1; unsigned char *coverage = NULL; size_t coverage_size; int sub; im_log((aIMCTX, 1, "i_circle_aa_low(im %p, centre(" i_DFp "), rad %.2f, r %p, ctx %p)\n", im, i_DFcp(x, y), rad, r, ctx)); if (first_row < 0) first_row = 0; if (last_row > im->ysize-1) last_row = im->ysize - 1; if (rad <= 0 || last_row < first_row) { /* outside the image */ return; } coverage_size = max_width; coverage = mymalloc(coverage_size); for(ly = first_row; ly < last_row; ly++) { frac min_frac_x[16]; frac max_frac_x[16]; i_img_dim min_frac_left_x = im->xsize * 16; i_img_dim max_frac_left_x = -1; i_img_dim min_frac_right_x = im->xsize * 16; i_img_dim max_frac_right_x = -1; /* reset work_y each row so the error doesn't build up */ double work_y = ly; double dy, dy_sqr; for (sub = 0; sub < 16; ++sub) { work_y += 1.0 / 16.0; dy = work_y - y; dy_sqr = dy * dy; if (dy_sqr < r_sqr) { double dx = sqrt(r_sqr - dy_sqr); double left_x = x - dx; double right_x = x + dx; frac frac_left_x = float_to_frac(left_x); frac frac_right_x = float_to_frac(right_x); if (frac_left_x < min_frac_left_x) min_frac_left_x = frac_left_x; if (frac_left_x > max_frac_left_x) max_frac_left_x = frac_left_x; if (frac_right_x < min_frac_right_x) min_frac_right_x = frac_right_x; if (frac_right_x > max_frac_right_x) max_frac_right_x = frac_right_x; min_frac_x[sub] = frac_left_x; max_frac_x[sub] = frac_right_x; } else { min_frac_x[sub] = max_frac_x[sub] = 0; max_frac_left_x = im->xsize * 16; min_frac_right_x = -1; } } if (min_frac_left_x != -1) { /* something to draw on this line */ i_img_dim min_x = (min_frac_left_x / 16); i_img_dim max_x = (max_frac_right_x + 15) / 16; i_img_dim left_solid = (max_frac_left_x + 15) / 16; i_img_dim right_solid = min_frac_right_x / 16; i_img_dim work_x; i_img_dim frac_work_x; i_sample_t *cout = coverage; for (work_x = min_x, frac_work_x = min_x * 16; work_x <= max_x; ++work_x, frac_work_x += 16) { if (work_x <= left_solid || work_x >= right_solid) { int pix_coverage = 0; int ch; double ratio; i_img_dim frac_work_right = frac_work_x + 16; for (sub = 0; sub < 16; ++sub) { frac pix_left = min_frac_x[sub]; frac pix_right = max_frac_x[sub]; if (pix_left < pix_right && pix_left < frac_work_right && pix_right >= frac_work_x) { if (pix_left < frac_work_x) pix_left = frac_work_x; if (pix_right > frac_work_right) pix_right = frac_work_right; pix_coverage += pix_right - pix_left; } } assert(pix_coverage <= 256); *cout++ = pix_coverage * 255 / 256; } else { /* full coverage */ *cout++ = 255; } } r(im, min_x, ly, max_x - min_x + 1, coverage, ctx); } } myfree(coverage); } static void scanline_flush_color(i_img *im, i_img_dim x, i_img_dim y, i_img_dim width, const unsigned char *cover, void *ctx) { flush_color_t *fc = ctx; i_render_color(&fc->r, x, y, width, cover, &fc->c); } static void scanline_flush_fill(i_img *im, i_img_dim x, i_img_dim y, i_img_dim width, const unsigned char *cover, void *ctx) { flush_fill_t *ff = ctx; i_render_fill(&ff->r, x, y, width, cover, ff->fill); } /* =item i_circle_out(im, x, y, r, col) =category Drawing =synopsis i_circle_out(im, 50, 50, 45, &color); Draw a circle outline centered at (x,y) with radius r, non-anti-aliased. Parameters: =over =item * (x, y) - the center of the circle =item * r - the radius of the circle in pixels, must be non-negative =back Returns non-zero on success. Implementation: =cut */ int i_circle_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, const i_color *col) { i_img_dim x, y; i_img_dim dx, dy; int error; dIMCTXim(im); im_log((aIMCTX, 1, "i_circle_out(im %p, centre(" i_DFp "), rad %" i_DF ", col %p)\n", im, i_DFcp(xc, yc), i_DFc(r), col)); im_clear_error(aIMCTX); if (r < 0) { im_push_error(aIMCTX, 0, "circle: radius must be non-negative"); return 0; } i_ppix(im, xc+r, yc, col); i_ppix(im, xc-r, yc, col); i_ppix(im, xc, yc+r, col); i_ppix(im, xc, yc-r, col); x = 0; y = r; dx = 1; dy = -2 * r; error = 1 - r; while (x < y) { if (error >= 0) { --y; dy += 2; error += dy; } ++x; dx += 2; error += dx; i_ppix(im, xc + x, yc + y, col); i_ppix(im, xc + x, yc - y, col); i_ppix(im, xc - x, yc + y, col); i_ppix(im, xc - x, yc - y, col); if (x != y) { i_ppix(im, xc + y, yc + x, col); i_ppix(im, xc + y, yc - x, col); i_ppix(im, xc - y, yc + x, col); i_ppix(im, xc - y, yc - x, col); } } return 1; } /* =item arc_seg(angle) Convert an angle in degrees into an angle measure we can generate simply from the numbers we have when drawing the circle. =cut */ static i_img_dim arc_seg(double angle, int scale) { i_img_dim seg = (angle + 45) / 90; double remains = angle - seg * 90; /* should be in the range [-45,45] */ while (seg > 4) seg -= 4; if (seg == 4 && remains > 0) seg = 0; return scale * (seg * 2 + sin(remains * PI/180)); } /* =item i_arc_out(im, x, y, r, d1, d2, col) =category Drawing =synopsis i_arc_out(im, 50, 50, 45, 45, 135, &color); Draw an arc outline centered at (x,y) with radius r, non-anti-aliased over the angle range d1 through d2 degrees. Parameters: =over =item * (x, y) - the center of the circle =item * r - the radius of the circle in pixels, must be non-negative =item * d1, d2 - the range of angles to draw the arc over, in degrees. =back Returns non-zero on success. Implementation: =cut */ int i_arc_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, double d1, double d2, const i_color *col) { i_img_dim x, y; i_img_dim dx, dy; int error; i_img_dim segs[2][2]; int seg_count; i_img_dim sin_th; i_img_dim seg_d1, seg_d2; int seg_num; i_img_dim scale = r + 1; i_img_dim seg1 = scale * 2; i_img_dim seg2 = scale * 4; i_img_dim seg3 = scale * 6; i_img_dim seg4 = scale * 8; dIMCTXim(im); im_log((aIMCTX,1,"i_arc_out(im %p,centre(" i_DFp "), rad %" i_DF ", d1 %f, d2 %f, col %p)", im, i_DFcp(xc, yc), i_DFc(r), d1, d2, col)); im_clear_error(aIMCTX); if (r <= 0) { im_push_error(aIMCTX, 0, "arc: radius must be non-negative"); return 0; } if (d1 + 360 <= d2) return i_circle_out(im, xc, yc, r, col); if (d1 < 0) d1 += 360 * floor((-d1 + 359) / 360); if (d2 < 0) d2 += 360 * floor((-d2 + 359) / 360); d1 = fmod(d1, 360); d2 = fmod(d2, 360); seg_d1 = arc_seg(d1, scale); seg_d2 = arc_seg(d2, scale); if (seg_d2 < seg_d1) { /* split into two segments */ segs[0][0] = 0; segs[0][1] = seg_d2; segs[1][0] = seg_d1; segs[1][1] = seg4; seg_count = 2; } else { segs[0][0] = seg_d1; segs[0][1] = seg_d2; seg_count = 1; } for (seg_num = 0; seg_num < seg_count; ++seg_num) { i_img_dim seg_start = segs[seg_num][0]; i_img_dim seg_end = segs[seg_num][1]; if (seg_start == 0) i_ppix(im, xc+r, yc, col); if (seg_start <= seg1 && seg_end >= seg1) i_ppix(im, xc, yc+r, col); if (seg_start <= seg2 && seg_end >= seg2) i_ppix(im, xc-r, yc, col); if (seg_start <= seg3 && seg_end >= seg3) i_ppix(im, xc, yc-r, col); y = 0; x = r; dy = 1; dx = -2 * r; error = 1 - r; while (y < x) { if (error >= 0) { --x; dx += 2; error += dx; } ++y; dy += 2; error += dy; sin_th = y; if (seg_start <= sin_th && seg_end >= sin_th) i_ppix(im, xc + x, yc + y, col); if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th) i_ppix(im, xc + y, yc + x, col); if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th) i_ppix(im, xc - y, yc + x, col); if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th) i_ppix(im, xc - x, yc + y, col); if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th) i_ppix(im, xc - x, yc - y, col); if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th) i_ppix(im, xc - y, yc - x, col); if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th) i_ppix(im, xc + y, yc - x, col); if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th) i_ppix(im, xc + x, yc - y, col); } } return 1; } static double cover(i_img_dim r, i_img_dim j) { double rjsqrt = sqrt(r*r - j*j); return ceil(rjsqrt) - rjsqrt; } /* =item i_circle_out_aa(im, xc, yc, r, col) =synopsis i_circle_out_aa(im, 50, 50, 45, &color); Draw a circle outline centered at (x,y) with radius r, anti-aliased. Parameters: =over =item * (xc, yc) - the center of the circle =item * r - the radius of the circle in pixels, must be non-negative =item * col - an i_color for the color to draw in. =back Returns non-zero on success. =cut Based on "Fast Anti-Aliased Circle Generation", Xiaolin Wu, Graphics Gems. I use floating point for I since for large circles the precision of a [0,255] value isn't sufficient when approaching the end of the octant. */ int i_circle_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, const i_color *col) { i_img_dim i, j; double t; i_color workc = *col; int orig_alpha = col->channel[3]; dIMCTXim(im); im_log((aIMCTX,1,"i_circle_out_aa(im %p,centre(" i_DFp "), rad %" i_DF ", col %p)", im, i_DFcp(xc, yc), i_DFc(r), col)); im_clear_error(aIMCTX); if (r <= 0) { im_push_error(aIMCTX, 0, "arc: radius must be non-negative"); return 0; } i = r; j = 0; t = 0; i_ppix_norm(im, xc+i, yc+j, col); i_ppix_norm(im, xc-i, yc+j, col); i_ppix_norm(im, xc+j, yc+i, col); i_ppix_norm(im, xc+j, yc-i, col); while (i > j+1) { double d; int cv, inv_cv; j++; d = cover(r, j); cv = (int)(d * 255 + 0.5); inv_cv = 255-cv; if (d < t) { --i; } if (inv_cv) { workc.channel[3] = orig_alpha * inv_cv / 255; i_ppix_norm(im, xc+i, yc+j, &workc); i_ppix_norm(im, xc-i, yc+j, &workc); i_ppix_norm(im, xc+i, yc-j, &workc); i_ppix_norm(im, xc-i, yc-j, &workc); if (i != j) { i_ppix_norm(im, xc+j, yc+i, &workc); i_ppix_norm(im, xc-j, yc+i, &workc); i_ppix_norm(im, xc+j, yc-i, &workc); i_ppix_norm(im, xc-j, yc-i, &workc); } } if (cv && i > j) { workc.channel[3] = orig_alpha * cv / 255; i_ppix_norm(im, xc+i-1, yc+j, &workc); i_ppix_norm(im, xc-i+1, yc+j, &workc); i_ppix_norm(im, xc+i-1, yc-j, &workc); i_ppix_norm(im, xc-i+1, yc-j, &workc); if (j != i-1) { i_ppix_norm(im, xc+j, yc+i-1, &workc); i_ppix_norm(im, xc-j, yc+i-1, &workc); i_ppix_norm(im, xc+j, yc-i+1, &workc); i_ppix_norm(im, xc-j, yc-i+1, &workc); } } t = d; } return 1; } /* =item i_arc_out_aa(im, xc, yc, r, d1, d2, col) =synopsis i_arc_out_aa(im, 50, 50, 45, 45, 125, &color); Draw a circle arc outline centered at (x,y) with radius r, from angle d1 degrees through angle d2 degrees, anti-aliased. Parameters: =over =item * (xc, yc) - the center of the circle =item * r - the radius of the circle in pixels, must be non-negative =item * d1, d2 - the range of angle in degrees to draw the arc through. If d2-d1 >= 360 a full circle is drawn. =back Returns non-zero on success. =cut Based on "Fast Anti-Aliased Circle Generation", Xiaolin Wu, Graphics Gems. */ int i_arc_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, double d1, double d2, const i_color *col) { i_img_dim i, j; double t; i_color workc = *col; i_img_dim segs[2][2]; int seg_count; i_img_dim sin_th; i_img_dim seg_d1, seg_d2; int seg_num; int orig_alpha = col->channel[3]; i_img_dim scale = r + 1; i_img_dim seg1 = scale * 2; i_img_dim seg2 = scale * 4; i_img_dim seg3 = scale * 6; i_img_dim seg4 = scale * 8; dIMCTXim(im); im_log((aIMCTX,1,"i_arc_out_aa(im %p,centre(" i_DFp "), rad %" i_DF ", d1 %f, d2 %f, col %p)", im, i_DFcp(xc, yc), i_DFc(r), d1, d2, col)); im_clear_error(aIMCTX); if (r <= 0) { im_push_error(aIMCTX, 0, "arc: radius must be non-negative"); return 0; } if (d1 + 360 <= d2) return i_circle_out_aa(im, xc, yc, r, col); if (d1 < 0) d1 += 360 * floor((-d1 + 359) / 360); if (d2 < 0) d2 += 360 * floor((-d2 + 359) / 360); d1 = fmod(d1, 360); d2 = fmod(d2, 360); seg_d1 = arc_seg(d1, scale); seg_d2 = arc_seg(d2, scale); if (seg_d2 < seg_d1) { /* split into two segments */ segs[0][0] = 0; segs[0][1] = seg_d2; segs[1][0] = seg_d1; segs[1][1] = seg4; seg_count = 2; } else { segs[0][0] = seg_d1; segs[0][1] = seg_d2; seg_count = 1; } for (seg_num = 0; seg_num < seg_count; ++seg_num) { i_img_dim seg_start = segs[seg_num][0]; i_img_dim seg_end = segs[seg_num][1]; i = r; j = 0; t = 0; if (seg_start == 0) i_ppix_norm(im, xc+i, yc+j, col); if (seg_start <= seg1 && seg_end >= seg1) i_ppix_norm(im, xc+j, yc+i, col); if (seg_start <= seg2 && seg_end >= seg2) i_ppix_norm(im, xc-i, yc+j, col); if (seg_start <= seg3 && seg_end >= seg3) i_ppix_norm(im, xc+j, yc-i, col); while (i > j+1) { int cv, inv_cv; double d; j++; d = cover(r, j); cv = (int)(d * 255 + 0.5); inv_cv = 255-cv; if (d < t) { --i; } sin_th = j; if (inv_cv) { workc.channel[3] = orig_alpha * inv_cv / 255; if (seg_start <= sin_th && seg_end >= sin_th) i_ppix_norm(im, xc+i, yc+j, &workc); if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th) i_ppix_norm(im, xc-i, yc+j, &workc); if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th) i_ppix_norm(im, xc+i, yc-j, &workc); if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th) i_ppix_norm(im, xc-i, yc-j, &workc); if (i != j) { if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th) i_ppix_norm(im, xc+j, yc+i, &workc); if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th) i_ppix_norm(im, xc-j, yc+i, &workc); if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th) i_ppix_norm(im, xc+j, yc-i, &workc); if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th) i_ppix_norm(im, xc-j, yc-i, &workc); } } if (cv && i > j) { workc.channel[3] = orig_alpha * cv / 255; if (seg_start <= sin_th && seg_end >= sin_th) i_ppix_norm(im, xc+i-1, yc+j, &workc); if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th) i_ppix_norm(im, xc-i+1, yc+j, &workc); if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th) i_ppix_norm(im, xc+i-1, yc-j, &workc); if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th) i_ppix_norm(im, xc-i+1, yc-j, &workc); if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th) i_ppix_norm(im, xc+j, yc+i-1, &workc); if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th) i_ppix_norm(im, xc-j, yc+i-1, &workc); if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th) i_ppix_norm(im, xc+j, yc-i+1, &workc); if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th) i_ppix_norm(im, xc-j, yc-i+1, &workc); } t = d; } } return 1; } /* =item i_box(im, x1, y1, x2, y2, color) =category Drawing =synopsis i_box(im, 0, 0, im->xsize-1, im->ysize-1, &color). Outlines the box from (x1,y1) to (x2,y2) inclusive with I. =cut */ void i_box(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val) { i_img_dim x,y; dIMCTXim(im); im_log((aIMCTX, 1,"i_box(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n", im, i_DFcp(x1,y1), i_DFcp(x2,y2), val)); for(x=x1;xxsize-1, im->ysize-1, &color); Fills the box from (x1,y1) to (x2,y2) inclusive with color. =cut */ void i_box_filled(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2, const i_color *val) { i_img_dim x, y, width; i_palidx index; dIMCTXim(im); im_log((aIMCTX,1,"i_box_filled(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n", im, i_DFcp(x1, y1), i_DFcp(x2,y2) ,val)); if (x1 > x2 || y1 > y2 || x2 < 0 || y2 < 0 || x1 >= im->xsize || y1 > im->ysize) return; if (x1 < 0) x1 = 0; if (x2 >= im->xsize) x2 = im->xsize - 1; if (y1 < 0) y1 = 0; if (y2 >= im->ysize) y2 = im->ysize - 1; width = x2 - x1 + 1; if (im->type == i_palette_type && i_findcolor(im, val, &index)) { i_palidx *line = mymalloc(sizeof(i_palidx) * width); for (x = 0; x < width; ++x) line[x] = index; for (y = y1; y <= y2; ++y) i_ppal(im, x1, x2+1, y, line); myfree(line); } else { i_color *line = mymalloc(sizeof(i_color) * width); for (x = 0; x < width; ++x) line[x] = *val; for (y = y1; y <= y2; ++y) i_plin(im, x1, x2+1, y, line); myfree(line); } } /* =item i_box_filledf(im, x1, y1, x2, y2, color) =category Drawing =synopsis i_box_filledf(im, 0, 0, im->xsize-1, im->ysize-1, &fcolor); Fills the box from (x1,y1) to (x2,y2) inclusive with a floating point color. =cut */ int i_box_filledf(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2, const i_fcolor *val) { i_img_dim x, y, width; dIMCTXim(im); im_log((aIMCTX, 1,"i_box_filledf(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n", im, i_DFcp(x1, y1), i_DFcp(x2, y2), val)); if (x1 > x2 || y1 > y2 || x2 < 0 || y2 < 0 || x1 >= im->xsize || y1 > im->ysize) return 0; if (x1 < 0) x1 = 0; if (x2 >= im->xsize) x2 = im->xsize - 1; if (y1 < 0) y1 = 0; if (y2 >= im->ysize) y2 = im->ysize - 1; width = x2 - x1 + 1; if (im->bits <= 8) { i_color c; c.rgba.r = SampleFTo8(val->rgba.r); c.rgba.g = SampleFTo8(val->rgba.g); c.rgba.b = SampleFTo8(val->rgba.b); c.rgba.a = SampleFTo8(val->rgba.a); i_box_filled(im, x1, y1, x2, y2, &c); } else { i_fcolor *line = mymalloc(sizeof(i_fcolor) * width); for (x = 0; x < width; ++x) line[x] = *val; for (y = y1; y <= y2; ++y) i_plinf(im, x1, x2+1, y, line); myfree(line); } return 1; } /* =item i_box_cfill(im, x1, y1, x2, y2, fill) =category Drawing =synopsis i_box_cfill(im, 0, 0, im->xsize-1, im->ysize-1, fill); Fills the box from (x1,y1) to (x2,y2) inclusive with fill. =cut */ void i_box_cfill(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_fill_t *fill) { i_render r; dIMCTXim(im); im_log((aIMCTX,1,"i_box_cfill(im* %p, p1(" i_DFp "), p2(" i_DFp "), fill %p)\n", im, i_DFcp(x1, y1), i_DFcp(x2,y2), fill)); ++x2; if (x1 < 0) x1 = 0; if (y1 < 0) y1 = 0; if (x2 > im->xsize) x2 = im->xsize; if (y2 >= im->ysize) y2 = im->ysize-1; if (x1 >= x2 || y1 > y2) return; i_render_init(&r, im, x2-x1); while (y1 <= y2) { i_render_fill(&r, x1, y1, x2-x1, NULL, fill); ++y1; } i_render_done(&r); } /* =item i_line(C, C, C, C, C, C, C) =category Drawing =for stopwords Bresenham's Draw a line to image using Bresenham's line drawing algorithm im - image to draw to x1 - starting x coordinate y1 - starting x coordinate x2 - starting x coordinate y2 - starting x coordinate color - color to write to image endp - endpoint flag (boolean) =cut */ void i_line(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp) { i_img_dim x, y; i_img_dim dx, dy; i_img_dim p; dx = x2 - x1; dy = y2 - y1; /* choose variable to iterate on */ if (i_abs(dx) > i_abs(dy)) { i_img_dim dx2, dy2, cpy; /* sort by x */ if (x1 > x2) { i_img_dim t; t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } dx = i_abs(dx); dx2 = dx*2; dy = y2 - y1; if (dy<0) { dy = -dy; cpy = -1; } else { cpy = 1; } dy2 = dy*2; p = dy2 - dx; y = y1; for(x=x1; x y2) { i_img_dim t; t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } dy = i_abs(dy); dx = x2 - x1; dy2 = dy*2; if (dx<0) { dx = -dx; cpx = -1; } else { cpx = 1; } dx2 = dx*2; p = dx2 - dy; x = x1; for(y=y1; y, C, C, C, C, C, C) =category Drawing Anti-alias draws a line from (x1,y1) to (x2, y2) in color. The point (x2, y2) is drawn only if C is set. =cut */ void i_line_aa(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp) { i_img_dim x, y; i_img_dim dx, dy; i_img_dim p; dx = x2 - x1; dy = y2 - y1; /* choose variable to iterate on */ if (i_abs(dx) > i_abs(dy)) { i_img_dim dx2, dy2, cpy; /* sort by x */ if (x1 > x2) { i_img_dim t; t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } dx = i_abs(dx); dx2 = dx*2; dy = y2 - y1; if (dy<0) { dy = -dy; cpy = -1; } else { cpy = 1; } dy2 = dy*2; p = dy2 - dx2; /* this has to be like this for AA */ y = y1; for(x=x1; xchannels;ch++) tval.channel[ch]=(unsigned char)(t1*(float)tval.channel[ch]+t2*(float)val->channel[ch]); i_ppix(im,x+1,y,&tval); i_gpix(im,x+1,y+cpy,&tval); for(ch=0;chchannels;ch++) tval.channel[ch]=(unsigned char)(t2*(float)tval.channel[ch]+t1*(float)val->channel[ch]); i_ppix(im,x+1,y+cpy,&tval); if (p<0) { p += dy2; } else { y += cpy; p += dy2-dx2; } } } else { i_img_dim dy2, dx2, cpx; /* sort bx y */ if (y1 > y2) { i_img_dim t; t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; } dy = i_abs(dy); dx = x2 - x1; dy2 = dy*2; if (dx<0) { dx = -dx; cpx = -1; } else { cpx = 1; } dx2 = dx*2; p = dx2 - dy2; /* this has to be like this for AA */ x = x1; for(y=y1; ychannels;ch++) tval.channel[ch]=(unsigned char)(t1*(double)tval.channel[ch]+t2*(double)val->channel[ch]); i_ppix(im,x,y+1,&tval); i_gpix(im,x+cpx,y+1,&tval); for(ch=0;chchannels;ch++) tval.channel[ch]=(unsigned char)(t2*(double)tval.channel[ch]+t1*(double)val->channel[ch]); i_ppix(im,x+cpx,y+1,&tval); if (p<0) { p += dx2; } else { x += cpx; p += dx2-dy2; } } } if (endp) { i_ppix(im, x1, y1, val); i_ppix(im, x2, y2, val); } else { if (x1 != x2 || y1 != y2) i_ppix(im, x1, y1, val); } } static double perm(i_img_dim n,i_img_dim k) { double r; i_img_dim i; r=1; for(i=k+1;i<=n;i++) r*=i; for(i=1;i<=(n-k);i++) r/=i; return r; } /* Note in calculating t^k*(1-t)^(n-k) we can start by using t^0=1 so this simplifies to t^0*(1-t)^n - we want to multiply that with t/(1-t) each iteration to get a new level - this may lead to errors who knows lets test it */ void i_bezier_multi(i_img *im,int l,const double *x,const double *y, const i_color *val) { double *bzcoef; double t,cx,cy; int k,i; i_img_dim lx = 0,ly = 0; int n=l-1; double itr,ccoef; /* this is the same size as the x and y arrays, so shouldn't overflow */ bzcoef=mymalloc(sizeof(double)*l); /* checked 5jul05 tonyc */ for(k=0;k %f\n",k,bzcoef[k]); */ i=0; for(t=0;t<=1;t+=0.005) { cx=cy=0; itr=t/(1-t); ccoef=pow(1-t,n); for(k=0;k (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */ if (i++) { i_line_aa(im,lx,ly,(i_img_dim)(0.5+cx),(i_img_dim)(0.5+cy),val, 1); } /* i_ppix(im,(i_img_dim)(0.5+cx),(i_img_dim)(0.5+cy),val); */ lx=(i_img_dim)(0.5+cx); ly=(i_img_dim)(0.5+cy); } ICL_info(val); myfree(bzcoef); } /* Flood fill REF: Graphics Gems I. page 282+ */ /* This should be moved into a seperate file? */ /* This is the truncation used: a double is multiplied by 16 and then truncated. This means that 0 -> 0 So a triangle of (0,0) (10,10) (10,0) Will look like it's not filling the (10,10) point nor the (10,0)-(10,10) line segment */ /* Flood fill algorithm - based on the Ken Fishkins (pixar) gem in graphics gems I */ /* struct stc { i_img_dim mylx,myrx; i_img_dim dadlx,dadrx; i_img_dim myy; int mydirection; }; Not used code??? */ struct stack_element { i_img_dim myLx,myRx; i_img_dim dadLx,dadRx; i_img_dim myY; int myDirection; }; /* create the link data to put push onto the stack */ static struct stack_element* crdata(i_img_dim left,i_img_dim right,i_img_dim dadl,i_img_dim dadr,i_img_dim y, int dir) { struct stack_element *ste; ste = mymalloc(sizeof(struct stack_element)); /* checked 5jul05 tonyc */ ste->myLx = left; ste->myRx = right; ste->dadLx = dadl; ste->dadRx = dadr; ste->myY = y; ste->myDirection = dir; return ste; } /* i_ccomp compares two colors and gives true if they are the same */ typedef int (*ff_cmpfunc)(i_color const *c1, i_color const *c2, int channels); static int i_ccomp_normal(i_color const *val1, i_color const *val2, int ch) { int i; for(i = 0; i < ch; i++) if (val1->channel[i] !=val2->channel[i]) return 0; return 1; } static int i_ccomp_border(i_color const *val1, i_color const *val2, int ch) { int i; for(i = 0; i < ch; i++) if (val1->channel[i] !=val2->channel[i]) return 1; return 0; } static int i_lspan(i_img *im, i_img_dim seedx, i_img_dim seedy, i_color const *val, ff_cmpfunc cmpfunc) { i_color cval; while(1) { if (seedx-1 < 0) break; i_gpix(im,seedx-1,seedy,&cval); if (!cmpfunc(val,&cval,im->channels)) break; seedx--; } return seedx; } static int i_rspan(i_img *im, i_img_dim seedx, i_img_dim seedy, i_color const *val, ff_cmpfunc cmpfunc) { i_color cval; while(1) { if (seedx+1 > im->xsize-1) break; i_gpix(im,seedx+1,seedy,&cval); if (!cmpfunc(val,&cval,im->channels)) break; seedx++; } return seedx; } #ifdef DEBUG_FLOOD_FILL #define ST_PUSH_NOTE(left, right, dadl, dadr, y, dir) \ fprintf(stderr, "push(left %" i_DF ", right %" i_DF ", dadleft %" i_DF ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \ i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__) #define ST_POP_NOTE(left, right, dadl, dadr, y, dir) \ fprintf(stderr, "popped(left %" i_DF ", right %" i_DF ", dadleft %" i_DF ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \ i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__) #define ST_STACK_NOTE(dadl, dadr, left, right, y, dir) \ fprintf(stderr, "stack(left %" i_DF ", right %" i_DF ", dadleft %" i_DF ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \ i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__) #else #define ST_PUSH_NOTE(left, right, dadl, dadr, y, dir) #define ST_POP_NOTE(left, right, dadl, dadr, y, dir) #define ST_STACK_NOTE(dadl, dadr, left, right, y, dir) #endif /* Macro to create a link and push on to the list */ #define ST_PUSH(left,right,dadl,dadr,y,dir) do { \ struct stack_element *s = crdata(left,right,dadl,dadr,y,dir); \ ST_PUSH_NOTE(left, right, dadl, dadr, y, dir); \ llist_push(st,&s); \ } while (0) /* pops the shadow on TOS into local variables lx,rx,y,direction,dadLx and dadRx */ /* No overflow check! */ #define ST_POP() do { \ struct stack_element *s; \ llist_pop(st,&s); \ lx = s->myLx; \ rx = s->myRx; \ dadLx = s->dadLx; \ dadRx = s->dadRx; \ y = s->myY; \ direction = s->myDirection; \ ST_POP_NOTE(lx, rx, dadLx, dadRx, y, direction); \ myfree(s); \ } while (0) #define ST_STACK(dir,dadLx,dadRx,lx,rx,y) do { \ i_img_dim pushrx = rx+1; \ i_img_dim pushlx = lx-1; \ ST_STACK_NOTE(lx, rx, dadLx, dadRx, y, dir); \ ST_PUSH(lx,rx,pushlx,pushrx,y+dir,dir); \ if (rx > dadRx) \ ST_PUSH(dadRx+1,rx,pushlx,pushrx,y-dir,-dir); \ if (lx < dadLx) \ ST_PUSH(lx,dadLx-1,pushlx,pushrx,y-dir,-dir); \ } while (0) #define SET(x,y) btm_set(btm,x,y) /* INSIDE returns true if pixel is correct color and we haven't set it before. */ #define INSIDE(x,y, seed) \ (assert((x) >= 0 && (x) < (im)->xsize && (y) >= 0 && (y) < (im)->ysize), \ (!btm_test(btm,x,y) && \ ( i_gpix(im,x,y,&cval),cmpfunc(seed,&cval,channels) ) )) /* The function that does all the real work */ static struct i_bitmap * i_flood_fill_low(i_img *im,i_img_dim seedx,i_img_dim seedy, i_img_dim *bxminp, i_img_dim *bxmaxp, i_img_dim *byminp, i_img_dim *bymaxp, i_color const *seed, ff_cmpfunc cmpfunc) { i_img_dim ltx, rtx; i_img_dim tx = 0; i_img_dim bxmin = seedx; i_img_dim bxmax = seedx; i_img_dim bymin = seedy; i_img_dim bymax = seedy; struct llist *st; struct i_bitmap *btm; int channels; i_img_dim xsize,ysize; i_color cval; /* used by the INSIDE() macro */ channels = im->channels; xsize = im->xsize; ysize = im->ysize; btm = btm_new(xsize, ysize); st = llist_new(100, sizeof(struct stack_element*)); /* Find the starting span and fill it */ ltx = i_lspan(im, seedx, seedy, seed, cmpfunc); rtx = i_rspan(im, seedx, seedy, seed, cmpfunc); for(tx=ltx; tx<=rtx; tx++) SET(tx, seedy); bxmin = ltx; bxmax = rtx; ST_PUSH(ltx, rtx, ltx, rtx, seedy+1, 1); ST_PUSH(ltx, rtx, ltx, rtx, seedy-1, -1); while(st->count) { /* Stack variables */ i_img_dim lx,rx; i_img_dim dadLx,dadRx; i_img_dim y; int direction; i_img_dim x; int wasIn=0; ST_POP(); /* sets lx, rx, dadLx, dadRx, y, direction */ if (y<0 || y>ysize-1) continue; if (bymin > y) bymin=y; /* in the worst case an extra line */ if (bymax < y) bymax=y; x = lx+1; if ( lx >= 0 && (wasIn = INSIDE(lx, y, seed)) ) { SET(lx, y); lx--; while(lx >= 0 && INSIDE(lx, y, seed)) { SET(lx,y); lx--; } /* lx should point at the left-most INSIDE() pixel */ ++lx; } if (bxmin > lx) bxmin = lx; while(x <= xsize-1) { /* printf("x=%d\n",x); */ if (wasIn) { if (INSIDE(x, y, seed)) { /* case 1: was inside, am still inside */ SET(x,y); } else { /* case 2: was inside, am no longer inside: just found the right edge of a span */ ST_STACK(direction, dadLx, dadRx, lx, (x-1), y); if (bxmax < x) bxmax = x; wasIn=0; } } else { if (x > rx) goto EXT; if (INSIDE(x, y, seed)) { SET(x, y); /* case 3: Wasn't inside, am now: just found the start of a new run */ wasIn = 1; lx = x; } else { /* case 4: Wasn't inside, still isn't */ } } x++; } EXT: /* out of loop */ if (wasIn) { /* hit an edge of the frame buffer while inside a run */ ST_STACK(direction, dadLx, dadRx, lx, (x-1), y); if (bxmax < x) bxmax = x; } } llist_destroy(st); *bxminp = bxmin; *bxmaxp = bxmax; *byminp = bymin; *bymaxp = bymax; return btm; } /* =item i_flood_fill(C, C, C, C) =category Drawing =synopsis i_flood_fill(im, 50, 50, &color); Flood fills the 4-connected region starting from the point (C, C) with I. Returns false if (C, C) are outside the image. =cut */ undef_int i_flood_fill(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol) { i_img_dim bxmin, bxmax, bymin, bymax; struct i_bitmap *btm; i_img_dim x, y; i_color val; dIMCTXim(im); im_log((aIMCTX, 1, "i_flood_fill(im %p, seed(" i_DFp "), col %p)", im, i_DFcp(seedx, seedy), dcol)); im_clear_error(aIMCTX); if (seedx < 0 || seedx >= im->xsize || seedy < 0 || seedy >= im->ysize) { im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image"); return 0; } /* Get the reference color */ i_gpix(im, seedx, seedy, &val); btm = i_flood_fill_low(im, seedx, seedy, &bxmin, &bxmax, &bymin, &bymax, &val, i_ccomp_normal); for(y=bymin;y<=bymax;y++) for(x=bxmin;x<=bxmax;x++) if (btm_test(btm,x,y)) i_ppix(im,x,y,dcol); btm_destroy(btm); return 1; } /* =item i_flood_cfill(C, C, C, C) =category Drawing =synopsis i_flood_cfill(im, 50, 50, fill); Flood fills the 4-connected region starting from the point (C, C) with C. Returns false if (C, C) are outside the image. =cut */ undef_int i_flood_cfill(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill) { i_img_dim bxmin, bxmax, bymin, bymax; struct i_bitmap *btm; i_color val; dIMCTXim(im); im_log((aIMCTX, 1, "i_flood_cfill(im %p, seed(" i_DFp "), fill %p)", im, i_DFcp(seedx, seedy), fill)); im_clear_error(aIMCTX); if (seedx < 0 || seedx >= im->xsize || seedy < 0 || seedy >= im->ysize) { im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image"); return 0; } /* Get the reference color */ i_gpix(im, seedx, seedy, &val); btm = i_flood_fill_low(im, seedx, seedy, &bxmin, &bxmax, &bymin, &bymax, &val, i_ccomp_normal); cfill_from_btm(im, fill, btm, bxmin, bxmax, bymin, bymax); btm_destroy(btm); return 1; } /* =item i_flood_fill_border(C, C, C, C, C) =category Drawing =synopsis i_flood_fill_border(im, 50, 50, &color, &border); Flood fills the 4-connected region starting from the point (C, C) with C, fill stops when the fill reaches a pixels with color C. Returns false if (C, C) are outside the image. =cut */ undef_int i_flood_fill_border(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol, const i_color *border) { i_img_dim bxmin, bxmax, bymin, bymax; struct i_bitmap *btm; i_img_dim x, y; dIMCTXim(im); im_log((aIMCTX, 1, "i_flood_cfill(im %p, seed(" i_DFp "), dcol %p, border %p)", im, i_DFcp(seedx, seedy), dcol, border)); im_clear_error(aIMCTX); if (seedx < 0 || seedx >= im->xsize || seedy < 0 || seedy >= im->ysize) { im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image"); return 0; } btm = i_flood_fill_low(im, seedx, seedy, &bxmin, &bxmax, &bymin, &bymax, border, i_ccomp_border); for(y=bymin;y<=bymax;y++) for(x=bxmin;x<=bxmax;x++) if (btm_test(btm,x,y)) i_ppix(im,x,y,dcol); btm_destroy(btm); return 1; } /* =item i_flood_cfill_border(C, C, C, C, C) =category Drawing =synopsis i_flood_cfill_border(im, 50, 50, fill, border); Flood fills the 4-connected region starting from the point (C, C) with C, the fill stops when it reaches pixels of color C. Returns false if (C, C) are outside the image. =cut */ undef_int i_flood_cfill_border(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill, const i_color *border) { i_img_dim bxmin, bxmax, bymin, bymax; struct i_bitmap *btm; dIMCTXim(im); im_log((aIMCTX, 1, "i_flood_cfill_border(im %p, seed(" i_DFp "), fill %p, border %p)", im, i_DFcp(seedx, seedy), fill, border)); im_clear_error(aIMCTX); if (seedx < 0 || seedx >= im->xsize || seedy < 0 || seedy >= im->ysize) { im_push_error(aIMCTX, 0, "i_flood_cfill_border: Seed pixel outside of image"); return 0; } btm = i_flood_fill_low(im, seedx, seedy, &bxmin, &bxmax, &bymin, &bymax, border, i_ccomp_border); cfill_from_btm(im, fill, btm, bxmin, bxmax, bymin, bymax); btm_destroy(btm); return 1; } static void cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm, i_img_dim bxmin, i_img_dim bxmax, i_img_dim bymin, i_img_dim bymax) { i_img_dim x, y; i_img_dim start; i_render r; i_render_init(&r, im, bxmax - bxmin + 1); for(y=bymin; y<=bymax; y++) { x = bxmin; while (x <= bxmax) { while (x <= bxmax && !btm_test(btm, x, y)) { ++x; } if (btm_test(btm, x, y)) { start = x; while (x <= bxmax && btm_test(btm, x, y)) { ++x; } i_render_fill(&r, start, y, x-start, NULL, fill); } } } i_render_done(&r); } /* =back =cut */ libimager-perl-1.004+dfsg.orig/MANIFEST.SKIP0000644000175000017500000000377512263740600017473 0ustar gregoagregoa# unused test images ^testimg/winrgboff\.bmp$ ^testimg/winrle\.bmp$ ^testimg/winrle8\.bmp$ ^testimg/os2rgb8\.bmp$ ^testimg/os2rle\.bmp$ ^testimg/os2rle8\.bmp$ ^testimg/base\.tga$ # unshipped test images ^xtestimg/ # unshipped tests ^xt/ # base for some other images ^testimg/pbm_base\.pgm$ # svn work files ^\.svn\b /\.svn\b # git work files ^\.git/ ^(?:.*/)?\.gitignore$ # editor trash ~$ (^|/)\#.*\#$ (^|/)\.\# # stuff we don't distribute ^TODO$ ^STATUS$ ^\.cvsignore$ /\.cvsignore$ ^announce/ ^bench/ ^design/ ^fuzz/ ^fileformatdocs/ ^extraimages/ ^fontfiles/.*\.sfd$ ^imcover.perl$ # might distribute one day ^tools/imager$ # trash left by Inline::C ^_Inline/ # distributions built ^Imager-\d\.\d\d(_\d\d)?\.tar\.gz$ # build trash Makefile$ Makefile\.old$ \bpm_to_blib$ \.o$ ^MANIFEST\.bak$ \bMYMETA\.yml$ ^testout/ ^FT2/testout/ ^GIF/testout/ ^ICO/testout/ ^JPEG/testout/ ^PNG/testout/ ^SGI/testout/ ^TIFF/testout/ ^T1/testout/ ^W32/testout/ # generated from .xs ^CountColor/CountColor\.c$ ^DynTest/DynTest\.c$ ^FT2/FT2\.c$ ^GIF/GIF\.c$ ^ICO/ICO\.c$ ^JPEG/JPEG\.c$ ^Mandelbrot/Mandelbrot\.c$ ^PNG/PNG\.c$ ^SGI/SGI\.c$ ^TIFF/TIFF\.c$ ^T1/T1\.c$ ^W32/W32\.c$ ^.*/Changes$ ^.*/MANIFEST(\.SKIP)?$ ^.+/inc/Devel/CheckLib\.pm$ ^.+/blib/ ^blib/ ^Flines/Flines\.c$ ^Imager\.c$ ^dynfilt/.*\.(so|dll)$ \.bs$ ^meta\.tmp$ /meta\.tmp$ ^imconfig\.h$ # generated if we build them in their own directory ^(PNG|TIFF|FT2|W32|GIF)/blib/ # not shipped with Imager itself ^(PNG|TIFF|FT2|W32|GIF)/MANIFEST # generated from .im files ^combine\.c$ ^compose\.c$ ^conv\.c$ ^convert\.c$ ^filters\.c$ ^flip\.c$ ^gaussian\.c$ ^paste\.c$ ^render\.c$ ^rotate\.c$ ^rubthru\.c$ ^scale\.c$ # trash from profiling \.gcno$ \.gcda$ \.gcov$ \bcover_db\b # old web page generation scripts ^samples/combines\.pl$ ^samples/hatches\.pl$ ^samples/logo$ ^samples/transform\.pl$ ^samples/transform1\.ppm$ # Win32 junk ^(.+/)?dll\.(base|exp)$ ^(.+/)?\w+\.def$ ^(.+/)?\w+\_def.old$ \.exe$ # sub-module build junk \.bak$ MYMETA.json # dist dir ^Imager-[01]\.[0-9]+/libimager-perl-1.004+dfsg.orig/transform.perl0000644000175000017500000000433512031434615020464 0ustar gregoagregoa#!perl -w use strict; use Imager; use Imager::Transform; my %opts; my @in; my $expr; my $func; my $out; my %con; my $numre = Imager::Expr->numre; while (defined(my $arg = shift)) { if ($arg =~ /^-/) { if ($arg eq '-g') { my $work = shift or die "$0: argument missing for -g\n"; if ($work =~ /^(\d+)x(\d+)?$/) { $opts{width} = $1; $opts{height} = $2 if defined $2; } elsif ($work =~ /^x(\d+)$/) { $opts{height} = $2; } else { die "$0: invalid geometry supplied to -g\n"; } } elsif ($arg eq '-f') { $func = shift or die "$0: argument missing for -f\n"; $expr = Imager::Transform->new($func) or die "$0: unknown transformation $func\n"; } elsif ($arg eq '-d') { my $func = shift or die "$0: argument missing for -d\n"; my $desc = Imager::Transform->describe($func) or die "$0: unknown transformation $func\n"; print $desc; exit; } elsif ($arg eq '-l') { print join("\n", sort Imager::Transform->list),"\n"; exit; } elsif ($arg eq '-o') { $out = shift or die "$0: argument missing for -o\n"; } elsif ($arg eq '--') { push(@in, @ARGV); last; } else { die "$0: Unknown option $arg\n"; } } else { if ($arg =~ /^([^\W\d]\w*)=($numre)$/) { exists $con{$1} and die "$0: constant $1 already defined\n"; $con{$1} = $2; } else { push(@in, $arg); } } } $expr or usage(); $expr->inputs <= @in or die "$0: not enough input images specified for $func\n"; for my $in (@in) { my $im = Imager->new(); $im->read(file=>$in) or die "Cannot read $in: ",$im->errstr,"\n"; $in = $im; } defined $out or $out = $func.".jpg"; $opts{jpegquality} = 100; my $im = $expr->transform(\%opts, \%con, @in) or die "$0: error transforming: ",$expr->errstr,"\n"; $im->write(file=>$out, jpegquality=>100) or die "0: Cannot write $out: ",$im->errstr,"\n"; sub usage { print < = ... ... $0 -l $0 -d -f - function to evaluate -l - list function names -d - describe -g x - dimensions of output image -o - output file EOS exit } libimager-perl-1.004+dfsg.orig/imgdouble.c0000644000175000017500000004030512263740601017677 0ustar gregoagregoa/* =head1 NAME imgdouble.c - implements double per sample images =head1 SYNOPSIS i_img *im = i_img_double_new(width, height, channels); # use like a normal image =head1 DESCRIPTION Implements double/sample images. This basic implementation is required so that we have some larger sample image type to work with. =over =cut */ #define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val); static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val); static i_img_dim i_glin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals); static i_img_dim i_plin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals); static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val); static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val); static i_img_dim i_glinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals); static i_img_dim i_plinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals); static i_img_dim i_gsamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int const *chans, int chan_count); static i_img_dim i_gsampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, int const *chans, int chan_count); static i_img_dim i_psamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count); static i_img_dim i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count); /* =item IIM_base_16bit_direct Base structure used to initialize a 16-bit/sample image. Internal. =cut */ static i_img IIM_base_double_direct = { 0, /* channels set */ 0, 0, 0, /* xsize, ysize, bytes */ ~0U, /* ch_mask */ i_double_bits, /* bits */ i_direct_type, /* type */ 0, /* virtual */ NULL, /* idata */ { 0, 0, NULL }, /* tags */ NULL, /* ext_data */ i_ppix_ddoub, /* i_f_ppix */ i_ppixf_ddoub, /* i_f_ppixf */ i_plin_ddoub, /* i_f_plin */ i_plinf_ddoub, /* i_f_plinf */ i_gpix_ddoub, /* i_f_gpix */ i_gpixf_ddoub, /* i_f_gpixf */ i_glin_ddoub, /* i_f_glin */ i_glinf_ddoub, /* i_f_glinf */ i_gsamp_ddoub, /* i_f_gsamp */ i_gsampf_ddoub, /* i_f_gsampf */ NULL, /* i_f_gpal */ NULL, /* i_f_ppal */ NULL, /* i_f_addcolors */ NULL, /* i_f_getcolors */ NULL, /* i_f_colorcount */ NULL, /* i_f_maxcolors */ NULL, /* i_f_findcolor */ NULL, /* i_f_setcolors */ NULL, /* i_f_destroy */ i_gsamp_bits_fb, NULL, /* i_f_psamp_bits */ i_psamp_ddoub, /* i_f_psamp */ i_psampf_ddoub /* i_f_psampf */ }; /* =item im_img_double_new(ctx, x, y, ch) XX =category Image creation/destruction =synopsis i_img *img = im_img_double_new(aIMCTX, width, height, channels); =synopsis i_img *img = i_img_double_new(width, height, channels); Creates a new double per sample image. Also callable as C. =cut */ i_img * im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) { size_t bytes; i_img *im; im_log((aIMCTX, 1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n", i_DFc(x), i_DFc(y), ch)); if (x < 1 || y < 1) { im_push_error(aIMCTX, 0, "Image sizes must be positive"); return NULL; } if (ch < 1 || ch > MAXCHANNELS) { im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS); return NULL; } bytes = x * y * ch * sizeof(double); if (bytes / y / ch / sizeof(double) != x) { im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation"); return NULL; } im = im_img_alloc(aIMCTX); *im = IIM_base_double_direct; i_tags_new(&im->tags); im->xsize = x; im->ysize = y; im->channels = ch; im->bytes = bytes; im->ext_data = NULL; im->idata = mymalloc(im->bytes); memset(im->idata, 0, im->bytes); im_img_init(aIMCTX, im); return im; } static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; if (I_ALL_CHANNELS_WRITABLE(im)) { for (ch = 0; ch < im->channels; ++ch) ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]); } else { for (ch = 0; ch < im->channels; ++ch) if (im->ch_mask & (1<idata)[off+ch] = Sample8ToF(val->channel[ch]); } return 0; } static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; for (ch = 0; ch < im->channels; ++ch) val->channel[ch] = SampleFTo8(((double *)im->idata)[off+ch]); return 0; } static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; if (I_ALL_CHANNELS_WRITABLE(im)) { for (ch = 0; ch < im->channels; ++ch) ((double *)im->idata)[off+ch] = val->channel[ch]; } else { for (ch = 0; ch < im->channels; ++ch) if (im->ch_mask & (1 << ch)) ((double *)im->idata)[off+ch] = val->channel[ch]; } return 0; } static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; for (ch = 0; ch < im->channels; ++ch) val->channel[ch] = ((double *)im->idata)[off+ch]; return 0; } static i_img_dim i_glin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { vals[i].channel[ch] = SampleFTo8(((double *)im->idata)[off]); ++off; } } return count; } else { return 0; } } static i_img_dim i_plin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; if (I_ALL_CHANNELS_WRITABLE(im)) { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]); ++off; } } } else { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { if (im->ch_mask & (1 << ch)) ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]); ++off; } } } return count; } else { return 0; } } static i_img_dim i_glinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { vals[i].channel[ch] = ((double *)im->idata)[off]; ++off; } } return count; } else { return 0; } } static i_img_dim i_plinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; if (I_ALL_CHANNELS_WRITABLE(im)) { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { ((double *)im->idata)[off] = vals[i].channel[ch]; ++off; } } } else { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { if (im->ch_mask & (1 << ch)) ((double *)im->idata)[off] = vals[i].channel[ch]; ++off; } } } return count; } else { return 0; } } static i_img_dim i_gsamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int const *chans, int chan_count) { int ch; i_img_dim count, i, w; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return 0; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = SampleFTo8(((double *)im->idata)[off+chans[ch]]); ++count; } off += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return 0; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = SampleFTo8(((double *)im->idata)[off+ch]); ++count; } off += im->channels; } } return count; } else { return 0; } } static i_img_dim i_gsampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, int const *chans, int chan_count) { int ch; i_img_dim count, i, w; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return 0; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = ((double *)im->idata)[off+chans[ch]]; ++count; } off += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return 0; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = ((double *)im->idata)[off+ch]; ++count; } off += im->channels; } } return count; } else { return 0; } } /* =item i_psamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, int *chans, int chan_count) Writes sample values to im for the horizontal line (l, y) to (r-1,y) for the channels specified by chans, an array of int with chan_count elements. Returns the number of samples written (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_psamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { i_img_dim offset; if (r > im->xsize) r = im->xsize; offset = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ /* and test if all channels specified are in the mask */ int all_in_mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } if (!((1 << chans[ch]) & im->ch_mask)) all_in_mask = 0; } if (all_in_mask) { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps); ++samps; ++count; } offset += im->channels; } } else { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << (chans[ch]))) ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps); ++samps; ++count; } offset += im->channels; } } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } for (i = 0; i < w; ++i) { unsigned mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & mask) ((double*)im->idata)[offset + ch] = Sample8ToF(*samps); ++samps; ++count; mask <<= 1; } offset += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =item i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, int *chans, int chan_count) Writes sample values to im for the horizontal line (l, y) to (r-1,y) for the channels specified by chans, an array of int with chan_count elements. Returns the number of samples written (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { i_img_dim offset; if (r > im->xsize) r = im->xsize; offset = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ /* and test if all channels specified are in the mask */ int all_in_mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } if (!((1 << chans[ch]) & im->ch_mask)) all_in_mask = 0; } if (all_in_mask) { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { ((double*)im->idata)[offset + chans[ch]] = *samps; ++samps; ++count; } offset += im->channels; } } else { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << (chans[ch]))) ((double*)im->idata)[offset + chans[ch]] = *samps; ++samps; ++count; } offset += im->channels; } } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } for (i = 0; i < w; ++i) { unsigned mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & mask) ((double*)im->idata)[offset + ch] = *samps; ++samps; ++count; mask <<= 1; } offset += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =item i_img_to_drgb(im) =category Image creation Returns a double/sample version of the supplied image. Returns the image on success, or NULL on failure. =cut */ i_img * i_img_to_drgb(i_img *im) { i_img *targ; i_fcolor *line; i_img_dim y; dIMCTXim(im); targ = im_img_double_new(aIMCTX, im->xsize, im->ysize, im->channels); if (!targ) return NULL; line = mymalloc(sizeof(i_fcolor) * im->xsize); for (y = 0; y < im->ysize; ++y) { i_glinf(im, 0, im->xsize, y, line); i_plinf(targ, 0, im->xsize, y, line); } myfree(line); return targ; } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/ICO/0000755000175000017500000000000012617614576016212 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/ICO/imicon.h0000644000175000017500000000100412460670607017625 0ustar gregoagregoa#ifndef IMAGER_IMICON_H #define IMAGER_IMICON_H #include "imext.h" extern i_img * i_readico_single(io_glue *ig, int index, int masked, int alpha_masked); extern i_img ** i_readico_multi(io_glue *ig, int *count, int masked, int alpha_masked); extern int i_writeico_wiol(i_io_glue_t *ig, i_img *im); extern int i_writeico_multi_wiol(i_io_glue_t *ig, i_img **im, int count); extern int i_writecur_wiol(i_io_glue_t *ig, i_img *im); extern int i_writecur_multi_wiol(i_io_glue_t *ig, i_img **im, int count); #endif libimager-perl-1.004+dfsg.orig/ICO/imicon.c0000644000175000017500000003355412460670607017637 0ustar gregoagregoa#include "imext.h" #include "imicon.h" #include "msicon.h" #include static void ico_push_error(int error) { char error_buf[ICO_MAX_MESSAGE]; ico_error_message(error, error_buf, sizeof(error_buf)); i_push_error(error, error_buf); } static i_img * read_one_icon(ico_reader_t *file, int index, int masked, int alpha_masked) { ico_image_t *image; int error; i_img *result; image = ico_image_read(file, index, &error); if (!image) { ico_push_error(error); i_push_error(0, "error reading ICO/CUR image"); return NULL; } if (masked && (image->bit_count != 32 || alpha_masked)) { /* check to make sure we should do the masking, if the mask has nothing set we don't mask */ int pos; int total = image->width * image->height; unsigned char *inp = image->mask_data; masked = 0; for (pos = 0; pos < total; ++pos) { if (*inp++) { masked = 1; break; } } } if (image->direct) { int x, y; i_color *line_buf; i_color *outp; ico_color_t *inp = image->image_data; int channels = masked || image->bit_count == 32 ? 4 : 3; if (!i_int_check_image_file_limits(image->width, image->height, channels, 1)) { ico_image_release(image); return NULL; } result = i_img_8_new(image->width, image->height, channels); if (!result) { ico_image_release(image); return NULL; } line_buf = mymalloc(image->width * sizeof(i_color)); for (y = 0; y < image->height; ++y) { outp = line_buf; for (x = 0; x < image->width; ++x) { outp->rgba.r = inp->r; outp->rgba.g = inp->g; outp->rgba.b = inp->b; outp->rgba.a = inp->a; ++outp; ++inp; } i_plin(result, 0, image->width, y, line_buf); } myfree(line_buf); } else { int pal_index; int y; unsigned char *image_data; int channels = masked ? 4 : 3; if (!i_int_check_image_file_limits(image->width, image->height, channels, 1)) { ico_image_release(image); return NULL; } result = i_img_pal_new(image->width, image->height, channels, 256); if (!result) { ico_image_release(image); return NULL; } /* fill in the palette */ for (pal_index = 0; pal_index < image->palette_size; ++pal_index) { i_color c; c.rgba.r = image->palette[pal_index].r; c.rgba.g = image->palette[pal_index].g; c.rgba.b = image->palette[pal_index].b; c.rgba.a = 255; if (i_addcolors(result, &c, 1) < 0) { i_push_error(0, "could not add color to palette"); ico_image_release(image); i_img_destroy(result); return NULL; } } /* fill in the image data */ image_data = image->image_data; for (y = 0; y < image->height; ++y) { i_ppal(result, 0, image->width, y, image_data); image_data += image->width; } } { unsigned char *inp = image->mask_data; char *outp; int x, y; char *mask; /* fill in the mask tag */ /* space for " .\n", width + 1 chars per line and NUL */ mask = mymalloc(3 + (image->width + 1) * image->height + 1); outp = mask; *outp++ = '.'; *outp++ = '*'; *outp++ = '\n'; for (y = 0; y < image->height; ++y) { for (x = 0; x < image->width; ++x) { *outp++ = *inp++ ? '*' : '.'; } if (y != image->height - 1) /* not on the last line */ *outp++ = '\n'; } *outp++ = '\0'; if (ico_type(file) == ICON_ICON) i_tags_set(&result->tags, "ico_mask", mask, (outp-mask)-1); else i_tags_set(&result->tags, "cur_mask", mask, (outp-mask)-1); myfree(mask); } /* if the user requests, treat the mask as an alpha channel. Note: this converts the image into a direct image if it was paletted */ if (masked) { unsigned char *inp = image->mask_data; int x, y; i_color *line_buf = mymalloc(sizeof(i_color) * image->width); for (y = 0; y < image->height; ++y) { int changed = 0; int first = 0; int last = 0; for (x = 0; x < image->width; ++x) { if (*inp++) { if (!changed) { first = x; i_glin(result, first, image->width, y, line_buf); changed = 1; } last = x; line_buf[x-first].rgba.a = 0; } } if (changed) { i_plin(result, first, last + 1, y, line_buf); } } myfree(line_buf); } if (ico_type(file) == ICON_ICON) { i_tags_setn(&result->tags, "ico_bits", image->bit_count); i_tags_set(&result->tags, "i_format", "ico", 3); } else { i_tags_setn(&result->tags, "cur_bits", image->bit_count); i_tags_set(&result->tags, "i_format", "cur", 3); i_tags_setn(&result->tags, "cur_hotspotx", image->hotspot_x); i_tags_setn(&result->tags, "cur_hotspoty", image->hotspot_y); } ico_image_release(image); return result; } i_img * i_readico_single(io_glue *ig, int index, int masked, int alpha_masked) { ico_reader_t *file; i_img *result; int error; i_clear_error(); file = ico_reader_open(ig, &error); if (!file) { ico_push_error(error); i_push_error(0, "error opening ICO/CUR file"); return NULL; } /* the index is range checked by msicon.c - don't duplicate it here */ result = read_one_icon(file, index, masked, alpha_masked); ico_reader_close(file); return result; } i_img ** i_readico_multi(io_glue *ig, int *count, int masked, int alpha_masked) { ico_reader_t *file; int index; int error; i_img **imgs; i_clear_error(); file = ico_reader_open(ig, &error); if (!file) { ico_push_error(error); i_push_error(0, "error opening ICO/CUR file"); return NULL; } imgs = mymalloc(sizeof(i_img *) * ico_image_count(file)); *count = 0; for (index = 0; index < ico_image_count(file); ++index) { i_img *im = read_one_icon(file, index, masked, alpha_masked); if (!im) break; imgs[(*count)++] = im; } ico_reader_close(file); if (*count == 0) { myfree(imgs); return NULL; } return imgs; } static int validate_image(i_img *im) { if (im->xsize > 256 || im->ysize > 256) { i_push_error(0, "image too large for ico file"); return 0; } if (im->channels < 1 || im->channels > 4) { /* this shouldn't happen, but check anyway */ i_push_error(0, "invalid channels"); return 0; } return 1; } static int translate_mask(i_img *im, unsigned char *out, const char *in) { int x, y; int one, zero; int len = strlen(in); int pos; int newline; /* set to the first newline type we see */ int notnewline; /* set to whatever in ( "\n\r" newline isn't ) */ if (len < 3) return 0; zero = in[0]; one = in[1]; if (in[2] == '\n' || in[2] == '\r') { newline = in[2]; notnewline = '\n' + '\r' - newline; } else { return 0; } pos = 3; y = 0; while (y < im->ysize && pos < len) { x = 0; while (x < im->xsize && pos < len) { if (in[pos] == newline) { /* don't process it, we look for it later */ break; } else if (in[pos] == notnewline) { ++pos; /* just drop it */ } else if (in[pos] == one) { *out++ = 1; ++x; ++pos; } else if (in[pos] == zero) { *out++ = 0; ++x; ++pos; } else if (in[pos] == ' ' || in[pos] == '\t') { /* just ignore whitespace */ ++pos; } else { return 0; } } while (x++ < im->xsize) { *out++ = 0; } while (pos < len && in[pos] != newline) ++pos; if (pos < len && in[pos] == newline) ++pos; /* actually skip the newline */ ++y; } while (y++ < im->ysize) { for (x = 0; x < im->xsize; ++x) *out++ = 0; } return 1; } static void derive_mask(i_img *im, ico_image_t *ico) { if (im->channels == 1 || im->channels == 3) { /* msicon.c's default mask is what we want */ myfree(ico->mask_data); ico->mask_data = NULL; } else { int channel = im->channels - 1; i_sample_t *linebuf = mymalloc(sizeof(i_sample_t) * im->xsize); int x, y; unsigned char *out = ico->mask_data; for (y = 0; y < im->ysize; ++y) { i_gsamp(im, 0, im->xsize, y, linebuf, &channel, 1); for (x = 0; x < im->xsize; ++x) { *out++ = linebuf[x] == 255 ? 0 : 1; } } myfree(linebuf); } } static void fill_image_base(i_img *im, ico_image_t *ico, const char *mask_name) { int x, y; ico->width = im->xsize; ico->height = im->ysize; ico->direct = im->type == i_direct_type; if (ico->direct) { int channels[4]; int set_alpha = 0; ico_color_t *out; i_sample_t *in; unsigned char *linebuf = mymalloc(ico->width * 4); ico->image_data = mymalloc(sizeof(ico_color_t) * ico->width * ico->height); switch (im->channels) { case 1: channels[0] = channels[1] = channels[2] = channels[3] = 0; ++set_alpha; break; case 2: channels[0] = channels[1] = channels[2] = 0; channels[3] = 1; break; case 3: channels[0] = 0; channels[1] = 1; channels[2] = 2; channels[3] = 2; ++set_alpha; break; case 4: channels[0] = 0; channels[1] = 1; channels[2] = 2; channels[3] = 3; break; } out = ico->image_data; for (y = 0; y < im->ysize; ++y) { i_gsamp(im, 0, im->xsize, y, linebuf, channels, 4); in = linebuf; for (x = 0; x < im->xsize; ++x) { out->r = *in++; out->g = *in++; out->b = *in++; out->a = set_alpha ? 255 : *in; in++; ++out; } } myfree(linebuf); ico->palette = NULL; } else { unsigned char *out; i_color *colors; int i; i_palidx *in; i_palidx *linebuf = mymalloc(sizeof(i_palidx) * ico->width); ico->image_data = mymalloc(sizeof(ico_color_t) * ico->width * ico->height); out = ico->image_data; for (y = 0; y < im->ysize; ++y) { i_gpal(im, 0, im->xsize, y, linebuf); in = linebuf; for (x = 0; x < im->xsize; ++x) { *out++ = *in++; } } myfree(linebuf); ico->palette_size = i_colorcount(im); ico->palette = mymalloc(sizeof(ico_color_t) * ico->palette_size); colors = mymalloc(sizeof(i_color) * ico->palette_size); i_getcolors(im, 0, colors, ico->palette_size); for (i = 0; i < ico->palette_size; ++i) { if (im->channels == 1 || im->channels == 2) { ico->palette[i].r = ico->palette[i].g = ico->palette[i].b = colors[i].rgba.r; } else { ico->palette[i].r = colors[i].rgba.r; ico->palette[i].g = colors[i].rgba.g; ico->palette[i].b = colors[i].rgba.b; } } myfree(colors); } { /* build the mask */ int mask_index; ico->mask_data = mymalloc(im->xsize * im->ysize); if (!i_tags_find(&im->tags, mask_name, 0, &mask_index) || !im->tags.tags[mask_index].data || !translate_mask(im, ico->mask_data, im->tags.tags[mask_index].data)) { derive_mask(im, ico); } } } static void unfill_image(ico_image_t *ico) { myfree(ico->image_data); if (ico->palette) myfree(ico->palette); if (ico->mask_data) myfree(ico->mask_data); } static void fill_image_icon(i_img *im, ico_image_t *ico) { fill_image_base(im, ico, "ico_mask"); ico->hotspot_x = ico->hotspot_y = 0; } int i_writeico_wiol(i_io_glue_t *ig, i_img *im) { ico_image_t ico; int error; i_clear_error(); if (!validate_image(im)) return 0; fill_image_icon(im, &ico); if (!ico_write(ig, &ico, 1, ICON_ICON, &error)) { ico_push_error(error); unfill_image(&ico); return 0; } unfill_image(&ico); if (i_io_close(ig) < 0) { i_push_error(0, "error closing output"); return 0; } return 1; } int i_writeico_multi_wiol(i_io_glue_t *ig, i_img **ims, int count) { ico_image_t *icons; int error; int i; i_clear_error(); if (count > 0xFFFF) { i_push_error(0, "too many images for ico files"); return 0; } for (i = 0; i < count; ++i) if (!validate_image(ims[i])) return 0; icons = mymalloc(sizeof(ico_image_t) * count); for (i = 0; i < count; ++i) fill_image_icon(ims[i], icons + i); if (!ico_write(ig, icons, count, ICON_ICON, &error)) { ico_push_error(error); for (i = 0; i < count; ++i) unfill_image(icons + i); myfree(icons); return 0; } for (i = 0; i < count; ++i) unfill_image(icons + i); myfree(icons); if (i_io_close(ig) < 0) { i_push_error(0, "error closing output"); return 0; } return 1; } void fill_image_cursor(i_img *im, ico_image_t *ico) { int hotx, hoty; fill_image_base(im, ico, "ico_mask"); if (!i_tags_get_int(&im->tags, "cur_hotspotx", 0, &hotx)) hotx = 0; if (!i_tags_get_int(&im->tags, "cur_hotspoty", 0, &hoty)) hoty = 0; if (hotx < 0) hotx = 0; else if (hotx >= im->xsize) hotx = im->xsize - 1; if (hoty < 0) hoty = 0; else if (hoty >= im->ysize) hoty = im->ysize - 1; ico->hotspot_x = hotx; ico->hotspot_y = hoty; } int i_writecur_wiol(i_io_glue_t *ig, i_img *im) { ico_image_t ico; int error; i_clear_error(); if (!validate_image(im)) return 0; fill_image_cursor(im, &ico); if (!ico_write(ig, &ico, 1, ICON_CURSOR, &error)) { ico_push_error(error); unfill_image(&ico); return 0; } unfill_image(&ico); if (i_io_close(ig) < 0) { i_push_error(0, "error closing output"); return 0; } return 1; } int i_writecur_multi_wiol(i_io_glue_t *ig, i_img **ims, int count) { ico_image_t *icons; int error; int i; i_clear_error(); if (count > 0xFFFF) { i_push_error(0, "too many images for ico files"); return 0; } for (i = 0; i < count; ++i) if (!validate_image(ims[i])) return 0; icons = mymalloc(sizeof(ico_image_t) * count); for (i = 0; i < count; ++i) fill_image_cursor(ims[i], icons + i); if (!ico_write(ig, icons, count, ICON_CURSOR, &error)) { ico_push_error(error); for (i = 0; i < count; ++i) unfill_image(icons + i); myfree(icons); return 0; } for (i = 0; i < count; ++i) unfill_image(icons + i); myfree(icons); if (i_io_close(ig) < 0) { i_push_error(0, "error closing output"); return 0; } return 1; } libimager-perl-1.004+dfsg.orig/ICO/testimg/0000755000175000017500000000000012617614576017666 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/ICO/testimg/rgba3232.ico0000644000175000017500000001027612031434614021574 0ustar gregoagregoa  ¨( @ ûƒ‡€ûˆ€û˜‹€ú¡€ù±‘§øÅ–ÿ÷Ø›ÿõì ÿôÿ¤ÿÚú›ÿÀõ“ÿ§ñŠÿ|èzÿGÞhÿDÙgÿ?Ógÿ8Ëfÿ1Áeÿ*·cÿ"¬bÿ¡aÿ–`ÿŠ^ÿ€\ÿ€\ÿ€\ÿ\ÿ\ÿ€]ÿ€\ÿ]ÿ\ÿýl€€üvƒ€û€…€û‰ˆƒû“ŠÊúžÿùªÿø½”ÿ÷Ñ™ÿöåžÿôù£ÿãüžÿÉö•ÿ°óÿìÿXáoÿEÛhÿ@Õgÿ;Ífÿ3Åeÿ-»dÿ%°bÿ¥bÿš`ÿ Ž_ÿ‚]ÿ€]ÿ\ÿ]ÿ]ÿ\ÿ]ÿÿU{€þ_}€ýh€€ýr‚‘ý|…æü†‡ÿú‰ÿûšŒÿù¤ÿø¶“ÿøÊ˜ÿ÷Þœÿõñ¡ÿíþ¡ÿÓù™ÿºóÿ ï‡ÿlåuÿGÝhÿB×gÿ<Ðgÿ6Èeÿ/¾dÿ'´cÿªbÿžaÿ“_ÿ†]ÿ]ÿ€\ÿ]ÿ]ÿâMz€÷Kz€þQyþ[|±ýe~úýoÿüyƒÿüƒ†ÿû‰ÿû–‹ÿú¡ÿù°‘ÿøÃ•ÿ÷×›ÿõêŸÿõÿ¤ÿÜûœÿÃö“ÿ©ñŠÿ€é|ÿIÞiÿDÙhÿ?Ógÿ9Êfÿ2Âdÿ*¸dÿ"®bÿ¢aÿ—_ÿ ‹^ÿ]ÿ]ÿ±N€ÆM}€ÛL{ïLyÝÿMyÿþW{ÿþb~ÿýk€ÿýuƒÿü…ÿü‰‡ÿû“ŠÿúŒÿù¨ÿø¼”ÿ÷Йÿöãÿõ÷¢ÿåýŸÿËø—ÿ²òŽÿ”ì‚ÿ]âpÿFÜhÿAÕgÿ:Îgÿ4Åeÿ-¼dÿ&±cÿ¦aÿ›`ÿ _ÿO‚€•NªN²¾M}úÓM|ÿèMzÿüLyÿÿTzÿþ^}ÿýhÿýr‚ÿü{„ÿû†‡ÿû‰ÿûš‹ÿú£ÿøµ’ÿøÈ—ÿöÝœÿõð¡ÿîþ¢ÿÕùšÿ¼ôÿ¢ïˆÿpævÿFÞhÿCØgÿ=Ñfÿ6Èfÿ0¾dÿ(µcÿ «aÿPP†€eP„ˆzP‚åŽOÿ£Nÿ·N~ÿÌM}ÿáM{ÿõLzÿÿQzÿþZ|ÿýdÿýnÿýxƒÿû‚…ÿûŒˆÿú•‹ÿú ÿù®ÿøÂ•ÿ÷ÕšÿöéŸÿõý¤ÿÞûœÿÄö”ÿ«ñ‹ÿ…ê}ÿMßjÿDÚhÿ?Ógÿ9Ëfÿ2Âeÿ8Nš;PªIQ‡ý]P…ÿrP„ÿ†Oÿ›N€ÿ¯N~ÿÄM}ÿÙM{ÿíLzÿÿMyÿÿV{ÿþa~ÿýk€ÿýuƒÿü~…ÿû‰‡ÿû’‰ÿúŒÿú¦ÿøº”ÿ÷Θÿöâÿôö¢ÿçüŸÿÎø—ÿµóŽÿ˜í…ÿaãqÿFÜhÿAÖhÿ/G¼‰3J®á6L ÿ9P’ÿBQ†ÿVQ…ÿkP„ÿ€O‚ÿ”Nÿ©Nÿ½N}ÿÒM|ÿæM{ÿûKyÿþSzÿþ^}ÿþg€ÿýq‚ÿý{„ÿû…‡ÿûމÿû™‹ÿú¢Žÿø´’ÿ÷Ç—ÿ÷Ûœÿõï ÿñþ£ÿ×úšÿ¾ô‘ÿ¤ð‰ÿuçxÿ,Fɸ.FÄü.G¾ÿ2J³ÿ5L¤ÿ8O—ÿ;QˆÿOQ†ÿcQ„ÿyOƒÿŒOÿ¡N€ÿ¶N~ÿÊM|ÿßL{ÿôLzÿþOzÿþY|ÿþd~ÿýnÿüwƒÿü†ÿû‹ˆÿú•ŠÿúŸÿù­ÿøÀ•ÿöÔšÿöèŸÿôü£ÿàûÿÆö”ÿ)CÕð*DÐÿ,EÊÿ-FÆÿ/GÁÿ0H¸ÿ3Kªÿ7Nœÿ;PŽÿHQ†ÿ\Q…ÿqPƒÿ…O‚ÿšNÿ¯NÿÃM}ÿ×L{ÿìLzÿÿLyÿþV{ÿþ`~ÿýj€ÿýt‚ÿü~…ÿû‡‡ÿû‘‰ÿûœŒÿú¥Žÿù¹“ÿ÷̘ÿöàœÿõô¢ÿ&@áÿ(AÜÿ(B×ÿ*DÒÿ,EÍÿ,FÇÿ.GÃÿ/H½ÿ2J¯ÿ5L ÿ9O“ÿ@Q‡ÿTQ†ÿiP„ÿ~O‚ÿ’Oÿ§N€ÿ¼M}ÿÐM|ÿäLzÿùLyÿÿSzÿþ]}ÿþgÿýp‚ÿüzƒÿû„‡ÿûމÿú˜‹ÿú¢Žÿø²‘ÿøÆ–ÿ#>îÿ$?èÿ&@ãÿ'AÞÿ(BÙÿ)CÔÿ*DÎÿ,EÉÿ-FÄÿ.G¿ÿ2I´ÿ5L¦ÿ8N˜ÿ;QŠÿMQ†ÿbP„ÿwP‚ÿ‹OÿŸNÿ´N~ÿÉM}ÿÝM{ÿòLyÿÿOyÿþX|ÿýc~ÿýmÿüvƒÿü€…ÿû‹ˆÿú”Šÿúžÿ#Mòÿ"@óÿ#>ïÿ$?êÿ%@åÿ&Aàÿ(BÛÿ)CÕÿ+CÑÿ+EËÿ-FÇÿ/FÁÿ0H¹ÿ3K«ÿ7Nœÿ:PÿFQ‡ÿ[Q…ÿoPƒÿ„O‚ÿ˜Oÿ¬NÿÁM}ÿÕM|ÿêLzÿÿLyÿÿU{ÿþ_}ÿýi€ÿýr‚ÿü}„ÿü‡‡ÿ(nðÿ%`ñÿ$Ròÿ#Eóÿ"=ñÿ$?ìÿ%@çÿ&Aâÿ'BÝÿ(BØÿ*CÒÿ+EÍÿ,EÈÿ.FÃÿ.G¾ÿ2J°ÿ5L¢ÿ9O“ÿ>Q‡ÿSQ…ÿhP„ÿ|O‚ÿ‘N€ÿ¥NÿºN}ÿÏL|ÿãL{ÿ÷LyÿþQ{ÿþ\}ÿýeÿüpÿ+Žïÿ*ïÿ(sðÿ'eòÿ%Wòÿ#Iòÿ!=òÿ#>îÿ%?èÿ&Aäÿ&Aßÿ(BÙÿ)CÔÿ+DÏÿ,EÊÿ-FÅÿ/GÀÿ1Hµÿ5L§ÿ7O™ÿìÿ$?çÿ&Aâÿ'AÜÿ(BØÿ*CÓÿ+DÍÿ,EÉÿ.FÃÿ/G¾ÿ2J²ÿ6L£ÿ9O•ÿ=R‡ÿQQ†ÿfP„ÿ{PƒÿOÿ£N€ÿ¸M~ä$ª’ÿ'°¬ÿ+¶Åÿ0¼ßÿ0¹ìÿ/«íÿ-žíÿ,îÿ*ïÿ(tðÿ'gñÿ%Xñÿ#Kòÿ"=óÿ#?îÿ$?éÿ%@äÿ&Aßÿ(BÙÿ)CÕÿ+DÏÿ+EÊÿ-FÅÿ/GÀÿ0I¶ÿ4L¨ÿ8Nšÿ;PŒÿJQ†ÿ_P„ÿtPƒÿˆO‚šRÿ¢nÿ#¨‰ÿ&®¢ÿ*´½ÿ.ºÖÿ1½ìÿ/°íÿ.¢íÿ,•îÿ+‡ïÿ)yðÿ'kðÿ%]òÿ$Pòÿ#Bóÿ#>ðÿ$?ëÿ%@æÿ&@áÿ(BÜÿ)BÖÿ*CÑÿ,DÌÿ-EÇÿ.GÂÿ/H¼ÿ3J­ÿ6MŸÿ:P‘ÿCQ‡îXQ…(‹,ÿ‘1ÿ˜IÿŸeÿ"¥ÿ%¬šÿ(²´ÿ-¸Ìÿ0¾æÿ0µíÿ.§íÿ,™îÿ+Œïÿ)~ïÿ(pðÿ&bñÿ$Uòÿ"Góÿ"=òÿ$?íÿ$?çÿ&Aâÿ'BÝÿ(BØÿ*DÓÿ+DÎÿ,EÉÿ.FÄÿ/G¾ÿ1J²ÿ5L¤±8O– z ÿ€%ÿˆ*ÿ/ÿ–?ÿœ[ÿ¤vÿ$©‘ÿ'°ªÿ+¶Ãÿ/¼Ýÿ1¹ìÿ/¬íÿ-Ÿíÿ+‘ïÿ*‚ïÿ(uðÿ'hñÿ%Zñÿ#Lóÿ">ôÿ#>ïÿ$?éÿ%@äÿ'Aàÿ(AÚÿ)CÕÿ*DÐÿ,EËÿ-FÅø/FÁj1H·iÿ pÿ wÿ#ÿ†)ÿ-ÿ”5ÿšQÿ¡lÿ"§‡ÿ&®¡ÿ)³»ÿ.ºÔÿ1¿ìÿ/±ìÿ-¤íÿ,•ïÿ+‡ïÿ)zïÿ(lñÿ&_ñÿ$Qòÿ"Cóÿ"=ñÿ$?ëÿ%@çÿ&Aáÿ(BÜÿ)C×ÿ*DÑã+DÌ.,FÇWÿ^ ÿfÿ mÿ uÿ|!ÿƒ&ÿŠ,ÿ‘0ÿ—Gÿžbÿ!¥}ÿ%¬˜ÿ)±±ÿ,¸Êÿ0½äÿ0¶ìÿ.¨íÿ-šîÿ+ïÿ*~ïÿ(rðÿ&cñÿ$Uòÿ#Hòÿ"=òÿ#?íÿ%?èÿ&Aãÿ'AÞË(BØ *DÔEÿMÿTÿ\ ÿcÿ kÿ rÿ yÿ%ÿˆ*ÿŽ/ÿ•>ÿXÿ¢tÿ$©Žÿ'¯¨ÿ+¶Áÿ/¼Úÿ1»ìÿ/­íÿ-Ÿíÿ+’îÿ*„ðÿ(vðÿ'hñÿ%[òÿ$Móÿ!@ôÿ#>ïÿ$?ê¡%@ä'Aß7ÿ<ÿBÿJÿQÿY ÿaÿhÿ oÿ wÿ}#ÿ…(ÿŒ-ÿ“4ÿšOÿ iÿ"§…ÿ&­Ÿÿ*³¹ÿ-¹Ñÿ1Àëÿ/²ìÿ.¥íÿ,—îÿ+‰ïÿ){ïÿ'mñÿ&_ñÿ$Ròû#Dó`#>ð$?ì-ÿ1ÿ6ÿ:ÿ?ÿGÿOÿWÿ] ÿeÿ lÿ tÿ{!ÿ‚&ÿ‰+ÿ‘1ÿ˜Eÿž`ÿ!¥{ÿ$«–ÿ(±¯ÿ+·Éÿ/½âÿ1·íÿ.©íÿ-›îÿ+Žïÿ)€ïÿ(rðÁ&eñ%Wò#Iò) ÿ) ÿ, ÿ0ÿ5ÿ9ÿ<ÿDÿLÿTÿ[ ÿbÿ jÿ qÿ xÿ€%ÿ‡)ÿŽ.ÿ•;ÿ›Vÿ¢qÿ#©ÿ&®¦ÿ+µ¿ÿ.»Øÿ0¼ìÿ/®ìÿ. îã+“ïH*„ï)wð'iñ( ÿ) ÿ) ÿ) ÿ* ÿ/ÿ2ÿ7ÿ;ÿBÿIÿQÿY ÿ_ ÿgÿ nÿ vÿ}#ÿ…'ÿŒ-ÿ“2ÿ™Lÿ gÿ"¦ƒÿ%­ÿ)²·ÿ-¹Ðû1¿é…0³í .¥í,—î+Šï) ÿ) ÿ( ÿ( ÿ( ÿ( ÿ) ÿ-ÿ2ÿ6ÿ9ÿ?ÿGÿNÿVÿ] ÿdÿ lÿ sÿz!ÿ%ÿ‰*ÿ0ÿ—Cÿ^ÿ £yÿ$ª”Þ(°­5+·Æ/½à0¸ì.«í( ÿ( ÿ( ÿ) ÿ) ÿ( ÿ) ÿ) ÿ) ÿ+ ÿ0ÿ4ÿ8ÿ<ÿDÿLÿSÿZ ÿbÿ iÿ qÿ wÿ$ÿ†)ÿŽ.ÿ”9ÿ›Uª¡p#©‹&®¤*´¾.»Ö( ÿ) ÿ( ÿ) ÿ( ÿ( ÿ) ÿ( ÿ) ÿ) ÿ) ÿ* ÿ.ÿ3ÿ7ÿ;ÿAÿHÿPÿXÿ_ ÿgÿ nÿ vÿ}"ÿ„'ÿ‹,Š’2™JŸf!¦€%¬›øøøøððààÀÀ€????libimager-perl-1.004+dfsg.orig/ICO/testimg/pal83232.ico0000644000175000017500000000427612031434614021530 0ustar gregoagregoa ¨( @(*+( , 02 68<@DFKIMPVR Y[ c^ g i qmv{$‚"†'CR„>R†?PЉ+DP‰:Q‹#;OIQ‡NQ†SQ…7P’^O†YOˆ7N— (YR„cP…‹.9Mœ4NnQ‚iQ„tO„5L¢~P€yP‚„NƒN…7K§Mƒ3I®ŠP’,2Lª–O€.J°œMƒ0Hµ§L‚¢N€€X§O}“.2Gº®N´L^´O|ºM~ÀNz-H½ÌNwÀL€•0ÇM|/FÂÎL~*GÄÔMz+EÉ„]-BÏÛL|âJ~(CÑèLy*AÖïK{öMu%BØ÷J|þLx'@ß–="Aá$>ç#9õŒ^!=ïÿO{ÿSu&Aê˜IAô ‘]þT~šM$BôÿYy%HòIó˜\–aýZ‚š_œXÿ_}ÿdx Qóaždýe dÿj|¤a"Xó! lýk†¢o$^òÿp¬b¤x&eòýu„ÿz%³`(jñ!¦‚û{‡)oïþƒ+·e"qò%¨‹©$vñ/½bü…†ÿ‰‚4Ã^ «•&|ð3ÁfûŠŠþ…/Çe)‚ð%­žúü”ˆ3Êh+‡ï(®¥ °©-‹í7Ïd&ðúš‹#±°ýž†(’ï<Ôiú Ž@Ùd+—ïý¤‰*´ºø¥-œíCÝhû©Œ/ ë$¶Ä'¡îNàhø¬”*¦íú°*¸Íö±–Yâr.¬íaãqù¶’/»Ö0±ì(²î'½Ùkæqø»”)½ß*·íûÀtçy.¼ì÷—|éx.¿èúÇ’„éöÈ™ùÍ”Ží•ì…õÏœøÓ—ð€ôÔ¦ð‹øÚ™®ò‰®ò’öà›¶ó½ôöæ¿õ—Æ÷”Ïù’õí Ðùœ×ú™ßü•ôô¡÷øœçý›àü ôû¤ðþ¢÷ÿž¡¨µºÏàèôýöïéßÁ»¹®¦››‡„nIIIOOI]O]Œ”š§¬·ÇØäíøûòëãÌ»¹³¦›‡„n]IIOOOOy†“𢬵¿ÏáíøýõîæÙÁ¹³£¦›‰…}]OOO]`vv~†”¡§µºÉÛêðüûñëÜÆ»¹££ ‡}nOOPW_dhyŒ“š¡­µÇÕåðùúòìãÌ»¹®¦›•|u9CMR[bpq~Œ“”§¨µºÏàíôýõïçÙÁƳ£¦›*6:@HP[_dqy‚“¡§µºÇÛèðüûñë߯»³®£.'(,7;CMW_`pv‚Œ“š§­·½ÕåíøûòîæÎ»¹X?4' 05;CGR[bpv†”¡§µ¿ËàêôüõñéÙZ\XF8.%)19@HQW`eqy†˜š§­ºÇÛèðþûòcc\XXLB3')07@CPR_dpqˆ“š§­º½Ïàíøicca\ZXS?8. *6<>HQ[_hq~†”¡§µ¿ËÞxriicaa\ZSF83%)1:>HNY_dqy‚Œ“¡§­ºzmmllicf^\ZXFB3+(05;CJW[bpvˆ“š¡™ŽŽzxrrrccca\ZSF3.!*69>HQ[bqv‚²ª™’Šzxrrlica^\ZSF=.%(17@EPW`dhyÍü¯Ÿ–Žzxmriiiac\\SL?3' -5;CMR_`ÊÝÑÈÀ¯¥™’Šzmrrlccaa\XS?8'")1:@HQ°ÊÖ×Èò¯™’Žƒmrrilcaa\\XFB.%),7@€‹°¾ÐÚÍü¯Ÿ–Žƒrxrlicc^\\XS?8'$02Ks„‘¤¾ÊÝÑÈÀ²¥™’Šzxrliifaa\XLD8.2/s€‹ž±ÄÖÑÍøª™’Šzxxliicca\ZXF#2j€‹«¾ÊÝÑü¯¥™Žƒzxzliica^\2Ks‡‘«¶ÊÝÑÈÀ²ª™’Šrmzrlica 2&2€‘°¾ÐÚÍò¯™’Žƒmrrik #2j€‡ž«¾ÐÝÑȼ²¥–’ƒrml 2Ks€‘«¶ÊÖÑȼ²ª™’Š{ 22sw‹ž°¾ÐÚÍø¯Ÿ– 22w‹—«¾ÐÝÑø²  #&w€—¶ÊÖÚÍ 2jw‘—°¾Ð #Kw„—«libimager-perl-1.004+dfsg.orig/ICO/testimg/pal256.ico0000644000175000017500000012017612263740600021363 0ustar gregoagregoah (ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀ?ÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿüüÿÿÿÿ ÿÿÿðÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿàÿðÿÀà?ÿ€ÿÿðÿÿüÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿÿüÿÿÿÿüÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿüÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿð?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/ICO/testimg/pal43232.ppm0000644000175000017500000000603612031434614021542 0ustar gregoagregoaP6 #CREATOR: Imager 32 32 255 9999999999999999993| 93| 3| 3| 3| 3| 3| 3| 3| `¿4r¡r¡Áµ(99999999999999993| 93| 93| 3| 3| 3| `¿43| `¿4r¡r¡Áµ(Áµ(Áµ(999999999999993| 3| 3| 3| 3| 3| 3| 3| 3| 3| `¿4r¡r¡Áµ(Áµ(Áµ(ïš*ïš*9999999999993| 93| 93| 3| 3| 3| 3| `¿4r¡r¡Áµ(Áµ(Áµ(ïš*Áµ(ïš*ïš*ïš*9999999993| 3| 3| 3| 3| 3| 3| 3| 3| `¿43| r¡r¡Áµ(Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ÕO*ÕO*9999999993| 93| 3| 3| 3| `¿43| r¡r¡r¡Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ïš*ëA#ïš*ëA#ëA#999993| 3| 3| 3| 3| 3| 3| 3| 3| 3| `¿4r¡r¡Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ïš*ëA#ëA#ëA#ëA#ëA#ëA#9993| 93| 3| 3| 3| 3| 3| 3| `¿4r¡r¡Áµ(Áµ(ïš*Áµ(ïš*ïš*ïš*ïš*ïš*ÕO*ëA#ëA#ëA#ëA#ëA#ëA#ëA#3| 3| 3| 3| 3| 3| 3| 3| 3| `¿43| r¡r¡Áµ(Áµ(Áµ(ïš*Áµ(ïš*ïš*ïš*ÕO*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*93| 3| 3| 3| 3| 3| 3| r¡r¡Áµ(Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ïš*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*3| 3| 3| 3| 3| `¿4r¡r¡Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ïš*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*ÕO*”OB3| 3| `¿4r¡r¡r¡Áµ(Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ëA#ïš*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB3| r¡r¡Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ïš*ïš*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OB”OBr¡Áµ(Áµ(Áµ(Áµ(ïš*ïš*ïš*ïš*ÕO*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ëA#ÕO*ÕO*ÕO*ÕO*ÕO*ÕO*”OB”OB”OB”OB”OBƒOˆƒOˆÁµ(Áµ(ïš*ïš*ïš*ïš*ïš*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ}Víïš*ïš*ïš*ïš*ïš*ëA#ïš*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Víïš*ïš*ÕO*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*ÕO*”OB”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Víïš*ëA#ëA#ëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}Ví}VíëA#ëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ôëA#ëA#ëA#ëA#ëA#ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ùëA#ëA#ÕO*ÕO*ÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùÕO*ÕO*ÕO*ÕO*”OBÕO*”OB”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ùæöæöæöÕO*ÕO*”OBÕO*”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ†‚ô}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæöæö”öÄ”öÄÕO*ÕO*”OB”OB”OB”OBƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæöæö”öÄ”öÄ”öÄ`¿4”OB”OB”OB”OBƒOˆƒOˆƒOˆ†‚ô}Ví}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô‘°ù†‚ô‘°ù‘°ùæöæöæö”öÄ”öÄ”öÄ”öÄ`¿4`¿4`¿4”OBƒOˆƒOˆƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæöæö”öÄ”öÄ”öÄ`¿4`¿4`¿4`¿4`¿4`¿4ƒOˆƒOˆƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæö”öÄ”öÄ”öÄ”öÄ`¿4`¿4`¿4`¿4`¿4`¿4`¿4`¿4ƒOˆ}Ví}Ví}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæöæö”öÄ”öÄ”öÄ”öÄ`¿4`¿4`¿4`¿4`¿4`¿4`¿4r¡r¡r¡}Ví}Ví}Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæö”öÄ”öÄ”öÄ”öÄ`¿4`¿4`¿4`¿4`¿4`¿4`¿4`¿4r¡r¡r¡r¡3| }Ví}Ví}Ví}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæöæö”öÄ”öÄ”öÄ`¿4`¿4`¿4`¿4`¿4`¿4`¿4`¿4r¡r¡r¡3| r¡3| r¡}V톂ô†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæöæö”öÄ”öÄ”öÄ”öÄ`¿4`¿4`¿4`¿4`¿4`¿4`¿4r¡r¡r¡r¡r¡r¡3| Áµ(9r¡†‚ô†‚ô†‚ô‘°ù‘°ù‘°ùæöæöæö”öÄ”öÄ”öÄ`¿4`¿4`¿4`¿4`¿4`¿4`¿4`¿4r¡r¡r¡r¡r¡3| Áµ(93| r¡r¡r¡libimager-perl-1.004+dfsg.orig/ICO/testimg/combo.ico0000644000175000017500000002765612031434614021460 0ustar gregoagregoa00 ¨%6 ¨Þ%(†.(0` ç*ÿç*ÿç*ÿç*ÿç*ÿç*õç*u±ç+±çÞ±çÿ±çÿ±çÿ±çÿ±çÿç*ÿç*ÿç*ÿç*ÿç*ÿç*üç*}±ç1±çû±çÿ±çÿ±çÿ±çÿ±çÿç*ÿç*ÿç*ÿç*ÿç*ÿç*ëç*k±ç-±çï±çÿ±çÿ±çÿ±çÿ±çÿç*ÿç*ÿç*ÿç*ÿç*ÿç*Âç*C±ç ±ç¼±çÿ±çÿ±çÿ±çÿ±çÿç*ÿç*ÿç*ÿç*ÿç*ïç*€ç*±ç ±çh±çÿ±çÿ±çÿ±çÿ±çÿç*üç*üç*óç*áç*Žç*#±ç±ç±ç•±çÿ±çÿ±çÿ±çÿç*Ãç*Ãç*›ç*Pç*±ç±ç±çh±ç¼±çï±çû±ç±ç ±ç ±ç-±ç1 -1+h¼ïûÞœI•ÿÿÿÿÿÿâd hÿÿÿÿÿÿÿÿØ6 ¼ÿÿÿÿÿÿÿÿíŠ-ïÿÿÿÿÿÿÿÿû½1ûÿÿÿÿÿÿÿÿþÉ+Þÿÿÿÿÿÿÿÿø¬œÿÿÿÿÿÿÿÿéjIâÿÿÿÿÿÿû¸dØíûþøé¸76нɬjçƒçƒ çƒ çƒçƒçƒh烼Cç-Cç Cç Cççƒçƒ4çƒÁçƒÿçƒÿCçïCç¼CçhCçCçÍtHÞ~ÝçƒÿçƒÿçƒÿCçÿCçÿCçÿCç•CçCç „K/ÏuÛæ‚ÿçƒÿçƒÿçƒÿCçÿCçÿCçÿCçÿCçhCç ¦^¯àþçƒÿçƒÿçƒÿçƒÿCçÿCçÿCçÿCçÿCç¼Cç ="@ÌsòçƒÿçƒÿçƒÿçƒÿçƒÿCçÿCçÿCçÿCçÿCçïCç-p?ŠÜ}ýçƒÿçƒÿçƒÿçƒÿçƒÿCçÿCçÿCçÿCçÿCçûCç1 ‹O±â€ÿçƒÿçƒÿçƒÿçƒÿçƒÿCçÿCçÿCçÿCçÿCçÞCç+ šW»æ‚ÿçƒÿçƒÿçƒÿçƒÿçƒÿÿÿÿÿàÿÿÿÿàÿÿÿÿàÿÿÿÿàÿÿÿÿàÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿðÿÿÿÿðÿÿÿÿðÿÿÿÿðÿÿÿÿðÿÿÿÿðÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿøÿÿÿÿðÿÿÿÿðÿÿÿÿàÿÿÿÿàÿÿÿÿÀÿÿÿÿÀ( @ç*Cç±ççƒÿÿðÿÿðÿÿðÿÿöÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿø/ÿÿüÿÿøÿÿðÿÿøÿÿøÿÿü¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßÿÿÿÿÿøÿÿðÿÿàÿÿð( ç*Cç±ççƒ3333"D" D" Dðøø?úÿÿÿ¿þŸø?üüü?ÿÿÿÿ?üøølibimager-perl-1.004+dfsg.orig/ICO/testimg/rgba3232.ppm0000644000175000017500000000603612031434614021615 0ustar gregoagregoaP6 #CREATOR: Imager 32 32 255 ( ) ( ) ( ( ) ( ) ) ) *.37;AHPX _gn v "}'„,‹2’J™fŸ€¦!›¬% ( ( ( ) ) ( ) ) ) +048<DLS Zbi q w $)†.Ž9”U›p¡‹©#¤®&¾´*Ö». ) ) ( ( ( ( )-269?GNV ]dl s !z%*‰0C—^y£ ”ª$­°(Æ·+à½/ì¸0í«. ( ) ) ) */27;BIQ Y _gn v #}'…-Œ2“L™g ƒ¦"­%·²)й-é¿1í³0í¥.î—,ïŠ+ ) ) ,059<DLT [bj q x %€)‡.Ž;•V›q¢©#¦®&¿µ+Ø».ì¼0ì®/î .ï“+ï„*ðw)ñi'-16:?GOW ]el t !{&‚+‰1‘E˜`ž{¥!–«$¯±(É·+â½/í·1í©.î›-ïŽ+ï€)ðr(ñe&òW%òI#7<BJQ Yaho w #}(…-Œ4“Oši …§"Ÿ­&¹³*ѹ-ëÀ1ì²/í¥.î—,ï‰+ï{)ñm'ñ_&òR$óD#ð>#ì?$EMT \ck r y %*ˆ/Ž>•Xt¢Ž©$¨¯'Á¶+Ú¼/ì»1í­/íŸ-î’+ð„*ðv(ñh'ò[%óM$ô@!ï>#ê?$ä@%ßA'W ^fm u !|&ƒ,Š0‘G—bž}¥!˜¬%±±)ʸ,ä½0ì¶0í¨.îš-ï+ï~*ðr(ñc&òU$òH#ò="í?#è?%ãA&ÞA'ØB(ÔD*ip w #)†-5”Qšl¡‡§"¡®&»³)Ôº.ì¿1ì±/í¤-ï•,ï‡+ïz)ñl(ñ_&òQ$óC"ñ="ë?$ç@%áA&ÜB(×C)ÑD*ÌD+ÇF, z %€*ˆ/?–[œv¤‘©$ª°'ö+ݼ/ì¹1í¬/íŸ-ï‘+ï‚*ðu(ñh'ñZ%óL#ô>"ï>#é?$ä@%àA'ÚA(ÕC)ÐD*ËE,ÅF-ÁF/·H1,‹1‘I˜eŸ¥"š¬%´²(̸-æ¾0íµ0í§.î™,ïŒ+ï~)ðp(ñb&òU$óG"ò="í?$ç?$âA&ÝB'ØB(ÓD*ÎD+ÉE,ÄF.¾G/²J1¤L5–O8Ršn¢‰¨#¢®&½´*Öº.ì½1í°/í¢.î•,ï‡+ðy)ðk'ò]%òP$óB#ð>#ë?$æ@%á@&ÜB(ÖB)ÑC*ÌD,ÇE-ÂG.¼H/­J3ŸM6‘P:‡QC…QX’ª$¬°'Ŷ+ß¼0ì¹0í«/íž-î,ï*ðt(ñg'ñX%òK#ó="î?#é?$ä@%ßA&ÙB(ÕC)ÏD+ÊE+ÅF-ÀG/¶I0¨L4šN8ŒP;†QJ„P_ƒPt‚OˆÏ¹-è¿0ì´0í¦.î˜,ïŠ+ð|)ðo(ña&òT$óF#ñ="ì>#ç?$âA&ÜA'ØB(ÓC*ÍD+ÉE,ÃF.¾G/²J2£L6•O9‡R=†QQ„PfƒP{O€N£~M¸í¯/í¡.î”+ï†*ðx(ñj'ò]%òO$ôA"ð="ê?$å@%á@&ÜB'ÕC)ÑC*ÌE+ÇF-ÂG.ºG0¬J4žN7P:‡QD†PYƒPm‚P‚€O–N«}MÀ|MÕzLèïŽ+ï*ðs(òe'òW%òI#ò=!î>#è?%äA&ßA&ÙB(ÔC)ÏD+ÊE,ÅF-ÀG/µH1§L5™O7‹Q<†PL„Q`ƒPu‚O‰€Ož~M³|MÇ|LÜzKðyNÿ|Xÿðn(ñ`%òR$óE#ñ="ì?$ç@%âA&ÝB'ØB(ÒC*ÍE+ÈE,ÃF.¾G.°J2¢L5“O9‡Q>…QS„Ph‚O|€N‘N¥}Nº|LÏ{LãyL÷{Qþ}\þeýpüòM#ó@"ï>#ê?$å@%àA&ÛB(ÕC)ÑC+ËE+ÇF-ÁF/¹H0«K3œN7P:‡QF…Q[ƒPo‚O„O˜N¬}MÁ|MÕzLêyLÿ{Uÿ}_þ€iý‚rý„}ü‡‡üî>#è?$ã@&ÞA'ÙB(ÔC)ÎD*ÉE,ÄF-¿G.´I2¦L5˜N8ŠQ;†QM„Pb‚PwO‹NŸ~N´}MÉ{MÝyLòyOÿ|Xþ~cýmýƒvü…€üˆ‹ûŠ”úžúá@&ÜA(×B(ÒD*ÍE,ÇF,ÃG.½H/¯J2 L5“O9‡Q@†QT„Pi‚O~O’€N§}M¼|MÐzLäyLùzSÿ}]þgþ‚pýƒzü‡„û‰Žû‹˜úŽ¢ú‘²ø–ÆøÕC)ÐD*ÊE,ÆF-ÁG/¸H0ªK3œN7ŽP;†QH…Q\ƒPq‚O…NšN¯}MÃ{L×zLìyLÿ{Vþ~`þ€jý‚tý…~ü‡‡û‰‘ûŒœûŽ¥ú“¹ù˜Ì÷œàö¢ôõÉF,ÄF.¾G.³J2¤L5—O8ˆQ;†QO„QcƒOyOŒ€N¡~N¶|MÊ{LßzLôzOþ|Yþ~dþnýƒwü†üˆ‹ûŠ•úŸú­ù•ÀøšÔöŸèö£üôûà”öƼG/®J3 L6’P9†QB…QV„Pk‚O€N”N©}N½|MÒ{MæyKûzSþ}^þ€gþ‚qý„{ý‡…û‰Žû‹™ûŽ¢ú’´ø—Ç÷œÛ÷ ïõ£þñšúבô¾‰ð¤xçušN8P;‡QI…P]„PrO†€N›~N¯}MÄ{MÙzLíyMÿ{Vÿ~aþ€kýƒuý…~ü‡‰û‰’ûŒú¦ú”ºø˜Î÷âö¢öôŸüç—øÎŽóµ…í˜qãahÜFhÖA†PP„Pe‚PzOŽN£~N·}MÌ{MázLõzQÿ|Zþdýnýƒxý…‚ûˆŒû‹•ú ú®ù•ÂøšÕ÷Ÿéö¤ýõœûÞ”öÄ‹ñ«}ê…jßMhÚDgÓ?fË9eÂ2‚ON•Nª}M¾|MÓzMèyLüzTÿ}^þhý‚rý„{ü‡†û‰û‹šû£ú’µø—ÈøœÝö¡ðõ¢þîšùÕô¼ˆï¢væphÞFgØCfÑ=fÈ6d¾0cµ(a« N±}MÆ{LÛyLïyMÿ{Wþ~bþ€kýƒuý…ü‡‰üŠ“ûŒú¨ù”¼ø™Ð÷ãö¢÷õŸýå—øËŽò²‚ì”pâ]hÜFgÕAgÎ:eÅ4d¼-c±&a¦`›_ zMâzK÷yQþ|[þ~eýoýƒyü†ƒü‰û‹–û¡ú‘°ù•Ãø›×÷Ÿêõ¤ÿõœûÜ“öÊñ©|é€iÞIhÙDgÓ?fÊ9dÂ2d¸*b®"a¢_—^‹ ]]{Uÿ}_þ€hý‚rý…|ý‡†ü‰úŒšû¤ù“¶ø˜ÊøœÞ÷¡ñõ¡þí™ùÓóº‡ï uålhÝGg×BgÐ$@I R^^mv${"‚.‹#.‹Xœx¤‹¨%¥®(º´*Ö»/ì¼.í¬.ë /í‹-ï‡+ïo)òe&ò^$óQ õ9#êA&êA&ß@'áA" [Y g q q ${.‹.“I˜d x¤ž­%°±#͸*è¿.ì±0í¦*íœ-í‹-ð‚)ïo)òe&óX"êA&õ9#òH%êA&ç>$ß@'ÖA*ÑC( g q ${${+‰.‹=–Xœl !‹¨%ž­%º´*͸*è¿.ì±0ë /ï—+ï‡+ð|&ïo)ò^$óQ òH%ôB$òH%ç>$ß@'ß@'ÖA*ÑC(ÏB-ÉE+${${.‹( I˜Xœl !©©° Ķ$ß½)ì±0í¬.ë /ï’(ð‚)ïo)òe&óX"òH%ôB$ôB$ç>$ß@'ß@'ÖA*ÖA*ÑC(ÉE+ÄG*ÂF/µH0.‹.“I˜ax¤•« º´*͸*è¿.ì±0í¦*íœ-í‹-ð|&ïo)òe&óX"òH%ôB$êA&ç>$ß@'ß@'ØB%ÑC(ÑC(ÉE+ÂF/ºG2°J.¢L5—N7Xœl !‹¨%¥®(º´*Ö»/ì¼.í¬.ë /ï—+ï‡+ñv$ñj(ò^$óQ êA&ôB$êA&ç>$ß@'ÖA*ÖA*ÏB-ÉE+ÉE+ÂF/½H-®I3¢L5O;‰PD„RY‹¨%¥®(͸*ß½)í·*í¦*ë /í‹-ï‡+ïo)òe&ò^$óQ õ9#êA&êA&ß@'ç>$ÖA*ÑC(ÑC(ÉE+ÉE+ÂF/µH0ªL2—N7‹Q:†QN†O^„OtPŠÍ¸*è¿.ì±0í¦*íœ-ï‡+ð|&ïo)òe&óX"òH%õ9#êA&êA&ç>$ÖA*ÖA*ÑC(ÑC(ÉE+ÂF/½H-®I3¢L5O;ŠP?†QN…Pc‚PyPŠ€N¢~Mºí¬.ë /ï—+ï‡+ñv$ñj(ò^$òH%ôB$õ9#êA&ß@'ß@'ß@'ÑC(ÖA*ÉE+ÉE+½H-ºG2®I3œM9O;„RCˆOY‚QnƒN„€O–N®zNÀ|LÛ~Jâí‹-ð‚)ïo)òe&óX"òH%ôB$êA&êA&ç>$ß@'ÖA*ÑC(ÏB-ÉE+ÄG*½H-µH0§K7—N7‹Q:‡QI…Pc„OtPŠƒMœ|O´|MÇ~Jâ{KïxLþyYÿïo)ò^$ò^$òH%ôB$êA&êA&êA&ÖA*ÖA*ÖA*ÑC(ÉE+ÄG*½H-µH0œM9—N7†R>…QS„Qi€P~ƒM€N¢~MºzMÔyLèuSÿ~Tþ}_ÿxdÿpÿòH%õ9#õ9#ç>$ç>$ß@'ÖA*ØB%ÏB-ÉE+ÄG*ÂF/µH0ªL2œM9’P7‡QI„RY‚QnƒN„€O–}O§|MÇzMÔyLè{Oÿ~Tþ}_ÿ|jÿ„uýƒþ†…üôB$êA&ß@'ß@'ÖA*ÑC(ÑC(ÉE+ÄG*½H-µH0¢L5œM9‹Q:†QN…Pc‚PyƒM€N¢L´~LÎ|LÛ{KïuSÿyYÿxdÿ†ký„uý†…üŠŠûˆ”üŽ úß@'ÖA*ÖA*ÑC(ÉE+ÄG*ÂF/½H-®I3¢L5—N7„RC…QS„Qi…NƒM€N¢~MºzMÔ|LÛxLþuSÿ‚Zýeýpÿzÿ†…üŠŠû‹šú¥ø–±ö’ÇúÖA*ÖA*ÉE+ÂF/ÂF/ºG2ªL2œM9O;†QN„RY„OtPŠ€O–|O´zNÀ|LÛ{Kï{OÿuSÿ}_ÿ|jÿ„uýƒþŠŠûˆ”üŽ ú‰¤ý’¶ù™Èö›àö¡ôôÄG*ÉE+ÂF/µH0¢L5—N7‹Q:†QN…Pc€P~PŠ€N¢~Mº|MÇ~JâuMöuSÿyYÿeýpÿ‡{ûƒþŠŠûˆ”üŽ ú”¬ø—Â÷Ôôæöžÿ÷ üà”÷ÆÂF/®I3N4O;„RC„RY‚QnƒN„€O–‚L§zNÀzMÔyLè{Oÿ~Tþ}_ÿeýpÿzÿ†…üŠŠû‹šú¥ø–±ö™Èö™Úø íõ¤ûôœùЗõ¿‹ð¦yçt—N7O;‡QI†O^„OtƒN„€O–N®|MÇ|LÛ~Jâ{Oÿ~Tþxdÿ†ký„uýƒþŠŠûˆ”ü†žý‰¤ý”»ø—Óø›àö¡ôô üà”÷Æó¶„ïqãadÙ@iÔ<…QS„Qi‚PyPŠ€N¢|O´zMÔ|LÛ{KïuSÿyYÿxdÿpÿ„uý†…üŠŠû‹šúŽ ú”¬ø—Â÷Ôôæö¤ûô üà—õ¿‰ò®é„hàNdÙ@dÏ7hÊ3^Ã4€P~€O–N®zNÀzMÔyLè{OÿuSÿ‚Zý†ký„uýzÿŠŠû…þ‹šúŽ ú’¶ù™Èö›àö íõ¢þðœùÐô½€ð¤yçthÝChàNdÏ7^Ã4fÁ3e·+b¬|O´|MÇ|LÛ{KïxLþyYÿ}_ÿ†ký„uýƒþ†…üˆ”ü‹šú”¬ø”»ø—Óøæöœø÷›ýç”÷Æ’ò®…ì•râYdÙ@iÔregister_reader ( type=>'ico', single => sub { my ($im, $io, %hsh) = @_; my $masked = exists $hsh{ico_masked} ? $hsh{ico_masked} : 1; my $alpha_masked = exists $hsh{ico_alpha_masked} ? $hsh{ico_alpha_masked} : 0; $im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked, $alpha_masked); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, multiple => sub { my ($io, %hsh) = @_; my $masked = exists $hsh{ico_masked} ? $hsh{ico_masked} : 1; my @imgs = i_readico_multi($io, $masked); unless (@imgs) { Imager->_set_error(Imager->_error_as_msg); return; } return map { bless { IMG => $_, DEBUG => $Imager::DEBUG, ERRSTR => undef }, 'Imager' } @imgs; }, ); # the readers can read CUR files too Imager->register_reader ( type=>'cur', single => sub { my ($im, $io, %hsh) = @_; my $masked = exists $hsh{ico_masked} ? $hsh{ico_masked} : 1; my $alpha_masked = exists $hsh{ico_alpha_masked} ? $hsh{ico_alpha_masked} : 0; $im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked, $alpha_masked); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, multiple => sub { my ($io, %hsh) = @_; my $masked = exists $hsh{ico_masked} ? $hsh{ico_masked} : 1; my @imgs = i_readico_multi($io, $masked); unless (@imgs) { Imager->_set_error(Imager->_error_as_msg); return; } return map { bless { IMG => $_, DEBUG => $Imager::DEBUG, ERRSTR => undef }, 'Imager' } @imgs; }, ); Imager->register_writer ( type=>'ico', single => sub { my ($im, $io, %hsh) = @_; unless (i_writeico_wiol($io, $im->{IMG})) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, multiple => sub { my ($class, $io, $opts, @images) = @_; if (!i_writeico_multi_wiol($io, map $_->{IMG}, @images)) { Imager->_set_error(Imager->_error_as_msg); return; } return 1; }, ); Imager->register_writer ( type=>'cur', single => sub { my ($im, $io, %hsh) = @_; unless (i_writecur_wiol($io, $im->{IMG})) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, multiple => sub { my ($class, $io, $opts, @images) = @_; if (!i_writecur_multi_wiol($io, map $_->{IMG}, @images)) { Imager->_set_error(Imager->_error_as_msg); return; } return 1; }, ); 1; __END__ =head1 NAME Imager::File::ICO - read MS Icon files =head1 SYNOPSIS use Imager; my $img = Imager->new; $img->read(file=>"foo.ico") or die $img->errstr; my @imgs = Imager->read_multi(file => "foo.ico") or die Imager->errstr; $img->write(file => "foo.ico") or die $img->errstr; Imager->write_multi({ file => "foo.ico" }, @imgs) or die Imager->errstr; =head1 DESCRIPTION Imager's MS Icon support is documented in L. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Files. =cut libimager-perl-1.004+dfsg.orig/ICO/t/0000755000175000017500000000000012617614576016455 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/ICO/t/t71icomult.t0000644000175000017500000000054312263740577020652 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; use Imager::Test qw(test_image); -d "testout" or mkdir "testout"; # checks that we load the ICO write handler automatically my $img = test_image(); ok(Imager->write_multi({ file => 'testout/icomult.ico' }, $img, $img), "write_multi ico with autoload") or print "# ",Imager->errstr,"\n"; libimager-perl-1.004+dfsg.orig/ICO/t/t60writefail.t0000644000175000017500000002172512263740577021167 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 69; use Imager ':handy'; # this file tries to cover as much of the write error handling cases in # msicon.c/imicon.c as possible. # # coverage checked with gcc/gcov # image too big for format tests, for each entry point { my $im = Imager->new(xsize => 257, ysize => 256); my $data; ok(!$im->write(data => \$data, type=>'ico'), "image too large"); is($im->errstr, "image too large for ico file", "check message"); } { my $im = Imager->new(xsize => 257, ysize => 256); my $data; ok(!Imager->write_multi({ data => \$data, type=>'ico' }, $im, $im), "image too large"); is(Imager->errstr, "image too large for ico file", "check message"); Imager->_set_error(''); } { my $im = Imager->new(xsize => 257, ysize => 256); my $data; ok(!$im->write(data => \$data, type=>'cur'), "image too large"); is($im->errstr, "image too large for ico file", "check message"); } { my $im = Imager->new(xsize => 257, ysize => 256); my $data; ok(!Imager->write_multi({ data => \$data, type=>'cur' }, $im), "image too large"); is(Imager->errstr, "image too large for ico file", "check message"); Imager->_set_error(''); } # low level write failure tests for each entry point (fail on close) { my $im = Imager->new(xsize => 10, ysize => 10); ok(!$im->write(callback => \&write_failure, type=>'ico'), "low level write failure (ico)"); is($im->errstr, "error closing output: synthetic error", "check message"); } { my $im = Imager->new(xsize => 10, ysize => 10); ok(!$im->write(callback => \&write_failure, type=>'cur'), "low level write failure (cur)"); is($im->errstr, "error closing output: synthetic error", "check message"); } { my $im = Imager->new(xsize => 10, ysize => 10); ok(!Imager->write_multi({ callback => \&write_failure, type=>'ico' }, $im, $im), "low level write_multi failure (ico)"); is(Imager->errstr, "error closing output: synthetic error", "check message"); Imager->_set_error(''); } { my $im = Imager->new(xsize => 10, ysize => 10); ok(!Imager->write_multi({ callback => \&write_failure, type=>'cur' }, $im, $im), "low level write_multi failure (cur)"); is(Imager->errstr, "error closing output: synthetic error", "check message"); Imager->_set_error(''); } # low level write failure tests for each entry point (fail on write) { my $im = Imager->new(xsize => 10, ysize => 10); my $io = Imager::io_new_cb(\&write_failure, undef, undef, undef, 1); $io->set_buffered(0); ok(!$im->write(io => $io, type=>'ico'), "low level write failure (ico)"); is($im->errstr, "Write failure: synthetic error", "check message"); } { my $im = Imager->new(xsize => 10, ysize => 10); my $io = Imager::io_new_cb(\&write_failure, undef, undef, undef, 1); $io->set_buffered(0); ok(!$im->write(io => $io, type=>'cur'), "low level write failure (cur)"); is($im->errstr, "Write failure: synthetic error", "check message"); } { my $im = Imager->new(xsize => 10, ysize => 10); my $io = Imager::io_new_cb(\&write_failure, undef, undef, undef, 1); $io->set_buffered(0); ok(!Imager->write_multi({ io => $io, type=>'ico' }, $im, $im), "low level write_multi failure (ico)"); is(Imager->errstr, "Write failure: synthetic error", "check message"); Imager->_set_error(''); } { my $im = Imager->new(xsize => 10, ysize => 10); my $io = Imager::io_new_cb(\&write_failure, undef, undef, undef, 1); $io->set_buffered(0); ok(!Imager->write_multi({ io => $io, type=>'cur' }, $im, $im), "low level write_multi failure (cur)"); is(Imager->errstr, "Write failure: synthetic error", "check message"); Imager->_set_error(''); } { my $im = Imager->new(xsize => 10, ysize => 10); ok(!$im->write(type => 'ico', io => limited_write_io(6)), "second write (resource) should fail (ico)"); is($im->errstr, "Write failure: limit reached", "check message"); $im->_set_error(''); ok(!$im->write(type => 'cur', io => limited_write_io(6)), "second (resource) write should fail (cur)"); is($im->errstr, "Write failure: limit reached", "check message"); $im->_set_error(''); ok(!$im->write(type => 'ico', io => limited_write_io(22)), "third write (bmi) should fail (32-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); $im->_set_error(''); ok(!$im->write(type => 'ico', io => limited_write_io(62)), "fourth write (data) should fail (32-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); $im->_set_error(''); ok(!$im->write(type => 'ico', io => limited_write_io(462)), "mask write should fail (32-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); } { # 1 bit write fails my $im = Imager->new(xsize => 10, ysize => 10, type => 'paletted'); my $red = NC(255, 0, 0); my $blue = NC(0, 0, 255); $im->addcolors(colors => [ $red, $blue ]); $im->box(filled => 1, color => $red, ymax => 5); $im->box(filled => 1, color => $blue, ymin => 6); ok(!$im->write(type => 'ico', io => limited_write_io(22)), "third write (bmi) should fail (1-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); ok(!$im->write(type => 'ico', io => limited_write_io(66)), "fourth write (palette) should fail (1-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); ok(!$im->write(type => 'ico', io => limited_write_io(74)), "fifth write (image) should fail (1-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); my $data; ok($im->write(data => \$data, type => 'ico'), "write 1 bit successfully"); my $read = Imager->new; ok($read->read(data => $data), "read it back"); is($read->type, 'paletted', "check type"); is($read->tags(name => 'ico_bits'), 1, "check bits"); is(Imager::i_img_diff($read, $im), 0, "check image correct"); } { # 4 bit write fails my $im = Imager->new(xsize => 10, ysize => 10, type => 'paletted'); my $red = NC(255, 0, 0); my $blue = NC(0, 0, 255); $im->addcolors(colors => [ ($red, $blue) x 8 ]); $im->box(filled => 1, color => $red, ymax => 5); $im->box(filled => 1, color => $blue, ymin => 6); ok(!$im->write(type => 'ico', io => limited_write_io(22)), "third write (bmi) should fail (4-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); ok(!$im->write(type => 'ico', io => limited_write_io(66)), "fourth write (palette) should fail (4-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); ok(!$im->write(type => 'ico', io => limited_write_io(130)), "fifth write (image) should fail (4-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); my $data; ok($im->write(data => \$data, type => 'ico'), "write 4 bit successfully"); my $read = Imager->new; ok($read->read(data => $data), "read it back"); is($read->type, 'paletted', "check type"); is($read->tags(name => 'ico_bits'), 4, "check bits"); is(Imager::i_img_diff($read, $im), 0, "check image correct"); } { # 8 bit write fails my $im = Imager->new(xsize => 10, ysize => 10, type => 'paletted'); my $red = NC(255, 0, 0); my $blue = NC(0, 0, 255); $im->addcolors(colors => [ ($red, $blue) x 9 ]); $im->box(filled => 1, color => $red, ymax => 5); $im->box(filled => 1, color => $blue, ymin => 6); ok(!$im->write(type => 'ico', io => limited_write_io(22)), "third write (bmi) should fail (8-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); ok(!$im->write(type => 'ico', io => limited_write_io(62)), "fourth write (palette) should fail (8-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); ok(!$im->write(type => 'ico', io => limited_write_io(62 + 1024)), "fifth write (image) should fail (8-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); ok(!$im->write(type => 'ico', io => limited_write_io(62 + 1024 + 10)), "sixth write (zeroes) should fail (8-bit)"); is($im->errstr, "Write failure: limit reached", "check message"); my $data; ok($im->write(data => \$data, type => 'ico'), "write 8 bit successfully"); my $read = Imager->new; ok($read->read(data => $data), "read it back"); is($read->type, 'paletted', "check type"); is($read->tags(name => 'ico_bits'), 8, "check bits"); is(Imager::i_img_diff($read, $im), 0, "check image correct"); } # write callback that fails sub write_failure { print "# synthesized write failure\n"; Imager::i_push_error(0, "synthetic error"); return; } sub limited_write_io { my ($limit) = @_; my $io = Imager::io_new_cb(limited_write($limit), undef, undef, undef, 1); $io->set_buffered(0); return $io; } sub limited_write { my ($limit) = @_; return sub { my ($data) = @_; $limit -= length $data; if ($limit >= 0) { print "# write of ", length $data, " bytes successful ($limit left)\n"; return 1; } else { print "# write of ", length $data, " bytes failed\n"; Imager::i_push_error(0, "limit reached"); return; } }; } libimager-perl-1.004+dfsg.orig/ICO/t/t73curmult.t0000644000175000017500000000054312263740600020656 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; use Imager::Test qw(test_image); -d "testout" or mkdir "testout"; # checks that we load the CUR write handler automatically my $img = test_image(); ok(Imager->write_multi({ file => 'testout/icomult.cur' }, $img, $img), "write_multi cur with autoload") or print "# ",Imager->errstr,"\n"; libimager-perl-1.004+dfsg.orig/ICO/t/t72cursing.t0000644000175000017500000000050312263740577020645 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; use Imager::Test qw(test_image); -d "testout" or mkdir "testout"; # checks that we load the CUR write handler automatically my $img = test_image(); ok($img->write(file => 'testout/cursing.cur'), "write cur with autoload") or print "# ",$img->errstr,"\n"; libimager-perl-1.004+dfsg.orig/ICO/t/t10icon.t0000644000175000017500000003732712460670607020124 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 111; use Imager::Test qw(is_image isnt_image test_image); BEGIN { use_ok('Imager::File::ICO'); } -d 'testout' or mkdir 'testout', 0777; my $im = Imager->new; # type=>'ico' or 'cur' and read ico and cur since they're pretty much # the same ok($im->read(file => "testimg/rgba3232.ico", type=>"ico", ico_masked => 0), "read 32 bit") or print "# ", $im->errstr, "\n"; is($im->getwidth, 32, "check width"); is($im->getwidth, 32, "check height"); is($im->type, 'direct', "check type"); is($im->tags(name => 'ico_bits'), 32, "check ico_bits tag"); is($im->tags(name => 'i_format'), 'ico', "check i_format tag"); my $mask = '.* ..........................****** ..........................****** ..........................****** ..........................****** ...........................***** ............................**** ............................**** .............................*** .............................*** .............................*** .............................*** ..............................** ..............................** ...............................* ...............................* ................................ ................................ ................................ ................................ ................................ ................................ *............................... **.............................. **.............................. ***............................. ***............................. ****............................ ****............................ *****........................... *****........................... *****........................... *****...........................'; is($im->tags(name => 'ico_mask'), $mask, "check ico_mask_tag"); # compare the pixels # ppm can't store 4 channels SKIP: { my $work = $im->convert(preset=>'noalpha'); my $comp = Imager->new; $comp->read(file => "testimg/rgba3232.ppm") or skip "could not read 24-bit comparison file:". $comp->errstr, 1; is(Imager::i_img_diff($comp->{IMG}, $work->{IMG}), 0, "compare image data"); } ok($im->read(file => 'testimg/pal83232.ico', type=>'ico', ico_masked => 0), "read 8 bit") or print "# ", $im->errstr, "\n"; is($im->getwidth, 32, "check width"); is($im->getwidth, 32, "check height"); is($im->type, 'paletted', "check type"); is($im->colorcount, 256, "color count"); is($im->tags(name => 'ico_bits'), 8, "check ico_bits tag"); is($im->tags(name => 'i_format'), 'ico', "check i_format tag"); SKIP: { my $comp = Imager->new; $comp->read(file => "testimg/pal83232.ppm") or skip "could not read 8-bit comparison file:". $comp->errstr, 1; is(Imager::i_img_diff($comp->{IMG}, $im->{IMG}), 0, "compare image data"); } $im->write(file=>'testout/pal83232.ppm'); ok($im->read(file => 'testimg/pal43232.ico', type=>'ico', ico_masked => 0), "read 4 bit") or print "# ", $im->errstr, "\n"; is($im->getwidth, 32, "check width"); is($im->getwidth, 32, "check height"); is($im->type, 'paletted', "check type"); is($im->colorcount, 16, "color count"); is($im->tags(name => 'ico_bits'), 4, "check ico_bits tag"); is($im->tags(name => 'i_format'), 'ico', "check i_format tag"); SKIP: { my $comp = Imager->new; $comp->read(file => "testimg/pal43232.ppm") or skip "could not read 4-bit comparison file:". $comp->errstr, 1; is(Imager::i_img_diff($comp->{IMG}, $im->{IMG}), 0, "compare image data"); } $im->write(file=>'testout/pal43232.ppm'); ok($im->read(file => 'testimg/pal13232.ico', type=>'ico', ico_masked => 0), "read 1 bit") or print "# ", $im->errstr, "\n"; is($im->getwidth, 32, "check width"); is($im->getwidth, 32, "check height"); is($im->type, 'paletted', "check type"); is($im->colorcount, 2, "color count"); is($im->tags(name => 'cur_bits'), 1, "check ico_bits tag"); is($im->tags(name => 'i_format'), 'cur', "check i_format tag"); $im->write(file=>'testout/pal13232.ppm'); # combo was created with the GIMP, which has a decent mechanism for selecting # the output format # you get different size icon images by making different size layers. my @imgs = Imager->read_multi(file => 'testimg/combo.ico', type=>'ico', ico_masked => 0); is(scalar(@imgs), 3, "read multiple"); is($imgs[0]->getwidth, 48, "image 0 width"); is($imgs[0]->getheight, 48, "image 0 height"); is($imgs[1]->getwidth, 32, "image 1 width"); is($imgs[1]->getheight, 32, "image 1 height"); is($imgs[2]->getwidth, 16, "image 2 width"); is($imgs[2]->getheight, 16, "image 2 height"); is($imgs[0]->type, 'direct', "image 0 type"); is($imgs[1]->type, 'paletted', "image 1 type"); is($imgs[2]->type, 'paletted', "image 2 type"); is($imgs[1]->colorcount, 256, "image 1 colorcount"); is($imgs[2]->colorcount, 16, "image 2 colorcount"); is_deeply([ $imgs[0]->getpixel(x=>0, 'y'=>0)->rgba ], [ 231, 17, 67, 255 ], "check image data 0(0,0)"); is_deeply([ $imgs[1]->getpixel(x=>0, 'y'=>0)->rgba ], [ 231, 17, 67, 255 ], "check image data 1(0,0)"); is_deeply([ $imgs[2]->getpixel(x=>0, 'y'=>0)->rgba ], [ 231, 17, 67, 255 ], "check image data 2(0,0)"); is_deeply([ $imgs[0]->getpixel(x=>47, 'y'=>0)->rgba ], [ 131, 231, 17, 255 ], "check image data 0(47,0)"); is_deeply([ $imgs[1]->getpixel(x=>31, 'y'=>0)->rgba ], [ 131, 231, 17, 255 ], "check image data 1(31,0)"); is_deeply([ $imgs[2]->getpixel(x=>15, 'y'=>0)->rgba ], [ 131, 231, 17, 255 ], "check image data 2(15,0)"); is_deeply([ $imgs[0]->getpixel(x=>0, 'y'=>47)->rgba ], [ 17, 42, 231, 255 ], "check image data 0(0,47)"); is_deeply([ $imgs[1]->getpixel(x=>0, 'y'=>31)->rgba ], [ 17, 42, 231, 255 ], "check image data 1(0,31)"); is_deeply([ $imgs[2]->getpixel(x=>0, 'y'=>15)->rgba ], [ 17, 42, 231, 255 ], "check image data 2(0,15)"); is_deeply([ $imgs[0]->getpixel(x=>47, 'y'=>47)->rgba ], [ 17, 231, 177, 255 ], "check image data 0(47,47)"); is_deeply([ $imgs[1]->getpixel(x=>31, 'y'=>31)->rgba ], [ 17, 231, 177, 255 ], "check image data 1(31,31)"); is_deeply([ $imgs[2]->getpixel(x=>15, 'y'=>15)->rgba ], [ 17, 231, 177, 255 ], "check image data 2(15,15)"); $im = Imager->new(xsize=>32, ysize=>32); $im->box(filled=>1, color=>'FF0000'); $im->box(filled=>1, color=>'0000FF', xmin => 6, ymin=>0, xmax => 21, ymax=>15); $im->box(filled=>1, color=>'00FF00', xmin => 10, ymin=>16, xmax => 25, ymax=>31); ok($im->write(file=>'testout/t10_32.ico', type=>'ico'), "write 32-bit icon"); my $im2 = Imager->new; ok($im2->read(file=>'testout/t10_32.ico', type=>'ico', ico_masked => 0), "read it back in"); is(Imager::i_img_diff($im->{IMG}, $im2->{IMG}), 0, "check they're the same"); is($im->bits, $im2->bits, "check same bits"); { my $im = Imager->new(xsize => 32, ysize => 32); $im->box(filled=>1, color=>'#FF00FF'); my $data; ok(Imager->write_multi({ data => \$data, type=>'ico' }, $im, $im), "write multi icons"); ok(length $data, "and it wrote data"); my @im = Imager->read_multi(data => $data, ico_masked => 0); is(@im, 2, "got all the images back"); is(Imager::i_img_diff($im->{IMG}, $im[0]{IMG}), 0, "check first image"); is(Imager::i_img_diff($im->{IMG}, $im[1]{IMG}), 0, "check second image"); } { # 1 channel image my $im = Imager->new(xsize => 32, ysize => 32, channels => 1); $im->box(filled=>1, color => [ 128, 0, 0 ]); my $data; ok($im->write(data => \$data, type=>'ico'), "write 1 channel image"); my $im2 = Imager->new; ok($im2->read(data => $data, ico_masked => 0), "read it back"); is($im2->getchannels, 4, "check channels"); my $imrgb = $im->convert(preset => 'rgb') ->convert(preset => 'addalpha'); is(Imager::i_img_diff($imrgb->{IMG}, $im2->{IMG}), 0, "check image matches expected"); } { # 2 channel image my $base = Imager->new(xsize => 32, ysize => 32, channels => 2); $base->box(filled => 1, color => [ 64, 192, 0 ]); my $data; ok($base->write(data => \$data, type=>'ico'), "write 2 channel image"); my $read = Imager->new; ok($read->read(data => $data, ico_masked => 0), "read it back"); is($read->getchannels, 4, "check channels"); my $imrgb = $base->convert(preset => 'rgb'); is(Imager::i_img_diff($imrgb->{IMG}, $read->{IMG}), 0, "check image matches expected"); } { # 4 channel image my $base = Imager->new(xsize => 32, ysize => 32, channels => 4); $base->box(filled=>1, ymax => 15, color => [ 255, 0, 255, 128 ]); $base->box(filled=>1, ymin => 16, color => [ 0, 255, 255, 255 ]); my $data; ok($base->write(data => \$data, type=>'ico'), "write 4 channel image"); my $read = Imager->new; ok($read->read(data => $data, type=>'ico', ico_masked => 0), "read it back") or print "# ", $read->errstr, "\n"; is(Imager::i_img_diff($base->{IMG}, $read->{IMG}), 0, "check image matches expected"); } { # mask handling my $base = Imager->new(xsize => 16, ysize => 16, channels => 3); $base->box(filled=>1, xmin => 5, xmax => 10, color => '#0000FF'); $base->box(filled=>1, ymin => 5, ymax => 10, color => '#0000FF'); my $mask = <settag(name => 'ico_mask', value => $mask); my $saved_mask = $base->tags(name => 'ico_mask'); my $data; ok($base->write(data => \$data, type => 'ico'), "write with mask tag set"); my $read = Imager->new; ok($read->read(data => $data, ico_masked => 0), "read it back"); my $mask2 = $mask; $mask2 =~ tr/01/.*/; $mask2 =~ s/\n$//; $mask2 =~ tr/\r x//d; $mask2 =~ s/^(.{3,19})$/$1 . "." x (16 - length $1)/gem; my $read_mask = $read->tags(name => 'ico_mask'); is($read_mask, $mask2, "check mask is correct"); } { # mask too short to handle my $mask = "xx"; my $base = Imager->new(xsize => 16, ysize => 16, channels => 3); $base->box(filled=>1, xmin => 5, xmax => 10, color => '#0000FF'); $base->box(filled=>1, ymin => 5, ymax => 10, color => '#0000FF'); $base->settag(name => 'ico_mask', value => $mask); my $data; ok($base->write(data => \$data, type=>'ico'), "save icon with short mask tag"); my $read = Imager->new; ok($read->read(data => $data, ico_masked => 0), "read it back"); my $read_mask = $read->tags(name => 'ico_mask'); my $expected_mask = ".*" . ( "\n" . "." x 16 ) x 16; is($read_mask, $expected_mask, "check the mask"); # mask that doesn't match what we expect $base->settag(name => 'ico_mask', value => 'abcd'); ok($base->write(data => \$data, type => 'ico'), "write with bad format mask tag"); ok($read->read(data => $data, ico_masked => 0), "read it back"); $read_mask = $read->tags(name => 'ico_mask'); is($read_mask, $expected_mask, "check the mask"); # mask with invalid char $base->settag(name => 'ico_mask', value => ".*\n....xxx.."); ok($base->write(data => \$data, type => 'ico'), "write with unexpected chars in mask"); ok($read->read(data => $data, ico_masked => 0), "read it back"); $read_mask = $read->tags(name => 'ico_mask'); is($read_mask, $expected_mask, "check the mask"); } { # check handling of greyscale paletted my $base = Imager->new(xsize => 16, ysize => 16, channels => 1, type => 'paletted'); my @grays = map Imager::Color->new($_), "000000", "666666", "CCCCCC", "FFFFFF"; ok($base->addcolors(colors => \@grays), "add some colors"); $base->box(filled => 1, color => $grays[1], xmax => 7, ymax => 7); $base->box(filled => 1, color => $grays[1], xmax => 7, ymin => 8); $base->box(filled => 1, color => $grays[1], xmin => 8, ymax => 7); $base->box(filled => 1, color => $grays[1], xmin => 8, ymax => 8); my $data; ok($base->write(data => \$data, type => 'ico'), "write grayscale paletted"); my $read = Imager->new; ok($read->read(data => $data, ico_masked => 0), "read it back") or print "# ", $read->errstr, "\n"; is($read->type, 'paletted', "check type"); is($read->getchannels, 3, "check channels"); my $as_rgb = $base->convert(preset => 'rgb'); is(Imager::i_img_diff($base->{IMG}, $read->{IMG}), 0, "check the image"); } { # check default mask processing # # the query at http://www.cpanforum.com/threads/5958 made it fairly # obvious that the way Imager handled the mask in 0.59 was confusing # when compared with loading other images with some sort of # secondary alpha channel (eg. gif) # So from 0.60 the mask is applied as an alpha channel by default. # make sure that application works. # the strange mask checks the optimization paths of the mask application my $mask = <new(xsize => 4, ysize => 5, type => 'paletted'); $im->addcolors(colors => [ '#FF0000' ]); $im->box(filled => 1, color => '#FF0000'); $im->settag(name => 'ico_mask', value => $mask); my $imcopy = $im->convert(preset=>'addalpha'); my $red_alpha = Imager::Color->new(255, 0, 0, 0); $imcopy->setpixel( 'x' => [ qw/0 3 0 1 2 3 2/ ], 'y' => [ qw/0 0 1 1 2 2 4/ ], color => $red_alpha); my $data; ok($im->write(data => \$data, type => 'ico'), "save icon + mask"); my $im2 = Imager->new; ok($im2->read(data => $data), "read ico with defaults"); is($im2->type, 'direct', 'expect a direct image'); is_image($im2, $imcopy, 'check against expected'); } { # read 24-bit images my $im = Imager->new; ok($im->read(file => 'testimg/rgb1616.ico'), "read 24-bit data image") or print "# ", $im->errstr, "\n"; my $vs = Imager->new(xsize => 16, ysize => 16); $vs->box(filled => 1, color => '#333366'); is_image($im, $vs, "check we got the right colors"); } { # check close failures are handled correctly my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; ok(!$im->write(type => "ico", callback => sub { 1 }, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } { # RT #69599 { my $ico = Imager->new(file => "testimg/pal256.ico", filetype => "ico"); ok($ico, "read a 256x256 pixel wide/high icon") or diag "Could not read 256x256 pixel icon: ",Imager->errstr; } SKIP: { my $im = test_image(); my $sc = $im->scale(xpixels => 256, ypixels => 256, type => "nonprop") or diag("Cannot scale: " . $im->errstr); $sc or skip("Cannot produce scaled image", 3); my $alpha = $sc->convert(preset => "addalpha") or diag "Cannot add alpha channel: " . $sc->errstr ; my $data; ok($alpha->write(data => \$data, type => "ico"), "save 256x256 image") or diag("Cannot save 256x256 icon:" . $alpha->errstr); my $read = Imager->new(data => $data, filetype => "ico"); ok($read, "read 256x256 pixel image back in") or diag(Imager->errstr); $read or skip("Couldn't read to compare", 1); is_image($read, $alpha, "check we read what we wrote"); } } { # RT #99507 # we now ignore the mask by default when reading a 32-bit image my $im = Imager->new(xsize => 2, ysize => 2, channels => 4); $im->setpixel(x => 0, y => 0, color => "#FF0000"); $im->setpixel(x => 1, y => 1, color => "#00FF00"); my $mask = <write(data => \$data, type => "ico", ico_mask => $mask), "write with dodgy mask"); my $im2 = Imager->new(data => \$data, filetype => "ico"); ok($im2, "read it back"); is_image($im2, $im, "should match original, despite bad mask"); my $im3 = Imager->new(data => \$data, filetype => "ico", ico_alpha_masked => 1); ok($im3, "read it back with ico_alpha_masked => 1"); my $cmp = $im->copy; $cmp->setpixel(x => 0, y => 0, color => [ 255, 0, 0, 0 ]); isnt_image($im3, $cmp, "bad mask makes some pixels transparent"); } libimager-perl-1.004+dfsg.orig/ICO/t/t41curmultread.t0000644000175000017500000000047412031434614021506 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; # checks that we load the CUR handler automatically for multiple image reads my @im = Imager->read_multi(file=>'testimg/pal43232.cur'); is(scalar(@im), 1, "check that cursor reader loaded correctly for singles") or print "# ", Imager->errstr, "\n"; libimager-perl-1.004+dfsg.orig/ICO/t/t30cursor.t0000644000175000017500000000502312031434614020465 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 25; BEGIN { use_ok('Imager::File::CUR'); } -d 'testout' or mkdir 'testout', 0777; my $im = Imager->new; ok($im->read(file => 'testimg/pal43232.cur', type=>'cur'), "read 4 bit"); is($im->getwidth, 32, "check width"); is($im->getheight, 32, "check width"); is($im->type, 'paletted', "check type"); is($im->tags(name => 'cur_bits'), 4, "check cur_bits tag"); is($im->tags(name => 'i_format'), 'cur', "check i_format tag"); is($im->tags(name => 'cur_hotspotx'), 1, "check cur_hotspotx tag"); is($im->tags(name => 'cur_hotspoty'), 18, "check cur_hotspoty tag"); my $mask = ".*" . ("\n" . "." x 32) x 32; is($im->tags(name => 'cur_mask'), $mask, "check cur_mask tag"); # these should get pushed back into range on saving $im->settag(name => 'cur_hotspotx', value => 32); $im->settag(name => 'cur_hotspoty', value => -1); ok($im->write(file=>'testout/hotspot.cur', type=>'cur'), "save with oor hotspot") or print "# ",$im->errstr, "\n"; { my $im2 = Imager->new; ok($im2->read(file=>'testout/hotspot.cur', type=>'cur'), "re-read the hotspot set cursor") or print "# ", $im->errstr, "\n"; is($im2->tags(name => 'cur_hotspotx'), 31, "check cur_hotspotx tag"); is($im2->tags(name => 'cur_hotspoty'), 0, "check cur_hotspoty tag"); } $im->settag(name => 'cur_hotspotx', value => -1); $im->settag(name => 'cur_hotspoty', value => 32); ok($im->write(file=>'testout/hotspot2.cur', type=>'cur'), "save with oor hotspot") or print "# ",$im->errstr, "\n"; { my $im2 = Imager->new; ok($im2->read(file=>'testout/hotspot2.cur', type=>'cur'), "re-read the hotspot set cursor") or print "# ", $im->errstr, "\n"; is($im2->tags(name => 'cur_hotspotx'), 0, "check cur_hotspotx tag"); is($im2->tags(name => 'cur_hotspoty'), 31, "check cur_hotspoty tag"); } { my $data = ''; ok($im->write(data => \$data, type => 'cur'), "write single to data"); print "# ", length $data, " bytes written\n"; my $im2 = Imager->new; ok($im2->read(data => $data), "read back in"); is(Imager::i_img_diff($im->{IMG}, $im2->{IMG}), 0, "check image"); } { my $data = ''; ok(Imager->write_multi({ type => 'cur', data => \$data }, $im, $im), "write multiple images"); print "# ", length $data, " bytes written\n"; my @im = Imager->read_multi(type => 'cur', data => $data) or print "# ", Imager->errstr, "\n"; is(@im, 2, "read them back in"); is(Imager::i_img_diff($im->{IMG}, $im[0]{IMG}), 0, "check first image"); is(Imager::i_img_diff($im->{IMG}, $im[1]{IMG}), 0, "check second image"); } libimager-perl-1.004+dfsg.orig/ICO/t/t21readmult.t0000644000175000017500000000043412031434614020766 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; # checks that we load the ICO handler automatically my @imgs = Imager->read_multi(file => 'testimg/combo.ico') or print "# ",Imager->errstr,"\n"; is(@imgs, 3, "check that icon reader loaded correctly for multiples"); libimager-perl-1.004+dfsg.orig/ICO/t/t50readfail.t0000644000175000017500000002342312031434614020725 0ustar gregoagregoa#!perl -w use strict; use Imager; use Test::More tests => 40; sub get_data; { # test file limits are obeyed (paletted) Imager->set_file_limits(reset => 1, width => 10); my $im = Imager->new; ok(!$im->read(file => 'testimg/pal13232.ico'), "can't read overwide image"); like($im->errstr, qr/image width/, "check message"); } { # test file limits are obeyed (direct) Imager->set_file_limits(reset => 1, width => 10); my $im = Imager->new; ok(!$im->read(file => 'testimg/rgba3232.ico'), "can't read overwide image"); like($im->errstr, qr/image width/, "check message"); } Imager->set_file_limits(reset => 1); { # file too short for magic my $im = Imager->new; ok(!$im->read(data=>"XXXX", type=>'ico'), "Can't read short image file"); is($im->errstr, "error opening ICO/CUR file: Short read", "check error message"); } { # read non-icon my $im = Imager->new; ok(!$im->read(file=>'t/t50readfail.t', type=>'ico'), "script isn't an icon"); is($im->errstr, "error opening ICO/CUR file: Not an icon file", "check message"); } { # file with not enough icon structures my $im = Imager->new; my $data = pack "H*", "00000100010000"; ok(!$im->read(data => $data, type=>'ico'), "ico file broken at resource entries"); is($im->errstr, "error opening ICO/CUR file: Short read", "check error message"); } { my $im = Imager->new; my $data = pack "H*", "00000200010000"; ok(!$im->read(data => $data, type=>'cur'), "cursor file broken at resource entries"); is($im->errstr, "error opening ICO/CUR file: Short read", "check error message"); } { # read negative index image my $im = Imager->new; ok(!$im->read(file=>'testimg/pal13232.ico', type=>'ico', page=>-1), "read page -1"); is($im->errstr, "error reading ICO/CUR image: Image index out of range", "check error message"); } { # read too high image index my $im = Imager->new; ok(!$im->read(file=>'testimg/pal13232.ico', type=>'ico', page=>1), "read page 1"); is($im->errstr, "error reading ICO/CUR image: Image index out of range", "check error message"); } { # image offset beyond end of file my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with bad offset"); # bad offset causes the seek to fail on an in-memory "file" # it may not fail this way on a real file. is($im->errstr, "error reading ICO/CUR image: I/O error", "check error message"); } { # short read on bmiheader my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with a short bitmap header"); is($im->errstr, "error reading ICO/CUR image: Short read", "check error message"); } { # invalid bmiheader my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with an invalid sub-image header"); is($im->errstr, "error reading ICO/CUR image: Not an icon file", "check error message"); } { # invalid bit count for "direct" image my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with an invalid 'direct' bits per pixel"); is($im->errstr, "error reading ICO/CUR image: Unknown value for bits/pixel", "check error message"); } { # short file reading palette my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with short palette"); is($im->errstr, "error reading ICO/CUR image: Short read", "check error message"); } { # short file reading 1 bit image data my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with short image data (1 bit)"); is($im->errstr, "error reading ICO/CUR image: Short read", "check error message"); } { # short file reading 32 bit image data my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with short image data (32 bit)"); is($im->errstr, "error reading ICO/CUR image: Short read", "check error message"); } { # short file reading 4 bit image data my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with short image data (4 bit)"); is($im->errstr, "error reading ICO/CUR image: Short read", "check error message"); } { # short file reading 8 bit image data my $im = Imager->new; # base image header + palette + a little data my $data = get_data <read(data => $data, type=>'ico'), "read from icon with short image data (8 bit)"); is($im->errstr, "error reading ICO/CUR image: Short read", "check error message"); } { # short file reading mask data my $im = Imager->new; my $data = get_data <read(data => $data, type=>'ico'), "read from icon with short mask data"); is($im->errstr, "error reading ICO/CUR image: Short read", "check error message"); } { # fail opening on a multi-read ok(!Imager->read_multi(file=>'t/t50readfail.t', type=>'ico'), "multi-read on non-icon"); is(Imager->errstr, "error opening ICO/CUR file: Not an icon file", "check message"); } { # invalid bit count for "direct" image (read_multi) my $data = get_data <read_multi(data => $data, type=>'ico'), "read from icon with an invalid 'direct' bits per pixel (multi)"); is(Imager->errstr, "error reading ICO/CUR image: Unknown value for bits/pixel", "check error message"); } # extract hex data from text # allows comments sub get_data { my ($src) = @_; $src =~ s/[\#;].*//mg; $src =~ tr/0-9A-F//cd; pack("H*", $src); } libimager-perl-1.004+dfsg.orig/ICO/t/t70icosing.t0000644000175000017500000000050312263740577020624 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; use Imager::Test qw(test_image); -d "testout" or mkdir "testout"; # checks that we load the ICO write handler automatically my $img = test_image(); ok($img->write(file => 'testout/icosing.ico'), "write ico with autoload") or print "# ",$img->errstr,"\n"; libimager-perl-1.004+dfsg.orig/ICO/t/t40readcurone.t0000644000175000017500000000042612031434614021302 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; # checks that we load the CUR handler automatically my $im = Imager->new; ok($im->read(file => 'testimg/pal43232.cur'), "check that cursor reader loaded correctly for singles") or print "# ", $im->errstr, "\n"; libimager-perl-1.004+dfsg.orig/ICO/t/t20readone.t0000644000175000017500000000042412031434614020564 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use Imager; # checks that we load the ICO handler automatically my $im = Imager->new; ok($im->read(file => 'testimg/rgba3232.ico'), "check that icon reader loaded correctly for singles") or print "# ", $im->errstr, "\n"; libimager-perl-1.004+dfsg.orig/ICO/lib/0000755000175000017500000000000012617614576016760 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/ICO/lib/Imager/0000755000175000017500000000000012617614576020164 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/ICO/lib/Imager/File/0000755000175000017500000000000012617614576021043 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/ICO/lib/Imager/File/CUR.pm0000644000175000017500000000015712031434614022014 0ustar gregoagregoapackage Imager::File::CUR; use strict; # all the work is done by Imager::File::ICO use Imager::File::ICO; 1; libimager-perl-1.004+dfsg.orig/ICO/Makefile.PL0000644000175000017500000000064112567572530020162 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; my %opts = ( NAME => 'Imager::File::ICO', VERSION_FROM => 'ICO.pm', OBJECT => 'ICO.o msicon.o imicon.o', INC => '-I..', clean => { FILES => 'testout' }, ); my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'Icon Image file support'; } WriteMakefile(%opts); libimager-perl-1.004+dfsg.orig/ICO/msicon.c0000644000175000017500000007403312263740577017653 0ustar gregoagregoa#include "imext.h" #include "msicon.h" #include #include #include #include #include static int read_packed(io_glue *ig, const char *format, ...); static int read_palette(ico_reader_t *file, ico_image_t *image, int *error); static int read_24bit_data(ico_reader_t *file, ico_image_t *image, int *error); static int read_32bit_data(ico_reader_t *file, ico_image_t *image, int *error); static int read_8bit_data(ico_reader_t *file, ico_image_t *image, int *error); static int read_4bit_data(ico_reader_t *file, ico_image_t *image, int *error); static int read_1bit_data(ico_reader_t *file, ico_image_t *image, int *error); static int read_mask(ico_reader_t *file, ico_image_t *image, int *error); static int ico_write_validate(ico_image_t const *images, int image_count, int *error); static int ico_image_size(ico_image_t const *image, int *bits, int *colors); static int write_packed(i_io_glue_t *ig, char const *format, ...); static int write_palette(i_io_glue_t *ig, ico_image_t const *image, int *error); static int write_32_bit(i_io_glue_t *ig, ico_image_t const *image, int *error); static int write_8_bit(i_io_glue_t *ig, ico_image_t const *image, int *error); static int write_4_bit(i_io_glue_t *ig, ico_image_t const *image, int *error); static int write_1_bit(i_io_glue_t *ig, ico_image_t const *image, int *error); static int write_mask(i_io_glue_t *ig, ico_image_t const *image, int *error); typedef struct { int width; int height; long offset; long size; int hotspot_x, hotspot_y; } ico_reader_image_entry; /* this was previously declared, now define it */ struct ico_reader_tag { /* the file we're dealing with */ i_io_glue_t *ig; /* number of images in the file */ int count; /* type of resource - 1=icon, 2=cursor */ int type; /* image information from the header */ ico_reader_image_entry *images; }; /* =head1 NAME msicon.c - functions for working with .ICO files. =head1 SYNOPSIS // reading int error; ico_reader_t *file = ico_reader_open(ig, &error); if (!file) { char buffer[100]; ico_error_message(error, buffer, sizeof(buffer)); fputs(buffer, stderr); exit(1); } int count = ico_image_count(file); for (i = 0; i < count; ++i) { ico_image_t *im = ico_image_read(file, index); printf("%d x %d image %d\n", im->width, im->height, im->direct ? "direct" : "paletted"); ico_image_release(im); } ico_reader_close(file); =head1 DESCRIPTION This is intended as a general interface to reading MS Icon files, and is written to be independent of Imager, even though it is part of Imager. You just need to supply something that acts like Imager's io_glue. It relies on icon images being generally small, and reads the entire image into memory when reading. =head1 READING ICON FILES =over =item ico_reader_open(ig, &error) Parameters: =over =item * io_glue *ig - an Imager IO object. This must be seekable. =item * int *error - pointer to an integer which an error code will be returned in on failure. =back =cut */ ico_reader_t * ico_reader_open(i_io_glue_t *ig, int *error) { long res1, type, count; ico_reader_t *file = NULL; int i; if (!read_packed(ig, "www", &res1, &type, &count)) { *error = ICOERR_Short_File; return NULL; } if (res1 != 0 || (type != 1 && type != 2) || count == 0) { *error = ICOERR_Invalid_File; return NULL; } file = malloc(sizeof(ico_reader_t)); if (!file) { *error = ICOERR_Out_Of_Memory; return NULL; } file->count = count; file->type = type; file->ig = ig; file->images = malloc(sizeof(ico_reader_image_entry) * count); if (file->images == NULL) { *error = ICOERR_Out_Of_Memory; free(file); return NULL; } for (i = 0; i < count; ++i) { long width, height, bytes_in_res, image_offset; ico_reader_image_entry *image = file->images + i; if (type == ICON_ICON) { if (!read_packed(ig, "bb xxxxxx dd", &width, &height, &bytes_in_res, &image_offset)) { free(file->images); free(file); *error = ICOERR_Short_File; return NULL; } image->hotspot_x = image->hotspot_y = 0; } else { long hotspot_x, hotspot_y; if (!read_packed(ig, "bb xx ww dd", &width, &height, &hotspot_x, &hotspot_y, &bytes_in_res, &image_offset)) { free(file->images); free(file); *error = ICOERR_Short_File; return NULL; } image->hotspot_x = hotspot_x; image->hotspot_y = hotspot_y; } /* a width or height of zero here indicates a width/height of 256 */ image->width = width ? width : 256; image->height = height ? height : 256; image->offset = image_offset; image->size = bytes_in_res; } return file; } /* =item ico_image_count // number of images in the file count = ico_image_count(file); =cut */ int ico_image_count(ico_reader_t *file) { return file->count; } /* =item ico_type // type of file - ICON_ICON for icon, ICON_CURSOR for cursor type = ico_type(file); =cut */ int ico_type(ico_reader_t *file) { return file->type; } /* =item ico_image_read Read an image from the file given it's index. =cut */ ico_image_t * ico_image_read(ico_reader_t *file, int index, int *error) { io_glue *ig = file->ig; ico_reader_image_entry *im; long bi_size, width, height, planes, bit_count; ico_image_t *result; if (index < 0 || index >= file->count) { *error = ICOERR_Bad_Image_Index; return NULL; } im = file->images + index; if (i_io_seek(ig, im->offset, SEEK_SET) != im->offset) { *error = ICOERR_File_Error; return NULL; } if (!read_packed(ig, "dddww xxxx xxxx xxxx xxxx xxxx xxxx", &bi_size, &width, &height, &planes, &bit_count)) { *error = ICOERR_Short_File; return NULL; } /* the bitmapinfoheader height includes the height of the and and xor masks */ if (bi_size != 40 || width != im->width || height != im->height * 2 || planes != 1) { /* don't know how to handle planes != 1 */ *error = ICOERR_Invalid_File; return NULL; } if (bit_count != 1 && bit_count != 4 && bit_count != 8 && bit_count != 24 && bit_count != 32) { *error = ICOERR_Unknown_Bits; return 0; } result = malloc(sizeof(ico_image_t)); if (!result) { *error = ICOERR_Out_Of_Memory; return NULL; } result->width = width; result->height = im->height; result->direct = bit_count > 8; result->bit_count = bit_count; result->palette = NULL; result->image_data = NULL; result->mask_data = NULL; result->hotspot_x = im->hotspot_x; result->hotspot_y = im->hotspot_y; if (bit_count == 32) { result->palette_size = 0; result->image_data = malloc(result->width * result->height * sizeof(ico_color_t)); if (!result->image_data) { free(result); *error = ICOERR_Out_Of_Memory; return NULL; } if (!read_32bit_data(file, result, error)) { free(result->image_data); free(result); return NULL; } } else if (bit_count == 24) { result->palette_size = 0; result->image_data = malloc(result->width * result->height * sizeof(ico_color_t)); if (!result->image_data) { free(result); *error = ICOERR_Out_Of_Memory; return NULL; } if (!read_24bit_data(file, result, error)) { free(result->image_data); free(result); return NULL; } } else { int read_result; result->palette_size = 1 << bit_count; result->palette = malloc(sizeof(ico_color_t) * result->palette_size); if (!result->palette) { free(result); *error = ICOERR_Out_Of_Memory; return NULL; } result->image_data = malloc(result->width * result->height); if (!result->image_data) { *error = ICOERR_Out_Of_Memory; free(result->palette); free(result); return 0; } if (!read_palette(file, result, error)) { free(result->palette); free(result->image_data); free(result); return 0; } switch (bit_count) { case 1: read_result = read_1bit_data(file, result, error); break; case 4: read_result = read_4bit_data(file, result, error); break; case 8: read_result = read_8bit_data(file, result, error); break; default: assert(0); /* this can't happen in theory */ read_result = 0; break; } if (!read_result) { free(result->palette); free(result->image_data); free(result); return 0; } } result->mask_data = malloc(result->width * result->height); if (!result->mask_data) { *error = ICOERR_Out_Of_Memory; free(result->palette); free(result->image_data); free(result); return 0; } if (!read_mask(file, result, error)) { free(result->mask_data); free(result->palette); free(result->image_data); free(result); return 0; } return result; } /* =item ico_image_release Release an image structure returned by ico_image_read. =cut */ void ico_image_release(ico_image_t *image) { free(image->mask_data); free(image->palette); free(image->image_data); free(image); } /* =item ico_reader_close Releases the read file structure. =cut */ void ico_reader_close(ico_reader_t *file) { i_io_close(file->ig); free(file->images); free(file); } /* =back =head1 WRITING ICON FILES =over =item ico_write(ig, images, image_count, type, &error) Parameters: =over =item * io_glue *ig - an Imager IO object. This only needs to implement writing for ico_write() =item * ico_image_t *images - array of images to be written. =item * int image_count - number of images =item * int type - must be ICON_ICON or ICON_CURSOR =item * int *error - set to an error code on failure. =back Returns non-zero on success. =cut */ int ico_write(i_io_glue_t *ig, ico_image_t const *images, int image_count, int type, int *error) { int i; int start_offset = 6 + 16 * image_count; int current_offset = start_offset; if (type != ICON_ICON && type != ICON_CURSOR) { *error = ICOERR_Bad_File_Type; return 0; } /* validate the images */ if (!ico_write_validate(images, image_count, error)) return 0; /* write the header */ if (!write_packed(ig, "www", 0, type, image_count)) { *error = ICOERR_Write_Failure; return 0; } /* work out the offsets of each image */ for (i = 0; i < image_count; ++i) { ico_image_t const *image = images + i; int bits, colors; int size = ico_image_size(image, &bits, &colors); int width_byte = image->width == 256 ? 0 : image->width; int height_byte = image->height == 256 ? 0 : image->height; if (type == ICON_ICON) { if (!write_packed(ig, "bbbbwwdd", width_byte, height_byte, colors, 0, 1, bits, (unsigned long)size, (unsigned long)current_offset)) { *error = ICOERR_Write_Failure; return 0; } } else { int hotspot_x = image->hotspot_x; int hotspot_y = image->hotspot_y; if (hotspot_x < 0) hotspot_x = 0; else if (hotspot_x >= image->width) hotspot_x = image->width - 1; if (hotspot_y < 0) hotspot_y = 0; else if (hotspot_y >= image->height) hotspot_y = image->height - 1; if (!write_packed(ig, "bbbbwwdd", width_byte, height_byte, colors, 0, hotspot_x, hotspot_y, (unsigned long)size, (unsigned long)current_offset)) { *error = ICOERR_Write_Failure; return 0; } } current_offset += size; } /* write out each image */ for (i = 0; i < image_count; ++i) { ico_image_t const *image = images + i; if (image->direct) { if (!write_32_bit(ig, image, error)) return 0; } else { if (image->palette_size <= 2) { if (!write_1_bit(ig, image, error)) return 0; } else if (image->palette_size <= 16) { if (!write_4_bit(ig, image, error)) return 0; } else { if (!write_8_bit(ig, image, error)) return 0; } } if (!write_mask(ig, image, error)) return 0; } return 1; } /* =back =head1 ERROR MESSAGES =over =item ico_error_message Converts an error code into an error message. =cut */ size_t ico_error_message(int error, char *buffer, size_t buffer_size) { char const *msg; size_t size; switch (error) { case ICOERR_Short_File: msg = "Short read"; break; case ICOERR_File_Error: msg = "I/O error"; break; case ICOERR_Write_Failure: msg = "Write failure"; break; case ICOERR_Invalid_File: msg = "Not an icon file"; break; case ICOERR_Unknown_Bits: msg = "Unknown value for bits/pixel"; break; case ICOERR_Bad_Image_Index: msg = "Image index out of range"; break; case ICOERR_Bad_File_Type: msg = "Bad file type parameter"; break; case ICOERR_Invalid_Width: msg = "Invalid image width"; break; case ICOERR_Invalid_Height: msg = "Invalid image height"; break; case ICOERR_Invalid_Palette: msg = "Invalid Palette"; break; case ICOERR_No_Data: msg = "No image data in image supplied to ico_write"; break; case ICOERR_Out_Of_Memory: msg = "Out of memory"; break; default: msg = "Unknown error code"; break; } size = strlen(msg) + 1; if (size > buffer_size) size = buffer_size; memcpy(buffer, msg, size); buffer[size-1] = '\0'; return size; } /* =back =head1 PRIVATE FUNCTIONS =over =item read_packed Reads packed data from a stream, unpacking it. =cut */ static int read_packed(io_glue *ig, const char *format, ...) { unsigned char buffer[100]; va_list ap; long *p; int size; const char *formatp; unsigned char *bufp; /* read efficiently, work out the size of the buffer */ size = 0; formatp = format; while (*formatp) { switch (*formatp++) { case 'b': case 'x': size += 1; break; case 'w': size += 2; break; case 'd': size += 4; break; case ' ': break; /* space to separate components */ default: fprintf(stderr, "invalid unpack char in %s\n", format); exit(1); } } if (size > sizeof(buffer)) { /* catch if we need a bigger buffer, but 100 is plenty */ fprintf(stderr, "format %s too long for buffer\n", format); exit(1); } if (i_io_read(ig, buffer, size) != size) { return 0; } va_start(ap, format); bufp = buffer; while (*format) { switch (*format) { case 'b': p = va_arg(ap, long *); *p = *bufp++; break; case 'w': p = va_arg(ap, long *); *p = bufp[0] + (bufp[1] << 8); bufp += 2; break; case 'd': p = va_arg(ap, long *); *p = bufp[0] + (bufp[1] << 8) + (bufp[2] << 16) + (bufp[3] << 24); bufp += 4; break; case 'x': ++bufp; /* skip a byte */ break; case ' ': /* nothing to do */ break; } ++format; } return 1; } /* =item read_palette Reads the palette data for an icon image. =cut */ static int read_palette(ico_reader_t *file, ico_image_t *image, int *error) { int palette_bytes = image->palette_size * 4; unsigned char *read_buffer = malloc(palette_bytes); unsigned char *inp; ico_color_t *outp; int i; if (!read_buffer) { *error = ICOERR_Out_Of_Memory; return 0; } if (i_io_read(file->ig, read_buffer, palette_bytes) != palette_bytes) { *error = ICOERR_Short_File; free(read_buffer); return 0; } inp = read_buffer; outp = image->palette; for (i = 0; i < image->palette_size; ++i) { outp->b = *inp++; outp->g = *inp++; outp->r = *inp++; outp->a = 255; ++inp; ++outp; } free(read_buffer); return 1; } /* =item read_32bit_data Reads 32 bit image data. =cut */ static int read_32bit_data(ico_reader_t *file, ico_image_t *image, int *error) { int line_bytes = image->width * 4; unsigned char *buffer = malloc(line_bytes); int y; int x; unsigned char *inp; ico_color_t *outp; if (!buffer) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height - 1; y >= 0; --y) { if (i_io_read(file->ig, buffer, line_bytes) != line_bytes) { free(buffer); *error = ICOERR_Short_File; return 0; } outp = image->image_data; outp += y * image->width; inp = buffer; for (x = 0; x < image->width; ++x) { outp->b = inp[0]; outp->g = inp[1]; outp->r = inp[2]; outp->a = inp[3]; ++outp; inp += 4; } } free(buffer); return 1; } /* =item read_24bit_data Reads 24 bit image data. =cut */ static int read_24bit_data(ico_reader_t *file, ico_image_t *image, int *error) { int line_bytes = image->width * 3; unsigned char *buffer; int y; int x; unsigned char *inp; ico_color_t *outp; line_bytes = (line_bytes + 3) / 4 * 4; buffer = malloc(line_bytes); if (!buffer) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height - 1; y >= 0; --y) { if (i_io_read(file->ig, buffer, line_bytes) != line_bytes) { free(buffer); *error = ICOERR_Short_File; return 0; } outp = image->image_data; outp += y * image->width; inp = buffer; for (x = 0; x < image->width; ++x) { outp->b = inp[0]; outp->g = inp[1]; outp->r = inp[2]; outp->a = 255; ++outp; inp += 3; } } free(buffer); return 1; } /* =item read_8bit_data Reads 8 bit image data. =cut */ static int read_8bit_data(ico_reader_t *file, ico_image_t *image, int *error) { int line_bytes = (image->width + 3) / 4 * 4; unsigned char *buffer = malloc(line_bytes); int y; int x; unsigned char *inp, *outp; if (!buffer) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height - 1; y >= 0; --y) { outp = image->image_data; outp += y * image->width; if (i_io_read(file->ig, buffer, line_bytes) != line_bytes) { free(buffer); *error = ICOERR_Short_File; return 0; } for (x = 0, inp = buffer; x < image->width; ++x) { *outp++ = *inp++; } } free(buffer); return 1; } /* =item read_4bit_data Reads 4 bit image data. =cut */ static int read_4bit_data(ico_reader_t *file, ico_image_t *image, int *error) { /* 2 pixels per byte, rounded up to the nearest dword */ int line_bytes = ((image->width + 1) / 2 + 3) / 4 * 4; unsigned char *read_buffer = malloc(line_bytes); int y; int x; unsigned char *inp, *outp; if (!read_buffer) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height - 1; y >= 0; --y) { if (i_io_read(file->ig, read_buffer, line_bytes) != line_bytes) { free(read_buffer); *error = ICOERR_Short_File; return 0; } outp = image->image_data; outp += y * image->width; inp = read_buffer; for (x = 0; x < image->width; ++x) { /* yes, this is kind of ugly */ if (x & 1) { *outp++ = *inp++ & 0x0F; } else { *outp++ = *inp >> 4; } } } free(read_buffer); return 1; } /* =item read_1bit_data Reads 1 bit image data. =cut */ static int read_1bit_data(ico_reader_t *file, ico_image_t *image, int *error) { /* 8 pixels per byte, rounded up to the nearest dword */ int line_bytes = ((image->width + 7) / 8 + 3) / 4 * 4; unsigned char *read_buffer = malloc(line_bytes); int y; int x; unsigned char *inp, *outp; if (!read_buffer) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height - 1; y >= 0; --y) { if (i_io_read(file->ig, read_buffer, line_bytes) != line_bytes) { free(read_buffer); *error = ICOERR_Short_File; return 0; } outp = image->image_data; outp += y * image->width; inp = read_buffer; for (x = 0; x < image->width; ++x) { *outp++ = (*inp >> (7 - (x & 7))) & 1; if ((x & 7) == 7) ++inp; } } free(read_buffer); return 1; } /* this is very similar to the 1 bit reader */ /* =item read_mask Reads the AND mask from an icon image. =cut */ static int read_mask(ico_reader_t *file, ico_image_t *image, int *error) { /* 8 pixels per byte, rounded up to the nearest dword */ int line_bytes = ((image->width + 7) / 8 + 3) / 4 * 4; unsigned char *read_buffer = malloc(line_bytes); int y; int x; int mask; unsigned char *inp, *outp; if (!read_buffer) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height - 1; y >= 0; --y) { if (i_io_read(file->ig, read_buffer, line_bytes) != line_bytes) { free(read_buffer); *error = ICOERR_Short_File; return 0; } outp = image->mask_data + y * image->width; inp = read_buffer; mask = 0x80; for (x = 0; x < image->width; ++x) { *outp++ = (*inp & mask) ? 1 : 0; mask >>= 1; if (!mask) { mask = 0x80; ++inp; } } } free(read_buffer); return 1; } /* =item ico_write_validate Check each image to make sure it can go into an icon file. =cut */ static int ico_write_validate(ico_image_t const *images, int image_count, int *error) { int i; for (i = 0; i < image_count; ++i) { ico_image_t const *image = images + i; if (image->width < 1 || image->width > 256) { *error = ICOERR_Invalid_Width; return 0; } if (image->height < 1 || image->height > 256) { *error = ICOERR_Invalid_Height; return 0; } if (!image->image_data) { *error = ICOERR_No_Data; return 0; } if (!image->direct) { if (image->palette_size < 0 || image->palette_size > 256 || !image->palette) { *error = ICOERR_Invalid_Palette; return 0; } } } return 1; } /* =item ico_image_size Calculate how much space the icon takes up in the file. =cut */ static int ico_image_size(ico_image_t const *image, int *bits, int *colors) { int size = 40; /* start with the BITMAPINFOHEADER */ /* add in the image area */ if (image->direct) { *bits = 32; *colors = 0; size += image->width * 4 * image->height; } else { if (image->palette_size <= 2) { *bits = 1; *colors = 2; } else if (image->palette_size <= 16) { *bits = 4; *colors = 16; } else { *bits = 8; *colors = 0; } /* palette size */ size += *colors * 4; /* image data size */ size += (image->width * *bits + 31) / 32 * 4 * image->height; } /* add in the mask */ size += (image->width + 31) / 32 * 4 * image->height; return size; } /* =item write_packed Pack numbers given a format to a stream. =cut */ static int write_packed(i_io_glue_t *ig, char const *format, ...) { unsigned char buffer[100]; va_list ap; unsigned long p; int size; const char *formatp; unsigned char *bufp; /* write efficiently, work out the size of the buffer */ size = 0; formatp = format; while (*formatp) { switch (*formatp++) { case 'b': size++; break; case 'w': size += 2; break; case 'd': size += 4; break; case ' ': break; /* space to separate components */ default: fprintf(stderr, "invalid unpack char in %s\n", format); exit(1); } } if (size > sizeof(buffer)) { /* catch if we need a bigger buffer, but 100 is plenty */ fprintf(stderr, "format %s too long for buffer\n", format); exit(1); } va_start(ap, format); bufp = buffer; while (*format) { switch (*format) { case 'b': p = va_arg(ap, int); *bufp++ = p; break; case 'w': p = va_arg(ap, int); *bufp++ = p & 0xFF; *bufp++ = (p >> 8) & 0xFF; break; case 'd': p = va_arg(ap, unsigned long); *bufp++ = p & 0xFF; *bufp++ = (p >> 8) & 0xFF; *bufp++ = (p >> 16) & 0xFF; *bufp++ = (p >> 24) & 0xFF; break; case ' ': /* nothing to do */ break; } ++format; } if (i_io_write(ig, buffer, size) != size) return 0; return 1; } /* =item write_palette Write the palette for an icon. =cut */ static int write_palette(i_io_glue_t *ig, ico_image_t const *image, int *error) { int full_size = image->palette_size; unsigned char *writebuf, *outp; ico_color_t *colorp; int i; if (image->palette_size <= 2) full_size = 2; else if (image->palette_size <= 16) full_size = 16; else full_size = 256; writebuf = calloc(full_size, 4); if (!writebuf) { *error = ICOERR_Out_Of_Memory; return 0; } outp = writebuf; colorp = image->palette; for (i = 0; i < image->palette_size; ++i) { *outp++ = colorp->b; *outp++ = colorp->g; *outp++ = colorp->r; *outp++ = 0xFF; ++colorp; } for (; i < full_size; ++i) { *outp++ = 0; *outp++ = 0; *outp++ = 0; *outp++ = 0; } if (i_io_write(ig, writebuf, full_size * 4) != full_size * 4) { *error = ICOERR_Write_Failure; free(writebuf); return 0; } free(writebuf); return 1; } /* =item write_bitmapinfoheader Write the BITMAPINFOHEADER for an icon image. =cut */ static int write_bitmapinfoheader(i_io_glue_t *ig, ico_image_t const *image, int *error, int bit_count, int clr_used) { if (!write_packed(ig, "d dd w w d d dd dd", 40UL, /* biSize */ (unsigned long)image->width, (unsigned long)2 * image->height, /* biWidth/biHeight */ 1, bit_count, /* biPlanes, biBitCount */ 0UL, 0UL, /* biCompression, biSizeImage */ 0UL, 0UL, /* bi(X|Y)PetsPerMeter */ (unsigned long)clr_used, /* biClrUsed */ 0UL)) { /* biClrImportant */ *error = ICOERR_Write_Failure; return 0; } return 1; } /* =item write_32_bit Write 32-bit image data to the icon. =cut */ static int write_32_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) { unsigned char *writebuf; ico_color_t *data = image->image_data, *colorp; unsigned char *writep; int x, y; if (!write_bitmapinfoheader(ig, image, error, 32, 0)) { return 0; } writebuf = malloc(image->width * 4); if (!writebuf) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height-1; y >= 0; --y) { writep = writebuf; colorp = data + y * image->width; for (x = 0; x < image->width; ++x) { *writep++ = colorp->b; *writep++ = colorp->g; *writep++ = colorp->r; *writep++ = colorp->a; ++colorp; } if (i_io_write(ig, writebuf, image->width * 4) != image->width * 4) { *error = ICOERR_Write_Failure; free(writebuf); return 0; } } free(writebuf); return 1; } /* =item write_8_bit Write 8 bit image data. =cut */ static int write_8_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) { static const unsigned char zeros[3] = { '\0' }; int y; const unsigned char *data = image->image_data; int zero_count = (0U - (unsigned)image->width) & 3; if (!write_bitmapinfoheader(ig, image, error, 8, 256)) { return 0; } if (!write_palette(ig, image, error)) return 0; for (y = image->height-1; y >= 0; --y) { if (i_io_write(ig, data + y * image->width, image->width) != image->width) { *error = ICOERR_Write_Failure; return 0; } if (zero_count) { if (i_io_write(ig, zeros, zero_count) != zero_count) { *error = ICOERR_Write_Failure; return 0; } } } return 1; } /* =item write_4_bit Write 4 bit image data. =cut */ static int write_4_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) { int line_size = ((image->width + 1) / 2 + 3) / 4 * 4; unsigned char *writebuf, *outp; int x, y; unsigned char const *data = image->image_data; unsigned char const *pixelp; if (!write_bitmapinfoheader(ig, image, error, 4, 16)) { return 0; } if (!write_palette(ig, image, error)) return 0; writebuf = malloc(line_size); if (!writebuf) { *error = ICOERR_Out_Of_Memory; return 0; } for (y = image->height-1; y >= 0; --y) { pixelp = data + y * image->width; outp = writebuf; memset(writebuf, 0, line_size); for (x = 0; x < image->width; ++x) { if (x & 1) { *outp |= *pixelp++ & 0x0F; ++outp; } else { *outp |= *pixelp++ << 4; } } if (i_io_write(ig, writebuf, line_size) != line_size) { *error = ICOERR_Write_Failure; free(writebuf); return 0; } } free(writebuf); return 1; } /* =item write_1_bit Write 1 bit image data. =cut */ static int write_1_bit(i_io_glue_t *ig, ico_image_t const *image, int *error) { int line_size = (image->width + 31) / 32 * 4; unsigned char *writebuf = malloc(line_size); unsigned char *outp; unsigned char const *data, *pixelp; int x,y; unsigned mask; if (!write_bitmapinfoheader(ig, image, error, 1, 2)) { return 0; } if (!write_palette(ig, image, error)) return 0; if (!writebuf) { *error = ICOERR_Out_Of_Memory; return 0; } data = image->image_data; for (y = image->height-1; y >= 0; --y) { memset(writebuf, 0, line_size); pixelp = data + y * image->width; outp = writebuf; mask = 0x80; for (x = 0; x < image->width; ++x) { if (*pixelp) *outp |= mask; mask >>= 1; if (!mask) { mask = 0x80; outp++; } } if (i_io_write(ig, writebuf, line_size) != line_size) { *error = ICOERR_Write_Failure; free(writebuf); return 0; } } free(writebuf); return 1; } /* =item write_mask Write the AND mask. =cut */ static int write_mask(i_io_glue_t *ig, ico_image_t const *image, int *error) { int line_size = (image->width + 31) / 32 * 4; unsigned char *writebuf = malloc(line_size); unsigned char *outp; unsigned char const *data, *pixelp; int x,y; unsigned mask; if (!writebuf) { *error = ICOERR_Out_Of_Memory; return 0; } data = image->mask_data; if (data) { for (y = image->height-1; y >= 0; --y) { memset(writebuf, 0, line_size); pixelp = data + y * image->width; outp = writebuf; mask = 0x80; for (x = 0; x < image->width; ++x) { if (*pixelp) *outp |= mask; mask >>= 1; if (!mask) { mask = 0x80; outp++; } ++pixelp; } if (i_io_write(ig, writebuf, line_size) != line_size) { *error = ICOERR_Write_Failure; free(writebuf); return 0; } } } else { memset(writebuf, 0, line_size); for (y = image->height-1; y >= 0; --y) { if (i_io_write(ig, writebuf, line_size) != line_size) { *error = ICOERR_Write_Failure; free(writebuf); return 0; } } } free(writebuf); return 1; } /* =back =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut */ libimager-perl-1.004+dfsg.orig/ICO/ICO.xs0000644000175000017500000000601112460670607017167 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "imicon.h" #include "ppport.h" DEFINE_IMAGER_CALLBACKS; MODULE = Imager::File::ICO PACKAGE = Imager::File::ICO PROTOTYPES: DISABLE Imager::ImgRaw i_readico_single(ig, index, masked = 0, alpha_masked = 0) Imager::IO ig int index bool masked bool alpha_masked void i_readico_multi(ig, masked = 0, alpha_masked = 0) Imager::IO ig bool masked bool alpha_masked PREINIT: i_img **imgs; int count; int i; PPCODE: imgs = i_readico_multi(ig, &count, masked, alpha_masked); if (imgs) { EXTEND(SP, count); for (i = 0; i < count; ++i) { SV *sv = sv_newmortal(); sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]); PUSHs(sv); } myfree(imgs); } int i_writeico_wiol(ig, im) Imager::IO ig Imager::ImgRaw im undef_int i_writeico_multi_wiol(ig, ...) Imager::IO ig PREINIT: int i; int img_count; i_img **imgs; CODE: if (items < 2) croak("Usage: i_writeico_multi_wiol(ig, images...)"); img_count = items - 1; RETVAL = 1; if (img_count < 1) { RETVAL = 0; i_clear_error(); i_push_error(0, "You need to specify images to save"); } else { imgs = mymalloc(sizeof(i_img *) * img_count); for (i = 0; i < img_count; ++i) { SV *sv = ST(1+i); imgs[i] = NULL; if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) { imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv))); } else { i_clear_error(); i_push_error(0, "Only images can be saved"); myfree(imgs); RETVAL = 0; break; } } if (RETVAL) { RETVAL = i_writeico_multi_wiol(ig, imgs, img_count); } myfree(imgs); } OUTPUT: RETVAL int i_writecur_wiol(ig, im) Imager::IO ig Imager::ImgRaw im undef_int i_writecur_multi_wiol(ig, ...) Imager::IO ig PREINIT: int i; int img_count; i_img **imgs; CODE: if (items < 2) croak("Usage: i_writecur_multi_wiol(ig, images...)"); img_count = items - 1; RETVAL = 1; if (img_count < 1) { RETVAL = 0; i_clear_error(); i_push_error(0, "You need to specify images to save"); } else { imgs = mymalloc(sizeof(i_img *) * img_count); for (i = 0; i < img_count; ++i) { SV *sv = ST(1+i); imgs[i] = NULL; if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) { imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv))); } else { i_clear_error(); i_push_error(0, "Only images can be saved"); myfree(imgs); RETVAL = 0; break; } } if (RETVAL) { RETVAL = i_writecur_multi_wiol(ig, imgs, img_count); } myfree(imgs); } OUTPUT: RETVAL BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/ICO/msicon.h0000644000175000017500000000255612263740577017661 0ustar gregoagregoa#ifndef IMAGER_MSICON_H_ #define IMAGER_MSICON_H_ #include "iolayert.h" typedef struct ico_reader_tag ico_reader_t; #define ICON_ICON 1 #define ICON_CURSOR 2 typedef struct { unsigned char r, g, b, a; } ico_color_t; typedef struct { int width; int height; int direct; int bit_count; void *image_data; int palette_size; ico_color_t *palette; unsigned char *mask_data; int hotspot_x, hotspot_y; } ico_image_t; extern ico_reader_t *ico_reader_open(i_io_glue_t *ig, int *error); extern int ico_image_count(ico_reader_t *file); extern int ico_type(ico_reader_t *file); extern ico_image_t *ico_image_read(ico_reader_t *file, int index, int *error); extern void ico_image_release(ico_image_t *image); extern void ico_reader_close(ico_reader_t *file); extern int ico_write(i_io_glue_t *ig, ico_image_t const *images, int image_count, int type, int *error); extern size_t ico_error_message(int error, char *buffer, size_t buffer_size); #define ICO_MAX_MESSAGE 80 #define ICOERR_Short_File 100 #define ICOERR_File_Error 101 #define ICOERR_Write_Failure 102 #define ICOERR_Invalid_File 200 #define ICOERR_Unknown_Bits 201 #define ICOERR_Bad_Image_Index 300 #define ICOERR_Bad_File_Type 301 #define ICOERR_Invalid_Width 302 #define ICOERR_Invalid_Height 303 #define ICOERR_Invalid_Palette 304 #define ICOERR_No_Data 305 #define ICOERR_Out_Of_Memory 400 #endif libimager-perl-1.004+dfsg.orig/compose.im0000644000175000017500000001447712263740600017572 0ustar gregoagregoa#include "imager.h" #include "imrender.h" #include "imageri.h" int i_compose_mask(i_img *out, i_img *src, i_img *mask, i_img_dim out_left, i_img_dim out_top, i_img_dim src_left, i_img_dim src_top, i_img_dim mask_left, i_img_dim mask_top, i_img_dim width, i_img_dim height, int combine, double opacity) { i_render r; i_img_dim dy; i_fill_combine_f combinef_8; i_fill_combinef_f combinef_double; int channel_zero = 0; mm_log((1, "i_compose_mask(out %p, src %p, mask %p, out(" i_DFp "), " "src(" i_DFp "), mask(" i_DFp "), size(" i_DFp ")," " combine %d opacity %f\n", out, src, mask, i_DFcp(out_left, out_top), i_DFcp(src_left, src_top), i_DFcp(mask_left, mask_top), i_DFcp(width, height), combine, opacity)); i_clear_error(); if (out_left >= out->xsize || out_top >= out->ysize || src_left >= src->xsize || src_top >= src->ysize || width <= 0 || height <= 0 || out_left + width <= 0 || out_top + height <= 0 || src_left + width <= 0 || src_top + height <= 0 || mask_left >= mask->xsize || mask_top >= mask->ysize || mask_left + width <= 0 || mask_top + height <= 0) return 0; if (out_left < 0) { width = out_left + width; src_left -= out_left; mask_left -= out_left; out_left = 0; } if (out_left + width > out->xsize) width = out->xsize - out_left; if (out_top < 0) { height = out_top + height; mask_top -= out_top; src_top -= out_top; out_top = 0; } if (out_top + height > out->ysize) height = out->ysize - out_top; if (src_left < 0) { width = src_left + width; out_left -= src_left; mask_left -= src_left; src_left = 0; } if (src_left + width > src->xsize) width = src->xsize - src_left; if (src_top < 0) { height = src_top + height; out_top -= src_top; mask_top -= src_top; src_top = 0; } if (src_top + height > src->ysize) height = src->ysize - src_top; if (mask_left < 0) { width = mask_left + width; out_left -= mask_left; src_left -= mask_left; mask_left = 0; } if (mask_left + width > mask->xsize) width = mask->xsize - mask_left; if (mask_top < 0) { height = mask_top + height; src_top -= mask_top; out_top -= mask_top; mask_top = 0; } if (mask_top + height > mask->ysize) height = mask->ysize - mask_top; if (opacity > 1.0) opacity = 1.0; else if (opacity <= 0) { i_push_error(0, "opacity must be positive"); return 0; } mm_log((1, "after adjustments: (out(" i_DFp "), src(" i_DFp ")," " mask(" i_DFp "), size(" i_DFp ")\n", i_DFcp(out_left, out_top), i_DFcp(src_left, src_top), i_DFcp(mask_left, mask_top), i_DFcp(width, height))); i_get_combine(combine, &combinef_8, &combinef_double); i_render_init(&r, out, width); #code out->bits <= 8 && src->bits<= 8 && mask->bits <= 8 IM_COLOR *src_line = mymalloc(sizeof(IM_COLOR) * width); IM_SAMPLE_T *mask_line = mymalloc(sizeof(IM_SAMPLE_T) * width); int adapt_channels = out->channels; if (adapt_channels == 1 || adapt_channels == 3) ++adapt_channels; for (dy = 0; dy < height; ++dy) { IM_GLIN(src, src_left, src_left + width, src_top + dy, src_line); IM_ADAPT_COLORS(adapt_channels, src->channels, src_line, width); IM_GSAMP(mask, mask_left, mask_left + width, mask_top + dy, mask_line, &channel_zero, 1); if (opacity < 1.0) { i_img_dim i; IM_SAMPLE_T *maskp = mask_line; for (i = 0; i < width; ++i) { *maskp = IM_ROUND(*maskp * opacity); ++maskp; } } IM_RENDER_LINE(&r, out_left, out_top+dy, width, mask_line, src_line, IM_SUFFIX(combinef)); } myfree(src_line); myfree(mask_line); #/code i_render_done(&r); return 1; } int i_compose(i_img *out, i_img *src, i_img_dim out_left, i_img_dim out_top, i_img_dim src_left, i_img_dim src_top, i_img_dim width, i_img_dim height, int combine, double opacity) { i_render r; i_img_dim dy; i_fill_combine_f combinef_8; i_fill_combinef_f combinef_double; mm_log((1, "i_compose(out %p, src %p, out(" i_DFp "), src(" i_DFp "), " "size(" i_DFp "), combine %d opacity %f\n", out, src, i_DFcp(out_left, out_top), i_DFcp(src_left, src_top), i_DFcp(width, height), combine, opacity)); i_clear_error(); if (out_left >= out->xsize || out_top >= out->ysize || src_left >= src->xsize || src_top >= src->ysize || width <= 0 || height <= 0 || out_left + width <= 0 || out_top + height <= 0 || src_left + width <= 0 || src_top + height <= 0) return 0; if (out_left < 0) { width = out_left + width; src_left -= out_left; out_left = 0; } if (out_left + width > out->xsize) width = out->xsize - out_left; if (out_top < 0) { height = out_top + height; src_top -= out_top; out_top = 0; } if (out_top + height > out->ysize) height = out->ysize - out_top; if (src_left < 0) { width = src_left + width; out_left -= src_left; src_left = 0; } if (src_left + width > src->xsize) width = src->xsize - src_left; if (src_top < 0) { height = src_top + height; out_top -= src_top; src_top = 0; } if (src_top + height > src->ysize) height = src->ysize - src_top; if (opacity > 1.0) opacity = 1.0; else if (opacity <= 0) { i_push_error(0, "opacity must be positive"); return 0; } i_get_combine(combine, &combinef_8, &combinef_double); i_render_init(&r, out, width); #code out->bits <= 8 && src->bits <= 8 IM_COLOR *src_line = mymalloc(sizeof(IM_COLOR) * width); IM_SAMPLE_T *mask_line = NULL; int adapt_channels = out->channels; if (opacity != 1.0) { i_img_dim i; IM_SAMPLE_T mask_value = IM_ROUND(opacity * IM_SAMPLE_MAX); mask_line = mymalloc(sizeof(IM_SAMPLE_T) * width); for (i = 0; i < width; ++i) mask_line[i] = mask_value; } if (adapt_channels == 1 || adapt_channels == 3) ++adapt_channels; for (dy = 0; dy < height; ++dy) { IM_GLIN(src, src_left, src_left + width, src_top + dy, src_line); IM_ADAPT_COLORS(adapt_channels, src->channels, src_line, width); IM_RENDER_LINE(&r, out_left, out_top+dy, width, mask_line, src_line, IM_SUFFIX(combinef)); } myfree(src_line); if (mask_line) myfree(mask_line); #/code i_render_done(&r); return 1; } libimager-perl-1.004+dfsg.orig/filterlist.perl0000755000175000017500000000063612031434615020635 0ustar gregoagregoa#!/usr/bin/perl use strict; use Imager; print "Filter Arguments\n"; for my $filt (keys %Imager::filters) { my @callseq=@{$Imager::filters{$filt}{'callseq'} || {}}; my %defaults=%{$Imager::filters{$filt}{'defaults'} || {}}; shift(@callseq); my @b=map { exists($defaults{$_}) ? $_.'('.$defaults{$_}.')' : $_ } @callseq; my $str=join(" ",@b); printf("%-15s %s\n",$filt,$str ); } libimager-perl-1.004+dfsg.orig/typemap0000644000175000017500000000700112263741005017161 0ustar gregoagregoa#i_img * T_PTR_NULL Imager::Color T_PTROBJ Imager::Color::Float T_PTROBJ Imager::ImgRaw T_IMAGER_IMAGE Imager::Font::TT T_PTROBJ Imager::IO T_PTROBJ Imager::FillHandle T_PTROBJ const char * T_PV float T_FLOAT float* T_ARRAY undef_int T_IV_U undef_neg_int T_IV_NEGU HASH T_HVREF utf8_str T_UTF8_STR i_img_dim T_IV # these types are for use by Inline, which can't handle types containing :: Imager__Color T_PTROBJ_INV Imager__Color__Float T_PTROBJ_INV Imager__ImgRaw T_IMAGER_IMAGE Imager__FillHandle T_PTROBJ_INV Imager__IO T_PTROBJ_INV # mostly intended for non-Imager-core use Imager T_IMAGER_FULL_IMAGE ############################################################################# INPUT T_PTR_NULL if (SvOK($arg)) $var = INT2PTR($type,SvIV($arg)); else $var = NULL # handles Imager objects rather than just raw objects T_IMAGER_IMAGE if (sv_derived_from($arg, \"Imager::ImgRaw\")) { IV tmp = SvIV((SV*)SvRV($arg)); $var = INT2PTR($type,tmp); } else if (sv_derived_from($arg, \"Imager\") && SvTYPE(SvRV($arg)) == SVt_PVHV) { HV *hv = (HV *)SvRV($arg); SV **sv = hv_fetch(hv, \"IMG\", 3, 0); if (sv && *sv && sv_derived_from(*sv, \"Imager::ImgRaw\")) { IV tmp = SvIV((SV*)SvRV(*sv)); $var = INT2PTR($type,tmp); } else Perl_croak(aTHX_ \"$var is not of type Imager::ImgRaw\"); } else Perl_croak(aTHX_ \"$var is not of type Imager::ImgRaw\"); T_IMAGER_FULL_IMAGE if (sv_derived_from($arg, \"Imager\") && SvTYPE(SvRV($arg)) == SVt_PVHV) { HV *hv = (HV *)SvRV($arg); SV **sv = hv_fetch(hv, \"IMG\", 3, 0); if (sv && *sv && sv_derived_from(*sv, \"Imager::ImgRaw\")) { IV tmp = SvIV((SV*)SvRV(*sv)); $var = INT2PTR($type,tmp); } else Perl_croak(aTHX_ \"$var is not of type Imager::ImgRaw\"); } else Perl_croak(aTHX_ \"$var is not of type Imager\"); # same as T_PTROBJ, but replace __ with ::, the opposite of the way # xsubpp's processing works # this is to compensate for Inline's problem with type names containing :: T_PTROBJ_INV if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\")) { IV tmp = SvIV((SV*)SvRV($arg)); $var = INT2PTR($type,tmp); } else croak(\"$var is not of type ${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\"); ############################################################################# OUTPUT T_IV_U if ($var == 0) $arg=&PL_sv_undef; else sv_setiv($arg, (IV)$var); T_IV_NEGU if ($var < 0) $arg=&PL_sv_undef; else sv_setiv($arg, (IV)$var); T_PTR_NULL sv_setiv($arg, (IV)$var); # same as T_PTROBJ T_IMAGER_IMAGE sv_setref_pv($arg, \"Imager::ImgRaw\", (void*)$var); T_PTROBJ_INV sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\", (void*)$var); # ugh, the things we do for ease of use # this isn't suitable in some cases T_IMAGER_FULL_IMAGE if ($var) { SV *imobj = NEWSV(0, 0); HV *hv = newHV(); sv_setref_pv(imobj, \"Imager::ImgRaw\", $var); hv_store(hv, "IMG", 3, imobj, 0); $arg = sv_2mortal(sv_bless(newRV_noinc((SV*)hv), gv_stashpv("Imager", 1))); } else { $arg = &PL_sv_undef; } libimager-perl-1.004+dfsg.orig/color.c0000644000175000017500000001057312263740600017051 0ustar gregoagregoa#include "imager.h" #include /* =head1 NAME color.c - color manipulation functions =head1 SYNOPSIS i_fcolor color; i_rgb_to_hsvf(&color); i_hsv_to_rgbf(&color); =head1 DESCRIPTION A collection of utility functions for converting between color spaces. =over =cut */ #define EPSILON (1e-8) #define my_max(a, b) ((a) < (b) ? (b) : (a)) #define my_min(a, b) ((a) > (b) ? (b) : (a)) /* =item i_rgb2hsvf(&color) Converts the first 3 channels of color into hue, saturation and value. Each value is scaled into the range 0 to 1.0. =cut */ void i_rgb_to_hsvf(i_fcolor *color) { double h = 0, s, v; double temp; double Cr, Cg, Cb; v = my_max(my_max(color->rgb.r, color->rgb.g), color->rgb.b); temp = my_min(my_min(color->rgb.r, color->rgb.g), color->rgb.b); if (v < EPSILON) s = 0; else s = (v-temp)/v; if (s == 0) h = 0; else { Cr = (v - color->rgb.r)/(v-temp); Cg = (v - color->rgb.g)/(v-temp); Cb = (v - color->rgb.b)/(v-temp); if (color->rgb.r == v) h = Cb - Cg; else if (color->rgb.g == v) h = 2 + Cr - Cb; else if (color->rgb.b == v) h = 4 + Cg - Cr; h = 60 * h; if (h < 0) h += 360; } color->channel[0] = h / 360.0; color->channel[1] = s; color->channel[2] = v; } /* =item i_rgb2hsv(&color) Converts the first 3 channels of color into hue, saturation and value. Each value is scaled into the range 0 to 255. =cut */ void i_rgb_to_hsv(i_color *color) { double h = 0, s, v; double temp; double Cr, Cg, Cb; v = my_max(my_max(color->rgb.r, color->rgb.g), color->rgb.b); temp = my_min(my_min(color->rgb.r, color->rgb.g), color->rgb.b); if (v == 0) s = 0; else s = (v-temp)*255/v; if (s == 0) h = 0; else { Cr = (v - color->rgb.r)/(v-temp); Cg = (v - color->rgb.g)/(v-temp); Cb = (v - color->rgb.b)/(v-temp); if (color->rgb.r == v) h = Cb - Cg; else if (color->rgb.g == v) h = 2 + Cr - Cb; else if (color->rgb.b == v) h = 4 + Cg - Cr; h = h * 60.0; if (h < 0) h += 360; } color->channel[0] = h * 255 / 360.0; color->channel[1] = s; color->channel[2] = v; } /* =item i_hsv_to_rgbf(&color) Convert a HSV value to an RGB value, each value ranges from 0 to 1. =cut */ void i_hsv_to_rgbf(i_fcolor *color) { double h = color->channel[0]; double s = color->channel[1]; double v = color->channel[2]; if (color->channel[1] < EPSILON) { /* ignore h in this case */ color->rgb.r = color->rgb.g = color->rgb.b = v; } else { int i; double f, m, n, k; h = fmod(h, 1.0) * 6; i = floor(h); f = h - i; m = v * (1 - s); n = v * (1 - s * f); k = v * (1 - s * (1 - f)); switch (i) { case 0: color->rgb.r = v; color->rgb.g = k; color->rgb.b = m; break; case 1: color->rgb.r = n; color->rgb.g = v; color->rgb.b = m; break; case 2: color->rgb.r = m; color->rgb.g = v; color->rgb.b = k; break; case 3: color->rgb.r = m; color->rgb.g = n; color->rgb.b = v; break; case 4: color->rgb.r = k; color->rgb.g = m; color->rgb.b = v; break; case 5: color->rgb.r = v; color->rgb.g = m; color->rgb.b = n; break; } } } /* =item i_hsv_to_rgb(&color) Convert a HSV value to an RGB value, each value ranges from 0 to 1. =cut */ void i_hsv_to_rgb(i_color *color) { double h = color->channel[0]; double s = color->channel[1]; double v = color->channel[2]; if (color->channel[1] == 0) { /* ignore h in this case */ color->rgb.r = color->rgb.g = color->rgb.b = v; } else { int i; double f; int m, n, k; h = h / 255.0 * 6; i = h; f = h - i; m = 0.5 + v * (255 - s) / 255; n = 0.5 + v * (255 - s * f) / 255; k = 0.5 + v * (255 - s * (1 - f)) / 255; switch (i) { case 0: color->rgb.r = v; color->rgb.g = k; color->rgb.b = m; break; case 1: color->rgb.r = n; color->rgb.g = v; color->rgb.b = m; break; case 2: color->rgb.r = m; color->rgb.g = v; color->rgb.b = k; break; case 3: color->rgb.r = m; color->rgb.g = n; color->rgb.b = v; break; case 4: color->rgb.r = k; color->rgb.g = m; color->rgb.b = v; break; case 5: color->rgb.r = v; color->rgb.g = m; color->rgb.b = n; break; } } } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager =cut */ libimager-perl-1.004+dfsg.orig/polygon.c0000644000175000017500000004557712461136230017434 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "draw.h" #include "log.h" #include "imrender.h" #include "imageri.h" #define IMTRUNC(x) ((int)((x)*16)) #define coarse(x) ((x)/16) #define fine(x) ((x)%16) /*#define DEBUG_POLY*/ #ifdef DEBUG_POLY #define POLY_DEB(x) x #else #define POLY_DEB(x) #endif typedef i_img_dim pcord; typedef struct { size_t n; pcord x,y; } p_point; typedef struct { size_t n; pcord x1,y1; pcord x2,y2; pcord miny,maxy; pcord minx,maxx; int updown; /* -1 means down, 0 vertical, 1 up */ int dir; /* 1 for down, -1 for up */ } p_line; typedef struct { size_t n; double x; } p_slice; typedef struct { int *line; /* temporary buffer for scanline */ i_img_dim linelen; /* length of scanline */ } ss_scanline; static int p_compy(const p_point *p1, const p_point *p2) { if (p1->y > p2->y) return 1; if (p1->y < p2->y) return -1; return 0; } static int p_compx(const p_slice *p1, const p_slice *p2) { if (p1->x > p2->x) return 1; if (p1->x < p2->x) return -1; return 0; } /* Change this to int? and round right goddamn it! */ static double p_eval_aty(p_line *l, pcord y) { int t; t=l->y2-l->y1; if (t) return ( (y-l->y1)*l->x2 + (l->y2-y)*l->x1 )/t; return (l->x1+l->x2)/2.0; } static double p_eval_atx(p_line *l, pcord x) { int t; t = l->x2-l->x1; if (t) return ( (x-l->x1)*l->y2 + (l->x2-x)*l->y1 )/t; return (l->y1+l->y2)/2.0; } static p_line * line_set_new(const i_polygon_t *polys, size_t count, size_t *line_count) { size_t i, j, n; p_line *lset, *line; size_t lines = 0; for (i = 0; i < count; ++i) lines += polys[i].count; line = lset = mymalloc(sizeof(p_line) * lines); n = 0; for (i = 0; i < count; ++i) { const i_polygon_t *p = polys + i; for(j = 0; j < p->count; j++) { line->x1 = IMTRUNC(p->x[j]); line->y1 = IMTRUNC(p->y[j]); line->x2 = IMTRUNC(p->x[(j + 1) % p->count]); line->y2 = IMTRUNC(p->y[(j + 1) % p->count]); /* don't include purely horizontal lines, we don't usefully intersect with them. */ if (line->y1 == line->y2) continue; line->miny = i_min(line->y1, line->y2); line->maxy = i_max(line->y1, line->y2); line->minx = i_min(line->x1, line->x2); line->maxx = i_max(line->x1, line->x2); line->n = n++; ++line; } } *line_count = n; return lset; } static p_point * point_set_new(const i_polygon_t *polys, size_t count, size_t *point_count) { size_t i, j, n; p_point *pset, *pt; size_t points = 0; for (i = 0; i < count; ++i) points += polys[i].count; *point_count = points; pt = pset = mymalloc(sizeof(p_point) * points); n = 0; for (i = 0; i < count; ++i) { const i_polygon_t *p = polys + i; for(j = 0; j < p->count; j++) { pt->n = n++; pt->x = IMTRUNC(p->x[j]); pt->y = IMTRUNC(p->y[j]); ++pt; } } return pset; } static void ss_scanline_reset(ss_scanline *ss) { memset(ss->line, 0, sizeof(int) * ss->linelen); } static void ss_scanline_init(ss_scanline *ss, i_img_dim linelen, int linepairs) { ss->line = mymalloc( sizeof(int) * linelen ); ss->linelen = linelen; ss_scanline_reset(ss); } static void ss_scanline_exorcise(ss_scanline *ss) { myfree(ss->line); } /* returns the number of matches */ static int lines_in_interval(p_line *lset, int l, p_slice *tllist, pcord minc, pcord maxc) { int k; int count = 0; for(k=0; k minc && lset[k].miny < maxc) { if (lset[k].miny == lset[k].maxy) { POLY_DEB( printf(" HORIZONTAL - skipped\n") ); } else { tllist[count].x=p_eval_aty(&lset[k],(minc+maxc)/2.0 ); tllist[count].n=k; count++; } } } return count; } /* marks the up variable for all lines in a slice */ static void mark_updown_slices(pIMCTX, p_line *lset, p_slice *tllist, int count) { p_line *l, *r; int k; for(k=0; ky1 == l->y2) { im_log((aIMCTX,1, "mark_updown_slices: horizontal line being marked: internal error!\n")); exit(3); } l->updown = (l->x1 == l->x2) ? 0 : (l->x1 > l->x2) ? (l->y1 > l->y2) ? -1 : 1 : (l->y1 > l->y2) ? 1 : -1; l->dir = l->y1 < l->y2 ? 1 : -1; POLY_DEB( printf("marking left line %d as %s(%d)\n", l->n, l->updown ? l->updown == 1 ? "up" : "down" : "vert", l->updown, l->updown) ); if (k+1 >= count) { im_log((aIMCTX, 1, "Invalid polygon spec, odd number of line crossings.\n")); return; } r = lset + tllist[k+1].n; if (r->y1 == r->y2) { im_log((aIMCTX, 1, "mark_updown_slices: horizontal line being marked: internal error!\n")); exit(3); } r->updown = (r->x1 == r->x2) ? 0 : (r->x1 > r->x2) ? (r->y1 > r->y2) ? -1 : 1 : (r->y1 > r->y2) ? 1 : -1; r->dir = r->y1 < r->y2 ? 1 : -1; POLY_DEB( printf("marking right line %d as %s(%d)\n", r->n, r->updown ? r->updown == 1 ? "up" : "down" : "vert", r->updown, r->updown) ); } } static unsigned char saturate(int in) { if (in>255) { return 255; } else if (in>0) return in; return 0; } typedef void (*scanline_flusher)(i_img *im, ss_scanline *ss, int y, void *ctx); /* This function must be modified later to do proper blending */ static void scanline_flush(i_img *im, ss_scanline *ss, int y, void *ctx) { int x, ch, tv; i_color t; i_color *val = (i_color *)ctx; POLY_DEB( printf("Flushing line %d\n", y) ); for(x=0; xxsize; x++) { tv = saturate(ss->line[x]); i_gpix(im, x, y, &t); for(ch=0; chchannels; ch++) t.channel[ch] = tv/255.0 * val->channel[ch] + (1.0-tv/255.0) * t.channel[ch]; i_ppix(im, x, y, &t); } } static int trap_square(pcord xlen, pcord ylen, double xl, double yl) { POLY_DEB( printf("trap_square: %d %d %.2f %.2f\n", xlen, ylen, xl, yl) ); return xlen*ylen-(xl*yl)/2.0; } /* pixel_coverage calculates the 'left side' pixel coverage of a pixel that is within the min/max ranges. The shape always corresponds to a square with some sort of a triangle cut from it (which can also yield a triangle). */ static int pixel_coverage(p_line *line, pcord minx, pcord maxx, pcord miny, pcord maxy) { double lycross, rycross; int l, r; POLY_DEB ( printf(" pixel_coverage(..., minx %g, maxx%g, miny %g, maxy %g)\n", minx/16.0, maxx/16.0, miny/16.0, maxy/16.0) ); if (!line->updown) { l = r = 0; } else { lycross = p_eval_atx(line, minx); rycross = p_eval_atx(line, maxx); l = lycross <= maxy && lycross >= miny; /* true if it enters through left side */ r = rycross <= maxy && rycross >= miny; /* true if it enters through left side */ } POLY_DEB( printf(" %4s(%+d): ", line->updown ? line->updown == 1 ? "up" : "down" : "vert", line->updown); printf(" (%2d,%2d) [%3d-%3d, %3d-%3d] lycross=%.2f rycross=%.2f", coarse(minx), coarse(miny), minx, maxx, miny, maxy, lycross, rycross); printf(" l=%d r=%d\n", l, r) ); if (l && r) return line->updown == 1 ? (double)(maxx-minx) * (2.0*maxy-lycross-rycross)/2.0 /* up case */ : (double)(maxx-minx) * (lycross+rycross-2*miny)/2.0; /* down case */ if (!l && !r) return (maxy-miny)*(maxx*2-p_eval_aty(line, miny)-p_eval_aty(line, maxy))/2.0; if (l && !r) return line->updown == 1 ? trap_square(maxx-minx, maxy-miny, p_eval_aty(line, miny)-minx, p_eval_atx(line, minx)-miny) : trap_square(maxx-minx, maxy-miny, p_eval_aty(line, maxy)-minx, maxy-p_eval_atx(line, minx)); if (!l && r) { int r = line->updown == 1 ? (maxx-p_eval_aty(line, maxy))*(maxy-p_eval_atx(line, maxx))/2.0 : (maxx-p_eval_aty(line, miny))*(p_eval_atx(line, maxx)-miny)/2.0; return r; } return 0; /* silence compiler warning */ } /* handle the scanline slice in three steps 1. Where only the left edge is inside a pixel 2a. Where both left and right edge are inside a pixel 2b. Where neither left or right edge are inside a pixel 3. Where only the right edge is inside a pixel */ static void render_slice_scanline(ss_scanline *ss, int y, p_line *l, p_line *r, pcord miny, pcord maxy) { pcord lminx, lmaxx; /* left line min/max within y bounds in fine coords */ pcord rminx, rmaxx; /* right line min/max within y bounds in fine coords */ i_img_dim cpix; /* x-coordinate of current pixel */ i_img_dim startpix; /* temporary variable for "start of this interval" */ i_img_dim stoppix; /* temporary variable for "end of this interval" */ /* Find the y bounds of scanline_slice */ POLY_DEB ( printf("render_slice_scanline(..., y=%d)\n"); printf(" left n=%d p1(%.2g, %.2g) p2(%.2g,%.2g) min(%.2g, %.2g) max(%.2g,%.2g) updown(%d)\n", l->n, l->x1/16.0, l->y1/16.0, l->x2/16.0, l->y2/16.0, l->minx/16.0, l->miny/16.0, l->maxx/16.0, l->maxy/16.0, l->updown); printf(" right n=%d p1(%.2g, %.2g) p2(%.2g,%.2g) min(%.2g, %.2g) max(%.2g,%.2g) updown(%d)\n", r->n, r->x1/16.0, r->y1/16.0, r->x2/16.0, r->y2/16.0, r->minx/16.0, r->miny/16.0, r->maxx/16.0, r->maxy/16.0, r->updown); ); lminx = i_min( p_eval_aty(l, maxy), p_eval_aty(l, miny) ); lmaxx = i_max( p_eval_aty(l, maxy), p_eval_aty(l, miny) ); rminx = i_min( p_eval_aty(r, maxy), p_eval_aty(r, miny) ); rmaxx = i_max( p_eval_aty(r, maxy), p_eval_aty(r, miny) ); startpix = i_max( coarse(lminx), 0 ); stoppix = i_min( coarse(rmaxx-1), ss->linelen-1 ); POLY_DEB( printf(" miny=%g maxy=%g\n", miny/16.0, maxy/16.0) ); for(cpix=startpix; cpix<=stoppix; cpix++) { int lt = coarse(lmaxx-1) >= cpix; int rt = coarse(rminx) <= cpix; int A, B, C; POLY_DEB( printf(" (%d,%d) lt=%d rt=%d\n", cpix, y, lt, rt) ); A = lt ? pixel_coverage(l, cpix*16, cpix*16+16, miny, maxy) : 0; B = lt ? 0 : 16*(maxy-miny); C = rt ? pixel_coverage(r, cpix*16, cpix*16+16, miny, maxy) : 0; POLY_DEB( printf(" A=%d B=%d C=%d\n", A, B, C) ); ss->line[cpix] += A+B-C; } POLY_DEB( printf("end render_slice_scanline()\n") ); } /* Antialiasing polygon algorithm specs: 1. only nice polygons - no crossovers 2. 1/16 pixel resolution 3. full antialiasing ( complete spectrum of blends ) 4. uses hardly any memory 5. no subsampling phase Algorithm outline: 1. Split into vertical intervals. 2. handle each interval For each interval we must: 1. find which lines are in it 2. order the lines from in increasing x order. since we are assuming no crossovers it is sufficent to check a single point on each line. */ /* Definitions: 1. Interval: A vertical segment in which no lines cross nor end. 2. Scanline: A physical line, contains 16 subpixels in the horizontal direction 3. Slice: A start stop line pair. */ static int i_poly_poly_aa_low(i_img *im, int count, const i_polygon_t *polys, i_poly_fill_mode_t mode, void *ctx, scanline_flusher flusher) { int i ,k; /* Index variables */ i_img_dim clc; /* Lines inside current interval */ /* initialize to avoid compiler warnings */ pcord tempy = 0; i_img_dim cscl = 0; /* Current scanline */ ss_scanline templine; /* scanline accumulator */ p_point *pset; /* List of points in polygon */ p_line *lset; /* List of lines in polygon */ p_slice *tllist; /* List of slices */ size_t pcount, lcount; dIMCTX; im_log((aIMCTX, 1, "i_poly_poly_aa_low(im %p, count %d, polys %p, ctx %p, flusher %p)\n", im, count, polys, ctx, flusher)); i_clear_error(); if (count < 1) { i_push_error(0, "no polygons to draw"); return 0; } for (k = 0; k < count; ++k) { if (polys[k].count < 3) { i_push_errorf(0, "polygons must have at least 3 points"); return 0; } } for (k = 0; k < count; ++k) { const i_polygon_t *p = polys + k; im_log((aIMCTX, 2, "poly %d\n", k)); for(i = 0; i < p->count; i++) { im_log((aIMCTX, 2, " (%.2f, %.2f)\n", p->x[i], p->y[i])); } } POLY_DEB( fflush(stdout); setbuf(stdout, NULL); ); pset = point_set_new(polys, count, &pcount); lset = line_set_new(polys, count, &lcount); ss_scanline_init(&templine, im->xsize, lcount); tllist = mymalloc(sizeof(p_slice) * lcount); qsort(pset, pcount, sizeof(p_point), (int(*)(const void *,const void *))p_compy); POLY_DEB( for(i=0;i (%d , %d) yspan ( %d , %d )\n", i, lset[i].n, lset[i].x1, lset[i].y1, lset[i].x2, lset[i].y2, lset[i].miny, lset[i].maxy); } printf("MAIN LOOP\n\n"); ); /* loop on intervals */ for(i=0; iysize); pcord miny, maxy; /* y bounds in fine coordinates */ POLY_DEB( pcord cc = (pset[i].y + pset[i+1].y)/2 ); POLY_DEB( printf("current slice is %d: %d to %d ( cpoint %d ) scanlines %d to %d\n", i, pset[i].y, pset[i+1].y, cc, startscan, stopscan) ); if (pset[i].y == pset[i+1].y) { POLY_DEB( printf("current slice thickness = 0 => skipping\n") ); continue; } clc = lines_in_interval(lset, lcount, tllist, pset[i].y, pset[i+1].y); qsort(tllist, clc, sizeof(p_slice), (int(*)(const void *,const void *))p_compx); mark_updown_slices(aIMCTX, lset, tllist, clc); POLY_DEB ( printf("Interval contains %d lines\n", clc); for(k=0; k(%2d, %2d) (%2d/%2d, %2d/%2d) -> (%2d/%2d, %2d/%2d) alignment=%s\n", k, lno, ln->x1, ln->y1, ln->x2, ln->y2, coarse(ln->x1), fine(ln->x1), coarse(ln->y1), fine(ln->y1), coarse(ln->x2), fine(ln->x2), coarse(ln->y2), fine(ln->y2), ln->updown == 0 ? "vert" : ln->updown == 1 ? "up" : "down"); } ); maxy = im->ysize * 16; miny = 0; for (k = 0; k < clc; ++k) { p_line const * line = lset + tllist[k].n; if (line->miny > miny) miny = line->miny; if (line->maxy < maxy) maxy = line->maxy; POLY_DEB( printf(" line miny %g maxy %g\n", line->miny/16.0, line->maxy/16.0) ); } POLY_DEB( printf("miny %g maxy %g\n", miny/16.0, maxy/16.0) ); for(cscl=startscan; cscldir; while (k < clc && acc) { current = lset + tllist[k++].n; acc += current->dir; } if (acc == 0) { render_slice_scanline(&templine, cscl, left, current, scan_miny, scan_maxy); } } } if (16*coarse(tempy) == tempy) { POLY_DEB( printf("flushing scan line %d\n", cscl) ); flusher(im, &templine, cscl, ctx); ss_scanline_reset(&templine); } /* else { scanline_flush(im, &templine, cscl, val); ss_scanline_reset(&templine); return 0; } */ } } /* Intervals */ if (16*coarse(tempy) != tempy) flusher(im, &templine, cscl-1, ctx); ss_scanline_exorcise(&templine); myfree(pset); myfree(lset); myfree(tllist); return 1; } /* =item i_poly_poly_aa(im, count, polys, mode, color) =synopsis i_poly_poly_aa(im, 1, &poly, mode, color); =category Drawing Fill the C polygons defined by C the color specified by C. At least one polygon must be supplied. All polygons must have at least 3 points. =cut */ int i_poly_poly_aa(i_img *im, int count, const i_polygon_t *polys, i_poly_fill_mode_t mode, const i_color *val) { i_color c = *val; return i_poly_poly_aa_low(im, count, polys, mode, &c, scanline_flush); } /* =item i_poly_aa_m(im, count, x, y, mode, color) =synopsis i_poly_aa_m(im, count, x, y, mode, color); =category Drawing Fill a polygon defined by the points specified by the x and y arrays with the color specified by C. =cut */ int i_poly_aa_m(i_img *im, int l, const double *x, const double *y, i_poly_fill_mode_t mode, const i_color *val) { i_polygon_t poly; poly.count = l; poly.x = x; poly.y = y; return i_poly_poly_aa(im, 1, &poly, mode, val); } int i_poly_aa(i_img *im, int l, const double *x, const double *y, const i_color *val) { i_polygon_t poly; poly.count = l; poly.x = x; poly.y = y; return i_poly_poly_aa(im, 1, &poly, i_pfm_evenodd, val); } struct poly_render_state { i_render render; i_fill_t *fill; unsigned char *cover; }; static void scanline_flush_render(i_img *im, ss_scanline *ss, int y, void *ctx) { i_img_dim x; i_img_dim left, right; struct poly_render_state *state = (struct poly_render_state *)ctx; left = 0; while (left < im->xsize && ss->line[left] <= 0) ++left; if (left < im->xsize) { right = im->xsize; /* since going from the left found something, moving from the right should */ while (/* right > left && */ ss->line[right-1] <= 0) --right; /* convert to the format the render interface wants */ for (x = left; x < right; ++x) { state->cover[x-left] = saturate(ss->line[x]); } i_render_fill(&state->render, left, y, right-left, state->cover, state->fill); } } /* =item i_poly_poly_aa_cfill(im, count, polys, mode, fill) =synopsis i_poly_poly_aa_cfill(im, 1, &poly, mode, fill); =category Drawing Fill the C polygons defined by C the fill specified by C. At least one polygon must be supplied. All polygons must have at least 3 points. =cut */ int i_poly_poly_aa_cfill(i_img *im, int count, const i_polygon_t *polys, i_poly_fill_mode_t mode, i_fill_t *fill) { struct poly_render_state ctx; int result; i_render_init(&ctx.render, im, im->xsize); ctx.fill = fill; ctx.cover = mymalloc(im->xsize); result = i_poly_poly_aa_low(im, count, polys, mode, &ctx, scanline_flush_render); myfree(ctx.cover); i_render_done(&ctx.render); return result; } /* =item i_poly_aa_cfill_m(im, count, x, y, mode, fill) =synopsis i_poly_aa_cfill(im, count, x, y, mode, fill); =category Drawing Fill a polygon defined by the points specified by the x and y arrays with the fill specified by C. =cut */ int i_poly_aa_cfill_m(i_img *im, int l, const double *x, const double *y, i_poly_fill_mode_t mode, i_fill_t *fill) { i_polygon_t poly; poly.count = l; poly.x = x; poly.y = y; return i_poly_poly_aa_cfill(im, 1, &poly, mode, fill); } int i_poly_aa_cfill(i_img *im, int l, const double *x, const double *y, i_fill_t *fill) { i_polygon_t poly; poly.count = l; poly.x = x; poly.y = y; return i_poly_poly_aa_cfill(im, 1, &poly, i_pfm_evenodd, fill); } libimager-perl-1.004+dfsg.orig/hlines.c0000644000175000017500000002112712263740600017212 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imageri.h" #include #define OVERLAPPED(start1, end1, start2, end2) \ (im_max((start1), (start2)) <= im_min((end1), (end2))) /* =head1 NAME hlines.c - implements a "class" for managing sets of horizontal line segments =head1 SYNOPSIS i_int_hlines hlines; // just for the specified range of y i_int_init_hlines(&hlines, start_y, count_y, start_x, width_x); // to cover a whole image i_int_init_hlines_img(&hlines, img); // add a hline segment, merging into existing i_int_hlines_add(&hlines, y, x, width); // work over the lines for (y = hlines.start; y < hlines.limit; ++y) { i_int_hline_entry *entry = hlines.entries[i]; if (entry) { for (i = 0; i < entry->count; ++i) { i_int_hline_seg *seg = entry->segs+i; // do something on line y for seg->minx to x_limit } } } // free it all up i_int_hlines_destroy(&hlines); =head1 DESCRIPTION Provides a class to manage sets of horizontal line segments. The intent is that when drawing shapes where the algorithm used might cause overlaps we can use this class to resolve the overlaps. Note that segment lists are intended to remain small, if we end up with a need for longer lists we should use different structure for the segment lists. =over =item i_int_init_hlines i_int_init_hlines(&hlines, start_y, count_y, start_x, width_x) Initializes the structure based on drawing an object within the given range. Any x or y values outside the given ranges will be ignored. =cut */ void i_int_init_hlines( i_int_hlines *hlines, i_img_dim start_y, i_img_dim count_y, i_img_dim start_x, i_img_dim width_x ) { size_t bytes = count_y * sizeof(i_int_hline_entry *); if (bytes / count_y != sizeof(i_int_hline_entry *)) { dIMCTX; im_fatal(aIMCTX, 3, "integer overflow calculating memory allocation\n"); } hlines->start_y = start_y; hlines->limit_y = start_y + count_y; hlines->start_x = start_x; hlines->limit_x = start_x + width_x; hlines->entries = mymalloc(bytes); memset(hlines->entries, 0, bytes); } /* =item i_int_init_hlines_img i_int_init_hlines_img(img); Initialize a hlines object as if we could potentially draw anywhere on the image. =cut */ void i_int_init_hlines_img(i_int_hlines *hlines, i_img *img) { i_int_init_hlines(hlines, 0, img->ysize, 0, img->xsize); } /* =item i_int_hlines_add i_int_hlines_add(hlines, y, x, width) Add to the list, merging with existing entries. =cut */ void i_int_hlines_add(i_int_hlines *hlines, i_img_dim y, i_img_dim x, i_img_dim width) { i_img_dim x_limit = x + width; if (width < 0) { dIMCTX; im_fatal(aIMCTX, 3, "negative width %d passed to i_int_hlines_add\n", width); } /* just return if out of range */ if (y < hlines->start_y || y >= hlines->limit_y) return; if (x >= hlines->limit_x || x_limit < hlines->start_x) return; /* adjust x to our range */ if (x < hlines->start_x) x = hlines->start_x; if (x_limit > hlines->limit_x) x_limit = hlines->limit_x; if (x == x_limit) return; if (hlines->entries[y - hlines->start_y]) { i_int_hline_entry *entry = hlines->entries[y - hlines->start_y]; i_img_dim i, found = -1; for (i = 0; i < entry->count; ++i) { i_int_hline_seg *seg = entry->segs + i; if (OVERLAPPED(x, x_limit, seg->minx, seg->x_limit)) { found = i; break; } } if (found >= 0) { /* ok, we found an overlapping segment, any other overlapping segments need to be merged into the one we found */ i_int_hline_seg *merge_seg = entry->segs + found; /* merge in the segment we found */ x = im_min(x, merge_seg->minx); x_limit = im_max(x_limit, merge_seg->x_limit); /* look for other overlapping segments */ /* this could be a for(), but I'm using continue */ i = found + 1; while (i < entry->count) { i_int_hline_seg *seg = entry->segs + i; if (OVERLAPPED(x, x_limit, seg->minx, seg->x_limit)) { /* merge this into the current working segment, then delete it by moving the last segment (if this isn't it) into it's place */ x = im_min(x, seg->minx); x_limit = im_max(x_limit, seg->x_limit); if (i < entry->count-1) { *seg = entry->segs[entry->count-1]; --entry->count; continue; } else { --entry->count; break; } } ++i; } /* store it back */ merge_seg->minx = x; merge_seg->x_limit = x_limit; } else { i_int_hline_seg *seg; /* add a new segment */ if (entry->count == entry->alloc) { /* expand it */ size_t alloc = entry->alloc * 3 / 2; entry = myrealloc(entry, sizeof(i_int_hline_entry) + sizeof(i_int_hline_seg) * (alloc - 1)); entry->alloc = alloc; hlines->entries[y - hlines->start_y] = entry; } seg = entry->segs + entry->count++; seg->minx = x; seg->x_limit = x_limit; } } else { /* make a new one - start with space for 10 */ i_int_hline_entry *entry = mymalloc(sizeof(i_int_hline_entry) + sizeof(i_int_hline_seg) * 9); entry->alloc = 10; entry->count = 1; entry->segs[0].minx = x; entry->segs[0].x_limit = x_limit; hlines->entries[y - hlines->start_y] = entry; } } /* =item i_int_hlines_destroy i_int_hlines_destroy(&hlines) Releases all memory associated with the structure. =cut */ void i_int_hlines_destroy(i_int_hlines *hlines) { size_t entry_count = hlines->limit_y - hlines->start_y; size_t i; for (i = 0; i < entry_count; ++i) { if (hlines->entries[i]) myfree(hlines->entries[i]); } myfree(hlines->entries); } /* =item i_int_hlines_fill_color i_int_hlines_fill(im, hlines, color) Fill the areas given by hlines with color. =cut */ void i_int_hlines_fill_color(i_img *im, i_int_hlines *hlines, const i_color *col) { i_img_dim y, i, x; for (y = hlines->start_y; y < hlines->limit_y; ++y) { i_int_hline_entry *entry = hlines->entries[y - hlines->start_y]; if (entry) { for (i = 0; i < entry->count; ++i) { i_int_hline_seg *seg = entry->segs + i; for (x = seg->minx; x < seg->x_limit; ++x) { i_ppix(im, x, y, col); } } } } } /* =item i_int_hlines_fill_fill i_int_hlines_fill_fill(im, hlines, fill) =cut */ void i_int_hlines_fill_fill(i_img *im, i_int_hlines *hlines, i_fill_t *fill) { i_render r; i_img_dim y, i; i_render_init(&r, im, im->xsize); for (y = hlines->start_y; y < hlines->limit_y; ++y) { i_int_hline_entry *entry = hlines->entries[y - hlines->start_y]; if (entry) { for (i = 0; i < entry->count; ++i) { i_int_hline_seg *seg = entry->segs + i; i_img_dim width = seg->x_limit-seg->minx; i_render_fill(&r, seg->minx, y, width, NULL, fill); } } } i_render_done(&r); #if 1 #else if (im->bits == i_8_bits && fill->fill_with_color) { i_color *line = mymalloc(sizeof(i_color) * im->xsize); i_color *work = NULL; if (fill->combine) work = mymalloc(sizeof(i_color) * im->xsize); for (y = hlines->start_y; y < hlines->limit_y; ++y) { i_int_hline_entry *entry = hlines->entries[y - hlines->start_y]; if (entry) { for (i = 0; i < entry->count; ++i) { i_int_hline_seg *seg = entry->segs + i; i_img_dim width = seg->x_limit-seg->minx; if (fill->combine) { i_glin(im, seg->minx, seg->x_limit, y, line); (fill->fill_with_color)(fill, seg->minx, y, width, im->channels, work); (fill->combine)(line, work, im->channels, width); } else { (fill->fill_with_color)(fill, seg->minx, y, width, im->channels, line); } i_plin(im, seg->minx, seg->x_limit, y, line); } } } myfree(line); if (work) myfree(work); } else { i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize); i_fcolor *work = NULL; if (fill->combinef) work = mymalloc(sizeof(i_fcolor) * im->xsize); for (y = hlines->start_y; y < hlines->limit_y; ++y) { i_int_hline_entry *entry = hlines->entries[y - hlines->start_y]; if (entry) { for (i = 0; i < entry->count; ++i) { i_int_hline_seg *seg = entry->segs + i; i_img_dim width = seg->x_limit-seg->minx; if (fill->combinef) { i_glinf(im, seg->minx, seg->x_limit, y, line); (fill->fill_with_fcolor)(fill, seg->minx, y, width, im->channels, work); (fill->combinef)(line, work, im->channels, width); } else { (fill->fill_with_fcolor)(fill, seg->minx, y, width, im->channels, line); } i_plinf(im, seg->minx, seg->x_limit, y, line); } } } myfree(line); if (work) myfree(work); } #endif } /* =back =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut */ libimager-perl-1.004+dfsg.orig/doco.perl0000755000175000017500000000276212031434614017401 0ustar gregoagregoa#!/usr/bin/perl -w use strict; use Cwd; # doco.perl - 24 Jan 18:09:40 EST 2001 # Addi - (addi@umich.edu) # # Extract documentation and help from the source files # # -f list FIXME comments for files # -f list FIXME comments for all files # -d list pod comments from file my $comm = shift or USAGE(); my @files; if ($comm eq "-f") { if (@ARGV) { @files = @ARGV; } else { @files = getfiles(); } for my $file (@files) { local(*FH, $/); open(FH,"< $file") or die $!; my $data = ; close(FH); while( $data =~ m/FIXME:(.*?)\*\//sg ) { printf("%10.10s:%5d %s\n", $file, ptol($data, pos($data)), $1); } } exit(0); } if ($comm eq "-d") { USAGE() if !@ARGV; my $file = shift; getfiles(); local(*FH, $/); open(FH, "< $file") or die $!; my $data = ; close(FH); $data =~ s/^(=item)/\n$1/mg; $data =~ s/^(=cut)/\n~~~~~~~~\n\n$1\n\n/mg; print "\n"; open(FH,"|pod2text ") or die "Cannot run pod2text: $!\n"; print FH $data; close(FH); exit(2); } sub USAGE { print<<'EOF'; doco.perl [-f files| stuff] -f list FIXME comments for files. -f list FIXME comments for all files. EOF exit; } sub getfiles { my $BASE=cwd; local(*FH); open(FH,"$BASE/MANIFEST") or die "Cannot open MANIFEST file: $!\n"; my @MANIFEST = ; chomp(@MANIFEST); return grep { m/\.(c|im)\s*$/ } @MANIFEST; } # string position to line number in string sub ptol { my ($str, $pos) = @_; my $lcnt=1; $lcnt++ while(substr($str,0,$pos)=~m/\n/g); $lcnt; } libimager-perl-1.004+dfsg.orig/map.c0000644000175000017500000000311412263740601016502 0ustar gregoagregoa/* =head1 NAME map.c - inplace image mapping and related functionality =head1 SYNOPSIS i_map(srcimage, coeffs, outchans, inchans) =head1 DESCRIPTION Converts images from one format to another, typically in this case for converting from RGBA to greyscale and back. =over =cut */ #include "imager.h" /* =item i_map(im, mapcount, maps, chmasks) maps im inplace into another image. Each map is a unsigned char array of 256 entries, its corresponding channel mask is the same numbered entry in the chmasks array. If two maps apply to the same channel then the second one is used. If no map applies to a channel then that channel is not altered. mapcount is the number of maps. =cut */ void i_map(i_img *im, unsigned char (*maps)[256], unsigned int mask) { i_color *vals; i_img_dim x, y; int i, ch; int minset = -1, maxset = 0; mm_log((1,"i_map(im %p, maps %p, chmask %u)\n", im, maps, mask)); if (!mask) return; /* nothing to do here */ for(i=0; ichannels; i++) if (mask & (1<xsize); for (y = 0; y < im->ysize; ++y) { i_glin(im, 0, im->xsize, y, vals); for (x = 0; x < im->xsize; ++x) { for(ch = minset; ch<=maxset; ch++) { if (!maps[ch]) continue; vals[x].channel[ch] = maps[ch][vals[x].channel[ch]]; } } i_plin(im, 0, im->xsize, y, vals); } myfree(vals); } /* =back =head1 SEE ALSO Imager(3) =head1 AUTHOR Arnar M. Hrafnkelsson =cut */ libimager-perl-1.004+dfsg.orig/CountColor/0000755000175000017500000000000012617614576017667 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/CountColor/CountColor.xs0000644000175000017500000000160112263740577022326 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #ifdef __cplusplus } #endif #include "imext.h" #include "imperl.h" DEFINE_IMAGER_CALLBACKS; int count_color(i_img *im, i_color *color) { i_img_dim x, y; int chan; i_color c; int count = 0; for (x = 0; x < im->xsize; ++x) { for (y = 0; y < im->ysize; ++y) { int match = 1; i_gpix(im, x, y, &c); for (chan = 0; chan < im->channels; ++chan) { if (c.channel[chan] != color->channel[chan]) { match = 0; break; } } if (match) ++count; } } return count; } MODULE = Imager::CountColor PACKAGE = Imager::CountColor PROTOTYPES: ENABLE int count_color(im, color) Imager::ImgRaw im Imager::Color color BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/CountColor/t/0000755000175000017500000000000012617614576020132 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/CountColor/t/t00countcolor.t0000644000175000017500000000164712031434613023020 0ustar gregoagregoa#!perl -w use strict; use blib; use Imager; use Test::More tests => 9; BEGIN { use_ok('Imager::CountColor' => 'count_color') } my $black = Imager::Color->new(0, 0, 0); my $blue = Imager::Color->new(0, 0, 255); my $red = Imager::Color->new(255, 0, 0); my $im = Imager->new(xsize=>50, ysize=>50); is(count_color($im, $black), 2500, "check black vs black image"); is(count_color($im, $red), 0, "check red vs black image"); $im->box(filled=>1, color=>$blue, xmin=>25); is(count_color($im, $black), 1250, "check black vs black/blue image"); is(count_color($im, $red), 0, "check red vs black/blue image"); is(count_color($im, $blue), 1250, "check blue vs black/blue image"); $im->box(filled=>1, color=>$red, ymin=>25); is(count_color($im, $black), 625, "check black vs black/blue/red image"); is(count_color($im, $blue), 625, "check black vs black/blue/red image"); is(count_color($im, $red), 1250, "check black vs black/blue/red image"); libimager-perl-1.004+dfsg.orig/CountColor/Makefile.PL0000644000175000017500000000057612567572530021646 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; my %opts = ( NAME => 'Imager::CountColor', VERSION_FROM => 'CountColor.pm', OBJECT => 'CountColor.o', INC => '-I..', ); my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'Color Count an Imager image'; } WriteMakefile(%opts); libimager-perl-1.004+dfsg.orig/CountColor/CountColor.pm0000644000175000017500000000150312263740577022311 0ustar gregoagregoapackage Imager::CountColor; use strict; use Imager; use vars qw($VERSION @ISA @EXPORT_OK); require Exporter; @EXPORT_OK = 'count_color'; BEGIN { $VERSION = "0.02"; @ISA = qw(Exporter); require XSLoader; XSLoader::load('Imager::CountColor', $VERSION); } 1; __END__ =head1 NAME Imager::CountColor - demonstrates writing a simple function using Imager. =head1 SYNOPSIS use Imager; use Imager::CountColor; my $im = Imager->new(...); # some Imager image ...; # some sort of manipulation print count_color($im, $color_object); =head1 DESCRIPTION This module is a simple demonstration of how to create an XS module that works with Imager objects. You may want to copy the source for this module as a start. =head1 SEE ALSO Imager, Imager::Filter::DynTest =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/draw.h0000644000175000017500000000103312370401737016670 0ustar gregoagregoa#include "imager.h" typedef struct { i_img_dim min,max; } minmax; typedef struct { minmax *data; i_img_dim lines; } i_mmarray; /* FIXME: Merge this into datatypes.{c,h} */ void i_mmarray_cr(i_mmarray *ar,i_img_dim l); void i_mmarray_dst(i_mmarray *ar); void i_mmarray_add(i_mmarray *ar,i_img_dim x,i_img_dim y); i_img_dim i_mmarray_gmin(i_mmarray *ar,i_img_dim y); i_img_dim i_mmarray_getm(i_mmarray *ar,i_img_dim y); void i_mmarray_info(i_mmarray *ar); #if 0 void i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val); #endif libimager-perl-1.004+dfsg.orig/ext.h0000644000175000017500000000361712263740600016541 0ustar gregoagregoa#include "imdatatypes.h" #ifndef IMAGER_EXT_H #define IMAGER_EXT_H /* structures for passing data between Imager-plugin and the Imager-module */ typedef struct { char *name; void (*iptr)(void* ptr); char *pcode; } func_ptr; typedef struct { int (*getstr)(void *hv_t,char* key,char **store); int (*getint)(void *hv_t,char *key,int *store); int (*getdouble)(void *hv_t,char* key,double *store); int (*getvoid)(void *hv_t,char* key,void **store); int (*getobj)(void *hv_t,char* key,char* type,void **store); } UTIL_table_t; typedef struct { undef_int (*i_has_format)(char *frmt); i_color*(*ICL_set)(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a); void (*ICL_info)(const i_color *cl); im_context_t (*im_get_context_f)(void); i_img*(*im_img_empty_ch_f)(im_context_t, i_img *im,i_img_dim x,i_img_dim y,int ch); void(*i_img_exorcise_f)(i_img *im); void(*i_img_info_f)(i_img *im,i_img_dim *info); void(*i_img_setmask_f)(i_img *im,int ch_mask); int (*i_img_getmask_f)(i_img *im); /* int (*i_ppix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val); int (*i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val); */ void(*i_box)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val); void(*i_line)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val,int endp); void(*i_arc)(i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,const i_color *val); void(*i_copyto)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty); void(*i_copyto_trans)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans); int(*i_rubthru)(i_img *im,i_img *src,i_img_dim tx,i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy); } symbol_table_t; #endif libimager-perl-1.004+dfsg.orig/PNG/0000755000175000017500000000000012617614576016224 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/PNG/impng.c0000644000175000017500000010642712263740600017475 0ustar gregoagregoa#include "impng.h" #include "png.h" #include #include /* this is a way to get number of channels from color space * Color code to channel number */ static int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA]; #define PNG_BYTES_TO_CHECK 4 static i_img * read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height); static i_img * read_direct16(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height); static i_img * read_paletted(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height); static i_img * read_bilevel(png_structp png_ptr, png_infop info_ptr, i_img_dim width, i_img_dim height); static int write_direct8(png_structp png_ptr, png_infop info_ptr, i_img *im); static int write_direct16(png_structp png_ptr, png_infop info_ptr, i_img *im); static int write_paletted(png_structp png_ptr, png_infop info_ptr, i_img *im, int bits); static int write_bilevel(png_structp png_ptr, png_infop info_ptr, i_img *im); static void get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth, int color_type); static int set_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr); static const char * get_string2(i_img_tags *tags, const char *name, char *buf, size_t *size); unsigned i_png_lib_version(void) { return png_access_version_number(); } static char const * const features[] = { #ifdef PNG_BENIGN_ERRORS_SUPPORTED "benign-errors", #endif #ifdef PNG_READ_SUPPORTED "read", #endif #ifdef PNG_WRITE_SUPPORTED "write", #endif #ifdef PNG_MNG_FEATURES_SUPPORTED "mng-features", #endif #ifdef PNG_CHECK_cHRM_SUPPORTED "check-cHRM", #endif #ifdef PNG_SET_USER_LIMITS_SUPPORTED "user-limits", #endif NULL }; const char * const * i_png_features(void) { return features; } static void wiol_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { io_glue *ig = png_get_io_ptr(png_ptr); ssize_t rc = i_io_read(ig, data, length); if (rc != length) png_error(png_ptr, "Read overflow error on an iolayer source."); } static void wiol_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { ssize_t rc; io_glue *ig = png_get_io_ptr(png_ptr); rc = i_io_write(ig, data, length); if (rc != length) png_error(png_ptr, "Write error on an iolayer source."); } static void wiol_flush_data(png_structp png_ptr) { io_glue *ig = png_get_io_ptr(png_ptr); if (!i_io_flush(ig)) png_error(png_ptr, "Error flushing output"); } static void error_handler(png_structp png_ptr, png_const_charp msg) { mm_log((1, "PNG error: '%s'\n", msg)); i_push_error(0, msg); longjmp(png_jmpbuf(png_ptr), 1); } /* For writing a warning might have information about an error, so send it to the error stack. */ static void write_warn_handler(png_structp png_ptr, png_const_charp msg) { mm_log((1, "PNG write warning '%s'\n", msg)); i_push_error(0, msg); } #define PNG_DIM_MAX 0x7fffffffL undef_int i_writepng_wiol(i_img *im, io_glue *ig) { png_structp png_ptr; png_infop info_ptr = NULL; i_img_dim width,height; volatile int cspace,channels; int bits; int is_bilevel = 0, zero_is_white; mm_log((1,"i_writepng(im %p ,ig %p)\n", im, ig)); i_clear_error(); if (im->xsize > PNG_UINT_31_MAX || im->ysize > PNG_UINT_31_MAX) { i_push_error(0, "image too large for PNG"); return 0; } height = im->ysize; width = im->xsize; /* if we ever have 64-bit i_img_dim * the libpng docs state that png_set_user_limits() can be used to * override the PNG_USER_*_MAX limits, but as implemented they * don't. We check against the theoretical limit of PNG here, and * try to override the limits below, in case the libpng * implementation ever matches the documentation. * * https://sourceforge.net/tracker/?func=detail&atid=105624&aid=3314943&group_id=5624 * fixed in libpng 1.5.3 */ if (width > PNG_DIM_MAX || height > PNG_DIM_MAX) { i_push_error(0, "Image too large for PNG"); return 0; } channels=im->channels; if (i_img_is_monochrome(im, &zero_is_white)) { is_bilevel = 1; bits = 1; cspace = PNG_COLOR_TYPE_GRAY; mm_log((1, "i_writepng: bilevel output\n")); } else if (im->type == i_palette_type) { int colors = i_colorcount(im); cspace = PNG_COLOR_TYPE_PALETTE; bits = 1; while ((1 << bits) < colors) { bits += bits; } mm_log((1, "i_writepng: paletted output\n")); } else { switch (channels) { case 1: cspace = PNG_COLOR_TYPE_GRAY; break; case 2: cspace = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: cspace = PNG_COLOR_TYPE_RGB; break; case 4: cspace = PNG_COLOR_TYPE_RGB_ALPHA; break; default: fprintf(stderr, "Internal error, channels = %d\n", channels); abort(); } bits = im->bits > 8 ? 16 : 8; mm_log((1, "i_writepng: direct output\n")); } mm_log((1,"i_writepng: cspace=%d, bits=%d\n",cspace, bits)); /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, error_handler, write_warn_handler); if (png_ptr == NULL) return 0; /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } /* Set error handling. REQUIRED if you aren't supplying your own * error hadnling functions in the png_create_write_struct() call. */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return(0); } png_set_write_fn(png_ptr, (png_voidp) (ig), wiol_write_data, wiol_flush_data); /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ /* by default, libpng (not PNG) limits the image size to a maximum * 1000000 pixels in each direction, but Imager doesn't. * Configure libpng to avoid that limit. */ png_set_user_limits(png_ptr, width, height); png_set_IHDR(png_ptr, info_ptr, width, height, bits, cspace, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (!set_png_tags(im, png_ptr, info_ptr)) { png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } if (is_bilevel) { if (!write_bilevel(png_ptr, info_ptr, im)) { png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } } else if (im->type == i_palette_type) { if (!write_paletted(png_ptr, info_ptr, im, bits)) { png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } } else if (bits == 16) { if (!write_direct16(png_ptr, info_ptr, im)) { png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } } else { if (!write_direct8(png_ptr, info_ptr, im)) { png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); if (i_io_close(ig)) return 0; return(1); } typedef struct { char *warnings; } i_png_read_state, *i_png_read_statep; static void read_warn_handler(png_structp, png_const_charp); static void cleanup_read_state(i_png_read_statep); i_img* i_readpng_wiol(io_glue *ig, int flags) { i_img *im = NULL; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; int channels; unsigned int sig_read; i_png_read_state rs; rs.warnings = NULL; sig_read = 0; mm_log((1,"i_readpng_wiol(ig %p)\n", ig)); i_clear_error(); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &rs, error_handler, read_warn_handler); if (!png_ptr) { i_push_error(0, "Cannot create PNG read structure"); return NULL; } png_set_read_fn(png_ptr, (png_voidp) (ig), wiol_read_data); #if defined(PNG_BENIGN_ERRORS_SUPPORTED) png_set_benign_errors(png_ptr, (flags & IMPNG_READ_IGNORE_BENIGN_ERRORS) ? 1 : 0); #elif PNG_LIBPNG_VER >= 10400 if (flags & IMPNG_READ_IGNORE_BENIGN_ERRORS) { i_push_error(0, "libpng not configured to ignore benign errors"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } #else if (flags & IMPNG_READ_IGNORE_BENIGN_ERRORS) { i_push_error(0, "libpng too old to ignore benign errors"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } #endif info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); i_push_error(0, "Cannot create PNG info structure"); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { if (im) i_img_destroy(im); mm_log((1,"i_readpng_wiol: error.\n")); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); cleanup_read_state(&rs); return NULL; } /* we do our own limit checks */ png_set_user_limits(png_ptr, PNG_DIM_MAX, PNG_DIM_MAX); png_set_sig_bytes(png_ptr, sig_read); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); mm_log((1, "png_get_IHDR results: width %u, height %u, bit_depth %d, color_type %d, interlace_type %d\n", (unsigned)width, (unsigned)height, bit_depth,color_type,interlace_type)); CC2C[PNG_COLOR_TYPE_GRAY]=1; CC2C[PNG_COLOR_TYPE_PALETTE]=3; CC2C[PNG_COLOR_TYPE_RGB]=3; CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4; CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2; channels = CC2C[color_type]; mm_log((1,"i_readpng_wiol: channels %d\n",channels)); if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) { mm_log((1, "i_readpnm: image size exceeds limits\n")); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return NULL; } if (color_type == PNG_COLOR_TYPE_PALETTE) { im = read_paletted(png_ptr, info_ptr, channels, width, height); } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 1 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { im = read_bilevel(png_ptr, info_ptr, width, height); } else if (bit_depth == 16) { im = read_direct16(png_ptr, info_ptr, channels, width, height); } else { im = read_direct8(png_ptr, info_ptr, channels, width, height); } if (im) get_png_tags(im, png_ptr, info_ptr, bit_depth, color_type); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if (im) { if (rs.warnings) { i_tags_set(&im->tags, "png_warnings", rs.warnings, -1); } } cleanup_read_state(&rs); mm_log((1,"(%p) <- i_readpng_wiol\n", im)); return im; } static i_img * read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height) { i_img * volatile vim = NULL; int color_type = png_get_color_type(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); i_img_dim y; int number_passes, pass; i_img *im; unsigned char *line; unsigned char * volatile vline = NULL; if (setjmp(png_jmpbuf(png_ptr))) { if (vim) i_img_destroy(vim); if (vline) myfree(vline); return NULL; } number_passes = png_set_interlace_handling(png_ptr); mm_log((1,"number of passes=%d\n",number_passes)); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { channels++; mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels)); png_set_expand(png_ptr); } png_read_update_info(png_ptr, info_ptr); im = vim = i_img_8_new(width,height,channels); if (!im) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return NULL; } line = vline = mymalloc(channels * width); for (pass = 0; pass < number_passes; pass++) { for (y = 0; y < height; y++) { if (pass > 0) i_gsamp(im, 0, width, y, line, NULL, channels); png_read_row(png_ptr,(png_bytep)line, NULL); i_psamp(im, 0, width, y, line, NULL, channels); } } myfree(line); vline = NULL; png_read_end(png_ptr, info_ptr); return im; } static i_img * read_direct16(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height) { i_img * volatile vim = NULL; i_img_dim x, y; int number_passes, pass; i_img *im; unsigned char *line; unsigned char * volatile vline = NULL; unsigned *bits_line; unsigned * volatile vbits_line = NULL; size_t row_bytes; if (setjmp(png_jmpbuf(png_ptr))) { if (vim) i_img_destroy(vim); if (vline) myfree(vline); if (vbits_line) myfree(vbits_line); return NULL; } number_passes = png_set_interlace_handling(png_ptr); mm_log((1,"number of passes=%d\n",number_passes)); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { channels++; mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels)); png_set_expand(png_ptr); } png_read_update_info(png_ptr, info_ptr); im = vim = i_img_16_new(width,height,channels); if (!im) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return NULL; } row_bytes = png_get_rowbytes(png_ptr, info_ptr); line = vline = mymalloc(row_bytes); memset(line, 0, row_bytes); bits_line = vbits_line = mymalloc(sizeof(unsigned) * width * channels); for (pass = 0; pass < number_passes; pass++) { for (y = 0; y < height; y++) { if (pass > 0) { i_gsamp_bits(im, 0, width, y, bits_line, NULL, channels, 16); for (x = 0; x < width * channels; ++x) { line[x*2] = bits_line[x] >> 8; line[x*2+1] = bits_line[x] & 0xff; } } png_read_row(png_ptr,(png_bytep)line, NULL); for (x = 0; x < width * channels; ++x) bits_line[x] = (line[x*2] << 8) + line[x*2+1]; i_psamp_bits(im, 0, width, y, bits_line, NULL, channels, 16); } } myfree(line); myfree(bits_line); vline = NULL; vbits_line = NULL; png_read_end(png_ptr, info_ptr); return im; } static i_img * read_bilevel(png_structp png_ptr, png_infop info_ptr, i_img_dim width, i_img_dim height) { i_img * volatile vim = NULL; i_img_dim x, y; int number_passes, pass; i_img *im; unsigned char *line; unsigned char * volatile vline = NULL; i_color palette[2]; if (setjmp(png_jmpbuf(png_ptr))) { if (vim) i_img_destroy(vim); if (vline) myfree(vline); return NULL; } number_passes = png_set_interlace_handling(png_ptr); mm_log((1,"number of passes=%d\n",number_passes)); png_set_packing(png_ptr); png_set_expand(png_ptr); png_read_update_info(png_ptr, info_ptr); im = vim = i_img_pal_new(width, height, 1, 256); if (!im) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return NULL; } palette[0].channel[0] = palette[0].channel[1] = palette[0].channel[2] = palette[0].channel[3] = 0; palette[1].channel[0] = palette[1].channel[1] = palette[1].channel[2] = palette[1].channel[3] = 255; i_addcolors(im, palette, 2); line = vline = mymalloc(width); memset(line, 0, width); for (pass = 0; pass < number_passes; pass++) { for (y = 0; y < height; y++) { if (pass > 0) { i_gpal(im, 0, width, y, line); /* expand indexes back to 0/255 */ for (x = 0; x < width; ++x) line[x] = line[x] ? 255 : 0; } png_read_row(png_ptr,(png_bytep)line, NULL); /* back to palette indexes */ for (x = 0; x < width; ++x) line[x] = line[x] ? 1 : 0; i_ppal(im, 0, width, y, line); } } myfree(line); vline = NULL; png_read_end(png_ptr, info_ptr); return im; } /* FIXME: do we need to unscale palette color values from the supplied alphas? */ static i_img * read_paletted(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height) { i_img * volatile vim = NULL; int color_type = png_get_color_type(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); i_img_dim y; int number_passes, pass; i_img *im; unsigned char *line; unsigned char * volatile vline = NULL; int num_palette, i; png_colorp png_palette; png_bytep png_pal_trans; png_color_16p png_color_trans; int num_pal_trans; if (setjmp(png_jmpbuf(png_ptr))) { if (vim) i_img_destroy(vim); if (vline) myfree(vline); return NULL; } number_passes = png_set_interlace_handling(png_ptr); mm_log((1,"number of passes=%d\n",number_passes)); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (!png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_palette)) { i_push_error(0, "Paletted image with no PLTE chunk"); return NULL; } if (png_get_tRNS(png_ptr, info_ptr, &png_pal_trans, &num_pal_trans, &png_color_trans)) { channels++; } else { num_pal_trans = 0; } png_read_update_info(png_ptr, info_ptr); im = vim = i_img_pal_new(width, height, channels, 256); if (!im) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return NULL; } for (i = 0; i < num_palette; ++i) { i_color c; c.rgba.r = png_palette[i].red; c.rgba.g = png_palette[i].green; c.rgba.b = png_palette[i].blue; if (i < num_pal_trans) c.rgba.a = png_pal_trans[i]; else c.rgba.a = 255; i_addcolors(im, &c, 1); } line = vline = mymalloc(width); for (pass = 0; pass < number_passes; pass++) { for (y = 0; y < height; y++) { if (pass > 0) i_gpal(im, 0, width, y, line); png_read_row(png_ptr,(png_bytep)line, NULL); i_ppal(im, 0, width, y, line); } } myfree(line); vline = NULL; png_read_end(png_ptr, info_ptr); return im; } struct png_text_name { const char *keyword; const char *tagname; }; static const struct png_text_name text_tags[] = { { "Author", "png_author" }, { "Comment", "i_comment" }, { "Copyright", "png_copyright" }, { "Creation Time", "png_creation_time" }, { "Description", "png_description" }, { "Disclaimer", "png_disclaimer" }, { "Software", "png_software" }, { "Source", "png_source" }, { "Title", "png_title" }, { "Warning", "png_warning" } }; static const int text_tags_count = sizeof(text_tags) / sizeof(*text_tags); static const char * const chroma_tags[] = { "png_chroma_white_x", "png_chroma_white_y", "png_chroma_red_x", "png_chroma_red_y", "png_chroma_green_x", "png_chroma_green_y", "png_chroma_blue_x", "png_chroma_blue_y" }; static const int chroma_tag_count = sizeof(chroma_tags) / sizeof(*chroma_tags); static void get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth, int color_type) { png_uint_32 xres, yres; int unit_type; i_tags_set(&im->tags, "i_format", "png", -1); if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) { mm_log((1,"pHYs (%u, %u) %d\n", (unsigned)xres, (unsigned)yres, unit_type)); if (unit_type == PNG_RESOLUTION_METER) { i_tags_set_float2(&im->tags, "i_xres", 0, xres * 0.0254, 5); i_tags_set_float2(&im->tags, "i_yres", 0, yres * 0.0254, 5); } else { i_tags_setn(&im->tags, "i_xres", xres); i_tags_setn(&im->tags, "i_yres", yres); i_tags_setn(&im->tags, "i_aspect_only", 1); } } { int interlace = png_get_interlace_type(png_ptr, info_ptr); i_tags_setn(&im->tags, "png_interlace", interlace != PNG_INTERLACE_NONE); switch (interlace) { case PNG_INTERLACE_NONE: i_tags_set(&im->tags, "png_interlace_name", "none", -1); break; case PNG_INTERLACE_ADAM7: i_tags_set(&im->tags, "png_interlace_name", "adam7", -1); break; default: i_tags_set(&im->tags, "png_interlace_name", "unknown", -1); break; } } /* the various readers can call png_set_expand(), libpng will make it's internal record of bit_depth at least 8 in that case */ i_tags_setn(&im->tags, "png_bits", bit_depth); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { int intent; if (png_get_sRGB(png_ptr, info_ptr, &intent)) { i_tags_setn(&im->tags, "png_srgb_intent", intent); } } else { /* Ignore these if there's an sRGB chunk, libpng simulates their existence if there's an sRGB chunk, and the PNG spec says that these are ignored if the sRGB is present, so ignore them. */ double gamma; double chroma[8]; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { i_tags_set_float2(&im->tags, "png_gamma", 0, gamma, 4); } if (png_get_cHRM(png_ptr, info_ptr, chroma+0, chroma+1, chroma+2, chroma+3, chroma+4, chroma+5, chroma+6, chroma+7)) { int i; for (i = 0; i < chroma_tag_count; ++i) i_tags_set_float2(&im->tags, chroma_tags[i], 0, chroma[i], 4); } } { int num_text; png_text *text; if (png_get_text(png_ptr, info_ptr, &text, &num_text)) { int i; int custom_index = 0; for (i = 0; i < num_text; ++i) { int j; int found = 0; int compressed = text[i].compression == PNG_ITXT_COMPRESSION_zTXt || text[i].compression == PNG_TEXT_COMPRESSION_zTXt; for (j = 0; j < text_tags_count; ++j) { if (strcmp(text_tags[j].keyword, text[i].key) == 0) { char tag_name[50]; i_tags_set(&im->tags, text_tags[j].tagname, text[i].text, -1); if (compressed) { sprintf(tag_name, "%s_compressed", text_tags[j].tagname); i_tags_setn(&im->tags, tag_name, 1); } found = 1; break; } } if (!found) { char tag_name[50]; sprintf(tag_name, "png_text%d_key", custom_index); i_tags_set(&im->tags, tag_name, text[i].key, -1); sprintf(tag_name, "png_text%d_text", custom_index); i_tags_set(&im->tags, tag_name, text[i].text, -1); sprintf(tag_name, "png_text%d_type", custom_index); i_tags_set(&im->tags, tag_name, (text[i].compression == PNG_TEXT_COMPRESSION_NONE || text[i].compression == PNG_TEXT_COMPRESSION_zTXt) ? "text" : "itxt", -1); if (compressed) { sprintf(tag_name, "png_text%d_compressed", custom_index); i_tags_setn(&im->tags, tag_name, 1); } ++custom_index; } } } } { png_time *mod_time; if (png_get_tIME(png_ptr, info_ptr, &mod_time)) { char time_formatted[80]; sprintf(time_formatted, "%d-%02d-%02dT%02d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second); i_tags_set(&im->tags, "png_time", time_formatted, -1); } } { png_color_16 *back; i_color c; if (png_get_bKGD(png_ptr, info_ptr, &back)) { switch (color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: { /* lib png stores the raw gray value rather than scaling it to 16-bit (or 8), we use 8-bit color for i_background */ int gray; switch (bit_depth) { case 16: gray = back->gray >> 8; break; case 8: gray = back->gray; break; case 4: gray = 0x11 * back->gray; break; case 2: gray = 0x55 * back->gray; break; case 1: gray = back->gray ? 0xFF : 0; break; default: gray = 0; } c.rgb.r = c.rgb.g = c.rgb.b = gray; break; } case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: { c.rgb.r = bit_depth == 16 ? (back->red >> 8) : back->red; c.rgb.g = bit_depth == 16 ? (back->green >> 8) : back->green; c.rgb.b = bit_depth == 16 ? (back->blue >> 8) : back->blue; break; } case PNG_COLOR_TYPE_PALETTE: c.rgb.r = back->red; c.rgb.g = back->green; c.rgb.b = back->blue; break; } c.rgba.a = 255; i_tags_set_color(&im->tags, "i_background", 0, &c); } } } #define GET_STR_BUF_SIZE 40 static int set_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr) { double xres, yres; int aspect_only, have_res = 1; if (i_tags_get_float(&im->tags, "i_xres", 0, &xres)) { if (i_tags_get_float(&im->tags, "i_yres", 0, &yres)) ; /* nothing to do */ else yres = xres; } else { if (i_tags_get_float(&im->tags, "i_yres", 0, &yres)) xres = yres; else have_res = 0; } if (have_res) { aspect_only = 0; i_tags_get_int(&im->tags, "i_aspect_only", 0, &aspect_only); xres /= 0.0254; yres /= 0.0254; png_set_pHYs(png_ptr, info_ptr, xres + 0.5, yres + 0.5, aspect_only ? PNG_RESOLUTION_UNKNOWN : PNG_RESOLUTION_METER); } { int intent; if (i_tags_get_int(&im->tags, "png_srgb_intent", 0, &intent)) { if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) { i_push_error(0, "tag png_srgb_intent out of range"); return 0; } png_set_sRGB(png_ptr, info_ptr, intent); } else { double chroma[8], gamma; int i; int found_chroma_count = 0; for (i = 0; i < chroma_tag_count; ++i) { if (i_tags_get_float(&im->tags, chroma_tags[i], 0, chroma+i)) ++found_chroma_count; } if (found_chroma_count) { if (found_chroma_count != chroma_tag_count) { i_push_error(0, "all png_chroma_* tags must be supplied or none"); return 0; } png_set_cHRM(png_ptr, info_ptr, chroma[0], chroma[1], chroma[2], chroma[3], chroma[4], chroma[5], chroma[6], chroma[7]); } if (i_tags_get_float(&im->tags, "png_gamma", 0, &gamma)) { png_set_gAMA(png_ptr, info_ptr, gamma); } } } { /* png_set_text() is sparsely documented, it isn't indicated whether multiple calls add to or replace the lists of texts, and whether the text/keyword data is copied or not. Examining the linpng code reveals that png_set_text() adds to the list and that the text is copied. */ int i; /* do our standard tags */ for (i = 0; i < text_tags_count; ++i) { char buf[GET_STR_BUF_SIZE]; size_t size; const char *data; data = get_string2(&im->tags, text_tags[i].tagname, buf, &size); if (data) { png_text text; int compression = size > 1000; char compress_tag[40]; if (memchr(data, '\0', size)) { i_push_errorf(0, "tag %s may not contain NUL characters", text_tags[i].tagname); return 0; } sprintf(compress_tag, "%s_compressed", text_tags[i].tagname); i_tags_get_int(&im->tags, compress_tag, 0, &compression); text.compression = compression ? PNG_TEXT_COMPRESSION_zTXt : PNG_TEXT_COMPRESSION_NONE; text.key = (char *)text_tags[i].keyword; text.text_length = size; text.text = (char *)data; #ifdef PNG_iTXt_SUPPORTED text.itxt_length = 0; text.lang = NULL; text.lang_key = NULL; #endif png_set_text(png_ptr, info_ptr, &text, 1); } } /* for non-standard tags ensure keywords are limited to 1 to 79 characters */ i = 0; while (1) { char tag_name[50]; char key_buf[GET_STR_BUF_SIZE], value_buf[GET_STR_BUF_SIZE]; const char *key, *value; size_t key_size, value_size; sprintf(tag_name, "png_text%d_key", i); key = get_string2(&im->tags, tag_name, key_buf, &key_size); if (key) { size_t k; if (key_size < 1 || key_size > 79) { i_push_errorf(0, "tag %s must be between 1 and 79 characters in length", tag_name); return 0; } if (key[0] == ' ' || key[key_size-1] == ' ') { i_push_errorf(0, "tag %s may not contain leading or trailing spaces", tag_name); return 0; } if (strstr(key, " ")) { i_push_errorf(0, "tag %s may not contain consecutive spaces", tag_name); return 0; } for (k = 0; k < key_size; ++k) { if (key[k] < 32 || (key[k] > 126 && key[k] < 161)) { i_push_errorf(0, "tag %s may only contain Latin1 characters 32-126, 161-255", tag_name); return 0; } } } sprintf(tag_name, "png_text%d_text", i); value = get_string2(&im->tags, tag_name, value_buf, &value_size); if (value) { if (memchr(value, '\0', value_size)) { i_push_errorf(0, "tag %s may not contain NUL characters", tag_name); return 0; } } if (key && value) { png_text text; int compression = value_size > 1000; sprintf(tag_name, "png_text%d_compressed", i); i_tags_get_int(&im->tags, tag_name, 0, &compression); text.compression = compression ? PNG_TEXT_COMPRESSION_zTXt : PNG_TEXT_COMPRESSION_NONE; text.key = (char *)key; text.text_length = value_size; text.text = (char *)value; #ifdef PNG_iTXt_SUPPORTED text.itxt_length = 0; text.lang = NULL; text.lang_key = NULL; #endif png_set_text(png_ptr, info_ptr, &text, 1); } else if (key) { i_push_errorf(0, "tag png_text%d_key found but not png_text%d_text", i, i); return 0; } else if (value) { i_push_errorf(0, "tag png_text%d_text found but not png_text%d_key", i, i); return 0; } else { break; } ++i; } } { char buf[GET_STR_BUF_SIZE]; size_t time_size; const char *timestr = get_string2(&im->tags, "png_time", buf, &time_size); if (timestr) { int year, month, day, hour, minute, second; png_time mod_time; if (sscanf(timestr, "%d-%d-%dT%d:%d:%d", &year, &month, &day, &hour, &minute, &second) == 6) { /* rough validation */ if (month < 1 || month > 12 || day < 1 || day > 31 || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 60) { i_push_error(0, "invalid date/time for png_time"); return 0; } mod_time.year = year; mod_time.month = month; mod_time.day = day; mod_time.hour = hour; mod_time.minute = minute; mod_time.second = second; png_set_tIME(png_ptr, info_ptr, &mod_time); } else { i_push_error(0, "png_time must be formatted 'y-m-dTh:m:s'"); return 0; } } } { /* no bKGD support yet, maybe later it may be simpler to do it in the individual writers */ } return 1; } static const char * get_string2(i_img_tags *tags, const char *name, char *buf, size_t *size) { int index; if (i_tags_find(tags, name, 0, &index)) { const i_img_tag *entry = tags->tags + index; if (entry->data) { *size = entry->size; return entry->data; } else { *size = sprintf(buf, "%d", entry->idata); return buf; } } return NULL; } static int write_direct8(png_structp png_ptr, png_infop info_ptr, i_img *im) { unsigned char *data, *volatile vdata = NULL; i_img_dim y; if (setjmp(png_jmpbuf(png_ptr))) { if (vdata) myfree(vdata); return 0; } png_write_info(png_ptr, info_ptr); vdata = data = mymalloc(im->xsize * im->channels); for (y = 0; y < im->ysize; y++) { i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels); png_write_row(png_ptr, (png_bytep)data); } myfree(data); return 1; } static int write_direct16(png_structp png_ptr, png_infop info_ptr, i_img *im) { unsigned *data, *volatile vdata = NULL; unsigned char *tran_data, * volatile vtran_data = NULL; i_img_dim samples_per_row = im->xsize * im->channels; i_img_dim y; if (setjmp(png_jmpbuf(png_ptr))) { if (vdata) myfree(vdata); if (vtran_data) myfree(vtran_data); return 0; } png_write_info(png_ptr, info_ptr); vdata = data = mymalloc(samples_per_row * sizeof(unsigned)); vtran_data = tran_data = mymalloc(samples_per_row * 2); for (y = 0; y < im->ysize; y++) { i_img_dim i; unsigned char *p = tran_data; i_gsamp_bits(im, 0, im->xsize, y, data, NULL, im->channels, 16); for (i = 0; i < samples_per_row; ++i) { p[0] = data[i] >> 8; p[1] = data[i] & 0xff; p += 2; } png_write_row(png_ptr, (png_bytep)tran_data); } myfree(tran_data); myfree(data); return 1; } static int write_paletted(png_structp png_ptr, png_infop info_ptr, i_img *im, int bits) { unsigned char *data, *volatile vdata = NULL; i_img_dim y; unsigned char pal_map[256]; png_color pcolors[256]; i_color colors[256]; int count = i_colorcount(im); int i; if (setjmp(png_jmpbuf(png_ptr))) { if (vdata) myfree(vdata); return 0; } i_getcolors(im, 0, colors, count); if (im->channels < 3) { /* convert the greyscale palette to color */ int i; for (i = 0; i < count; ++i) { i_color *c = colors + i; c->channel[3] = c->channel[1]; c->channel[2] = c->channel[1] = c->channel[0]; } } if (i_img_has_alpha(im)) { int i; int bottom_index = 0, top_index = count-1; /* fill out the palette map */ for (i = 0; i < count; ++i) pal_map[i] = i; /* the PNG spec suggests sorting the palette by alpha, but that's unnecessary - all we want to do is move the opaque entries to the end */ while (bottom_index < top_index) { if (colors[bottom_index].rgba.a == 255) { pal_map[bottom_index] = top_index; pal_map[top_index--] = bottom_index; } ++bottom_index; } } for (i = 0; i < count; ++i) { int srci = i_img_has_alpha(im) ? pal_map[i] : i; pcolors[i].red = colors[srci].rgb.r; pcolors[i].green = colors[srci].rgb.g; pcolors[i].blue = colors[srci].rgb.b; } png_set_PLTE(png_ptr, info_ptr, pcolors, count); if (i_img_has_alpha(im)) { unsigned char trans[256]; int i; for (i = 0; i < count && colors[pal_map[i]].rgba.a != 255; ++i) { trans[i] = colors[pal_map[i]].rgba.a; } png_set_tRNS(png_ptr, info_ptr, trans, i, NULL); } png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); vdata = data = mymalloc(im->xsize); for (y = 0; y < im->ysize; y++) { i_gpal(im, 0, im->xsize, y, data); if (i_img_has_alpha(im)) { i_img_dim x; for (x = 0; x < im->xsize; ++x) data[x] = pal_map[data[x]]; } png_write_row(png_ptr, (png_bytep)data); } myfree(data); return 1; } static int write_bilevel(png_structp png_ptr, png_infop info_ptr, i_img *im) { unsigned char *data, *volatile vdata = NULL; i_img_dim y; if (setjmp(png_jmpbuf(png_ptr))) { if (vdata) myfree(vdata); return 0; } png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); vdata = data = mymalloc(im->xsize); for (y = 0; y < im->ysize; y++) { i_gsamp(im, 0, im->xsize, y, data, NULL, 1); png_write_row(png_ptr, (png_bytep)data); } myfree(data); return 1; } static void read_warn_handler(png_structp png_ptr, png_const_charp msg) { i_png_read_statep rs = (i_png_read_statep)png_get_error_ptr(png_ptr); char *workp; size_t new_size; mm_log((1, "PNG read warning '%s'\n", msg)); /* in case this is part of an error report */ i_push_error(0, msg); /* and save in the warnings so if we do manage to succeed, we * can save it as a tag */ new_size = (rs->warnings ? strlen(rs->warnings) : 0) + 1 /* NUL */ + strlen(msg) /* new text */ + 1; /* newline */ workp = myrealloc(rs->warnings, new_size); if (!rs->warnings) *workp = '\0'; strcat(workp, msg); strcat(workp, "\n"); rs->warnings = workp; } static void cleanup_read_state(i_png_read_statep rs) { if (rs->warnings) myfree(rs->warnings); } libimager-perl-1.004+dfsg.orig/PNG/testimg/0000755000175000017500000000000012617614576017700 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/PNG/testimg/cover16.png0000644000175000017500000000156612263740600021664 0ustar gregoagregoa‰PNG  IHDR 1ñ‘“bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~üÞzTXtRaw profile type xmpxÚí˜AŽ!D÷œÂG€ªOU÷qp»HYæøYØ{<“Ä3‘’ÉêªëQ /‘~|ûž‡Ãµ0qãôâ¬"ê¨ê@Te­ìð˜ÇãqÂÈZìp5ktæèÎAU-ZS,n†j¥[Œ¢›Ž"WÌÉ‘[nܼ°yQwVWu¨ {Qצa²%/쀊BSPe;^¦O€#7n†Bb«ˆ½–1’Bb´8Îl˜˜¶mcØ$†¦!c²påÊ“™À$ôÓºéUáâ]Ãï]D¨š¢¡ÕÙ¡USãÖUbSˆïxÊ®†¶«…ˆ©ªMU]UÃab²`°$LàŽwQq~+­ab\wCÔTÇô¢’œÏšù,y†Q4]ìÀU!²‰†ªŠCÓçJzÉ‚ª.÷Y<Eú}E¡MkâÈÍ¡©á57n˜·åÓ‚ëØÉ÷eô4½&½.y?ð7ˆqä–¸a¾=þ¹!äK›þ/…>в_´ É~}ZèW¡|A´GÏ×@ûìUÙ!ÚßÞúý Ý“üGŸúS(_íÙ wˆöl{D{6È=¢=äÑž rhÏù¸£Ó‹Ú;xUCÁØ'Gú Aœû ‹w„ vpAg †üí,IDAT×1 0 „<èÿß”¼ÌNÙJ‰‹‹`TA êeífÉäŸÌlÇ-‰&) tEXtcommentimage description¸"‡ö%tEXtdate:create2012-04-09T12:01:39+10:00TÜÁð%tEXtdate:modify2012-04-09T12:01:39+10:00%yLtEXttiff:alphaunassociatedŒ(³tEXttiff:photometricRGB³ IßtEXttiff:rows-per-strip2ä;„IEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/comment.png0000644000175000017500000000025412263740600022032 0ustar gregoagregoa‰PNG  IHDRwSÞsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÜ%$Ý¥tEXtCommentTest comment•ÃwÝ IDAT×cøÿÿ?þþÜÌYçIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/rgb16.png0000644000175000017500000000621112263740600021310 0ustar gregoagregoa‰PNG  IHDR––ãó:ö PIDATxœíÝÏk"IðgõuFLDWуFa³²;^¹ Ìaþææðâì’LÈ:=(¢H“¦¦Ã{xÒXÓó«;ŸÏAŠžÝ±WúÙoUwU """""""""""""""""""""""""""""""""""""""òä~‹ú  H¥ “™·“ɨÏäõK$|H¥<Èd'h'“WWqŸÛKãûàyà8óv¿Ôÿžÿ+nbär9¨×çít:ê3yýR)×r9Ûêõn7h§Ó³YÜçöÒ¸.Ø6t»óv¿Tä!dõcü>}€F …¨ÏäõËd& ^·,àÓ§½= Ñ°, PP4™€eÀÞÞ¼ý*ChVBƯÙ€r9ê3yýR©ápþ[·Û@³™Jé·¾Íp8o·Û@p¥F!òrìÇÎ'«/‰j5ê3yý‚ߺP …t(—“IýÖáxEòêŒî.E"ª/‘Û)„"1SEb¦ŠÄL!‰™B(3…P$f ¡HÌB‘˜)„"1SEb¦ŠÄL!‰™B(3…P$f‘¯'”å$€ï§R€çe2€ã°LïCù߆CÏ&Ç\×óß×ûe^…0faaK§×å‘R Ì?]æoö<ߟLÇu-k4šLlÛq†CÏsÝdð¼T pœL&h_]ée[ñP#µ¹L¸¼Ìf‹ 3l¹`ÛÅ"0mmÇÇ¥0óO—ù.Çñ<×lÛ¶-«ÛDZíá0øæÑ¨T¦ÓõuÀqÖÖË8(„ÏÎ ^.œŸçó€m—ËÀpX,ãq¥ôûfØÂÇUBÇñ}Çév=¯ÙÜÛsÇi·=϶ `4*ãã­-`0¨Vñ¸X†Ãr8?ç÷çó äóSŸEXð66€³³Z èv›Màà ZFÑ »£· —Õù¾çžgÛ@¹lYAœ\7*^³yxį߯T€ƒƒfèõêuàìlcC|~ ácüÌ öî`YŒ_«t:õzp™w»ëëÀt:ïÞ?laøŠßdr6»ù¦QßO$‚8•ËÃ!py™ÉÙ,ÐhœžÝn­t:­VÅÓÓF#è¾òLŧ¢>źÇúöÇÀ·o;;@»Ýh§§Œ¢YŸ*rË[ '_ ìyã1ðûï“ °±qvÔë½`YïÞíöÎpt´½ÔLÕÆ§¢>JXÝÛÜNN¿ímà舣¾¸‚w73–¥Òx äó¶ ärççAµdPùyr²¹©ÚøtÂ2ãǎ埻»Àþ>CÈêgŽô^NðÂ,rmÍq‚ø1 áþþî.pxØlÝn½®(>”Bxo‹ñ{ÿèt>|¾|ùûoàß_rÝ[É­dªÕ~Èd./ƒpš[Ì¢ø0 á=„ÅïãGàóçV øú•Ç•º·Œ°ÚìðôãüEñ¾Â¥¬fü™µ‘û<…Q—§.…]JÎ_áØÏÕ‰Ÿ),о?ŸÇÇœ0›)„wQ‚5 À²xë…c¿U‹Ÿi1Šæ|TNÚ¥’êa8-e evAùÜ÷<ùÉ[/«?“ÅJ¥ß67ON‚Ïju0þ”ûË"UÂPfôÇÇî–Å;Ÿ«?£È§‹Üˆtg§Ýl›}ˆ\N]Óp á-» æcwN°^~"õêàýRÞAÝÞ>: BÈIáꚆQwôó hÁ”kFQ]л-vMY9 ŽûÍçŠB á f 4§\³­.è2Ì®)ã×ju:ó(žŸk|x“BxƒYy瓟<¢.èòXñXýxª‡‹Â¸ÎËm¹Þ¯Vz=ÕÀû2ëa­ÖëÍæÁA0û”Óß„Âk‹ë!*`0ÈféT5ðaXñ²Ùé¨T TôÐâ&…ðcÆÈ1~¿ÖꇗɼUÃø1ŠŒ¥:¥¤^cG”¯™à»^Øæš÷¸Ïîׯ ßÅâx lmmuJI!¼f¾Í…ñ»ï‹•$ +ëa¿—A­2…ðz4È+åóÁ‹'ÎÏyDÑÇc§4v] Ÿ??>yD#C…P50"ª‡aB#¢‘a…P•0"ª„aBpÔ÷æ ày¬~lk4ø´82|óÆó‚ªÈ6¯2…P$f ¡HÌB‘˜)„"1SEb¦ŠÄL!„ï‰Ä÷ï@*uy d2lóxÜg÷zpK¶ïßço%e›ÇWÙŠÿç| ŸJ9ÉŒÇ@±È6Ç}v¯GØ[Iy|•)„p`mñ;>¶¶ØfUŒûì^V?ÆÛtQ\[‹ûÜ⥪FD•0ŒBî9äº@:=_f“ÏóˆF†ÇQŸë¦Óó…bù|pDï ÕåuMõðù¨ÞM!¼¦‘áóÑhðn á5V¼éÈf R€R‰õPÒ‡aG”u»Û• 0f³ª„]X×82dä?F‘±T§ôa3FŽñcµy¨I!¼Òá(—€f³×jµós —S=\k ÷cêõj5àà Ùœo£Žèœ.©XñlÈ忝n¯×yDõpy¬Ü•)ØL ^ލ#jRo`§Ô¶|þì ØØèt€V‹mÕÃe˜5ðìlcètZ­ mÛù¼:¢7ébº…Y?ËÁ¨Vu«&Œy†[‚ZV£1Ÿjàí´Iè-ÌzÈøµÛÀÎ÷fâÆiÜ@;™f³¸Ï÷¥`ÀF£bøöí?€v{g'ˆ¢j`…0ëáx ”JGGÀö6CÈ=›æ[ÇŒÇz%”Ùeä¿££íí`w^ÕÀ0êP…2Zôû@¥rrlnòS]SZ삞œlnŸý~¥¢?£Jø‹]Óý}`w×|7)ïý­ÚþMfüxçóŸþú ØßßÝUô>Â¥˜]ÓÃC Ùdü’I. €Õ‰âbü:÷ï/_>|›MuAïC!\ŠÙ5å“ðòuG1,~Ÿ?ü|ýÚjÇÕ]žBxwGÑ÷d’5³Rú}n²=¯™¿f <Ö4ÞzáØOV?Åï1Â{ ‹¢¹Š·& àôô×Ýñwqúµe½{ÜtáØOÅï1ÂZŒ¢¹‘!ÜÙÚíímàèèW©auÏ|îÇžž6šýÂGùñ1FµÊõ‡¼…Ã97üdUÜØÎÎø¸ÿår1x¼«É™.¬~æs?>xà?ÃKñ{ …ð 0гL2~\ÁøqMã×jN½ôz¼…³¾L§Ü Ê|ìñ|±4#Çïä¢Û‹‹lv>ÙºV»9çSuïù(„O,¬6öz@½ÎÏZ èv›Màà€Ó߸/¢9zäfÝæÞ‰÷ çbØØæ›]̑׹³¾qÁÿÁø™µQuï9(„Ïb±6òq?×apRøÿ[[ŒGŒÜ'˜±à…?Ÿ„sù­K=/•ò}ÇÉ劲_´ É~}ZèW¡|A´GÏ×@ûìUÙ!ÚßÞúý Ý“üGŸúS(_íÙ wˆöl{D{6È=¢=äÑž rhÏù¸£Ó‹Ú;xUCÁØ'Gú Aœû ‹w„ vpAg †üí:IDAT×̱ ÁÏdŒÆhÉž"¢ nN²%‡*(€F UQÌÙŠÌrŒ;tã¾ÀZ¯ª{ó™(áBÇŽÙ1¢tEXtcommentimage description¸"‡ö%tEXtdate:create2012-04-09T12:33:39+10:00ÉËwÌ%tEXtdate:modify2012-04-09T12:08:21+10:00&ÑtEXttiff:alphaunassociatedŒ(³tEXttiff:photometricRGB³ IßtEXttiff:rows-per-strip2ä;„IEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/coverpali.png0000644000175000017500000000021012263740600022344 0ustar gregoagregoa‰PNG  IHDR äH`uPLTEÿÿÿÿÿÿÿÿÿÿÿÿªNhŒtRNS¿?¿?½ñ%8IDAT™c(````p’Ê@—«!ô‡ÑIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/gray.png0000644000175000017500000000017312263740600021332 0ustar gregoagregoa‰PNG  IHDR:˜ ½BIDAT•cxóÿÿÿÿ›ä`€‰—Á˜!À€˜>3000œý `6dã}yeî…_0Fc5…·Ž}A×9ß¿,­üt•IEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/rgb8.png0000644000175000017500000000407412263740600021236 0ustar gregoagregoa‰PNG  IHDR––³cæµsRGB®Îé pHYs  šœtIMEÛ 58Ú dtÎIDATxÚíÏkÛØÇ?c[!OŸ±0ö"ÂÔÂtÌÌdȦ0‹þÍ] tÈ&3C2%£b”EŒ°0¾x|QzQx ¥yžæGgÜ$¾jÏg׹ϕ¬«s@AAAAAAAAAa ¾Y÷…pÀª¥y»•ÇàiCõÒ–£ÊÁ€ÿþ jëþY|Á·4 _Æø ÷–£Ê@A .žN¡!¼‚>4K£Ð›F¼zM?¢iÂDð¢'UX¤°Ch—'… >ô:uÀ!8ë¼zm…Up¡ mè–FaÜ&M—vÕ®£n‚»æIEEÎèÊŽ(…‚(D¡(D¡ Q( Q(ˆBAŠBA ›£öe}sã¡L•üæ/ä$†™&3ä—¢ÐBm.™‡˜ÿ¼ùË&Ÿé,šÎ”NLVÅ8hãpY…›3ç±Üâ¯B›j1Ýá4 õÐ7_¥M6Uê4ŠS´JÐÓ€Åwèz‰]ÖJ*ÏgÞ@µIZ¤Î m>ê)Ô¹ŽÍðµÖ‡F5™¶8ÝaÒ%m‘´™û¨FùDÖJ*¯Çx›xÈq—I‹´Ðæ’­¬…·,v¹Á(ÚÆ!sÑÃÒçއœ…Œ{åY+‘¿"aωzŒw9 9 ‰¿cQGߣm•ê%Õ‹« ¤yãÐNXzüµEÿñ6G»Œ{¼ë3 Ð^9,ÖJ¾.“ïùsÃ>ïzŒ‹8þs÷ëô&å?3zcÂ3¢çîñöçrıV¢ð íqø‚·Î?GÞ­.ƒ”†ÂŸÓNð¾b4(Gköû ‰àxŸƒ£>ïŠeïAäÝ*²®ñí„Ñ€ƒ}N†Ä¡Õköûû™£—¼ù‰?6|w‰ô4Ýs¼%Azõü Xm±f¿¿_øu—ßBâÇßýqt Õ_òXk±&þî‰cÿí‡vZ´Q¡ƒi1ýã—¼Ùˆ¿›ó*Æaé1ér! ?AŸyŸhŸƒŸøcSþ>²X|›š¶Ði`W+¶ùóÐ]&FFÎ7èoÕbçœÁˆÁˆîOSÉ%…÷–Ð×ïQµY׊~ÄÞ!ÊgîÛUNkVE°(¡Åõ{@zëWÕ›ùl‚”oQ>IÛ®rZ±*‚>ªÇ¸OdC ½µœö#zc|uu½( ?Ž`ñýu±%%ôf9íÙ=¢7ÆŸÛ²"V¬Š`Hû({JèGå´è—Q´Ì°$ˆ¶(ôX¶I†osfaWƒ¸}Æð˜v‚·…¿–˜v˜l±°3‚×AÜZЙLm¹º°B¡ƒÙbÑaòHw!ü¼&˜Ò™°µ°¢–Z¡ÐcÙ"Ýá´EZ¿mÛ’UÔ5­”SZ©µÔ–zèé]Û–l«¥ž¦µr+êkWX!wÉÌÌ]2›«èu-u3ssÜlóËaE"Xö n^a¹B —CI¡¤ðó—.Ÿaêèg¹)æÁ—Ãg†ºæ™iåá´Ò# E¡ Q( Qø™äTÞã,ñÞãä%ùHåÞ;,=Þ;䕯^¡ÁÑx)-gÖëÿôǼ²­Ô8_½BM=¥uÊNJk‰W …K´Åéi ]—J Ë®ð’j†;§1§‘áÚ¿æ2—yƒyƒÌÝünR+þ¿ÊD«"h‹Âr-‡V-„¥pÁքΔ@ãÙ\KóÊUáI‡Å–¤pe9ÔxS‚ [6×Rã°ØbÒ±¨‚-ŸwM=¡}ÌðŒí9¾AÌ+Ì}ζ9’´­¨¢)48 ?&Œ ¾A4Ê'‰C”oEµHá%UEcLïˆÝ1= ƒXDpÜ»ê¥òpÚAÓ‹èOèZu^SœÅLºD}Æ=‹"ˆUˆAŒè²ç£ŠŽ]U¬×j¦-þüžÃ=¢¾E͵ NJð–>ªMâ¡Òï‰*JhÔ¿êÍ–EÛîWçtF F l(§×%t4`4à¼c]ëëš–\—Óö‹¥ì[Rø‹C~ÿ‘ƒ}ëJ¨¥ ¯Ëé Ãë.é±xíïègÞ¼ädh] µWaQNcÂÕ>±ÅU¿þÂo»Òƒíó,æT ÎtBäC·à¢¹Ìï?òæ¥Õþ°¹™åªÅânÔ£ö#] ß4 z.ýHÔbq7ñ‘ºß _qý']ö2£»ÄK ¾ÂÞÜ7å©ãžôæ~‹TSM]á'´×îÓœö®:äÇ¡tÈÂ8žž®3§¢òÿ!?ÅœŠi s*6GEcŽ?¦÷_vþÝ´'×¾™†ZûF5/eZÌæEN Š™M' ÿÑÌ&/›†êôUœö•j_È̦͋¼ÀUø)&¡}=9­ÐyG gÚ¦ý×zeÝ ™œf—K>Ì•)tÞ>¿°šÝ<4mç²Í—Á5‚rUçÝ4Á…êó®åá4Q(ˆBAŠBA ¢P…¢P…‚(D¡(D¡ …µYû~aÌ )ÓÛͲ³ŒÄ¦Q® Ì ƒüIPÐ,B3CED ŒEG=ƒëÍøfÝ?û-ø‚Ï'î’ÛÄ·ÙÕB_á^ØrT(ˆA±ÆCÍk+¬€8eÚÄPɯfL8L'X]” h0”dʃ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ Àÿ®R–?бIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/paltrans.png0000644000175000017500000000034712263740600022217 0ustar gregoagregoa‰PNG  IHDR(-SKPLTE§§§yyyYYYììì333ÆÆÆ²²²”œû”ôfffùùùFFFååå,,,ÙÙÙ1?þ ÿÿÿÿ)ÿfqÿÍÑÿæèÿ©GîtRNS§yYì3ƲùìfùFå,Ùù ™Xw`8IDAT•cà“á`c€Aaaq>~„'H²‹ kaàácgB°23qó"ñ‡øI}+4&IEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/graya.png0000644000175000017500000000022012263740600021464 0ustar gregoagregoa‰PNG  IHDRµú7êWIDAT(‘cxóæ?lÚ$/Ï€˜xyaLccI¦š‚ÏŸa̳gl`64dcãå}ùòÊ•¹s/\øõ ]£±±šš‚ÂÛ·;öå ! Gù³ÿ"M{ߺöIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/cover.png0000644000175000017500000000021512263740600021503 0ustar gregoagregoa‰PNG  IHDR aaMÐsRGB®Îé pHYs  šœtIMEÜ$:>©:IDAT×cüÿŸá?Ãfdd8È€°002¼Nˆ"jIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/palette_out.png0000644000175000017500000004726112031434614022724 0ustar gregoagregoa‰PNG  IHDRHJ'°ù IDATxœíÝ»nãÊÒ°á^  †töwÿ÷±_€‚J€ HÙüYšR©ú@‰‡&ù>À`<¶Æ–ÉfwWŸêŸ?þ@ÿ™ú @- E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$hý¿©ßÀZÝn·?S¿‡.6›Í?S¿`hÿüù3«ç`öt`t»Ý¦|+I›Í¦ôu“N¥&º @Ùívûs»ÝîÁÑõzø=ûøø!<I± iì ¤ëìAJ ŒH:öçó9\¯× ¥šl6›°Ùl¢’~úx” ¤Ë ÜïóÆ$€‘I§^‚£Óé4ñ;zÖ4Íýã7Ùl6áv»/Åë›¾Žž©ßæ‰Sì& ³G5G!„p:î\l ` 3_©÷PÃûÃü0ƒPãñ8õ[!„p8ÜÏK$Kb `$s8Ö;¨]¯×§%µÔmðßO~³C ^F ‚¥a‰F5‡‘3¤­á µ”Ó5ÜËw̽p»ëžË¾½ÿ¨–åu €ìAvɆ0æ³Cp†!pÌ7QZ9–VlT€ïéëôžÔ÷™Cgì•F{ ›Ks˜˜×T?ûRR.¦,]žßWžõ5Ýk‘ºç}ÝÏÜ÷‘N§SµÁ‘ìEÒ§ÙYRæôqà¹×¾êÕ{#Ç•·¯®¼£;$ôª4/MŒ·„Nhír SîëºáÓMæ{V›Y=w4¬S¦J^[3}ÏbÝÑiÿ^tG¢¤¾ŠÕUc—…Òç·´ƒZóóÛ·Òú@ßÓ\ÒÖÜý/)ÞÌÑ÷÷·ûÚ¯¯¯ì÷Zìà-H‰\´×.u|wìûØç€ ] ¡W%™Áu#w´i­£jsUÒÀ…-”‘B“|/öú*2«{®~b¯ÓetÎå16lï¡Ü×5t&Jë+ùúÔK¡^é z³‡öÙõ^§>?ëû_Rèº Ø”ÅÝ¥|Ä¢9鼕¶C!¤¯¥®Óì ÞE€„Þ”f÷:œKh$æ¬´Ó Ò~¿OfW¯1³ºî—$g,ٹϱŠt4t‡c©‰®õUÍu•~~sO}ok{~ûÖ¥>8ŸÏàWÊ»ågÌ™¤!ßkî÷(ýÙ___áp8<IHx‡4 W¥™Á½ÎF®Bœóèý”r¦¯¯/÷Ú{ Øñx ‡Ã!œN§‡†Èv>¦Î\žZåG©²%צ¤Á®µŒê2ðõõ•|ŸMÓ„ëõºŠ¬ó¯ÔWc—ƒWŸßØ÷:N³L5>¿}+©ruAì÷ÑnÏçä×÷û}á÷þÉÏ{'Pêø¼Zž½ÿ×eö(÷>mÙÿüü,s@z—Ê îȧ*Ay½4 —˥Ϸºx»Ý.œÏç‡ÖÒ×_7º± I‚$é@]¯×§Ñº:W¥{DºG±×êNmet·Û…þÞûïïïhçJ~¿¥uSºÔWc—ƒ.ϯÜÓÜý-é .ñÞÇ‚#ýµÒYÂÒ ¨K»õóóã~~»Ý†~ƒ$}ÿ†žÉÔe¼¯öW×E¥ï?œÕ°7 ËD€„Á•Ž>å:—Ë%Úˆ Nw²r#z©Î•÷õTT½¿¤dÿ›mÀm§Ç’ÎCíeTF]éXørõÕØå ôùÕ÷4weIžÝò‡;,M쀠®ÁQíVêý%Pî[ªÌŸÏçAê¶’@=õ¬ u-A€„YÐÌœO“n\eäÎS:ªü cNë¾cK?K;ŵ•Qïþ$½nŒrPúüƬýþÊþ#{r§Óu‘ ¦ßm·Æ˜É+À|·Lwý=rÀÐþ3õº¨­ãY³±¯ÕõzíµóéðœM{Ó!@Ы’ÜVµÓ#ïK…/=tÆXÞóîÌÁ’Ë­ÖÕþôǼ&„ð<{TS¥N|ø3´ÒÕ²jÌ÷L‰%vœ®€KrhÇãñÞùùù¹o¯ÍÔ§µ•Л½-»ù7×¹’ûØ4Íý=èk`—†È2»Ø÷cùì±Úš¦IîC²'$Å:çóùa Tåôr¹$;õk_Ž¥åê«ÃáðP/ )—Ë%l·Û·ökȳ³ÝnÃn·KÒ ºõ²ÿ(„ùì=JÕ¹Dã¹G§Ó©h©™®J^/õ‚Ô 1|¤¾Ï~¿l)tìûzå\“÷mËzIÝ÷ÊÒîËåR´Üt.eu#z£“.žN§ÞŽù>÷¢???Uu%+öþä>•s+ßCÊCjT¯ïƒbÇTßn·‡÷!³H©ûñê©oº£à½±É}÷ŽØµ§ŸN§°ßï¿”¦K}%e!çp8„ÿýï!„ô©_¹;kPštsˆD±cŠGú™)¥ ŸûÎqõN[ÄèË»³Çòþíu‰•}iÇåÚ”œè}Ýn÷ôL¦Êô’ë1 ƒ ½Ùl6ÿ´ÜÂï4·7ª'_× ›m$¼Jó|>Wu„²®põû/Y6ÐG#§šØ’.éüM}Ýd)^ª‘꣓2è}?ýóåzy QõuÌ-ÃÓ¾¿¿³÷^îÃØKð~~~î²·´ÅK>YÛLmߺÔW]®Å÷÷÷òàÈÏ!„§Ù]Mw®e”\¤Ê™ ò¼Ž¢7«›˜åm´]G±ú,„ßÙ¢óùÜiØ~ì) ~R3C¹Ù­ë^Ç!–Øåë„DI}¯ÿýï÷e¦1%ƒú5ö9J}o»´Ûù:³G(B€„ÞÉèdªC, 4&¶1”Ž©®¤÷ûý½Ò¬¥ó¦;8¥ûRìë¼ÆHØé5î1¯I±Ì&®,¡g’¼ýJzF§Y$$™Ï{¯M–¥ÒýJBß/Ù¢½»7årÿs=³4Ô^‡åê+]f»îùK)Yúz8–Ið“šñÉí¿°Ë2¯¤3Y²D6Ùz³ï¿©¥ÒR?êg¨döO/ŒérïrreùóóÓ]ž˜ÌÔƒ¹ë˜úz®Ž”¯ëg¦išäŒhûy‚##@B¯¤Ò#³‘×=ümÝn·‡ÊoN'må‚¡Ü×õïê½ö•k1T@ –¼îºá÷ÞOŸK b ¡œJÊ`éLS¬ã• ’¦˜E’÷d;ï2©ƒïÏÏÏÑÞÛTJê+¹OMÓt*]trÏP¿ÏOnOŸ¼ß®jì8Æ‚#ý5o/«õýýý°5¦tàb»ÝÞ¿OÉžÒÒà(¶FL±DLê¾ý~Ÿ\ÎèÕrm¼k^r­_Ý»×÷¾V¬QÒAm_—ü>MÓtZó=…Ò}%_—פ|ùºü̾öf½ÒYu¶Cx^¶u:’££c(i0cKôì,ÝqöÈuIu¦à庵ÌÒŽÁ+^0B¾tÀ(•Îs—ÙÛ%ucéºì)z÷𙉗%^¥§ªYv¹¤ì Ó§ Ö@Ϯʿµwë¿>êoÕ’Ê=¦C€„Q•vPÇ]G¿JpÕËšr{”Æ¢gÔçîÑk*8Ò4Ô~½úïããã~PCªÝ²¤^LÕ©Þµ×Ö²¼Ó!@Âd¼àHW–×ëuv{Vr¡ˆÍœœN'7XÊ}ÿÃáðôZiÄ¥³ÞwþT¤ÅfÃlД;¾xJ^žÙ¬oÉïôêñ¶CKI^Û4M8ŸÏO u΂¤×•æË™;}L´7ó _ï+ù«þÿ—Ë¥èÙKÕ?:8z5Ç‘%ÁQíË5cyÂt*ù½Så4I&BY"åü`ÈÞýÿ€> a©ÅT’ÀédŽòï}Œk*Ù£üî6²£4FúØïœ¾f‘Bð8ÝùîrDû~¿—ï[Mg{£’ÎÚàHþZfëLQ¶S÷Mr»Øe1©Y?}Ä/“—ë`Ë,CÍ)út:Y:ç••ßKþª*Jsëx?68ê2Cû9Õ:ƒ«ÿBø[Ÿt}ß:™l*hÕKsˇC•×óF€„IÅ‚¡Ú7çn6·õDýìÈ»•»^¾ԈÝù’¼÷©—’‘ÚÃáðÜÕëN‚ú\áï,’Í×eG¬kùÝb÷Mf•ô2»¥,¬‘7">·Mü]èz>µ|NG©I^—ZÊ*º.iGZÉ€˜^:—KþZÓñÞ–WÿµŸ¿¬Jš¦)ZùÛfë“Ô2T}€¾ ar¹5éC­/ïƒÙòýÉ¿u`ëTÆþ¯&#±!üvR:ä{苾‡²×%f¿ß?tº¥þùù9è{|‡í¸èQÕTÇ«–À(F'€üùùyXf'eÇë€ÈkbKoÐMj鬘û5–Ù#¯ó¬ëyÁ¹îXK`””É=‡vI—–Úë¢ļºÛä6ʽ‡ê‚#á½74ɬ²4Ñ×^ßÏý~ÍMÕežzE¿ PŠ U©}æ(%Õ™IG^BÊØ÷Ñd´_‚¤ÒÁän·eŒ=ÀÜ \ÖLh±{Vs0ŸB3¾Üò:á º,Anù­%Òl`4DÝa#½$R/}ôêô’ú~ît¨м]ôrÜ®udéÒq oäAz–j,ÍëþÑ¥ü;õÇû>Z­Kj=êys úú6ö2à%t ßMÛÐÇñÜC{µ¾_"»ZÂ~˜$LfnûŽ^QûéDÀ;æ4ë‡ec°¥ôéXp´&±»5^ , 0¢w7ãš§èëjœE*¡6sÿ©9ipíï¯o¹Mó€fŸ{°Llyݜ˘Ô|øÂÜ͵Ã|° “ŠåŨydÚ Ll2GFÏžÉÈontVï‡qN›¤£ÑwBãÒ%'c?ÞQßZ.ÇÉÒ Q_éë9×eu©Á}mN§S§£ÿųFú€]7¥ž‹úÞ'×EÜàÄ<Ôˆ £³©œnd^órcÚ§XÅmÓW¿Ï«dó¯l|õ®“>…lìëhjÐäÐ}¤t¿§T§¤Ýì+§Ç(¥òuÉçº&4N˜¥ýüüdOÉR,ÒeJi¿Ôd±cÕW^pT{"Ñ’ç#„ßgÛ~=6[d? ŽÞ9 ÁÖÇöÔ´âÇJ )û©™£5*©³¤þˆµ¡^B^ûÿ¡ a2¹ÄÖØvKŽ~µ'Q¥òõÝh~||<œdé#À‡ÃdžSA’>R:„ß{ì¨&¿ë uùôfºG¯ógÅ’ z÷iÌ I~¾äªÒôi‰___÷ ¶ÖD—}꫾ê’?M_×Z¯oîù!„ÿý7„ð['•FÇã1œÏçlpT*uítp¤;ä±N¸œ`§¿¯÷ýk½_CòŽý—\qVj¶ÔÖ‰D˜&Qš80õ‡[v¡y9l¶ûHÃùö(»|_/Yç+y'† JÛ¡‘ã¿åêΑäÓˆ}/™Iz¶BFÇsc;s ãT2]›Þ£óE5“$¹Bø-;ö½É}Ò–š—Ãö¥¯úJÊ€©(9.ºý»šº.ÏGƒ£X€dŸ¡’G%eO_ÓØ`—ޤl§rS5MöûýCP›ÈmWÍ=ÊF%“µm‘þ·M¨«ûJUý5¯íÞE€„ɤ†à/#xuMzª’î)8úGrOÈÏóNÔïcªÍϱ Af•ì2»Ø%½œeÌœ=%ã.åT—©\ç@/A3Un¿‡žYšëž™W Q_Io¿ßG;x5wúº<¥ò…Oþún ^’V§IH-y”å͹{³†àHè I}îþ±Ô/RèÕ 1%ÁÑšê Œ‹ U±ŒZN5ò‚#[1™Ð ’ì{é2Ê=éä¤:ÞÌÅétrgËÆê÷±·Ëv¦.óÒ1•}bšÌjé îóósô÷X‹>ê+=ú=ÇYˆWžùü»³C9%ˤ=zÉ£]d«½Gc±×@Lúšy5X¯.«ã> /H¨ÆÔ2Ä”Ì9ÁÒà•´÷3ô2‡§% µÎî¤èCJ–aLÅ»ž]:ÆÞrÍŽ¬N•dWö‰içóùéyXÃ;OßÏ•éˆÏ¶“—{>$èþùù™¤ìØ2-ϣ̕,y ¡Îeµ‘kã-¿{û‘0ò  ²†líÏTÁÙZÍåù}7ØTÁQ¹ý`ÁÆÄ à-cî ^UššA—eÀÖ!Q÷`Ì ¡ 5.[FÞúÑ¥œ®±Ñ¾ÝnÞ]˜ƒÒr°Ýn£å`ŽÏ¤½¿öä:êqt1ÇgëÁ f¡¶†7µ‡Øn·‰^¥“¬G°s'4yÙæ§X–$Ëìr£ïú÷ô‚¤5¶Ï5XN»º,–$ÉÕ'Ø)—w,¥Ö½KG»Š aúXØ’†uL±Î Y½×畼7Vê$-¡°Zú¨o€¼ü~R$ÈI%÷µG³ŸN§û†vÛ¡;wÕPºÔWBòŽÙëXºÌkJv–Èùzá÷ÞÛ¯O} £Ðõ¸ä: Á¯Çu®S ¤¾'úQÒ~ÒÆb H˜L­ kÙÕC(;IÆsÙbc)·òwl„Z'¤Œ%£Ô’þš=,Á–µ!¦Tä]‹¦iÂù|vE–ç$i±úJÞ †ô)†¢ÆºC/Ÿ»^¯O_ !„ÿý7„ð7 ¬G><ÀŽAêñÿþ÷¿÷ÏÅ:Ûr‚]½U㽚{²jÉQß!a:H•]²¡“zôç§:Q‹™£u{%÷‚$Û1Ö2µÖ3U¹ŽvóÈô¹üN/•³yj¶Ûm¸\.O¿_*ÁïívssÊÌA×úJË%–k»&ò;ßn·{Ž#¯lIY•à(vMtbØËå2j²o=È”r¼÷~¿¿—×âev®þlÙÃá ’JÛÖÚR@`Y0:ix¥õ*Hý9yœÑzÄö^tÍwäÑùV>??:`ûýþ©¬Ks·Û= È^§¾Ù±˜¶ÛíÃ2;™íJIS$øíKI}û|jp¥æúDîj‰©õþ"¯®–r+eu̽t:Ç‘üÛÒyäã‚£×ÙkûîsËY¼‹ Õ¨i‰]ù„žšqÄòtÙ\.££Þ給i’1ùòÿÎçs2Hòù¾²?I/³“Q`ï‘רÃ*– ¯úªÖk"³G©à(öùTÐ>Fp´ÙlÂv»}¤Y"y~ýÇÇGlIÁPOtB}‡/ð†šGñž¡;r±}ÉSYn7Å’Ó¥9(çufu(e¶Ö$°y³ ú@rÍËë04ò ¡ µÍ- ×÷5vsz_œÍàÿ̽C¶¦2¶¦ßµ‹Zƒ#-ø 5#@€Š,±£V{§¿ÖäWKK?ëÁ ï#@zRKRÁµurÆRÛ¬AùtR§™á×—å²WÀÚ° èÑØ£ÿ±`ˆûþ”$‰µA=¨¡ô°á•#ï„;ïІ1xG}k±CP'[tI¬O°}+eQ^_Ë`òX†‡© a¥xÝðŽ™?CK% aº ÜëÔhúhâ9°×¹æ†ñ<8]r|ÈÏ‘€Ë%r²]Ó=±`Hÿ­Oyœc²Øwj S³Ì:ÿQÝr?I‚›Ì8„ÇÙÕ’ë¿Äe­sñN=/‡nðbH˜”×èÚÑȱ³¯‡à/_J5´æÈØÁ;:™£þÛ¼fè·1ˆ¹F¥J:eR澿¿³×e裾-™ÍÒœÐïûëë+œN§°ßïgŸ¯D/!Ì垪/äkMÓD—Šé2£g$ ¬G_‡±ëh9Æ;„¿uµ7£©ï‡íLÛk>çr¹d©º>áþ¡oH˜\ªÃa—M‘`0„|öõ):~:ý>mÍMµü¾bª‘ÂØ5ô–Ïåt™Iˆ%SL-å*i¬Gr!…ð{-ì5÷©ç¹ì!ü¾w}ÏSÉ«så!6ó<æÀJû±÷õû쑎RYUöô³¡¯¡wÝíµ¶Á(yÆ÷ññn·[hš&¹ÂÁæ«òî• v¹wè&c;!¤³°Oeê¥t–ÖËat§GF€E*·Î¼¥1µ\cM/1ò‚x›ÐU¼º´JÁ¦iÂñx¼'bõ¾§žYë9‘\H¹Ÿg—Ε $R3&2‹‘XSzçfžuÇUÊ}ªn–àh¬ x»ÝÞôÜRV½ÿ(7E»í÷ûì1ìÌa(H˜„×–4ÀcèÒqŸr ´ííÒ1™ÛH¾IœšWN÷ûýÃLJ®c[6²ÙlþѰÌé I‹}~ òLîv»§kb¯Çñx ŸŸŸ£¿Ç¡x3&Ûí6œÏç¢`pÊ™gáÕ6ï—Žr³DS×+¯£DÓòf‘t}¯gül16$àEµuܵ9ΓZ{>–¾;}ïlØÏC»Ýn’ƒ.—ËÓž½óùü´'dêôäwª±èÂ[¢«éਖû¸ßï_ C=-½W21Xû˜{‡Q ¡ZS/­‹©­ãn;,KŽà‹íEšš$-QìºË3Xr æ²ÜÐû]k ŽJÕx‚ ^C`„±‘(£›[#‹ušºœÎ}VÂ3õ5…Ÿðˆ £IåÞ˜ g©†ûñN§Óbfj¾Î}ygßÚÜGÆo·ÛŸÚëƒÚß_lp´ävìãÔñì•ëÏ=ÃTXb‡A¼Ó¹`i]9éÐÌ-0’FÏË]2åuîRncËÊÞ9λcæBÒä¹Í-3“SðÚ®÷TËhb÷½ïë8åò:{Ä·GÞïèÖX«Üó6—%k“ª§ŠP$ôÎv6J–tÈ)X^p4ææàÒŠYŸ¬3ÕȤœ` ޼NΛøµ®×ièëܵclË©’^Íã‘ÓÍ$Xôî¥Ú ß÷|>ßs!©$û³^!AÎÏÏÏÓ©rMì‰n’,6¦í0ýi?-P*©¯^€¨-=€È~i×ÚÒ„ÂcÁ›üëáÕáö°“)ÛU@ ¡WÒÙè’gC:©àhlº#§ä ᱂·Ë¤¦j|c#¾Soæ5p:‰û:{Á‘.¯6O•SOjd»¤Ã¦*zìñßûý>\.—‡„±öú0¥‚$¹f:ˆÓ3HB~×±½.­¯JÌ!=€þ=ÿý÷_÷5±•Ú–ßÕžÈl ]ö½úÀþßßð„ ½Ó#“Þñ±ò÷÷÷÷S>MÕ8ë$ƒ^Gµ$GÃäÛd°š\ÛX‚Ó¡ékâuÅ×××è×Ù.72_»ÿ-|I9í³Ã&_kš&\¯×‡×ê÷kïën·»IÞûísùt¼œ@—Ëå>Р¯_Ó4î5×÷øv»ý«SÔ¥¾ŠIÝ•¼U IDATËXyž¢î2-ÁQªî˜ªÞȱeûëëëˆz{™¨KÉ}˜ª]4$ôÆŽÈË2Žök÷Ï{z›„°¶ÑJ¯Cëü{ð]ªcŸ›-šjo—yËÒbÃ×96s;Ù+—,3„÷—VÉH« žÞŸ×y8ŸÏ÷ IÓ³J}²ïKL^âÔX‡[:¶z&ih¯ÖW©%g±%„^™žªÓ.¿›üNSÏ2wáí]”A{íe‚åuõ°u[âuÿgè÷xлÜ÷Üÿ­MÓ4nc«M½´.ÖÉ™ªó#×)yÉ\§qˆë+s©²˜KúîÒ*/H2_¿?_ºó¾ßï³AÒ‡8”$N=O×çt:¹³ecxµ¾Ê½65[8ö" v©7j=4'„¿ƒûý>yòeûo:ÚÐKí %î&C€„Qy›eD¶ÆàHSÕI+íÚ¯SL×D¢S\goæ(dÞn·äòAM:pyúýuÇ"WäzOÑÁõ§ê%tPWÛ!Z§CÆ‚£)Á%’¬Ú¯Ç=Á ¡Wº¶ òÜŽ¢öÔR±/5¹c-AhŸú<¶\®ËrôŒaéõ•µÔzC,©Þ0-ÅX¥Ò}Gµbóü8Kë&z'€$ŒbŽ£±]~ív»ý±³±ÖjÔuyÝR¤öEŒÕ9®ýÚ×vRÚét*ª¯æÜÌ¡ÞH©©~°<,±Ã ì)Pµªµ“ÓÇ*éÇI’=ÊÞÛA/=ék ÞñÎúóïèsi]ŒwÍä Í;´a,6RÌétšìy”ûݵ®Š½_}l}Ï3Gcñê‘Üï8u½B·üi0$ ÊkŒc‰Çb_»É~Ê8uŒ·|îz½º—G„w»ÉÆüwÄ~EêxgõšdŽ)ÑáÀ…ûß}ï|8î÷þp8„ãñøtÍåd»¦K¾ÂãA š>Ùn¬c¾…ÜÿXà`Ë€—·kÇ}¨ß/7°âÕ)µÕ%'`Úú¢Ö.óE€„Þ¥:S/§±¯×©Ùï÷“6À±Ä•úkÒy×É`-}­Kò÷ôe³ÙÜ;ŒÞµ6©jíÇ;—æ¿ÑÇ;‡ðø{ u¼³\Ãïïïl°9ôQßšN+¼²*ïßš0Z²X‘Kº,lB^Ýq× >Ò=—ßë]^pd¡°Iokª7Bø[w„N`ÿô ƒÊu8¦˜ôhojvC>«–N®ãng6bï¥C¯—VyÔ¯G±¥UzöHÕ;RÂÝûߩكÔÿõè`Ï[b×w†xû}t ¤ÉÌRÃ%ñK[&ôûÝï÷nî !ØDxõ†ýœwü´÷;õQÞS3Ïv°Eç@ª©ÞÐׯÖÁÖ××WøúúªúˆxóF€„^•t8ÄØK;lçD:4©xl%wÝÁ‘NÎù|Žî1‘Îð˜ÁÑn·{Žb×R‚#é©ëҪʗ§yü¾WÊìDÓ4áx<†¯¯¯û3å RΧ܋$ïÁ>ûc?k©€¢4érnfCŒ™øXךWÖõ#¯LLQoèÁ«Ü̳` À0º)×¼ë¥_!”í}©©ã :sKa¦L™Úg$KѦÚÄnÙëûJY•™ƒâe§‡àèÝÉ—"$i±ÏM—Éý~ÿ$YÄMQVõ CŽž³Ÿ×"Aòh³£)ò{Ö\oN«0$Œª¦ ÁsYžáuÆôuÔK˜jèÐx›«cÁQMú^î9UÒÛ\0´ÛíFYb;lÁ^g9db‚Y¤Á¾·,M’ÀTïa´û´ê ¡÷-æÊDmu€å @*ðî±Þ???UurRR¹–fªŽql/Í-90~1«`h$ŠEïæÒQ–`É&Êyûޝa £˜ÓHö˜£“væÈž\7õ±è]èŽzl{jöhÊŽ~éu–åƒÞ @£ÚSí=êËG}c^jÙ¿`Y0¸\mªSµÆ–ZFg󕔞8E• dR 3—´_` ³6cåBçó9{òÛñx MÓ<ì_òž›!‚¦.¤=¨¡tÏÌÐRùÓ–l Ï#€º ¡±Îÿ\F¯‡îØèGúoMŸ^góÕ¢K¢ÝÔQé:Í3†.ÇÑ‹ý~ÿTÄÂ1ÈIi|z¿‹Ì"ɽ8ŸÏ÷\H*åýzARìd;ûžtésf©$–÷ –C=4[÷J=b^Ó©¬× $ … ½‘§Ò§:öSvúKNI’Ï{É»ÒÁ‘N«¾~ÿXwbrùXrùú¦ƒ£.G¥K®#ïØc»ôR@Ï××W8NÉ™P[¾dGì¿¿¿Ýúj»Ý>oòóå}Ö@f ¤ƒí];ý¹>g¨‡æšÎ¿«ˆ°RËç¼àhŽË#ß«OíuHJzv‰Y$ô‰ ƒÒ6˜Ú )ˆHç¨O¥Ï×*7Kd“¼ oýÁñY4V^¿Ýnݦž±gJm6›ôh¶Ìé I‹}~hÞs‘»î¥ÏH—gÉ–ƒŸŸ·ÌaïÝÜ;Ó²\5„øÀÃê—Òò÷Jp4§{ìµ;±÷¯÷뽇»¦5Õ»X$Œ¢†àHtéXõYéNu öûý½C—›é²tnN#¹¥J7/A.Úív£,±‹=gºÃ(åW2ñ ½É]îµw ^)Ò[CÙS­Ët_eË`niÝÜ#›µŽ½Ö¾®S,.0ˆ9Vàžš»±åö©×Ͷã+§rßíñÓžZ–Z½"¶×§6%§È ™1ëãÙ½ÝnÙÓkì´Õ~?»šsÓ·¹ß[/øy•\é{@øÏÔo0¼µwÖpD2 Ì á-kÏô=µ\§·d$ÇÛO1Çe/”Õ¸©öõ%¶9{è`;{dŽ÷ôg/Õ\óŒa|– ŽJòøˆÒüµ«œÎyy]©1s!…ð{š]î„:9êÛ,±‰Àvö¨ß§Æ¥us4ç:ùR§Ê1õMÓ$÷!Í}ðâ^[Åó†± ¡HI^/¯ÈØr­Mš:g%ÇÇgð ym*8šCgÆv”½#ž_)§µïÜ…ª! ïÄ,éˆÉïy>Ÿï¹ô:ÿ1xARlRì=Iä½F6ÇçN+-ïÞ x».:ÁÒ”0èdÖ’‚¤’¶HÄ’‘ó¼a H(&9BðGdS§BA*ÉÔLËn·»w¼æØÑ-á58%§×…ð|L±×ðÔÜÙ ú©$9^9šÃñÎ1áv»EGbíñßûý>\.—‡„±öÞ÷0ÉÏŽ²ÍÕc¦ÓéM$Âcž™¥ùÐR'=Úû?§%¨CKÕϱ\m5×5%$8òž]Vd)V¿¤Žæ½¾&ÞïÕ%0ʪ*xÞÐ'$déNgªÓaGd¥Ã1ƨ³n|S#‘]޼žƒÒßA7P±e,ùëÜrÄy4¥:©ŽY,GT¬¯¼§¦iîK{„~>mÇj·Û݃$ML}§ó“¥è2¯I¶³\òw×ÙÂÔï#?;˜Õ\¦TR?—̈υÎ?æGºœH»š|( z¼öwL¹Äê¶íÍ…ðX§ÆžxÞ0$$ÑŽXî¯#а¯WYÛ º4ÀkV¬KÐVô„oDtãSšè´ÆàÈ.­“`¾ýÚýó±@Þkð£Î«]ê!5Û)Ó¼Z¿×F‚$MÏ*õ%$IÒæý~ÿô,JÙ ÚļS_Eò€ÙW÷ŒL©¤~Öj|–º°IšÕç½×FsÉÿã•×XÐt>Ÿ{OrþŽX[üùù™œ*HD®?æyC¯PL:œ¥ÁÑ”R¯ ŽRËìÿSn  ,óÉ-í* xR_›UÓ›éLý¿½´jnK=¼ É|ý~½t¹ßï÷Ù ©ÏC¼ï#AS—CJJë¨W>š¦I.Am?_Õý¯MjðÊ~Þ;×éû †XE› jäT2|~ª}+{ª=Vzj©ÓCxî4{ Qsù´¬%ÝÙ ®gLŽÇ£»¹~Ê£„å=ö5£ËÆhøð–”›nh’0vÌ¥ß%ºãÔŽ Åì†ÏN¬R9K¥ ޼ØÛ¬Ï©fprKèj?Vº±„-»6!ª4ô‡Ãá¡Ìè#ÕsypæH~é„éÎXÎXÂåžÊ{“=%u”~ éäÒb ÷z,]°’ât™áñzu]ŸGð—*É?¸”cܱlHH²§èH%ëxèÏO5ºœkx¿¾¾î³Gûýþ)ØÐÿ¾^¯Ã½Ñ„Ü.2ˆûJf:½²ë5ê^Þ;kIú8»`µ}Ï>>>: ŒùœK²ØÂÃ,Wƒ5±zÃæçá™{MÉ^'3JrÇZúºÙl(s÷Ö.WjE€„,I¼)K–¼ÎˆþÜñx|د0•ÜHdÉ2µZ+q2ˆ?Ò|éL§ý|é’%çíØl6×áx<ºÏ‘NÎçó¨ )¥né’&ö;X©Áf6^×%ɯ¨µîÂ+×bÌý9<;˜#$¼¬¦%v!<.…)©eiÝœâ¹wȇ’›éÔbkù½eUk8Zýãã#Ün·èL’MS<ÿ^‡¯d6¢Ï÷:çú¢Ì gê}IúÞaî°*RiÛÎß;ºk3äZ{'XZEy‰èh;aÛívð½·ÛÍ NJ‚[ÃÒ3ϹàˆÓY1äAÂKj›=B˜nÏØÒè@¤išÙuhj:Ý À/f•0'HÐ"@Âj-5Ù'ðªÔ }¹Y¤¥îÍaÔèí/jG€„U[j§Ý–Ú=+$®ôyA’Þ{0æó”;)sÍËì(·ë4·2Oû‹šqHŠ”nÀÖôTGŒÆ:$©[{¨€§ëÏkâuZJž9VøÕÿÿŠóùœ<ž]ê£.ÏüÚî7êWòüHY?ŸÏár¹Ðþo"@B'^ÇÒŽZI=¦Ýn÷ô¹TG‡5“$ÁSld½ôXb}úe.wZ-¦:ŠÃùþþ¾ßS¯LÛgaè“%í/–ˆ ÕXA‡ðÛÙ‘J9V9‡Ð4Íìó¡Ì;ĵÎ$Äž ˜¼c¿sú ’ä¨ï>GÇsï?6ò=‡Ž.ÃKóu»ÝÚÛX2v˜œböˆöKC€„b¶‚Á½{öÈb*½^퀯5²dI:/^PÓ4ÍS‡-„ð´ÔMê]î«ÓÖ%H’×x3[!ü}Ï¹Ž˜s§Nf”¤^œºžFûüIpdïŸ}ÆœÔh±H(âU¶µŒ`yŸXå,£Wœ ³lv´\wæmÙ( Žæ–èv© ¼ºÀK»ßï³)¼ª´ó'ïÝ«¶Ûm8ŸÏE¹9Œ|7M3»MúxMlÑAí/–ŠSì°ÒÉ­µƒƒ~Å–‚véD®ufi³Ùücÿ¨¯…ÍfSX¤PÃívsÿ,ÙZËìÍ©\Óþbn˜ABoj]²±¦Ñ`(vfiΤ3ém.·X*„ZÌqí/æŠ$dÕ>2ô… QK-¶£WæxѱßfŒuóiÌ´L‡²¹<´¿À´Xb‡Â{•1Kë0¯Ü¹QFý‘ìw‘¥?:HòîCŸùÆ0‡ on×Ïbíïœï+í/æŽ O•³­”¯×ëÓÿ‘Ó©¼àHN×£r/í°êc‹ç’èÏR¼·Q9,Ç—óß ì¹ó®ÛùYJ-á~{§ j$­OIûksÕ‚öKF€´rR9K¥ì5·Ûí¡‚–8MŸ–¥ä á±·KQæì¿¼à¨$·GMë²¢Oü"ó{7r¬têºÕœwg ÇÇÎ š‡Òö·v´¿X"$<Œ¼ëÙ"[i?5º±€hê$u›ÍÆâ÷*mÔOwmÙÒe׎´Æf:íñÓd~/Óvhþ|||„ÛívŸ±°×Oê ÝQßívÕÌ ¥îe¬Þ¨½î°ï+vODM÷cͺ´¿µ£ýÅ’ ­˜y¼^¯îHÖétzZ¶aÕÕ6Êåuh3z53±‘V]vCøíLè™N)«Ûí6\.wiÎK«Æ&Ï—îé:BïM’‡JûŽXž&¯î˜ËÒ Ø2;f•êòjû[ãsdÑþb n·Û½rîèÔ…ð;,Sù± •ó|u)s6ÿùù Ûí6œÏ燀hnK«j ³HMÓ„Óéôt efi.òÔlaíKƒtÀšÛ¯RsÀºF¯¶¿5¶½!Ðþb9ä5¶Ò°ÖZA 5Oe¼PÞ’¯C._ë2@æ÷r^Çܛɨn·³©7D®³ ¥ÖÃJÐþbîȃ´rº³b;.s®œ•3´’ÎyÓ4Q[H \·z°\thz ˜…’ãç>9Kë&z'€1 Á5ÇÑ«ÔqÃ@ 2¿—I]—Ü,׈;N´¿@؃„Âó©9µ¢sµnÞq¸úóï`yX¼=Iûýþ~Üúf³™l/’W‡èã‰Cxž9š#½ÌNö‚ÙC3$Tíû–N®Ímo´¿X$<ð*hïÈØ1ógØJÙ&xÜív£½Œ/u®z{½Eæ÷þxפ¤£½ÝnÃÏÏÏËÿ¿‹Ø}Ûn·ê9Ü{ª ;ú[Èï7T ôóós¿ÞÇã±hÔZ‚6©ÏbÁí/0 $$+è\‡shR9K¥ìUÆûýþ©ÁC‡Ýt=7uŒ1™ß_·ÙlþÑA«¾FzfÈÎÈǰÛíÂåryêd…îAS_c[whR‡‡¥AúH÷\—šÈu“÷› Õõ¹ÌèIÀ*ßGë3H‘ÙÃý~ÿð>lÝýýý½ÚC&bííTGåÓþbÍð WAO0éÑ^/±£ÍgCå¼<:bj´5õ=d~]ìšH€áÍbäô$éŽ]l„ÛÖ%’¿%·ï¬¶ YV½<Ð[‚ªË·Ôç±€ULïÞ ¸…ð;p¡¯½´)‡Ãá!±ðèú,×öêä×c¢ýÅZ ­\I-ÆŲ­TÎ^GëëëkU ë ¹…ÌïÝØN¹×‘nš&Ün·§ûb;Y2Ó'°¾–ÙàÈëÜyR¼šË€”a„ðwöUž,V‚$MÏ*õér¹„Ýn÷4»+³JR·ÇðùùÙûϯ…žµÏM®µ÷j(´¿X;N±CÖTÓû!üíä¤*g‹¬õ8÷?!¼VVmæ÷H°TmÇx*öšèk{½ç·4pyGnä;„hüþ3è›|ƒ~ö>ÈŸ§YR¹.Þ,›Ì*õUŸJÀåuð½å°kÙƒBÈÖ_SµÁ´¿X3f4epd­u]:|}/7!ó{wÞµ’Ñqé˜ËÒ©”ý~ŸÜ3öŽ’Ì –fYìûÖ÷"pH4Ö ÅÚÍ-¤ýÅÚ0ƒ­¹vŒkÂ5¬G­3_a¿Hv Ô‹ ³Ét3Ç¥O´M¦B€×÷÷wUËëRغ>¥Ëë¶Ûm´cH¹™KuêVc^› õ ÅR± Oj9EèËGÏ—D:QR·è É vû̇䑟¿¶Î÷xû¿¼“íú&ß¿4 󂤗¾j.’ÀZ ­TlDn.•ôÚ:6k×å8z¡aj5Ž/UI`êÍ(½sÄt—ôBX_]¢Í8áx<ºG¯÷yìº=þóóóô<ꣿí=º^¯Éã÷Û£æg$årºé„CdÒÕÚž¬ÒŠéÜÇã1M8éLݱŠY>ï%{Ä2”æ ÑŸ'óûôš¦ Çã1Ù©úþþ¾ß“>f.8ž8MÏèå®M_É{õ÷‹IºœœN'÷çê‡ËåBû Œ„ !¿siG­¤‚žB®b>¡iš{‡ Ë××RÊ˰d©išp:ž‚VÛYïKÉÒ ¡¸%Úl6ÿèÙX=£ç]÷!î‡G„ÒgÐ (–ðüÚk›1ûøsÚ_¬Ç|ãNo­©‚æX``¼@Ä{¾í•¡¬}V)„ü5ãPiO¼ÙÃÜ!K¡ÛßšÐþb­0{TàëSÛFf¤éQå¦i?c37µ/9µA’ #™ì´h±TH¬K  0Ý·óÜ,ÒØy½é­R³HSV§Óéa&‰™#C"@Z™Ûíö'vtrJ- ê,¦÷—É–S:CËäIú$³5>iŸ`IDAT±;åSµ’=a² ˆÍøÞél^Û¤ƒ¤ëõzÿXêŒXô9£ýÆÇ)v —j,n·ÛSÇÓkj©œcù0¹r*Ø{4?^Gº$à•ü;¯þÑ5Ë’Ùc×½ú^N°ËíI²÷¦ïA y©¼ÏÏO÷$<[ŸÔ|¸þýhz -˜×é,iÄbòØ9¼“¬b•³1Ê2™ù))§·Ûí)Il¬ãD^{´´~67›ÍýÛY¤ãñv»]¸\.n óT]æ¼Vº|¬æÎtô±ëïøo=«'ä…PvOJ\.—ûs:‚üx<ÞÉêY$aƒêZó$y׋ö¨ÒB¥–'É¿uòM!•³—ïH*ç1–;¥–ox »^òÁ2™ùxµœG·#±ßïï'Ô!öÝÇZƒ£Ú_ œb·2×ëõ¾f[*`¯¬­rÖb•óœB¤u)§Þa#¨Ëf³ùÇþQ_ ›Í¦h†§ÏÀW– ­­Þ(¹¥†˜•“ÁIçó9 {û‘æ¨æúŒökA€ÝT£ÌMÓds0­(Õ ¶Œ6Å ’ÔÞ*çtN >H æíçjC9ðêi8Kë&z'@ÿVÂ65Oác}ô‰uÞç±>C,ß²3GæxïÞÞRär"Õ $M]‡è¶KMd ,‡4,=:9ÕP¤’ðÕÊn¼õ6ç¢~¶£àXw»ÝÂétše9EwÒ—%G:HòÊ@—SÓXV÷žX^¢~÷†ÅòVi¯+²ÌNN/ŒíC’ÓììÑå6N(}.û´?Ç àìqê5ð ä¹”¯ÑÞb L‚£Ø&öX¤¹šÛ‰Eø{ÈÂõz}*±Îƒ¼.×Ùâ¨ïù(yn½{iOM+}þõ)nOüH®‰õ­#;“ôýý}?ÍÎKΫ•ä®’:üççç)غ\.ÑŸ@‘ )§ï\IíL‘|Bxž—zlÊýG±r¿Ýn³÷³äûsF€´Pºrþ÷ßÝ×xÊÏÏÏäKbŽÇ£Ûàm6›§Y¤9$Ä/ Ž$ òÊ¥íDÄŽþùùéÔ°‡0ýüÒòé‡ÞÀ¯O»ÓLJðØ™ãxâGúHv9Y0wO„wìwþÀ[É3W$å‚ =H"ÁWjöCf˜Þ)rýR”^]W:ðÓy¼Y?¹Æ:Ù²üŸØ©uIX¤…’¥IÅFؾ¿¿’ÄÖæ|>?å¼H RIÏËív»G¶ ÚÎOi9•Ž3 cë×vDÿH’ÏX‡\Ï`ÈÇ»Ý.›wG/ ò–ØÅò­¾^’)G¯Ç(5“¤Wä86Å[†gõQô¬xj‰péÀOßtpP²nÓ4O³­ÞµZû –ƒiÁ¤’Êy©G‰êevó KPdÙI®ŒêÏÇfb÷^wNt.סÃx$ÿŽbô}Ó{“äã.K‚½ü>Î¿éØ…¿Ak÷mÙβž±­}†åÓËðr€·J@¼Dè™$ùþ±ÙÄf‘’û'õ5šj€ÒG¥9Æ2Á%σiaìÆÐ>:žS¸ÝnÑ ¿2‹„eÑiÛi°ŽÇãÛûädFIw´Q™E’ ¼Úý0¥dä;„x玎Ý# ’d¦Ç»núó^0+ú˜Ó“ìQ*áò¡Ûoë6{@’(¹S¶¿^pdŸ¿È Ï ‹c¾h {*ì’ý;¯á÷_²¥Ît¢œ7âÍöåNMÓÔrºìŸ×ßérÉu‘ŽqìOŽL‡Ã¡x–"Eê÷ŸŸŸp¹\îÅù|~ø#d¹óä¸ÜÌP u]É=q‚%ž,ÒB‘(sTC‡ÓÑî¦izŸ)¦S×LÚk(÷¨ÆÙÒ¥k}°é¥Ãæ‹ ÌV×åi§Ó)¹ ¡ý÷"º²G(ä…ð*ó“Е*©Äå÷“ÌÛíö´ÑV}?FŽGÒ¥cÑçrÈ7÷$“HR~†¥O5³'œÅNQ“䤱û^ãŒÆ’ȑϯî ì’äw(±ý¬¹ú ô{‡P׬xêhoM–Ôñ aÍf(Ui{9ºVÐ50ÙõÑޱͺ‘»^¯÷†×dTO6tt€»éÚqð:Bïv޼rÚeOJskÅÞN Yøž(GˆIöT´® .Ñ9ž=ÆÏ.äy}åd:ý¬—ÞóXûÂß2&ß«õ“—ôÚk—‡hc¹Ž¤}MæI„µ"@š„Nÿ­•VÐVm‹TÖôTt:’ÉCxn„˜9(;¥ÉyÝÿ½5ù’Äøx<ñ%ŠuÃoyéÙ2¡;I¹N‹¤(3¯‰”fy6{\±wúcÊŠÔ vúkûýþ¡òêú’es]Ú,9¹²d_Ò;{ßtØÜÉœòºúksßÇ&QöxÏÏÖ†iFtp¤³t«¯ß?N%§¶Âîã„¡>Ù÷£fNýn¹d€Òñ-ÉN‡÷™ž¥ŒmFNð!¼¶üSF©så´¤ é²¤;FÒÓÁSIàM™éFw¶Cx¼Æ:¿™Ü›×Ê»Çúä4:vñù«l½ló#駞͒ç<„ò\Xò³S1¥íKéÏó>¶ìÏ) ’rצ¤ÞËÍ égH'‰¥nÃZ ÍŒN@'{¼üG©Šº´ó96©ès œ72´Á‘î„iÌ <Òºç¥PªÃñÊý>:ò³uÙ±ïS¾]†—I–Xô³ñ(uÝ>>>:Ÿ &<îÇpd9š|ìÕ¹Cí…-m¯tTûòÊÿ“Ÿ_¢´íí#øñ^û¾MÓ„ý~Ïs„ÕùçÏŸEÔ²H·ÛíEçó9;KTÍE—J?Õˆ4MsùŒÍ¨œ)ò7R[þJôºç»ŒÚò”*_6Pºœ¨VùÜêËLv™«sªØ}ù°®ûl¹±#ߟŸŸÒÁã~ôLê„öãB|9­Ô]ê…’:¡4ÉÍ6õ=8¨^l¹ Ì•ì*¡ë°\{ië4/¢^Ú1ƒ43¥ Í"«Ëèž\›ØžÝÑõ‚¤Ô½µ“Ù#/8òÊd­eÑ.ùñÞ§^rs8žÊNê`tc—ÚÅ®£½æÞó/Ï=÷bXmgù¾)Vo–æ:+bü.uŠ*¹=M] /Qrø„I]‚£.Ëãbd 0 ÙÏaMhê‘ù±éŽ®íôÚý i¸sûKàë#P¯µŒÚòBüh`¼/Ök—¹Þƒ£ØžMÏc8rÏä¥è½dÞ‹,õÎíÒ_Ï Âo𣃕ØÒà>ËJî¼W~V«(t@TúŒa°Þéw@ôÈ9³Ã‘Μt>½Î1Ïø4RÁ­zÍC;E®¾.§o.Mn`‡@ø‹ Œ.5›„þx‘sŠ+Á  ­@n¹ÂZ0²\¯)ÊhŸ ½SÑ»? ó¢gŽôÇ}É-³Ó …çú|R_ã"@Z ½'õ¹%ÈDV±÷è=ú{yPJËÜXe´KGÃ{-ûêÂÀÇüyËíºìC Á/røù|®.z“Z§Ê0õ0 Žùž‘®Ç|‡°¼€(¥4 !Ç|¿¦ïc¾C¨§|v=WpÌ÷xº”?}B—ÜîÇ4R ÎíL’ÜÏW~ÉÕ%ï&ŠÔ-ïBÞ÷¤¾^G€4#CtP—&Ö0h68âxÓ2ÒÑ9ŸÏ½&Š­Y,Wˆ-3º,ÑF—ò§ŸqÉ1Ã=™Žn»BxΕd¦’@I«e å},¡£¾úC€4#©‘8ù¼µ¦Í¯¹FAÄ£D DãÑÊutÔëþŽ©¥|–Ô!Ä—c2ã8ŽÒòG°.ºíÒ[r?SÁoåõÆ\fº.¥¾†G€43¥ (Iηº1(ÈëPô=i8éò]ŽËc9|µ$hýgê7µ @€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€-$h @‹ ZHÐ"@€´ E€­ÿ¼uÅ5<šØIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/palette.png0000644000175000017500000002214712031434614022031 0ustar gregoagregoa‰PNG  IHDRHJÕžbÊtIMEÑ 1í¿\6 pHYs ð ðB¬4˜0PLTE!!!111NNNwww   ½½½ÎÎÎÖÖÖÞÞÞçççïïï÷÷÷ÿÿÿ¾ºÁ¥tRNSÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà#]#®IDATxÚík^9¶ÀaVÐöÝÀ³‹é 4v6жW̬;½€±Ý½€ðÈ÷ ¦ï÷“L6`±³ç–ŽT/é=ªÊ¡”Öù”±e•þU*÷Ö· µ—­—ž@³HH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€äHH€ä*+T6ú“’£¬–Oª`œ*d 9Êr1WäöáéyµúšûÜ }-ø+y ÜdýåæL‘óˆR„)÷Axâž«y”$7Y?^N™^-‹' Ò“ú·¢ ¹Éúó© ir~»Xìîžm©b~‘ÀëöÕ›O•ELnÂé÷øô¯^bM…‡)ÿÚŠ(µzÇ“5…/ÇG‡l#ÙR¾Ö󬟔à?‰¾û¿}Ò¸’R;Cï0~ 6Ø>Öÿųâ<\Þ+ókvÞ|ªlU7à>_)©Ã ]¨6mP*¯qH{ÄH¿k¼ÌñCJ&Cbª³z`gGÁk¿ }+i M H‹ù’i9H†«Z:HñM”*Ìl»û 5äÕnE&SÌ;’i÷°…Ä÷FÒ€0ç&óóÒŠ†]äDœòZÓã#H#Ü…Ç^ålÔƒCtæ =CYbHÛ ÈHHñ)ì ééf…=Ê1"æ—Z5àtWcHÔÁáTÀ‘p.ƒÍ4ó\ps@¸ðØ¡8Zõξf£Û§ÀnCª¿Éy}2Lõ¶æ`Ièkæw÷v[5¶£Ãà^!EèÓç1 b=!^`¨b·Ù£t@Yâ˜R{?~­(³ðµ½ÎñÔèÄ”R¢ùrëV;5$˜rÖ3¶÷§‰UÃîÌù‚ØzÞa~f{Ùäüj>g±4“qöNÝʘ԰ää_ï7ëS±È]ƒÄL²ƒaíËDp'ßNr#ð§ˆ{ÛÈubÕ°P±_ìL*¤æÏÇS‘#²@^Ì|O}»8ØC_ï¨ÎŠèkÍŸ¦@‡ $­/7†mîšhƯK,y"™ßêó¥°jð÷Þq!EïP~Ž’ uŽÏgW·Â*ñx­b·›ÑQ²D§‘׸—ªaö¡ç 1ËÛÿR¿Fk7ö§°©[ꑈ¯®žî…UÃðÞ«¤9éß`=]}…¨ÝåÇññT–Ú˱#cü¶s€¤}ì0¡8æÄìÉŸX'V n¦ôÒEÆA¾únñCU£-Éèð-QfÒˆ‚´Â|íÒ…âÞ—!%¿Q{H©n@ZlÒ»J!íg!qgø|ñ`‚ôRüÖ]ß%g!j?Xi! *´ZÝ1ÏÕ‡dŠXÈCê×Rboίd³“óùû²|±†œÄG¤C›ÒYEš@¤ì  ¯eÌ!íîf¢V¸Ê±ÀÍݦRgHëå=âôƒøšœ] zE³åÈCöƒ[4*œ;©À—›7;Ø:$³âê¥..…5(ý al¼ùÓhÕåƒiÜ=“Sÿ…!:xòë¶øŸ?h$cÉÍÎÕÆQ·’qEºTöÿeèÀfõP×TŸÿÙ¬ÌÕÇM‰±áxzkJøçffemƒ™²Æ@<ùõŸ¹iŽÖŸ?»·/±'n·£®b¼Æÿä‘ÂZ“@2:¤³Š5‚㘇%ŶßÔØ0ºÐ¥Èð"ýïñ-³vqһʳ•Cú|ª>!|Wó)T‡[&Md?J;|¸/ ot%³Š^ø#!~CÄŒ'ÆïÄ6ÿÁœ}àËûAœ3ª7¤è]ó+²Š¿å–†©´Ÿqó‘òf†©ŸHT} C:«f‡ˆ¿ÑÝ1 ÉI†nŸlVË÷'"yÉp’yiHcîhÃýNÈ9”0×»ÖèœÀ¼Ú+ÝGvò#§Æ«%_þu§\ý ¾UÉ臄~d…MÜÒØ€@2i×WHŸlfå É1ò>†d4&¾4¤¡¤×¶`ІÒÊ8«2ô 66”‡tä ¤Cæ'r…´óSƒ™€Gr‹)Ð!€=HŒ ’ â×]Ò#8¤AÝ!!×J:Á¬!AXcfL… –Üø¦@‡µ0÷ìâ¡c2q cCRœQ_gH‘k¥œ`öÆ"`ŸÇª º¹H#s ƒ˜U—8¦Æ†üá~{ÏÒØÈê#īןeþ¥AZ…­!‰5>ä‘È“)¿ÂèÀgŲõ°WcÆØOöîD³±Aš)¯LQ_Hð¼÷ä’Q—€´ú8†žx?¿¿–ƒ» 0+^'Ùu3Ɔ|XŸ°ÆZ’¡î’ÊCú ‹—†¤dú‰¸È‹ÒáÍÃÓç·j˜¤>ÐÏŠCRïÔØçcC2”׆Å!-3~û´úòV 8Þ.I56pHÿ¶76HFõ†Ôs€d§Ì.¯s¯Ò@ ©g†ôÉÞØ*@zþ¶¤!½+i¥…ä”Aî=¤wòê¬í!(Z*¤¤>i ¡þm*°ƒôOïr»Åò¿GíVk?Iè …´Z®,À)Ûq­Å A^{!C%_l#^ÀÜÅ®#5ÿ33]£ )Þ­¤÷ì4ÞÊûе|V܇ Ab¡kUçfŒW®µ2UÃõÁé/ ‰…º£:aþ¥Ù"d`¿)ûJAom ÇŠyµÁçý^56³ÝÇZ ËOÇâ(j ¹Ë1Es¹˜ß ¡_h8#Ï«@ÀnÅ,iKÕ:ð·XÙ!)Í,ÊcU**W³IHû*$yÝÙÕœ–€T Ø §’@HÜRµŒª†ôe¾HîhHŸˆYQ¨ü‚Òš‚¤¥>^ŸN(Hò‡³Þ=»gd¬uÐü›süúR…§ïÊ!±NÄ€Å_£áÈLšj˜14:ˆe‹!Qê¬Hê!ófv‰Ó&@k ÝT¬"U ŒoÕj Ó,¹¶Ñpd¶ÖIª§öÈÝëÄv‹4¬$»ªTFFbÚ@5,¿†³HÄ–€i†r/ ‰ëjµæ–¹’”;4ô‹§Èä? Õ˜š#ç£e‹=©»j ’‘‘˜6PMàñ=z¯rkiÞ™Uê±UCF¥ÚB³3RâmÐ÷ ,ô«ü‡E]ˆýŒšgd`j^KbÚhb».j[%^6Re»ÅM@F„®Rm!‚ôáIJÜ^a )ß²Þä>g_ˆt ¸·‰*6xFFbÚ`éLÞu‘à¦øéŸó"¬rµ~ë‰ïïXº¬ú>GM;âåŸO‘au!ÆüAˆw«5O)'4##1m`©Iè4¨ËJ6Òc»bHøí²m,qHü B‰µÍ¼ÝtÀÂÁ’YaÇ’†ÄŸˆ@¢ôS,Hž{Ä-Ò#r2Z®5¤dV(¤k ¤—Fã¤Ä$ AZƒ$ùYÿ–pýT¿^ ¸9,)sÞBsslÚØ! ª,WW+H—˜¥)¢È\Ö¡ÞPµT’x.Ù-Ð@¤ºSlÚØÁ"ði€ºöãB²þÕ"Š¢„ŸÚÓI‘I+0Hv ÔŒøé…i#Ò|¥Jü^yLChUk¤õ€”¤›v0¨ò=è)¹þH`j·‘ìdÄ‹dp¦Hó•*Iðð†Su"¼á·’?¦zµùºÚJÕ $,+[!gŠ@ÚÜ´ÁúÍI•$xqŒ·È4 ¼¡Êš‚u‚d™?›Þö•ú3Ø{?[!«^â96j"”0m@FVIBIÐØ@ý¦ºA:1çÅI j£̪CU`À°zÒÙŒŒ|%‰´`“Òï§_mÕ™ºAR’ü:$<‰ÛH™¼ñÌÿ Hõ’ÌÓ{ÎÃ~,Hd|<êf§’ûÑ@ Òu1HΞsO }ü®îÊBª8¼ÁH Rþ%ŒWL€7J‰… *0 )¤¥KaHï~THê«\‚]'?"x_PÄ+GU`@D«ì!.N›é*•$ˆ—EcPü€$ÒÑi.¼Ûð„ˆmª±T4ÐAÔl{ÈÕã´%R¯q¹E$ü(0›©tW‚ã[j¨"¶:h †(Ð@^ýPVzñtY] JÅMêIÍiÎ÷ö¤b×M¦JÓW²è½c^ræ#*Œ *+ƒâ$ÌšÆ{½ÄwelHó)G²Ëš®À€:ÄÑ(YC,‡¤TE¥‚ÊÐЯ–?–»+ÅÛþW¥bB SÉF “û‰@‡m)ºRä6õý­qÉ ýú ©½é¥­#>’ᙲÃéŸÊËZ[ thJÎÁL’ßføÀ!M+ç®9¤ÑôƒX|´ùò¹$Mr¿Ez@1HÓêƒîkih†Ô(É"Ñ&@²„4ùSôÏ]^#VÑ­¸~Vú@_NY;Ç ½“ IH†àÕ•AêIqh³Áù‚K¤Çæõ݆h~¾×!ZH a9‡Ç*úžxŽú(¤) I`xÒIå¤*„ÄÒH¬Dk·ÈD´ËK A牽sÈ'*Mê¾È<”<‡%E«FÌGŸ<¦DfoÄÎn·¹FnOÇW öž}9‰;nKr’o·ÑmPcFøÝKW`H*ªYœ´"¶6¾º0p% D|…õW„.´gR¢{ñ|^qÔ~¥TW4˜{„2 €Ú™×&ÃÑp:CSFè ð¿X Cêi->Zh[]8QtjµÞœŠV¹´LÎfu­ãÀŠ%(=F¡5ÛϸD ž9qoÓ`'ñÒtj¡3.,‘‘±/Š"‹äh.‰ˆÕóðå$î Ž §Tm&Y¥vTHœ bÉõ¨»Q´A\=àïZº:ÐlHIC«à˜$¢Œw9†m;.v”—>ç4šÖµl ÙcTâ²-(Ž&à;þ¢¥+0Hx C¯/ q·^«à¡Dì÷sèúG0”ŽG…о¤.‰Ò]ž‘Î!Ñ>ôõ’ÈȈ!õHHøf z ¤*µa¿!Ý ÝHù+p„Äv¿‰ì±¶€D:¬— <#ÃéU%j¸Ýu Ó·Q^øQb:O §s¢<£®Cè@edh!mk!‰ƒƒRMiûJ œÀ1aZ,«q="¿ßâj‰¶ÿ„6ÐáéqŽgdh i³^Ò#ø  ¾ÔôŽEÞ€Í'Öe‰“( ¼:œ¶‡¤t¸¿Ä32hHú¬—T™¤¶"½þqm•Y´z[,°ÐJßÂ<¿%zAh+0ðßÕ:ܰ¤6,#ƒ†$úx뛚…Xc‹¨æa”úì)ª§Y̓m§Ça¨xF`äºbæÈg\ÕW`ࢠt –‘ACâ[%™šXï޲ИöþnN'ÖK£¦V4¬É­Û#ÕÒ™¯¢»íAöÑëÑW`ŸÑ:À/S=1 H¦n¨à…àídwó‡!þ~¨««BÓɽM$JÀˆ—À\ÑÝà ÒU#؃fdh ˜ ÁOÆþM,©ñS]~HCÒÙ¹±&º¾Cfµ)z’òµâP'´E“ÎCwtÆ’ÏŽ f…\_Á IÜR ièɬëé+0HZHxOÌ @2õ$®$Ì=œ"nL«êŠÚ ÙûïQtÆJ‘sÏѳzHppØHÒz5ÈœæþèìL¡tf¥k*0H+6èáQJüôOôÄ$!aÍV-~Òt|yHdOÌÁè|~3;ËË̪K]AYm4Q@¨gTOL´? ÕlUt¢äØ~1Hšž˜,QBŽ­YX)ätés˜{œ TOL’¶ã… kiÒÛLÒz%4=1 bÓŒ 9]A‚„œZøŠ1›4Ù…DuÄE¿ÛV*}ô6TY *HTOÌ?ž‹FyÒ$HˆM*R¢C”QHvOþÝÞÆÊ?lR‰$ƒo*hu°fÐ÷ý m°üCUzÕCº¶…„CHïi3•¤©D9kH»CCê?H)ÿ°qH…MÂt†¼$¥®³¿~’¶ÒQ9Híj¯W#Õ@²í‰é4(UA’¸h|·ÞAÂM_5$D™Ýdù‡Š YöÄtTÛ°<ûAæf‡éÀwÏŸ&*#ƒ¨jhÉ®¶hUR$Ëž˜NƒjóÇ2’6OLón B•tJÍ[H–¥”«’j YöÄt”ªÀ ýz|+e°q—ö.‘p±„¹;R•ƒ –¨’eOL·A© Šð„>åYæ­±©+ îiGNòÙdù‡ÍB*SÌGdzxàAC–‚$ÿÐ&Ë?Tɢݢ۠¾‘È8òrº(¤MU¨’mOL' ©’uOL'!+0î9BúXÒš‚´ž‹ å!9ôÄt–¬À€ ê+M a‡®UQHDIÙëÕIiH.=1íEW2Ûˆ<S….M’\IÊ]¯^JCré‰i-Ú ˜èŒ ªdlÏFuƚ╸^ƒ”†äÒÓZ´0A3“ÍÈ@˜!%¹ ¤×k²œzbZ‹¶: ªæ™‘u/µ€”æzTy½) É¥'¦µh+0 ÓÀ’oâ] £ãWô°T¬Ò×kJ ÙöÄ´mtx4MÃØ2*¿^ƒ”†äÒnÑZVº ŽÓ !‹@ÚÈõ¤ž´§AûÿÝ ÙöÄ´ª'&= ,ÐaCN«¿^ƒ”‡dÛÓE´Ði`[˜IddÄ)¤;®Ðšï%¯× @²ë‰é4(ÕSû %Ъ2PñijºƒE,8Zó½ìõš¤4$Ûž˜NƒR=1iÁxU"##~ö²X·›íŽ!6 Ë—Û`þH¬zbº JõĤ tUˆŒ ÞI5_ˆJ¸©¦fGgÓEóÇÊ^¯IÊC2öÄ,0¨mþX^$‹¼EÒ>vìivtÞ´’QÙë5IyHÆž˜- )ëÛ²ÈǽŸq#×k’AU’äç)çÚ¶„4D Ñû\¯Iþæî¤Âƒ„”t°¨¬€õQÚk~ë5IIH"÷Éi.‘>ºŠÓe‹@J,Ô—¤…tÆé.Úk~Àd÷&»¥—‚ç>È=1Kåø²Aß AÊ:XTVH ¦iÊÙÞ¸ê7Р›ni_R’û õÄ,•ã+튪3NÆ–| ƒEe…¸ÙEÖÊ*Ø^à^÷eÕ×k#e %¹XjRÑ|*1h´mgHù@‹“14»8³D¨äáHJ^¢mN–o+¾^))Î}P²^¨ÞÖƒ²§áÀÙK“t°Ù…ëÛj<ï¿Á xXÐR×k#¥ ‰Ü9•î-á0(3¢9»Òr6»4»xŸ7Ç5÷Z¬3S‰õ-u½6RV'­i[`;h1g&ÐÁ²²‚8K¦VVè0›Øa%J]¯üh¾å!ÙûËù¶Ü=;ºš/vXây­!%aõUN:ô¥!] =;IH c‡”âR’Ú$®<¤8V¿8¤^ ÉæÐ%»Ä$xÍä¿»^­|ƒ_of—'x"ö|^ R«_Rìð±ÍÈž¿_vÄ©yg[Ñí|&5û&ªlë{iT e %aõžvR#iÁ¸Ðtó²ÍÈž¿Ã8Ø ¡úì6WfÝÞu™UIHï©dâã³ÙU1½!õ®Úö$$ t°ÍÈa/l“„’}èÐkÅy¶»*š.«ÍܨJÊ@B’ì9$v Ÿ_ƒôqÌ"Gƒ ƒO½¶<‡ƒu%í¶áQbeò të$»#àY/ÚÌŠ¤ $¤×K © ™$ñS¬J6úÕ2#ƒ'ÁdOÑÖ…Òýï´®ÍܨHJ@ @ʬÊÄïXvœ’$ t°ÎÈX/Ÿžßçâé¶ùâ³7bhÊܨFJ@Zê -ý–9†t' Ùfd°ö±Rü ˜z¹› ½)‹MÒQÊ@ºÞ ¤^IHi¿F—èWébR‡AJ®½ÞéE!í¤L³U4V¿æ¢‚€ÔQŽïÒ5t­N¬ñõ;¾“ÅA¹ëìïe RÚ¶‹¨nìn®I\*!‰_Lº!K³Ã£žÚKóu€8@bE½RtºuêS:ì7œ‚ýÅ©àpWôÊnòín$€3¹?…¸ÚìõF U!eîû@bÎ2˜t¤©ïʲ×9fÍd¯žÄúZŒ°žXó¿›1 oè²A÷ ‰kÇwè0<:t öççkÖA°ÕÚÕùxá÷‰èy:f¡ÏÝäzY§…è.¹Á„Š„Ûî¬vKqqÓ«ù4qKUeκhN Àº ŸÏ­Z5¦C]ŽY¬Ë.Ä5U8ËZ\ÀX,ù i†:„ðôöa+iƒÁ»•l4V¿ $®¤Ã¬»mExuÛQ¤dœG”, &°GA÷Þ“A²N¼O Ý9›ÙÛÓ‡Ü=ŒÝv¼ÓL·íí#þš^j'þëñp³Be ñû. ¼’…ß±¡ÛZfÆ0æ‘4§d_ƒ®£åv»Á™õ4z“Ë ‡ð@ÇrØbÛ`Jîö‹ó†7”Äm’$$X]Öå|ÂL”f#>/~3<áas2ˆJk ;ˆÁü&.É(ëèÔòt {n¤Ãýü˶Ñ‘bZì.üÓj«x1HòM/ ”!žœÏoí E‡e<ì)#G3ÓêîÔ9Ϭ—PŠEd°µ¡:Tr–?Æ^'3+®hlÒl÷ +„䢯ØxîÑÙ¼x_’Zg<)Uu7)Rv¤3Hn³*,¥ LŠlwòÁ¡Èv·. ¬ã¸ácôNRuþN*6«ÂRæà ¥4(zpÈQ‚Õp<8Ä㹟ŒÅ9|?Ðí–¢¨ïŸUa)sçw>%Ç…Žàê˜CÇ#x:žs=X+θ¶Fé€~áY–2Êìx¨fNqWfñ‘”Ùt<÷»œY+fg|ôÍWtV…¥ŒY(ZULÏ‹˜…Ô1ÏÍBéxî Ȭ‹ùe< üŽ)>«¢RÂÀÊì¡fQG«f$—ÇÆs×1A£}ZÜG?z3›±ûP•YñY•®Š\-+ÃJ7 Ë@ÙñܯKšÆB•‡2³*(eQŒâ6ÞºªÊŠù¾ó¬*i¼d³ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ’ y ÿJ?ßÓŽk‡bIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/pal.png0000644000175000017500000000031012263740600021135 0ustar gregoagregoa‰PNG  IHDR(-SKPLTE§§§æèÿyyyYYYììì333ÍÑÿÆÆÆ²²²”œû”ôfqÿ)ÿfffÿÿÿùùùFFFååå,,,ÙÙÙ1?þ ÿZᩳ8IDAT•càáãeàâ`€1 va„7H²« kaædG°±0ó !ñ‡ì0)áÑÙIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/rgb8i.png0000644000175000017500000000627012263740600021407 0ustar gregoagregoa‰PNG  IHDR––ÄdÖ#sRGB®Îé pHYs  šœtIMEÛ 6]›Î÷ JIDATxÚíßoW†Æ1¶B"o“ÐÚDu³D)VTTD‹²Š !+‹Xi¯»½IW¢R÷Ž?‚»-ª”Vª„".ÛJ@—(J‹èFT(¨QäÂ"gS»$‘ãØÇÎ^˜M!±ã±=¶Çá{40ñÌ™wÞókÎùæ T;^ú÷É4oôsèîÆßnܱ–f;y-ÍnM®ü·Ó*¬úØ›úÏPoú4Ó©°ºá—«Šº«ýdž=†$g¾Vqµén³MùÞ¡EEšCßœæÛTÜ!X[Eyù°Évu÷6µáëYšî7în} Ú•’æ!¡HµÉ{`Kó÷“›jŽˆ½²ãZúœ°y_SÁ9!ý‘ý|¾ÆŽ5v¬˜iùo–Süvµãtl¸Àîá4W»ñÈ͕ЋLžUç nä©3„%×[um‹ì•Zs WþÊå {êBêÒ„5+CôÎÒté|ÆœPŽ<$Ùso–-m3·–%Ÿ—!ÏVå^Ã&Þà‘ 7ŽŽýdÉZœ[ÓÍ5ðú¶bâÜeµ7VU’ý ¨±l¾ÓŠIÚ™Q:®Eöq1©ÞפšÜÛ|Ť2ÉoÎh”}ö1½‚)ë]ìÓ.û¤¶n†çiLÛ¢öQóDÓ» kŸ Ì©=:TõÛ„´\‚ ²¯`‚žŽîÁËò?ÜÍøÇ¦ªoÖ˜mÊþ«ke­¾·{z9÷Œw|‡Ÿ-„·?úÈFÒò[å—¦‡èÝÐÁñí¥eUm~Q›Þ9.oÑ•ïÈÜ©É#½n†7 O¦M2½Ê\Ó3±’¶¯¶yëÐ"½3|¥²üûö¦“˜kyÿˆ/Tf¶7gyãׂ˟¶Oú«_rd Y Nï&GÕö„MÜk/¸~y›Y ßVO£y”÷Aú²&¶bbß´FéÕðd’ö-[U2+äWÖðd¾´7v¾ñÕeMÒKm­<¸Äùû쟥i–¦¡nåÌׯ-4IOú/:ï¿$rx°ü*žšƒòP!‚ ¯ïXÚábn£k9Ã]¼€mAƒSÀXÈgôÇVh.ŠB³›A›s[Á ›þhé…•OUñNm"êÀÛν£|ïdÚ75v›"<õþ-ìiåæ1îµãu3—ASn¿ÿqèfx¾yUè¬*Ì72ØG÷ð–“Ô[<Ê7•Da OÎqy’v•ÂÒJlçÜåu–Fá>¦éSº fØl°/ÃÈY¹¾Íƒ!Žçm]Z3‡Ž¿ùœ¯B êÒÝ<þ„O»øÁ@R« À¤ë>ù”ÝuÐZ´sï(7ÍÄ´­åÌ1ŽÞ¤ýžÖ®{©к0ua(Üþ}7Ü(ÆÅ¹à> …xó >ú•½ÚÊûu/_|Ä£7õѧ1±ÒÏ€Ê)Z•¡›ýÙfAJÜâ+¬v3=uy/~¶ìX [ Š‚¸‡ù’?¦HbXº„Õ·á A3ؾÄZ í¡ŒbˆÂ²Ž›À•þõÁÂiôãrgÎTƒÜhýl#‚ ‚ ‚ Ûé¿\P„ S—[›¯(¸3†|‘m4Ñ‹2Šañóñz¾ÓàT~¸ßå©Ð ¶¢ÄµÀjÖìÄ[f2M…¢PŠBQ˜¢ÏšˆZ[ :ð‰§vÆAoÐô¶=¬´ªhy#QÏâïyx÷mbþ…á„÷³ðü þÝɤ‹ÿ´h(x&8/NÂl3ë© Úúï³ÿ1»3Eg¬*<ÞÍýý ôç;»³éWê-–ÂTŒÂy.厑ŠÂ8)¯`…R*TXmgòK>Tÿ¼!úËiŸÌQdɦä]æÜjòzRÃås9Š,™ÂFæ/q¾yë"/§q^3…ŠVMB#'¸QËÓOUû”7èÁÕS‹oÇ{–+|šœÍáãìì^Ý(4íâVZÅy’tLÐuK5PXÏb/à 4lˆôS¿¨…-Ì´1¥a ~ÊÆ¶)Zft P!ÑÌœµk4Xƒ4Ï¡$Ê­ÐB¨“ÑbÄê×…éÅ*·B31>s’Ì1> b¦ä Xn…QL^ìêW1ÎáÌ&¼v¢¦r+ S7JgÈJÈÂh'áºr+Lb˜£9X„xí •¹f †64(‡3´LідH'¦Ú˜iÑGM a˜ÞEê5T¸XÏp/}(Œa¾E×ZÙ˜P˜èàV—6Ú\“ÇÎz±kr6¯+gñ9ôÔÆ0ÐsƒËÔxªånœ`¤§D ÈHÔk5š¨Ûá­ÔV8µêoÉJˆÝS´M±?Žq‰*±P,ÄBA, ±P(/UÛ+?&ŒÄ«‰‰H³ÔRœ`„hœDR,Ô‰[Õ<«åi‹ÕD,„ëYlcª@5‘ÍGE¢ÑExj̆Ã6"Õ,6°\Cd‘jâÆò¬–úY˜²ÍB¨Žp 3v¼.ÜÍÌ×HYh&úR)LSÌaân"âF¢æê™kÂíÂç`¦……p]%ÙYUAÎ53ßÎχ¹ãdº…™”—™ÜJ‹!‰!öÊJhmH(Ä/œ›iÁówsïæš*ÃË*›WMÄ÷î#Ünå¡“éTÓp5Æ”¯{س€ÓÑۜÂó[¹}„I^‘jýY¥sóÞå§c|q^mËdgíSjŸâðòþº~à§wùþãõk¤-4mbî0wz9ÄÝÒ˜—Ö˶)^Ž3ö#=Ü9Ì|s‰V8ªT S…ωçnŸæª w›—ÖÈúEÞx„5ÈGð8õU«tå_=‹.ܧ¹z„xJ_ø2Ùàý;4h›âêiÜ®²}¯A¿¦üë`âÏ|ÓÅ­"­Í[xq¬~†1Ž’d¢C/.êÅB ¡Vžâz'£zóoÔêÌ£Ä/†–~§‡Ü¯þ‹ ¿ · · ¿>ý[wÑæÇåÆåÆæ×ì o¡…_'£v|ÅX½][êÂØ}tŽb÷i°"üv°ÐDÔJЉ§™¹Z–õÐÉÞ..Ó<‡Óƒ5Xþ‚¨H¬ô‚X~ $wßEdg.£e/ˆ;ã슰SÅ2å[ñˆ…baÁ$Pžc|FõsŒ‰ ÉR …çFžUóÜHByí- SçÃ>J§{1¾aR B|vF;ñÙ5ø:JÅ[ÃÄêÁ9Gó2µú/ˆ …åZæšñ8 ZË?q¡‹ûUYQWEP/Æ0û±¹q¹qù±ã£WZ5á·ávává·ébîP/ÃÜaêÒzS©øA}Žt§>~6ÚÉõS´­^]÷uË_YÁ\I‹ŽeC¦|ÅBA,ÄB±P ±P(ÏsaêsÆc¬¤U£AüÆü£:ºêÔªÀÙ>¾œ Y›[¶6· ‚ ‚ ‚ ‚ ð?äô-Ç»Æ^IEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/coverpal.png0000644000175000017500000000020412263740600022176 0ustar gregoagregoa‰PNG  IHDR “OPãPLTEÿÿÿÿÿÿÿÿÿÿÿÿªNhŒtRNS¿?¿?½ñ%8IDAT™c( c‚Fe  uo6øIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/coveri.png0000644000175000017500000000014412263740600021655 0ustar gregoagregoa‰PNG  IHDR f}F+IDAT™mÆÁ € ÀÀc2Gs4t²òÂðð’&Uò)÷žY.‡áÙ ^?bëvnS·/IEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/bipalette.png0000644000175000017500000000020112370401736022334 0ustar gregoagregoa‰PNG  IHDRZÍ0‰0PLTE!!!111NNNwww   ½½½ÎÎÎÖÖÖÞÞÞçççïïï÷÷÷ÿÿÿ¾ºÁ¥ IDAT™cp`hDÁog1àIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/bilevel.png0000644000175000017500000000010512263740600022005 0ustar gregoagregoa‰PNG  IHDRZÍ0‰ IDAT™cp`hDÁog1àIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/testimg/badcrc.png0000644000175000017500000000010512263740600021601 0ustar gregoagregoa‰PNG  IHDRxSÞ IDAT™c```£ ãIEND®B`‚libimager-perl-1.004+dfsg.orig/PNG/PNG.pm0000644000175000017500000000242212460670607017177 0ustar gregoagregoapackage Imager::File::PNG; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.92"; require XSLoader; XSLoader::load('Imager::File::PNG', $VERSION); } Imager->register_reader ( type=>'png', single => sub { my ($im, $io, %hsh) = @_; my $flags = 0; $hsh{png_ignore_benign_errors} and $flags |= IMPNG_READ_IGNORE_BENIGN_ERRORS; $im->{IMG} = i_readpng_wiol($io, $flags); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, ); Imager->register_writer ( type=>'png', single => sub { my ($im, $io, %hsh) = @_; $im->_set_opts(\%hsh, "i_", $im); $im->_set_opts(\%hsh, "png_", $im); unless (i_writepng_wiol($im->{IMG}, $io)) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, ); __END__ =head1 NAME Imager::File::PNG - read and write PNG files =head1 SYNOPSIS use Imager; my $img = Imager->new; $img->read(file=>"foo.png") or die $img->errstr; $img->write(file => "foo.png") or die $img->errstr; =head1 DESCRIPTION Imager's PNG support is documented in L. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Files. =cut libimager-perl-1.004+dfsg.orig/PNG/README0000644000175000017500000000105712263740600017070 0ustar gregoagregoaImager::File::PNG provides PNG file format support for Imager. It requires libpng, including development files, to be installed. libpng 1.2 or later is supported, with minor extra features with libpng 1.4 and libpng 1.5.3. For Linux distributions this typically requires installation of the associated -dev or -devel package. See Imager::Install for more information. Imager::File::PNG is currently shipped as part of Imager, but Imager may install without installing Imager::File::PNG, so if you need PNG support, add a dependency on Imager::File::PNG. libimager-perl-1.004+dfsg.orig/PNG/t/0000755000175000017500000000000012617614576016467 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/PNG/t/00load.t0000644000175000017500000000011712031434614017711 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use_ok("Imager::File::PNG"); libimager-perl-1.004+dfsg.orig/PNG/t/10png.t0000644000175000017500000006750512370401736017602 0ustar gregoagregoa#!perl -w use strict; use Imager qw(:all); use Test::More; use Imager::Test qw(test_image_raw test_image is_image is_imaged test_image_16 test_image_double); my $debug_writes = 1; -d "testout" or mkdir "testout"; init_log("testout/t102png.log",1); plan tests => 251; # this loads Imager::File::PNG too ok($Imager::formats{"png"}, "must have png format"); diag("Library version " . Imager::File::PNG::i_png_lib_version()); my %png_feat = map { $_ => 1 } Imager::File::PNG->features; my $green = i_color_new(0, 255, 0, 255); my $blue = i_color_new(0, 0, 255, 255); my $red = i_color_new(255, 0, 0, 255); my $img = test_image_raw(); my $timg = Imager::ImgRaw::new(20, 20, 4); my $trans = i_color_new(255, 0, 0, 127); i_box_filled($timg, 0, 0, 20, 20, $green); i_box_filled($timg, 2, 2, 18, 18, $trans); Imager::i_tags_add($img, "i_xres", 0, "300", 0); Imager::i_tags_add($img, "i_yres", 0, undef, 200); # the following confuses the GIMP #Imager::i_tags_add($img, "i_aspect_only", 0, undef, 1); open(FH,">testout/t102.png") || die "cannot open testout/t102.png for writing\n"; binmode(FH); my $IO = Imager::io_new_fd(fileno(FH)); ok(Imager::File::PNG::i_writepng_wiol($img, $IO), "write") or diag(Imager->_error_as_msg()); close(FH); open(FH,"testout/t102.png") || die "cannot open testout/t102.png\n"; binmode(FH); $IO = Imager::io_new_fd(fileno(FH)); my $cmpimg = Imager::File::PNG::i_readpng_wiol($IO); close(FH); ok($cmpimg, "read png"); print "# png average mean square pixel difference: ",sqrt(i_img_diff($img,$cmpimg))/150*150,"\n"; is(i_img_diff($img, $cmpimg), 0, "compare saved and original images"); my %tags = map { Imager::i_tags_get($cmpimg, $_) } 0..Imager::i_tags_count($cmpimg) - 1; ok(abs($tags{i_xres} - 300) < 1, "i_xres: $tags{i_xres}"); ok(abs($tags{i_yres} - 200) < 1, "i_yres: $tags{i_yres}"); is($tags{i_format}, "png", "i_format: $tags{i_format}"); open FH, "> testout/t102_trans.png" or die "Cannot open testout/t102_trans.png: $!"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); ok(Imager::File::PNG::i_writepng_wiol($timg, $IO), "write tranparent"); close FH; open FH,"testout/t102_trans.png" or die "cannot open testout/t102_trans.png\n"; binmode(FH); $IO = Imager::io_new_fd(fileno(FH)); $cmpimg = Imager::File::PNG::i_readpng_wiol($IO); ok($cmpimg, "read transparent"); close(FH); print "# png average mean square pixel difference: ",sqrt(i_img_diff($timg,$cmpimg))/150*150,"\n"; is(i_img_diff($timg, $cmpimg), 0, "compare saved and original transparent"); # REGRESSION TEST # png.c 1.1 would produce an incorrect image when loading images with # less than 8 bits/pixel with a transparent palette entry open FH, "< testimg/palette.png" or die "cannot open testimg/palette.png: $!\n"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); # 1.1 may segfault here (it does with libefence) my $pimg = Imager::File::PNG::i_readpng_wiol($IO); ok($pimg, "read transparent paletted image"); close FH; open FH, "< testimg/palette_out.png" or die "cannot open testimg/palette_out.png: $!\n"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); my $poimg = Imager::File::PNG::i_readpng_wiol($IO); ok($poimg, "read palette_out image"); close FH; if (!is(i_img_diff($pimg, $poimg), 0, "images the same")) { print <set_file_limits(reset=>1, width=>149), "set width limit 149"); my $im = Imager->new; ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image width/, "check message"); ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image height/, "check message"); ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside width limit"); ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside height limit"); # 150 x 150 x 3 channel image uses 67500 bytes ok(Imager->set_file_limits(reset=>1, bytes=>67499), "set bytes limit 67499"); ok(!$im->read(file=>$limit_file), "should fail - too many bytes"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/storage size/, "check error message"); ok(Imager->set_file_limits(reset=>1, bytes=>67500), "set bytes limit 67500"); ok($im->read(file=>$limit_file), "should succeed - just inside bytes limit"); Imager->set_file_limits(reset=>1); } { # check if the read_multi fallback works my @imgs = Imager->read_multi(file => 'testout/t102.png'); is(@imgs, 1, "check the image was loaded"); is(i_img_diff($img, $imgs[0]), 0, "check image matches"); # check the write_multi fallback ok(Imager->write_multi({ file => 'testout/t102m.png', type => 'png' }, @imgs), 'test write_multi() callback'); # check that we fail if we actually write 2 ok(!Imager->write_multi({ file => 'testout/t102m.png', type => 'png' }, @imgs, @imgs), 'test write_multi() callback failure'); } { # check close failures are handled correctly my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); print "# closecb called\n"; return 0; }; ok(!$im->write(type => "png", callback => sub { 1 }, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } { ok(grep($_ eq 'png', Imager->read_types), "check png in read types"); ok(grep($_ eq 'png', Imager->write_types), "check png in write types"); } { # read error reporting my $im = Imager->new; ok(!$im->read(file => "testimg/badcrc.png", type => "png"), "read png with bad CRC chunk should fail"); is($im->errstr, "IHDR: CRC error", "check error message"); } SKIP: { # ignoring "benign" errors $png_feat{"benign-errors"} or skip "libpng not configured for benign error support", 3; SKIP: { Imager::File::PNG::i_png_lib_version() < 10610 or skip "1.6.10 and later treat CRC errors as non-benign", 1; my $im = Imager->new; ok($im->read(file => "testimg/badcrc.png", type => "png", png_ignore_benign_errors => 1), "read bad crc with png_ignore_benign_errors"); } SKIP: { Imager::File::PNG::i_png_lib_version() >= 10600 or skip "unused palette not benign errored before 1.6.0", 2; my $im = Imager->new; ok($im->read(file => "testimg/bipalette.png", type => "png", png_ignore_benign_errors => 1), "read grey image with palette with png_ignore_benign_errors"); ok(!$im->read(file => "testimg/bipalette.png", type => "png", png_ignore_benign_errors => 0), "read grey image with palette without png_ignore_benign_errors should fail"); } } { # write error reporting my $im = test_image(); ok(!$im->write(type => "png", callback => limited_write(1), buffered => 0), "write limited to 1 byte should fail"); is($im->errstr, "Write error on an iolayer source.: limit reached", "check error message"); } SKIP: { # https://sourceforge.net/tracker/?func=detail&aid=3314943&group_id=5624&atid=105624 # large images Imager::File::PNG::i_png_lib_version() >= 10503 or skip("older libpng limits image sizes", 12); { my $im = Imager->new(xsize => 1000001, ysize => 1, channels => 1); ok($im, "make a wide image"); my $data; ok($im->write(data => \$data, type => "png"), "write wide image as png") or diag("write wide: " . $im->errstr); my $im2 = Imager->new; ok($im->read(data => $data, type => "png"), "read wide image as png") or diag("read wide: " . $im->errstr); is($im->getwidth, 1000001, "check width"); is($im->getheight, 1, "check height"); is($im->getchannels, 1, "check channels"); } { my $im = Imager->new(xsize => 1, ysize => 1000001, channels => 1); ok($im, "make a tall image"); my $data; ok($im->write(data => \$data, type => "png"), "write wide image as png") or diag("write tall: " . $im->errstr); my $im2 = Imager->new; ok($im->read(data => $data, type => "png"), "read tall image as png") or diag("read tall: " . $im->errstr); is($im->getwidth, 1, "check width"); is($im->getheight, 1000001, "check height"); is($im->getchannels, 1, "check channels"); } } { # test grayscale read as greyscale my $im = Imager->new; ok($im->read(file => "testimg/gray.png", type => "png"), "read grayscale"); is($im->getchannels, 1, "check channel count"); is($im->type, "direct", "check type"); is($im->bits, 8, "check bits"); is($im->tags(name => "png_bits"), 8, "check png_bits tag"); is($im->tags(name => "png_interlace"), 0, "check png_interlace tag"); } { # test grayscale + alpha read as greyscale + alpha my $im = Imager->new; ok($im->read(file => "testimg/graya.png", type => "png"), "read grayscale + alpha"); is($im->getchannels, 2, "check channel count"); is($im->type, "direct", "check type"); is($im->bits, 8, "check bits"); is($im->tags(name => "png_bits"), 8, "check png_bits tag"); is($im->tags(name => "png_interlace"), 0, "check png_interlace tag"); } { # test paletted + alpha read as paletted my $im = Imager->new; ok($im->read(file => "testimg/paltrans.png", type => "png"), "read paletted with alpha"); is($im->getchannels, 4, "check channel count"); is($im->type, "paletted", "check type"); is($im->tags(name => "png_bits"), 8, "check png_bits tag"); is($im->tags(name => "png_interlace"), 0, "check png_interlace tag"); } { # test paletted read as paletted my $im = Imager->new; ok($im->read(file => "testimg/pal.png", type => "png"), "read paletted"); is($im->getchannels, 3, "check channel count"); is($im->type, "paletted", "check type"); is($im->tags(name => "png_bits"), 8, "check png_bits tag"); is($im->tags(name => "png_interlace"), 0, "check png_interlace tag"); } { # test 16-bit rgb read as 16 bit my $im = Imager->new; ok($im->read(file => "testimg/rgb16.png", type => "png"), "read 16-bit rgb"); is($im->getchannels, 3, "check channel count"); is($im->type, "direct", "check type"); is($im->tags(name => "png_interlace"), 0, "check png_interlace tag"); is($im->bits, 16, "check bits"); is($im->tags(name => "png_bits"), 16, "check png_bits tag"); } { # test 1-bit grey read as mono my $im = Imager->new; ok($im->read(file => "testimg/bilevel.png", type => "png"), "read bilevel png"); is($im->getchannels, 1, "check channel count"); is($im->tags(name => "png_interlace"), 0, "check png_interlace tag"); is($im->type, "paletted", "check type"); ok($im->is_bilevel, "should be bilevel"); is($im->tags(name => "png_bits"), 1, "check png_bits tag"); } SKIP: { # test interlaced read as interlaced and matches original my $im_i = Imager->new(file => "testimg/rgb8i.png", filetype => "png"); ok($im_i, "read interlaced") or skip("Could not read rgb8i.png: " . Imager->errstr, 7); is($im_i->getchannels, 3, "check channel count"); is($im_i->type, "direct", "check type"); is($im_i->tags(name => "png_bits"), 8, "check png_bits"); is($im_i->tags(name => "png_interlace"), 1, "check png_interlace"); my $im = Imager->new(file => "testimg/rgb8.png", filetype => "png"); ok($im, "read non-interlaced") or skip("Could not read testimg/rgb8.png: " . Imager->errstr, 2); is($im->tags(name => "png_interlace"), 0, "check png_interlace"); is_image($im_i, $im, "compare interlaced and non-interlaced"); } { my @match = ( [ "cover.png", "coveri.png" ], [ "cover16.png", "cover16i.png" ], [ "coverpal.png", "coverpali.png" ], ); for my $match (@match) { my ($normal, $interlace) = @$match; my $n_im = Imager->new(file => "testimg/$normal"); ok($n_im, "read $normal") or diag "reading $normal: ", Imager->errstr; my $i_im = Imager->new(file => "testimg/$interlace"); ok($i_im, "read $interlace") or diag "reading $interlace: ", Imager->errstr; SKIP: { $n_im && $i_im or skip("Couldn't read a file", 1); is_image($i_im, $n_im, "check normal and interlace files read the same"); } } } { my $interlace = 0; for my $name ("cover.png", "coveri.png") { SKIP: { my $im = Imager->new(file => "testimg/$name"); ok($im, "read $name") or diag "Failed to read $name: ", Imager->errstr; $im or skip("Couldn't load $name", 5); is($im->tags(name => "i_format"), "png", "$name: i_format"); is($im->tags(name => "png_bits"), 8, "$name: png_bits"); is($im->tags(name => "png_interlace"), $interlace, "$name: png_interlace"); is($im->getchannels, 4, "$name: four channels"); is($im->type, "direct", "$name: direct type"); is_deeply([ $im->getsamples(y => 0, width => 5) ], [ ( 255, 255, 0, 255 ), ( 255, 255, 0, 191 ), ( 255, 255, 0, 127 ), ( 255, 255, 0, 63 ), ( 0, 0, 0, 0) ], "$name: check expected samples row 0"); is_deeply([ $im->getsamples(y => 1, width => 5) ], [ ( 255, 0, 0, 255 ), ( 255, 0, 0, 191 ), ( 255, 0, 0, 127 ), ( 255, 0, 0, 63 ), ( 0, 0, 0, 0) ], "$name: check expected samples row 1"); } $interlace = 1; } } { my $interlace = 0; for my $name ("coverpal.png", "coverpali.png") { SKIP: { my $im = Imager->new(file => "testimg/$name"); ok($im, "read $name") or diag "Failed to read $name: ", Imager->errstr; $im or skip("Couldn't load $name", 5); is($im->tags(name => "i_format"), "png", "$name: i_format"); is($im->tags(name => "png_bits"), 4, "$name: png_bits"); is($im->tags(name => "png_interlace"), $interlace, "$name: png_interlace"); is($im->getchannels, 4, "$name: four channels"); is($im->type, "paletted", "$name: paletted type"); is_deeply([ $im->getsamples(y => 0, width => 5) ], [ ( 255, 255, 0, 255 ), ( 255, 255, 0, 191 ), ( 255, 255, 0, 127 ), ( 255, 255, 0, 63 ), ( 0, 0, 0, 0) ], "$name: check expected samples row 0"); is_deeply([ $im->getsamples(y => 1, width => 5) ], [ ( 255, 0, 0, 255 ), ( 255, 0, 0, 191 ), ( 255, 0, 0, 127 ), ( 255, 0, 0, 63 ), ( 0, 0, 0, 0) ], "$name: check expected samples row 1"); } $interlace = 1; } } { my $interlace = 0; for my $name ("cover16.png", "cover16i.png") { SKIP: { my $im = Imager->new(file => "testimg/$name"); ok($im, "read $name") or diag "Failed to read $name: ", Imager->errstr; $im or skip("Couldn't load $name", 5); is($im->tags(name => "i_format"), "png", "$name: i_format"); is($im->tags(name => "png_bits"), 16, "$name: png_bits"); is($im->tags(name => "png_interlace"), $interlace, "$name: png_interlace"); is($im->getchannels, 4, "$name: four channels"); is($im->type, "direct", "$name: direct type"); is_deeply([ $im->getsamples(y => 0, width => 5, type => "16bit") ], [ ( 65535, 65535, 0, 65535 ), ( 65535, 65535, 0, 49087 ), ( 65535, 65535, 0, 32639 ), ( 65535, 65535, 0, 16191 ), ( 65535, 65535, 65535, 0) ], "$name: check expected samples row 0"); is_deeply([ $im->getsamples(y => 1, width => 5, type => "16bit") ], [ ( 65535, 0, 0, 65535 ), ( 65535, 0, 0, 49087 ), ( 65535, 0, 0, 32639 ), ( 65535, 0, 0, 16191 ), ( 65535, 65535, 65535, 0) ], "$name: check expected samples row 1"); } $interlace = 1; } } { my $pim = Imager->new(xsize => 5, ysize => 2, channels => 3, type => "paletted"); ok($pim, "make a 3 channel paletted image"); ok($pim->addcolors(colors => [ qw(000000 FFFFFF FF0000 00FF00 0000FF) ]), "add some colors"); is($pim->setscanline(y => 0, type => "index", pixels => [ 0, 1, 2, 4, 3 ]), 5, "set some pixels"); is($pim->setscanline(y => 1, type => "index", pixels => [ 4, 1, 0, 4, 2 ]), 5, "set some more pixels"); ok($pim->write(file => "testout/pal3.png"), "write to testout/pal3.png") or diag("Cannot save testout/pal3.png: ".$pim->errstr); my $in = Imager->new(file => "testout/pal3.png"); ok($in, "read it back in") or diag("Cann't read pal3.png back: " . Imager->errstr); is_image($pim, $in, "check it matches"); is($in->type, "paletted", "make sure the result is paletted"); is($in->tags(name => "png_bits"), 4, "4 bit representation"); } { # make sure the code that pushes maxed alpha to the end doesn't break my $pim = Imager->new(xsize => 8, ysize => 2, channels => 4, type => "paletted"); ok($pim, "make a 4 channel paletted image"); ok($pim->addcolors (colors => [ NC(255, 255, 0, 128), qw(000000 FFFFFF FF0000 00FF00 0000FF), NC(0, 0, 0, 0), NC(255, 0, 128, 64) ]), "add some colors"); is($pim->setscanline(y => 0, type => "index", pixels => [ 5, 0, 1, 7, 2, 4, 6, 3 ]), 8, "set some pixels"); is($pim->setscanline(y => 1, type => "index", pixels => [ 7, 4, 6, 1, 0, 4, 2, 5 ]), 8, "set some more pixels"); ok($pim->write(file => "testout/pal4.png"), "write to testout/pal4.png") or diag("Cannot save testout/pal4.png: ".$pim->errstr); my $in = Imager->new(file => "testout/pal4.png"); ok($in, "read it back in") or diag("Cann't read pal4.png back: " . Imager->errstr); is_image($pim, $in, "check it matches"); is($in->type, "paletted", "make sure the result is paletted"); is($in->tags(name => "png_bits"), 4, "4 bit representation"); } { my $pim = Imager->new(xsize => 8, ysize => 2, channels => 1, type => "paletted"); ok($pim, "make a 1 channel paletted image"); ok($pim->addcolors(colors => [ map NC($_, 0, 0), 0, 7, 127, 255 ]), "add some colors^Wgreys"); is($pim->setscanline(y => 0, type => "index", pixels => [ 0, 2, 1, 3, 2, 1, 0, 3 ]), 8, "set some pixels"); is($pim->setscanline(y => 1, type => "index", pixels => [ 3, 0, 2, 1, 0, 0, 2, 3 ]), 8, "set some more pixels"); ok($pim->write(file => "testout/pal1.png"), "write to testout/pal1.png") or diag("Cannot save testout/pal1.png: ".$pim->errstr); my $in = Imager->new(file => "testout/pal1.png"); ok($in, "read it back in") or diag("Cann't read pal1.png back: " . Imager->errstr); # PNG doesn't have a paletted greyscale type, so it's written as # paletted color, convert our source image for the comparison my $cmpim = $pim->convert(preset => "rgb"); is_image($in, $cmpim, "check it matches"); is($in->type, "paletted", "make sure the result is paletted"); is($in->tags(name => "png_bits"), 2, "2 bit representation"); } { my $pim = Imager->new(xsize => 8, ysize => 2, channels => 2, type => "paletted"); ok($pim, "make a 2 channel paletted image"); ok($pim->addcolors(colors => [ NC(0, 255, 0), NC(128, 255, 0), NC(255, 255, 0), NC(128, 128, 0) ]), "add some colors^Wgreys") or diag("adding colors: " . $pim->errstr); is($pim->setscanline(y => 0, type => "index", pixels => [ 0, 2, 1, 3, 2, 1, 0, 3 ]), 8, "set some pixels"); is($pim->setscanline(y => 1, type => "index", pixels => [ 3, 0, 2, 1, 0, 0, 2, 3 ]), 8, "set some more pixels"); ok($pim->write(file => "testout/pal2.png"), "write to testout/pal2.png") or diag("Cannot save testout/pal2.png: ".$pim->errstr); my $in = Imager->new(file => "testout/pal2.png"); ok($in, "read it back in") or diag("Can't read pal1.png back: " . Imager->errstr); # PNG doesn't have a paletted greyscale type, so it's written as # paletted color, convert our source image for the comparison my $cmpim = $pim->convert(preset => "rgb"); is_image($in, $cmpim, "check it matches"); is($in->type, "paletted", "make sure the result is paletted"); is($in->tags(name => "png_bits"), 2, "2 bit representation"); } { my $imbase = test_image(); my $mono = $imbase->convert(preset => "gray") ->to_paletted(make_colors => "mono", translate => "errdiff"); ok($mono->write(file => "testout/bilevel.png"), "write bilevel.png"); my $in = Imager->new(file => "testout/bilevel.png"); ok($in, "read it back in") or diag("Can't read bilevel.png: " . Imager->errstr); is_image($in, $mono, "check it matches"); is($in->type, "paletted", "make sure the result is paletted"); is($in->tags(name => "png_bits"), 1, "1 bit representation"); } SKIP: { my $im = test_image_16(); ok($im->write(file => "testout/rgb16.png", type => "png"), "write 16-bit/sample image") or diag("Could not write rgb16.png: ".$im->errstr); my $in = Imager->new(file => "testout/rgb16.png") or diag("Could not read rgb16.png: ".Imager->errstr); ok($in, "read rgb16.png back in") or skip("Could not load image to check", 4); is_imaged($in, $im, 0, "check image matches"); is($in->bits, 16, "check we got a 16-bit image"); is($in->type, "direct", "check it's direct"); is($in->tags(name => "png_bits"), 16, "check png_bits"); } SKIP: { my $im = test_image_double(); my $cmp = $im->to_rgb16; ok($im->write(file => "testout/rgbdbl.png", type => "png"), "write double/sample image - should write as 16-bit/sample") or diag("Could not write rgbdbl.png: ".$im->errstr); my $in = Imager->new(file => "testout/rgbdbl.png") or diag("Could not read rgbdbl.png: ".Imager->errstr); ok($in, "read pngdbl.png back in") or skip("Could not load image to check", 4); is_imaged($in, $cmp, 0, "check image matches"); is($in->bits, 16, "check we got a 16-bit image"); is($in->type, "direct", "check it's direct"); is($in->tags(name => "png_bits"), 16, "check png_bits"); } SKIP: { my $im = Imager->new(file => "testimg/comment.png"); ok($im, "read file with comment") or diag("Cannot read comment.png: ".Imager->errstr); $im or skip("Cannot test tags file I can't read", 5); is($im->tags(name => "i_comment"), "Test comment", "check i_comment"); is($im->tags(name => "png_interlace"), "0", "no interlace"); is($im->tags(name => "png_interlace_name"), "none", "no interlace (text)"); is($im->tags(name => "png_srgb_intent"), "0", "srgb perceptual"); is($im->tags(name => "png_time"), "2012-04-16T07:37:36", "modification time"); is($im->tags(name => "i_background"), "color(255,255,255,255)", "background color"); } SKIP: { # test tag writing my $im = Imager->new(xsize => 1, ysize => 1); ok($im->write(file => "testout/tags.png", i_comment => "A Comment", png_author => "An Author", png_author_compressed => 1, png_copyright => "A Copyright", png_creation_time => "16 April 2012 22:56:30+1000", png_description => "A Description", png_disclaimer => "A Disclaimer", png_software => "Some Software", png_source => "A Source", png_title => "A Title", png_warning => "A Warning", png_text0_key => "Custom Key", png_text0_text => "Custom Value", png_text0_compressed => 1, png_text1_key => "Custom Key2", png_text1_text => "Another Custom Value", png_time => "2012-04-20T00:15:10", ), "write with many tags") or diag("Cannot write with many tags: ", $im->errstr); my $imr = Imager->new(file => "testout/tags.png"); ok($imr, "read it back in") or skip("Couldn't read it back: ". Imager->errstr, 1); is_deeply({ map @$_, $imr->tags }, { i_format => "png", i_comment => "A Comment", png_author => "An Author", png_author_compressed => 1, png_copyright => "A Copyright", png_creation_time => "16 April 2012 22:56:30+1000", png_description => "A Description", png_disclaimer => "A Disclaimer", png_software => "Some Software", png_source => "A Source", png_title => "A Title", png_warning => "A Warning", png_text0_key => "Custom Key", png_text0_text => "Custom Value", png_text0_compressed => 1, png_text0_type => "text", png_text1_key => "Custom Key2", png_text1_text => "Another Custom Value", png_text1_type => "text", png_time => "2012-04-20T00:15:10", png_interlace => 0, png_interlace_name => "none", png_bits => 8, }, "check tags are what we expected"); } SKIP: { # cHRM test my $im = Imager->new(xsize => 1, ysize => 1); ok($im->write(file => "testout/tagschrm.png", type => "png", png_chroma_white_x => 0.3, png_chroma_white_y => 0.32, png_chroma_red_x => 0.7, png_chroma_red_y => 0.28, png_chroma_green_x => 0.075, png_chroma_green_y => 0.8, png_chroma_blue_x => 0.175, png_chroma_blue_y => 0.05), "write cHRM chunk"); my $imr = Imager->new(file => "testout/tagschrm.png", ftype => "png"); ok($imr, "read tagschrm.png") or diag("reading tagschrm.png: ".Imager->errstr); $imr or skip("read of tagschrm.png failed", 1); is_deeply({ map @$_, $imr->tags }, { i_format => "png", png_interlace => 0, png_interlace_name => "none", png_bits => 8, png_chroma_white_x => 0.3, png_chroma_white_y => 0.32, png_chroma_red_x => 0.7, png_chroma_red_y => 0.28, png_chroma_green_x => 0.075, png_chroma_green_y => 0.8, png_chroma_blue_x => 0.175, png_chroma_blue_y => 0.05, }, "check chroma tags written"); } { # gAMA my $im = Imager->new(xsize => 1, ysize => 1); ok($im->write(file => "testout/tagsgama.png", type => "png", png_gamma => 2.22), "write with png_gammma tag"); my $imr = Imager->new(file => "testout/tagsgama.png", ftype => "png"); ok($imr, "read tagsgama.png") or diag("reading tagsgama.png: ".Imager->errstr); $imr or skip("read of tagsgama.png failed", 1); is_deeply({ map @$_, $imr->tags }, { i_format => "png", png_interlace => 0, png_interlace_name => "none", png_bits => 8, png_gamma => "2.22", }, "check gamma tag written"); } { # various bad tag failures my @tests = ( [ [ png_chroma_white_x => 0.5 ], "all png_chroma_* tags must be supplied or none" ], [ [ png_srgb_intent => 4 ], "tag png_srgb_intent out of range" ], [ [ i_comment => "test\0with nul" ], "tag i_comment may not contain NUL characters" ], [ [ png_text0_key => "" ], "tag png_text0_key must be between 1 and 79 characters in length" ], [ [ png_text0_key => ("x" x 80) ], "tag png_text0_key must be between 1 and 79 characters in length" ], [ [ png_text0_key => " x" ], "tag png_text0_key may not contain leading or trailing spaces" ], [ [ png_text0_key => "x " ], "tag png_text0_key may not contain leading or trailing spaces" ], [ [ png_text0_key => "x y" ], "tag png_text0_key may not contain consecutive spaces" ], [ [ png_text0_key => "\x7F" ], "tag png_text0_key may only contain Latin1 characters 32-126, 161-255" ], [ [ png_text0_key => "x", png_text0_text => "a\0b" ], "tag png_text0_text may not contain NUL characters" ], [ [ png_text0_key => "test" ], "tag png_text0_key found but not png_text0_text" ], [ [ png_text0_text => "test" ], "tag png_text0_text found but not png_text0_key" ], [ [ png_time => "bad format" ], "png_time must be formatted 'y-m-dTh:m:s'" ], [ [ png_time => "2012-13-01T00:00:00" ], "invalid date/time for png_time" ], ); my $im = Imager->new(xsize => 1, ysize => 1); for my $test (@tests) { my ($tags, $error) = @$test; my $im2 = $im->copy; my $data; ok(!$im2->write(data => \$data, type => "png", @$tags), "expect $error"); is($im2->errstr, $error, "check error message"); } } sub limited_write { my ($limit) = @_; return sub { my ($data) = @_; $limit -= length $data; if ($limit >= 0) { print "# write of ", length $data, " bytes successful ($limit left)\n" if $debug_writes; return 1; } else { print "# write of ", length $data, " bytes failed\n"; Imager::i_push_error(0, "limit reached"); return; } }; } libimager-perl-1.004+dfsg.orig/PNG/Makefile.PL0000644000175000017500000000665612567572530020210 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Getopt::Long; use Config; my $verbose = $ENV{IM_VERBOSE}; my @libpaths; my @incpaths; GetOptions("incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$verbose); our $BUILDING_IMAGER; our %IMAGER_LIBS; my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; my %opts = ( NAME => 'Imager::File::PNG', VERSION_FROM => 'PNG.pm', OBJECT => 'PNG.o impng.o', clean => { FILES => 'testout' }, ); my @inc; if ($BUILDING_IMAGER) { push @inc, "-I.."; unshift @INC, "../lib"; } else { unshift @INC, "inc"; print "PNG: building independently\n"; require Imager::ExtUtils; push @inc, Imager::ExtUtils->includes; $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ]; # Imager required configure through use my @Imager_req = ( Imager => "0.90" ); if ($MM_ver >= 6.46) { $opts{META_MERGE} = { configure_requires => { @Imager_req, }, build_requires => { @Imager_req, "Test::More" => "0.47", }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; $opts{PREREQ_PM} = { @Imager_req, XSLoader => 0, }; } } require Imager::Probe; # these are mostly needed when pkg-config isn't available my @alts = ( { altname => "v1.6", incsuffix => "libpng16", libbase => "png16", }, { altname => "v1.5", incsuffix => "libpng15", libbase => "png15", }, { altname => "v1.4", incsuffix => "libpng14", libbase => "png14", }, { altname => "v1.2", incsuffix => "libpng12", libbase => "png12", }, { altname => "v1.0", incsuffix => "libpng10", libbase => "png10", }, ); my %probe = ( name => "PNG", altname => "Generic", pkg => [ qw/libpng libpng16 libpng15 libpng14 libpng12 libpng10/ ], inccheck => sub { -e File::Spec->catfile($_[0], "png.h") }, libbase => "png", testcode => _png_test_code(), testcodeheaders => [ "png.h", "stdio.h" ], incpath => \@incpaths, libpath => \@libpaths, verbose => $verbose, alternatives => [ @alts, { altname => "base (+libz)", libbase => [ "png", "z" ], }, ( # a static libpng may require libz too map +{ %$_, altname => "$_->{altname} (+libz)", libbase => [ $_->{libbase}, "z" ], }, @alts ), ], ); my $probe_res = Imager::Probe->probe(\%probe); if ($probe_res) { $IMAGER_LIBS{PNG} = 1; push @inc, $probe_res->{INC}; $opts{LIBS} = $probe_res->{LIBS}; $opts{DEFINE} = $probe_res->{DEFINE}; $opts{INC} = "@inc"; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'PNG Image file support'; } WriteMakefile(%opts); } else { $IMAGER_LIBS{PNG} = 0; if ($BUILDING_IMAGER) { ExtUtils::MakeMaker::WriteEmptyMakefile(%opts); } else { # fail in good way die "OS unsupported: PNG libraries or headers not found\n"; } } sub _png_test_code { return <<'CODE'; fprintf(stderr, "PNG: library version %ld, header version %ld\n", (long)png_access_version_number(), (long)PNG_LIBPNG_VER); if (png_access_version_number() != PNG_LIBPNG_VER) { fprintf(stderr, "PNG: Your header version number doesn't match the library version number\n"); return 1; } return 0; CODE } libimager-perl-1.004+dfsg.orig/PNG/PNG.xs0000644000175000017500000000157512335373543017225 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "impng.h" DEFINE_IMAGER_CALLBACKS; MODULE = Imager::File::PNG PACKAGE = Imager::File::PNG Imager::ImgRaw i_readpng_wiol(ig, flags=0) Imager::IO ig int flags undef_int i_writepng_wiol(im, ig) Imager::ImgRaw im Imager::IO ig unsigned i_png_lib_version() MODULE = Imager::File::PNG PACKAGE = Imager::File::PNG PREFIX=i_png_ void i_png_features(...) PREINIT: const char * const *p; PPCODE: p = i_png_features(); while (*p) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(*p, 0))); ++p; } int IMPNG_READ_IGNORE_BENIGN_ERRORS() CODE: RETVAL = IMPNG_READ_IGNORE_BENIGN_ERRORS; OUTPUT: RETVAL BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/PNG/impng.h0000644000175000017500000000046112263740600017471 0ustar gregoagregoa#ifndef IMAGER_IMPNG_H #define IMAGER_IMPNG_H #include "imext.h" i_img *i_readpng_wiol(io_glue *ig, int flags); #define IMPNG_READ_IGNORE_BENIGN_ERRORS 1 undef_int i_writepng_wiol(i_img *im, io_glue *ig); unsigned i_png_lib_version(void); extern const char * const * i_png_features(void); #endif libimager-perl-1.004+dfsg.orig/dynaload.h0000644000175000017500000000226712031434614017532 0ustar gregoagregoa#ifndef _DYNALOAD_H_ #define _DYNALOAD_H_ #include "log.h" #include "EXTERN.h" #include "perl.h" #include "ppport.h" #include "ext.h" typedef struct DSO_handle_tag DSO_handle; typedef struct { HV* hv; char *key; void *store; } UTIL_args; #if 0 int getobj(void *hv_t,char *key,char *type,void **store); int getint(void *hv_t,char *key,int *store); int getdouble(void *hv_t,char *key,double *store); int getvoid(void *hv_t,char *key,void **store); #endif void *DSO_open(char* file,char** evalstring); func_ptr *DSO_funclist(DSO_handle *handle); int DSO_close(void *); void DSO_call(DSO_handle *handle,int func_index,HV* hv); #ifdef __EMX__ /* OS/2 */ # ifndef RTLD_LAZY # define RTLD_LAZY 0 # endif /* RTLD_LAZY */ int dlclose(minthandle_t); #endif /* __EMX__ */ #ifdef DLSYMUN #define I_EVALSTR "_evalstr" #define I_SYMBOL_TABLE "_symbol_table" #define I_UTIL_TABLE "_util_table" #define I_FUNCTION_LIST "_function_list" #define I_INSTALL_TABLES "_install_tables" #else #define I_EVALSTR "evalstr" #define I_SYMBOL_TABLE "symbol_table" #define I_UTIL_TABLE "util_table" #define I_FUNCTION_LIST "function_list" #define I_INSTALL_TABLES "install_tables" #endif #endif /* _DYNALOAD_H_ */ libimager-perl-1.004+dfsg.orig/regmach.c0000644000175000017500000002151312263740601017336 0ustar gregoagregoa#include "regmach.h" #include #include "imageri.h" /*#define DEBUG*/ #ifdef DEBUG #define DBG(x) printf x #else #define DBG(x) #endif static float MAX_EXP_ARG; /* = log(DBL_MAX); */ /* these functions currently assume RGB images - there seems to be some support for other color spaces, but I can't tell how you find what space an image is using. HSV conversions from pages 401-403 "Procedural Elements for Computer Graphics", 1985, ISBN 0-07-053534-5. The algorithm presents to produce an HSV color calculates all components at once - I don't, so I've simiplified the algorithm to avoid unnecessary calculation (any errors (of which I had a few ;) are mine). */ /* returns the value (brightness) of color from 0 to 1 */ static double hsv_value(i_color color) { return i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b) / 255.0; } /* returns the hue (color) of color from 0 to 360 */ static double hsv_hue(i_color color) { int val; int temp; temp = i_min(i_min(color.rgb.r, color.rgb.g), color.rgb.b); val = i_max(color.rgb.r, i_max(color.rgb.g, color.rgb.b)); if (val == 0 || val==temp) { return 0; } else { double cr = (val - color.rgb.r) / (double)(val - temp); double cg = (val - color.rgb.g) / (double)(val - temp); double cb = (val - color.rgb.b) / (double)(val - temp); double hue; if (color.rgb.r == val) { hue = cb-cg; } else if (color.rgb.g == val) { hue = 2.0 + cr-cb; } else { /* if (blue == val) */ hue = 4.0 + cg - cr; } hue *= 60.0; /* to degrees */ if (hue < 0) hue += 360; return hue; } } /* return the saturation of color from 0 to 1 */ static double hsv_sat(i_color color) { int value = i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b); if (value == 0) { return 0; } else { int temp = i_min(i_min(color.rgb.r, color.rgb.g), color.rgb.b); return (value - temp) / (double)value; } } static i_color make_hsv(double hue, double sat, double val, int alpha) { int i; i_color c; for( i=0; i< MAXCHANNELS; i++) c.channel[i]=0; DBG(("hsv=%f %f %f\n", hue, sat, val)); if (sat <= 0) { /* handle -ve in case someone supplies a bad value */ /* should this be * 256? */ c.rgb.r = c.rgb.g = c.rgb.b = 255 * val; } else { int i, m, n, k, v; double f; if (val < 0) val = 0; if (val > 1) val = 1; if (sat > 1) sat = 1; /* I want to handle -360 <= hue < 720 so that the caller can fiddle with colour */ if (hue >= 360) hue -= 360; else if (hue < 0) hue += 360; hue /= 60; i = hue; /* floor */ f = hue - i; val *= 255; m = val * (1.0 - sat); n = val * (1.0 - sat * f); k = val * (1.0 - sat * (1 - f)); v = val; switch (i) { case 0: c.rgb.r = v; c.rgb.g = k; c.rgb.b = m; break; case 1: c.rgb.r = n; c.rgb.g = v; c.rgb.b = m; break; case 2: c.rgb.r = m; c.rgb.g = v; c.rgb.b = k; break; case 3: c.rgb.r = m; c.rgb.g = n; c.rgb.b = v; break; case 4: c.rgb.r = k; c.rgb.g = m; c.rgb.b = v; break; case 5: c.rgb.r = v; c.rgb.g = m; c.rgb.b = n; break; } } c.rgba.a = alpha; return c; } static i_color make_rgb(int r, int g, int b, int a) { i_color c; if (r < 0) r = 0; if (r > 255) r = 255; c.rgb.r = r; if (g < 0) g = 0; if (g > 255) g = 255; c.rgb.g = g; if (b < 0) b = 0; if (b > 255) b = 255; c.rgb.b = b; c.rgba.a = a; return c; } /* greatly simplifies the code */ #define nout n_regs[codes->rout] #define na n_regs[codes->ra] #define nb n_regs[codes->rb] #define nc n_regs[codes->rc] #define nd n_regs[codes->rd] #define cout c_regs[codes->rout] #define ca c_regs[codes->ra] #define cb c_regs[codes->rb] #define cc c_regs[codes->rc] #define cd c_regs[codes->rd] /* this is a pretty poor epsilon used for loosening up equality comparisons It isn't currently used for inequalities */ #define n_epsilon(x, y) (fabs(x)+fabs(y))*0.001 static i_color bcol = {{ 0 }}; i_color i_rm_run(struct rm_op codes[], size_t code_count, double n_regs[], size_t n_regs_count, i_color c_regs[], size_t c_regs_count, i_img *images[], size_t image_count) { double dx, dy; struct rm_op *codes_base = codes; size_t count_base = code_count; DBG(("rm_run(%p, %d)\n", codes, code_count)); while (code_count) { DBG((" rm_code %d\n", codes->code)); switch (codes->code) { case rbc_add: nout = na + nb; break; case rbc_subtract: nout = na - nb; break; case rbc_mult: nout = na * nb; break; case rbc_div: if (fabs(nb) < 1e-10) nout = 1e10; else nout = na / nb; break; case rbc_mod: if (fabs(nb) > 1e-10) { nout = fmod(na, nb); } else { nout = 0; /* close enough ;) */ } break; case rbc_pow: nout = pow(na, nb); break; case rbc_uminus: nout = -na; break; case rbc_multp: cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb, 255); break; case rbc_addp: cout = make_rgb(ca.rgb.r + cb.rgb.r, ca.rgb.g + cb.rgb.g, ca.rgb.b + cb.rgb.b, 255); break; case rbc_subtractp: cout = make_rgb(ca.rgb.r - cb.rgb.r, ca.rgb.g - cb.rgb.g, ca.rgb.b - cb.rgb.b, 255); break; case rbc_sin: nout = sin(na); break; case rbc_cos: nout = cos(na); break; case rbc_atan2: nout = atan2(na, nb); break; case rbc_sqrt: nout = sqrt(na); break; case rbc_distance: dx = na-nc; dy = nb-nd; nout = sqrt(dx*dx+dy*dy); break; case rbc_getp1: i_gpix(images[0], na, nb, c_regs+codes->rout); if (images[0]->channels < 4) cout.rgba.a = 255; break; case rbc_getp2: i_gpix(images[1], na, nb, c_regs+codes->rout); if (images[1]->channels < 4) cout.rgba.a = 255; break; case rbc_getp3: i_gpix(images[2], na, nb, c_regs+codes->rout); if (images[2]->channels < 4) cout.rgba.a = 255; break; case rbc_value: nout = hsv_value(ca); break; case rbc_hue: nout = hsv_hue(ca); break; case rbc_sat: nout = hsv_sat(ca); break; case rbc_hsv: cout = make_hsv(na, nb, nc, 255); break; case rbc_hsva: cout = make_hsv(na, nb, nc, nd); break; case rbc_red: nout = ca.rgb.r; break; case rbc_green: nout = ca.rgb.g; break; case rbc_blue: nout = ca.rgb.b; break; case rbc_alpha: nout = ca.rgba.a; break; case rbc_rgb: cout = make_rgb(na, nb, nc, 255); break; case rbc_rgba: cout = make_rgb(na, nb, nc, nd); break; case rbc_int: nout = (int)(na); break; case rbc_if: nout = na ? nb : nc; break; case rbc_ifp: cout = na ? cb : cc; break; case rbc_le: nout = na <= nb + n_epsilon(na,nb); break; case rbc_lt: nout = na < nb; break; case rbc_ge: nout = na >= nb - n_epsilon(na,nb); break; case rbc_gt: nout = na > nb; break; case rbc_eq: nout = fabs(na-nb) <= n_epsilon(na,nb); break; case rbc_ne: nout = fabs(na-nb) > n_epsilon(na,nb); break; case rbc_and: nout = na && nb; break; case rbc_or: nout = na || nb; break; case rbc_not: nout = !na; break; case rbc_abs: nout = fabs(na); break; case rbc_ret: return ca; break; case rbc_jump: /* yes, order is important here */ code_count = count_base - codes->ra; codes = codes_base + codes->ra; continue; case rbc_jumpz: if (!na) { /* yes, order is important here */ code_count = count_base - codes->rb; codes = codes_base + codes->rb; continue; } break; case rbc_jumpnz: if (na) { /* yes, order is important here */ code_count = count_base - codes->rb; codes = codes_base + codes->rb; continue; } break; case rbc_set: nout = na; break; case rbc_setp: cout = ca; break; case rbc_log: if (na > 0) { nout = log(na); } else { nout = DBL_MAX; } break; case rbc_exp: if (!MAX_EXP_ARG) MAX_EXP_ARG = log(DBL_MAX); if (na <= MAX_EXP_ARG) { nout = exp(na); } else { nout = DBL_MAX; } break; case rbc_print: nout = na; printf("r%d is %g\n", codes->ra, na); break; case rbc_det: nout = na*nd-nb*nc; break; default: /*croak("bad opcode"); */ printf("bad op %d\n", codes->code); return bcol; } --code_count; ++codes; } return bcol; /* croak("no return opcode"); */ } libimager-perl-1.004+dfsg.orig/quant.c0000644000175000017500000014770012263740601017067 0ustar gregoagregoa/* quant.c - provides general image quantization currently only used by gif.c, but maybe we'll support producing 8-bit (or bigger indexed) png files at some point */ #include "imager.h" #include "imageri.h" static void makemap_webmap(i_quantize *); static void makemap_addi(i_quantize *, i_img **imgs, int count); static void makemap_mediancut(i_quantize *, i_img **imgs, int count); static void makemap_mono(i_quantize *); static void makemap_gray(i_quantize *, int step); static int makemap_palette(i_quantize *, i_img **imgs, int count); static void setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) { cl->rgba.r=r; cl->rgba.g=g; cl->rgba.b=b; cl->rgba.a=a; } /* make a colour map overwrites mc_existing/mc_count in quant Note that i_makemap will be called once for each image if mc_perimage is set and the format support multiple colour maps per image. This means we don't need any special processing at this level to handle multiple colour maps. */ /* =item i_quant_makemap(C, C, C) =category Image quantization Analyzes the C images in C according to the rules in C to build a color map (optimal or not depending on C<< quant->make_colors >>). =cut */ void i_quant_makemap(i_quantize *quant, i_img **imgs, int count) { if (quant->translate == pt_giflib) { /* giflib does it's own color table generation */ /* previously we used giflib's quantizer, but it didn't handle multiple images, which made it hard to build a global color map We've implemented our own median cut code so we can ignore the giflib version */ makemap_mediancut(quant, imgs, count); return; } switch (quant->make_colors & mc_mask) { case mc_none: /* use user's specified map */ break; case mc_web_map: makemap_webmap(quant); break; case mc_median_cut: makemap_mediancut(quant, imgs, count); break; case mc_mono: makemap_mono(quant); break; case mc_gray: makemap_gray(quant, 1); break; case mc_gray4: makemap_gray(quant, 85); break; case mc_gray16: makemap_gray(quant, 17); break; case mc_addi: default: makemap_addi(quant, imgs, count); break; } } static void translate_closest(i_quantize *, i_img *, i_palidx *); static void translate_errdiff(i_quantize *, i_img *, i_palidx *); static void translate_addi(i_quantize *, i_img *, i_palidx *); /* =item i_quant_translate(C, C) =category Image quantization Quantize the image given the palette in C. On success returns a pointer to a memory block of C<< img->xsize * img->ysize >> C entries. On failure returns NULL. You should call myfree() on the returned block when you're done with it. This function will fail if the supplied palette contains no colors. =cut */ i_palidx * i_quant_translate(i_quantize *quant, i_img *img) { i_palidx *result; size_t bytes; mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img)); /* there must be at least one color in the paletted (though even that isn't very useful */ if (quant->mc_count == 0) { i_push_error(0, "no colors available for translation"); return NULL; } bytes = img->xsize * img->ysize; if (bytes / img->ysize != img->xsize) { i_push_error(0, "integer overflow calculating memory allocation"); return NULL; } result = mymalloc(bytes); switch (quant->translate) { case pt_closest: case pt_giflib: translate_closest(quant, img, result); break; case pt_errdiff: translate_errdiff(quant, img, result); break; case pt_perturb: default: translate_addi(quant, img, result); break; } return result; } static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) { quant->perturb = 0; translate_addi(quant, img, out); } #define PWR2(x) ((x)*(x)) typedef int (*cmpfunc)(const void*, const void*); typedef struct { unsigned char r,g,b; char fixed; char used; int dr,dg,db; int cdist; int mcount; } cvec; typedef struct { int cnt; int vec[256]; } hashbox; typedef struct { int boxnum; int pixcnt; int cand; int pdc; } pbox; static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line); static void reorder(pbox prescan[512]); static int pboxcmp(const pbox *a,const pbox *b); static void boxcenter(int box,cvec *cv); static float frandn(void); static void boxrand(int box,cvec *cv); static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1); static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]); static int mindist(int boxnum,cvec *cv); static int maxdist(int boxnum,cvec *cv); /* Some of the simpler functions are kept here to aid the compiler - maybe some of them will be inlined. */ static int pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); } static int pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); } static unsigned char g_sat(int in) { if (in>255) { return 255; } else if (in>0) return in; return 0; } static float frand(void) { return rand()/(RAND_MAX+1.0); } #ifdef NOTEF static int eucl_d(cvec* cv,i_color *cl) { return PWR2(cv->r-cl->channel[0])+PWR2(cv->g-cl->channel[1])+PWR2(cv->b-cl->channel[2]); } #endif static int eucl_d_ch(cvec* cv,i_sample_t *chans) { return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1]) + PWR2(cv->b - chans[2]); } static int ceucl_d(i_color *c1, i_color *c2) { return PWR2(c1->channel[0]-c2->channel[0]) +PWR2(c1->channel[1]-c2->channel[1]) +PWR2(c1->channel[2]-c2->channel[2]); } static const int gray_samples[] = { 0, 0, 0 }; /* This quantization algorithm and implementation routines are by Arnar M. Hrafnkelson. In case any new ideas are here they are mine since this was written from scratch. The algorithm uses local means in the following way: For each point in the colormap we find which image points have that point as it's closest point. We calculate the mean of those points and in the next iteration it will be the new entry in the colormap. In order to speed this process up (i.e. nearest neighbor problem) We divied the r,g,b space up in equally large 512 boxes. The boxes are numbered from 0 to 511. Their numbering is so that for a given vector it is known that it belongs to the box who is formed by concatenating the 3 most significant bits from each component of the RGB triplet. For each box we find the list of points from the colormap who might be closest to any given point within the box. The exact solution involves finding the Voronoi map (or the dual the Delauny triangulation) and has many issues including numerical stability. So we use this approximation: 1. Find which point has the shortest maximum distance to the box. 2. Find all points that have a shorter minimum distance than that to the box This is a very simple task and is not computationally heavy if one takes into account that the minimum distances from a pixel to a box is always found by checking if it's inside the box or is closest to some side or a corner. Finding the maximum distance is also either a side or a corner. This approach results 2-3 times more than the actual points needed but is still a good gain over the complete space. Usually when one has a 256 Colorcolor map a search over 30 is often obtained. A bit of an enhancement to this approach is to keep a seperate list for each side of the cube, but this will require even more memory. Arnar M. Hrafnkelsson (addi@umich.edu); */ /* Extracted from gifquant.c, removed dependencies on gif_lib, and added support for multiple images. starting from 1nov2000 by TonyC . */ static void makemap_addi(i_quantize *quant, i_img **imgs, int count) { cvec *clr; int cnum, i, bst_idx=0, ld, cd, iter, currhb, img_num; i_img_dim x, y; i_sample_t *val; float dlt, accerr; hashbox *hb; i_mempool mp; i_img_dim maxwidth = 0; i_sample_t *line; const int *sample_indices; mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n", quant, quant->mc_count, quant->mc_colors, imgs, count)); if (makemap_palette(quant, imgs, count)) return; i_mempool_init(&mp); clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size); hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512); for (i=0; i < quant->mc_count; ++i) { clr[i].r = quant->mc_colors[i].rgb.r; clr[i].g = quant->mc_colors[i].rgb.g; clr[i].b = quant->mc_colors[i].rgb.b; clr[i].fixed = 1; clr[i].mcount = 0; } /* mymalloc doesn't clear memory, so I think we need this */ for (; i < quant->mc_size; ++i) { /*clr[i].r = clr[i].g = clr[i].b = 0;*/ clr[i].dr = 0; clr[i].dg = 0; clr[i].db = 0; clr[i].fixed = 0; clr[i].mcount = 0; } cnum = quant->mc_size; dlt = 1; for (img_num = 0; img_num < count; ++img_num) { if (imgs[img_num]->xsize > maxwidth) maxwidth = imgs[img_num]->xsize; } line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line)); prescan(imgs, count, cnum, clr, line); cr_hashindex(clr, cnum, hb); for(iter=0;iter<3;iter++) { accerr=0.0; for (img_num = 0; img_num < count; ++img_num) { i_img *im = imgs[img_num]; sample_indices = im->channels >= 3 ? NULL : gray_samples; for(y=0;yysize;y++) { i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3); val = line; for(x=0;xxsize;x++) { ld=196608; /*i_gpix(im,x,y,&val);*/ currhb=pixbox_ch(val); /* printf("box = %d \n",currhb); */ for(i=0;imc_count = 0; for (i = 0; i < cnum; ++i) { if (clr[i].fixed || clr[i].used) { /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/ quant->mc_colors[quant->mc_count].rgb.r = clr[i].r; quant->mc_colors[quant->mc_count].rgb.g = clr[i].g; quant->mc_colors[quant->mc_count].rgb.b = clr[i].b; ++quant->mc_count; } } #else /* transfer the colors back */ for (i = 0; i < cnum; ++i) { quant->mc_colors[i].rgb.r = clr[i].r; quant->mc_colors[i].rgb.g = clr[i].g; quant->mc_colors[i].rgb.b = clr[i].b; } quant->mc_count = cnum; #endif #if 0 mm_log((1, "makemap_addi returns - quant.mc_count = %d\n", quant->mc_count)); for (i = 0; i < quant->mc_count; ++i) mm_log((5, " map entry %d: (%d, %d, %d)\n", i, clr[i].r, clr[i].g, clr[i].b)); #endif i_mempool_destroy(&mp); mm_log((1, "makemap_addi() - %d colors\n", quant->mc_count)); } typedef struct { i_sample_t rgb[3]; int count; } quant_color_entry; #define MEDIAN_CUT_COLORS 32768 #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \ (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3)) #define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \ (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3)) /* scale these to cover the whole range */ #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31) #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31) #define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31) typedef struct { i_sample_t min[3]; /* minimum for each channel */ i_sample_t max[3]; /* maximum for each channel */ i_sample_t width[3]; /* width for each channel */ int start, size; /* beginning and size of the partition */ i_img_dim pixels; /* number of pixels represented by this partition */ } medcut_partition; /* =item calc_part(part, colors) Calculates the new color limits for the given partition. Giflib assumes that the limits for the non-split channels stay the same, but this strikes me as incorrect, especially if the colors tend to be color ramps. Of course this could be optimized by not recalculating the channel we just sorted on, but it's not worth the effort right now. =cut */ static void calc_part(medcut_partition *part, quant_color_entry *colors) { int i, ch; for (ch = 0; ch < 3; ++ch) { part->min[ch] = 255; part->max[ch] = 0; } for (i = part->start; i < part->start + part->size; ++i) { for (ch = 0; ch < 3; ++ch) { if (part->min[ch] > colors[i].rgb[ch]) part->min[ch] = colors[i].rgb[ch]; if (part->max[ch] < colors[i].rgb[ch]) part->max[ch] = colors[i].rgb[ch]; } } for (ch = 0; ch < 3; ++ch) { part->width[ch] = part->max[ch] - part->min[ch]; } } /* simple functions to sort by each channel - we could use a global, but that would be bad */ static int color_sort_red(void const *left, void const *right) { return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0]; } static int color_sort_green(void const *left, void const *right) { return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1]; } static int color_sort_blue(void const *left, void const *right) { return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2]; } static int (*sorters[])(void const *, void const *) = { color_sort_red, color_sort_green, color_sort_blue, }; static void makemap_mediancut(i_quantize *quant, i_img **imgs, int count) { quant_color_entry *colors; i_mempool mp; int imgn, i, ch; i_img_dim x, y, max_width; i_color *line; int color_count; i_img_dim total_pixels; medcut_partition *parts; int part_num; int in, out; /* number of channels we search for the best channel to partition this isn't terribly efficient, but it should work */ int chan_count; mm_log((1, "makemap_mediancut(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n", quant, quant->mc_count, quant->mc_colors, imgs, count)); if (makemap_palette(quant, imgs, count)) return; i_mempool_init(&mp); colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS); for (i = 0; i < MEDIAN_CUT_COLORS; ++i) { colors[i].rgb[0] = MED_CUT_RED(i); colors[i].rgb[1] = MED_CUT_GREEN(i); colors[i].rgb[2] = MED_CUT_BLUE(i); colors[i].count = 0; } max_width = -1; for (imgn = 0; imgn < count; ++imgn) { if (imgs[imgn]->xsize > max_width) max_width = imgs[imgn]->xsize; } line = i_mempool_alloc(&mp, sizeof(i_color) * max_width); /* build the stats */ total_pixels = 0; chan_count = 1; /* assume we just have grayscale */ for (imgn = 0; imgn < count; ++imgn) { total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize; for (y = 0; y < imgs[imgn]->ysize; ++y) { i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line); if (imgs[imgn]->channels > 2) { chan_count = 3; for (x = 0; x < imgs[imgn]->xsize; ++x) { ++colors[MED_CUT_INDEX(line[x])].count; } } else { /* a gray-scale image, just use the first channel */ for (x = 0; x < imgs[imgn]->xsize; ++x) { ++colors[MED_CUT_GRAY_INDEX(line[x])].count; } } } } /* eliminate the empty colors */ out = 0; for (in = 0; in < MEDIAN_CUT_COLORS; ++in) { if (colors[in].count) { colors[out++] = colors[in]; } } /*printf("out %d\n", out); for (i = 0; i < out; ++i) { if (colors[i].count) { printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1], colors[i].rgb[2], colors[i].count); } }*/ if (out < quant->mc_size) { /* just copy them into the color table */ for (i = 0; i < out; ++i) { for (ch = 0; ch < 3; ++ch) { quant->mc_colors[i].channel[ch] = colors[i].rgb[ch]; } } quant->mc_count = out; } else { /* build the starting partition */ parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size); parts[0].start = 0; parts[0].size = out; parts[0].pixels = total_pixels; calc_part(parts, colors); color_count = 1; while (color_count < quant->mc_size) { /* initialized to avoid compiler warnings */ int max_index = 0, max_ch = 0; /* index/channel with biggest spread */ int max_size; medcut_partition *workpart; int cum_total; int half; /* find the partition with the most biggest span with more than one color */ max_size = -1; for (i = 0; i < color_count; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (parts[i].width[ch] > max_size && parts[i].size > 1) { max_index = i; max_ch = ch; max_size = parts[i].width[ch]; } } } /* nothing else we can split */ if (max_size == -1) break; workpart = parts+max_index; /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/ qsort(colors + workpart->start, workpart->size, sizeof(*colors), sorters[max_ch]); /* find the median or something like it we need to make sure both sides of the split have at least one color in them, so we don't test at the first or last entry */ i = workpart->start; cum_total = colors[i].count; ++i; half = workpart->pixels / 2; while (i < workpart->start + workpart->size - 1 && cum_total < half) { cum_total += colors[i++].count; } /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/ /* found the spot to split */ parts[color_count].start = i; parts[color_count].size = workpart->start + workpart->size - i; workpart->size = i - workpart->start; parts[color_count].pixels = workpart->pixels - cum_total; workpart->pixels = cum_total; /* recalculate the limits */ calc_part(workpart, colors); calc_part(parts+color_count, colors); ++color_count; } /* fill in the color table - since we could still have partitions that have more than one color, we need to average the colors */ for (part_num = 0; part_num < color_count; ++part_num) { long sums[3]; medcut_partition *workpart; workpart = parts+part_num; for (ch = 0; ch < 3; ++ch) sums[ch] = 0; for (i = workpart->start; i < workpart->start + workpart->size; ++i) { for (ch = 0; ch < 3; ++ch) { sums[ch] += colors[i].rgb[ch] * colors[i].count; } } for (ch = 0; ch < 3; ++ch) { quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels; } } quant->mc_count = color_count; } /*printf("out %d colors\n", quant->mc_count);*/ i_mempool_destroy(&mp); mm_log((1, "makemap_mediancut() - %d colors\n", quant->mc_count)); } static void makemap_mono(i_quantize *quant) { quant->mc_colors[0].rgba.r = 0; quant->mc_colors[0].rgba.g = 0; quant->mc_colors[0].rgba.b = 0; quant->mc_colors[0].rgba.a = 255; quant->mc_colors[1].rgba.r = 255; quant->mc_colors[1].rgba.g = 255; quant->mc_colors[1].rgba.b = 255; quant->mc_colors[1].rgba.a = 255; quant->mc_count = 2; } static void makemap_gray(i_quantize *quant, int step) { int gray = 0; int i = 0; while (gray < 256) { setcol(quant->mc_colors+i, gray, gray, gray, 255); ++i; gray += step; } quant->mc_count = i; } static void makemap_webmap(i_quantize *quant) { int r, g, b; int i = 0; for (r = 0; r < 256; r+=0x33) for (g = 0; g < 256; g+=0x33) for (b = 0; b < 256; b += 0x33) setcol(quant->mc_colors+i++, r, g, b, 255); quant->mc_count = i; } static int in_palette(i_color *c, i_quantize *quant, int size) { int i; for (i = 0; i < size; ++i) { if (c->channel[0] == quant->mc_colors[i].channel[0] && c->channel[1] == quant->mc_colors[i].channel[1] && c->channel[2] == quant->mc_colors[i].channel[2]) { return i; } } return -1; } /* =item makemap_palette(quant, imgs, count) Tests if all the given images are paletted and have a common palette, if they do it builds that palette. A possible improvement might be to eliminate unused colors in the images palettes. =cut */ static int makemap_palette(i_quantize *quant, i_img **imgs, int count) { int size = quant->mc_count; int i; int imgn; char used[256]; int col_count; mm_log((1, "makemap_palette(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n", quant, quant->mc_count, quant->mc_colors, imgs, count)); /* we try to build a common palette here, if we can manage that, then that's the palette we use */ for (imgn = 0; imgn < count; ++imgn) { int eliminate_unused; if (imgs[imgn]->type != i_palette_type) { mm_log((1, "makemap_palette() -> 0 (non-palette image)\n")); return 0; } if (!i_tags_get_int(&imgs[imgn]->tags, "gif_eliminate_unused", 0, &eliminate_unused)) { eliminate_unused = 1; } if (eliminate_unused) { i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize); i_img_dim x, y; memset(used, 0, sizeof(used)); for (y = 0; y < imgs[imgn]->ysize; ++y) { i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line); for (x = 0; x < imgs[imgn]->xsize; ++x) used[line[x]] = 1; } myfree(line); } else { /* assume all are in use */ memset(used, 1, sizeof(used)); } col_count = i_colorcount(imgs[imgn]); for (i = 0; i < col_count; ++i) { i_color c; i_getcolors(imgs[imgn], i, &c, 1); if (used[i]) { if (in_palette(&c, quant, size) < 0) { if (size < quant->mc_size) { quant->mc_colors[size++] = c; } else { mm_log((1, "makemap_palette() -> 0 (too many colors)\n")); return 0; } } } } } mm_log((1, "makemap_palette() -> 1 (%d total colors)\n", size)); quant->mc_count = size; return 1; } #define pboxjump 32 /* Define one of the following 4 symbols to choose a colour search method The idea is to try these out, including benchmarking, to see which is fastest in a good spread of circumstances. I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and IM_CFHASHBOX for large images with large palettes. Some other possibilities include: - search over entries sorted by luminance Initially I was planning on testing using the macros and then integrating the code directly into each function, but this means if we find a bug at a late stage we will need to update N copies of the same code. Also, keeping the code in the macros means that the code in the translation functions is much more to the point, there's no distracting colour search code to remove attention from what makes _this_ translation function different. It may be advisable to move the setup code into functions at some point, but it should be possible to do this fairly transparently. If IM_CF_COPTS is defined then CFLAGS must have an appropriate definition. Each option needs to define 4 macros: CF_VARS - variables to define in the function CF_SETUP - code to setup for the colour search, eg. allocating and initializing lookup tables CF_FIND - code that looks for the color in val and puts the best matching index in bst_idx CF_CLEANUP - code to clean up, eg. releasing memory */ #ifndef IM_CF_COPTS /*#define IM_CFLINSEARCH*/ #define IM_CFHASHBOX /*#define IM_CFSORTCHAN*/ /*#define IM_CFRAND2DIST*/ #endif /* return true if the color map contains only grays */ static int is_gray_map(const i_quantize *quant) { int i; for (i = 0; i < quant->mc_count; ++i) { if (quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.g || quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.b) { mm_log((1, " not a gray map\n")); return 0; } } mm_log((1, " is a gray map\n")); return 1; } #ifdef IM_CFHASHBOX /* The original version I wrote for this used the sort. If this is defined then we use a sort to extract the indices for the hashbox */ #define HB_SORT /* assume i is available */ #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \ int currhb; \ long ld, cd #ifdef HB_SORT static long *gdists; /* qsort is annoying */ /* int might be smaller than long, so we need to do a real compare rather than a subtraction*/ static int distcomp(void const *a, void const *b) { long ra = gdists[*(int const *)a]; long rb = gdists[*(int const *)b]; if (ra < rb) return -1; else if (ra > rb) return 1; else return 0; } #endif /* for each hashbox build a list of colours that are in the hb or is closer than other colours This is pretty involved. The original gifquant generated the hashbox as part of it's normal processing, but since the map generation is now separated from the translation we need to do this on the spot. Any optimizations, even if they don't produce perfect results would be welcome. */ static void hbsetup(i_quantize *quant, hashbox *hb) { long *dists, mind, maxd; int cr, cb, cg, hbnum, i; i_color cenc; #ifdef HB_SORT int *indices = mymalloc(quant->mc_count * sizeof(int)); #endif dists = mymalloc(quant->mc_count * sizeof(long)); for (cr = 0; cr < 8; ++cr) { for (cg = 0; cg < 8; ++cg) { for (cb = 0; cb < 8; ++cb) { /* centre of the hashbox */ cenc.channel[0] = cr*pboxjump+pboxjump/2; cenc.channel[1] = cg*pboxjump+pboxjump/2; cenc.channel[2] = cb*pboxjump+pboxjump/2; hbnum = pixbox(&cenc); hb[hbnum].cnt = 0; /* order indices in the order of distance from the hashbox */ for (i = 0; i < quant->mc_count; ++i) { #ifdef HB_SORT indices[i] = i; #endif dists[i] = ceucl_d(&cenc, quant->mc_colors+i); } #ifdef HB_SORT /* it should be possible to do this without a sort but so far I'm too lazy */ gdists = dists; qsort(indices, quant->mc_count, sizeof(int), distcomp); /* any colors that can match are within mind+diagonal size of a hashbox */ mind = dists[indices[0]]; i = 0; maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump); while (i < quant->mc_count && dists[indices[i]] < maxd) { hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++]; } #else /* work out the minimum */ mind = 256*256*3; for (i = 0; i < quant->mc_count; ++i) { if (dists[i] < mind) mind = dists[i]; } /* transfer any colours that might be closest to a colour in this hashbox */ maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump); for (i = 0; i < quant->mc_count; ++i) { if (dists[i] < maxd) hb[hbnum].vec[hb[hbnum].cnt++] = i; } #endif } } } #ifdef HB_SORT myfree(indices); #endif myfree(dists) ; } #define CF_SETUP hbsetup(quant, hb) #define CF_FIND \ currhb = pixbox(&val); \ ld = 196608; \ for (i = 0; i < hb[currhb].cnt; ++i) { \ cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \ if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \ } #define CF_CLEANUP myfree(hb) #endif #ifdef IM_CFLINSEARCH /* as simple as it gets */ #define CF_VARS long ld, cd #define CF_SETUP /* none needed */ #define CF_FIND \ ld = 196608; \ for (i = 0; i < quant->mc_count; ++i) { \ cd = ceucl_d(quant->mc_colors+i, &val); \ if (cd < ld) { ld = cd; bst_idx = i; } \ } #define CF_CLEANUP #endif #ifdef IM_CFSORTCHAN static int gsortchan; static i_quantize *gquant; static int chansort(void const *a, void const *b) { return gquant->mc_colors[*(int const *)a].channel[gsortchan] - gquant->mc_colors[*(int const *)b].channel[gsortchan]; } #define CF_VARS int *indices, sortchan, diff; \ long ld, cd; \ int vindex[256] /* where to find value i of chan */ static void chansetup(i_img *img, i_quantize *quant, int *csortchan, int *vindex, int **cindices) { int *indices, sortchan, chan, i, chval; int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange; /* find the channel with the maximum range */ /* the maximum stddev would probably be better */ for (chan = 0; chan < img->channels; ++chan) { chanmins[chan] = 256; chanmaxs[chan] = 0; for (i = 0; i < quant->mc_count; ++i) { if (quant->mc_colors[i].channel[chan] < chanmins[chan]) chanmins[chan] = quant->mc_colors[i].channel[chan]; if (quant->mc_colors[i].channel[chan] > chanmaxs[chan]) chanmaxs[chan] = quant->mc_colors[i].channel[chan]; } } maxrange = -1; for (chan = 0; chan < img->channels; ++chan) { if (chanmaxs[chan]-chanmins[chan] > maxrange) { maxrange = chanmaxs[chan]-chanmins[chan]; sortchan = chan; } } indices = mymalloc(quant->mc_count * sizeof(int)) ; for (i = 0; i < quant->mc_count; ++i) { indices[i] = i; } gsortchan = sortchan; gquant = quant; qsort(indices, quant->mc_count, sizeof(int), chansort) ; /* now a lookup table to find entries faster */ for (chval=0, i=0; i < quant->mc_count; ++i) { while (chval < 256 && chval < quant->mc_colors[indices[i]].channel[sortchan]) { vindex[chval++] = i; } } while (chval < 256) { vindex[chval++] = quant->mc_count-1; } *csortchan = sortchan; *cindices = indices; } #define CF_SETUP \ chansetup(img, quant, &sortchan, vindex, &indices) int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex, int sortchan) { int i, bst_idx, diff, maxdiff; long ld, cd; i = vindex[val.channel[sortchan]]; bst_idx = indices[i]; ld = 196608; diff = 0; maxdiff = quant->mc_count; while (diff < maxdiff) { if (i+diff < quant->mc_count) { cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]); if (cd < ld) { bst_idx = indices[i+diff]; ld = cd; maxdiff = sqrt(ld); } } if (i-diff >= 0) { cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]); if (cd < ld) { bst_idx = indices[i-diff]; ld = cd; maxdiff = sqrt(ld); } } ++diff; } return bst_idx; } #define CF_FIND \ bst_idx = chanfind(val, quant, indices, vindex, sortchan) #define CF_CLEANUP myfree(indices) #endif #ifdef IM_CFRAND2DIST /* This is based on a method described by Addi in the #imager channel on the 28/2/2001. I was about 1am Sydney time at the time, so I wasn't at my most cogent. Well, that's my excuse :) what I have at the moment is: hashboxes, with optimum hash box filling; simple linear search; and a lookup in the widest channel (currently the channel with the maximum range) There is one more way that might be simple to implement. You want to hear? what's that? somebody said that was not true For each of the colors in the palette start by creating a sorted list of the form: [distance, color] Where they are sorted by distance. distance to where? Where the elements in the lists are the distances and colors of the other colors in the palette ok So if you are at color 0 ok - now to search for the closest color when you are creating the final image is done like this: a) pick a random color from the palette b) calculate the distance to it c) only check the vectors that are within double the distance in the list of the color you picked from the palette. Does that seem logical? Lets imagine that we only have grayscale to make an example: Our palette has 1 4 10 20 as colors. And we want to quantize the color 11 lets say we picked 10 randomly the double distance is 2 since abs(10-11)*2 is 2 And the list at vector 10 is this: [0, 10], [6 4], [9, 1], [10, 20] so we look at the first one (but not the second one since 6 is at a greater distance than 2. Any of that make sense? yes, though are you suggesting another random jump to one of the colours with the possible choices? or an exhaustive search? TonyC: It's possible to come up with a recursive/iterative enhancement but this is the 'basic' version. Which would do an iterative search. You can come up with conditions where it pays to switch to a new one. And the 'random' start can be switched over to a small tree. So you would have a little index at the start. to get you into the general direction Perhaps just an 8 split. that is - split each dimension in half. yep I get the idea But this would seem to be a good approach in our case since we usually have few codevectors. So we only need 256*256 entries in a table. We could even only index some of them that were deemed as good candidates. I was considering adding paletted output support for PNG and TIFF at some point, which support 16-bit palettes ohh. 'darn' ;) */ typedef struct i_dists { int index; long dist; } i_dists; #define CF_VARS \ i_dists *dists; static int dists_sort(void const *a, void const *b) { return ((i_dists *)a)->dist - ((i_dists *)b)->dist; } static void rand2dist_setup(i_quantize *quant, i_dists **cdists) { i_dists *dists = mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count); int i, j; long cd; for (i = 0; i < quant->mc_count; ++i) { i_dists *ldists = dists + quant->mc_count * i; i_color val = quant->mc_colors[i]; for (j = 0; j < quant->mc_count; ++j) { ldists[j].index = j; ldists[j].dist = ceucl_d(&val, quant->mc_colors+j); } qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort); } *cdists = dists; } #define CF_SETUP \ bst_idx = rand() % quant->mc_count; \ rand2dist_setup(quant, &dists) static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) { i_dists *cdists; long cd, ld; long maxld; int i; int bst_idx; cdists = dists + index * quant->mc_count; ld = 3 * 256 * 256; maxld = 8 * ceucl_d(&val, quant->mc_colors+index); for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) { cd = ceucl_d(&val, quant->mc_colors+cdists[i].index); if (cd < ld) { bst_idx = cdists[i].index; ld = cd; } } return bst_idx; } #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx) #define CF_CLEANUP myfree(dists) #endif static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) { i_img_dim x, y, k; int i, bst_idx = 0; i_color val; int pixdev = quant->perturb; CF_VARS; CF_SETUP; if (img->channels >= 3) { if (pixdev) { k=0; for(y=0;yysize;y++) for(x=0;xxsize;x++) { i_gpix(img,x,y,&val); val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn())); val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn())); val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn())); CF_FIND; out[k++]=bst_idx; } } else { k=0; for(y=0;yysize;y++) for(x=0;xxsize;x++) { i_gpix(img,x,y,&val); CF_FIND; out[k++]=bst_idx; } } } else { if (pixdev) { k=0; for(y=0;yysize;y++) for(x=0;xxsize;x++) { i_gpix(img,x,y,&val); val.channel[1] = val.channel[2] = val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn())); CF_FIND; out[k++]=bst_idx; } } else { k=0; for(y=0;yysize;y++) for(x=0;xxsize;x++) { i_gpix(img,x,y,&val); val.channel[1] = val.channel[2] = val.channel[0]; CF_FIND; out[k++]=bst_idx; } } } CF_CLEANUP; } static int floyd_map[] = { 0, 0, 7, 3, 5, 1 }; static int jarvis_map[] = { 0, 0, 0, 7, 5, 3, 5, 7, 5, 3, 1, 3, 5, 3, 1 }; static int stucki_map[] = { 0, 0, 0, 8, 4, 2, 4, 8, 4, 2, 1, 2, 4, 2, 1 }; struct errdiff_map { int *map; int width, height, orig; }; static struct errdiff_map maps[] = { { floyd_map, 3, 2, 1 }, { jarvis_map, 5, 3, 2 }, { stucki_map, 5, 3, 2 }, }; typedef struct errdiff_tag { int r, g, b; } errdiff_t; /* perform an error diffusion dither */ static void translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) { int *map; int mapw, maph, mapo; int i; errdiff_t *err; i_img_dim errw; int difftotal; i_img_dim x, y, dx, dy; int bst_idx = 0; int is_gray = is_gray_map(quant); CF_VARS; if ((quant->errdiff & ed_mask) == ed_custom) { map = quant->ed_map; mapw = quant->ed_width; maph = quant->ed_height; mapo = quant->ed_orig; } else { int index = quant->errdiff & ed_mask; if (index >= ed_custom) index = ed_floyd; map = maps[index].map; mapw = maps[index].width; maph = maps[index].height; mapo = maps[index].orig; } errw = img->xsize+mapw; err = mymalloc(sizeof(*err) * maph * errw); /*errp = err+mapo;*/ memset(err, 0, sizeof(*err) * maph * errw); difftotal = 0; for (i = 0; i < maph * mapw; ++i) difftotal += map[i]; /*printf("map:\n"); for (dy = 0; dy < maph; ++dy) { for (dx = 0; dx < mapw; ++dx) { printf("%2d", map[dx+dy*mapw]); } putchar('\n'); }*/ CF_SETUP; for (y = 0; y < img->ysize; ++y) { for (x = 0; x < img->xsize; ++x) { i_color val; errdiff_t perr; i_gpix(img, x, y, &val); if (img->channels < 3) { val.channel[1] = val.channel[2] = val.channel[0]; } else if (is_gray) { int gray = 0.5 + color_to_grey(&val); val.channel[0] = val.channel[1] = val.channel[2] = gray; } perr = err[x+mapo]; perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal; perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal; perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal; /*printf("x %3d y %3d in(%3d, %3d, %3d) di(%4d,%4d,%4d)\n", x, y, val.channel[0], val.channel[1], val.channel[2], perr.r, perr.g, perr.b);*/ val.channel[0] = g_sat(val.channel[0]-perr.r); val.channel[1] = g_sat(val.channel[1]-perr.g); val.channel[2] = g_sat(val.channel[2]-perr.b); CF_FIND; /* save error */ perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0]; perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1]; perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2]; /*printf(" out(%3d, %3d, %3d) er(%4d, %4d, %4d)\n", quant->mc_colors[bst_idx].channel[0], quant->mc_colors[bst_idx].channel[1], quant->mc_colors[bst_idx].channel[2], perr.r, perr.g, perr.b);*/ for (dx = 0; dx < mapw; ++dx) { for (dy = 0; dy < maph; ++dy) { err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy]; err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy]; err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy]; } } *out++ = bst_idx; } /* shift up the error matrix */ for (dy = 0; dy < maph-1; ++dy) { memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw); } memset(err+(maph-1)*errw, 0, sizeof(*err)*errw); } CF_CLEANUP; myfree(err); } /* Prescan finds the boxes in the image that have the highest number of colors and that result is used as the initial value for the vectores */ static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) { int i,k,j; i_img_dim x,y; i_sample_t *val; const int *chans; pbox prebox[512]; for(i=0;i<512;i++) { prebox[i].boxnum=i; prebox[i].pixcnt=0; prebox[i].cand=1; } /* process each image */ for (i = 0; i < count; ++i) { i_img *im = imgs[i]; chans = im->channels >= 3 ? NULL : gray_samples; for(y=0;yysize;y++) { i_gsamp(im, 0, im->xsize, y, line, chans, 3); val = line; for(x=0;xxsize;x++) { prebox[pixbox_ch(val)].pixcnt++; } } } for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt; qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp); for(i=0;i=prebox[k].cand) { k++; j=1; } else { if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i])); else boxrand(prebox[k].boxnum,&(clr[i])); /* printf("(%d,%d) %d %d -> (%d,%d,%d)\n",k,j,prebox[k].boxnum,prebox[k].pixcnt,clr[i].r,clr[i].g,clr[i].b); */ j++; i++; } } } static void reorder(pbox prescan[512]) { int nidx; pbox c; nidx=0; c=prescan[0]; c.cand++; c.pdc=c.pixcnt/(c.cand*c.cand); /* c.pdc=c.pixcnt/c.cand; */ while(c.pdc < prescan[nidx+1].pdc && nidx < 511) { prescan[nidx]=prescan[nidx+1]; nidx++; } prescan[nidx]=c; } static int pboxcmp(const pbox *a,const pbox *b) { if (a->pixcnt > b->pixcnt) return -1; if (a->pixcnt < b->pixcnt) return 1; return 0; } static void boxcenter(int box,cvec *cv) { cv->r=15+((box&448)>>1); cv->g=15+((box&56)<<2); cv->b=15+((box&7)<<5); } static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) { *r0=(box&448)>>1; *r1=(*r0)|31; *g0=(box&56)<<2; *g1=(*g0)|31; *b0=(box&7)<<5; *b1=(*b0)|31; } static void boxrand(int box,cvec *cv) { cv->r=6+(rand()%25)+((box&448)>>1); cv->g=6+(rand()%25)+((box&56)<<2); cv->b=6+(rand()%25)+((box&7)<<5); } static float frandn(void) { float u1,u2,w; w=1; while (w >= 1 || w == 0) { u1 = 2 * frand() - 1; u2 = 2 * frand() - 1; w = u1*u1 + u2*u2; } w = sqrt((-2*log(w))/w); return u1*w; } /* Create hash index */ static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) { int bx,mind,cd,cumcnt,i; /* printf("indexing... \n");*/ cumcnt=0; for(bx=0; bx<512; bx++) { mind=196608; for(i=0; i approx -> %d\n",bx,hb[bx].cnt); */ /* statbox(bx,cnum,clr); */ cumcnt+=hb[bx].cnt; } /* printf("Average search space: %d\n",cumcnt/512); */ } static int maxdist(int boxnum,cvec *cv) { int r0,r1,g0,g1,b0,b1; int r,g,b,mr,mg,mb; r=cv->r; g=cv->g; b=cv->b; bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1); mr=i_max(abs(b-b0),abs(b-b1)); mg=i_max(abs(g-g0),abs(g-g1)); mb=i_max(abs(r-r0),abs(r-r1)); return PWR2(mr)+PWR2(mg)+PWR2(mb); } static int mindist(int boxnum,cvec *cv) { int r0,r1,g0,g1,b0,b1; int r,g,b,mr,mg,mb; r=cv->r; g=cv->g; b=cv->b; bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1); /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */ if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0; mr=i_min(abs(b-b0),abs(b-b1)); mg=i_min(abs(g-g0),abs(g-g1)); mb=i_min(abs(r-r0),abs(r-r1)); mr=PWR2(mr); mg=PWR2(mg); mb=PWR2(mb); if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb; if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg; if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr; if (r0<=r && r<=r1) return mg+mb; if (g0<=g && g<=g1) return mr+mb; if (b0<=b && b<=b1) return mg+mr; return mr+mg+mb; } static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx); static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx); static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx); /* =item i_quant_transparent(C, C, C, C) =category Image quantization Dither the alpha channel on C into the palette indexes in C. Pixels to be transparent are replaced with C. The method used depends on the tr_* members of C. =cut */ void i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img, i_palidx trans_index) { switch (quant->transp) { case tr_none: break; default: quant->tr_threshold = 128; /* fall through */ case tr_threshold: transparent_threshold(quant, data, img, trans_index); break; case tr_errdiff: transparent_errdiff(quant, data, img, trans_index); break; case tr_ordered: transparent_ordered(quant, data, img, trans_index); break; } } static void transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img, i_palidx trans_index) { i_img_dim x, y; i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t)); int trans_chan = img->channels > 2 ? 3 : 1; for (y = 0; y < img->ysize; ++y) { i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1); for (x = 0; x < img->xsize; ++x) { if (line[x] < quant->tr_threshold) data[y*img->xsize+x] = trans_index; } } myfree(line); } static void transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img, i_palidx trans_index) { int *map; int index; int mapw, maph, mapo; int errw, *err, *errp; int difftotal, out, error; i_img_dim x, y, dx, dy; int i; i_sample_t *line; int trans_chan = img->channels > 2 ? 3 : 1; /* no custom map for transparency (yet) */ index = quant->tr_errdiff & ed_mask; if (index >= ed_custom) index = ed_floyd; map = maps[index].map; mapw = maps[index].width; maph = maps[index].height; mapo = maps[index].orig; errw = img->xsize+mapw-1; err = mymalloc(sizeof(*err) * maph * errw); errp = err+mapo; memset(err, 0, sizeof(*err) * maph * errw); line = mymalloc(img->xsize * sizeof(i_sample_t)); difftotal = 0; for (i = 0; i < maph * mapw; ++i) difftotal += map[i]; for (y = 0; y < img->ysize; ++y) { i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1); for (x = 0; x < img->xsize; ++x) { line[x] = g_sat(line[x]-errp[x]/difftotal); if (line[x] < 128) { out = 0; data[y*img->xsize+x] = trans_index; } else { out = 255; } error = out - line[x]; for (dx = 0; dx < mapw; ++dx) { for (dy = 0; dy < maph; ++dy) { errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy]; } } } /* shift up the error matrix */ for (dy = 0; dy < maph-1; ++dy) memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw); memset(err+(maph-1)*errw, 0, sizeof(*err)*errw); } myfree(err); myfree(line); } /* builtin ordered dither maps */ static unsigned char orddith_maps[][64] = { { /* random this is purely random - it's pretty awful */ 48, 72, 196, 252, 180, 92, 108, 52, 228, 176, 64, 8, 236, 40, 20, 164, 120, 128, 84, 116, 24, 28, 172, 220, 68, 0, 188, 124, 184, 224, 192, 104, 132, 100, 240, 200, 152, 160, 244, 44, 96, 204, 144, 16, 140, 56, 232, 216, 208, 4, 76, 212, 136, 248, 80, 168, 156, 88, 32, 112, 148, 12, 36, 60, }, { /* dot8 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)' */ 240, 232, 200, 136, 140, 192, 228, 248, 220, 148, 100, 76, 80, 104, 152, 212, 180, 116, 56, 32, 36, 60, 120, 176, 156, 64, 28, 0, 8, 44, 88, 160, 128, 92, 24, 12, 4, 40, 68, 132, 184, 96, 48, 20, 16, 52, 108, 188, 216, 144, 112, 72, 84, 124, 164, 224, 244, 236, 196, 168, 172, 204, 208, 252, }, { /* dot4 perl spot.perl \ 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))' */ 196, 72, 104, 220, 200, 80, 112, 224, 76, 4, 24, 136, 84, 8, 32, 144, 108, 28, 52, 168, 116, 36, 56, 176, 216, 140, 172, 244, 228, 148, 180, 248, 204, 92, 124, 236, 192, 68, 96, 208, 88, 12, 44, 156, 64, 0, 16, 128, 120, 40, 60, 188, 100, 20, 48, 160, 232, 152, 184, 252, 212, 132, 164, 240, }, { /* hline perl spot.perl '$y-3' */ 160, 164, 168, 172, 176, 180, 184, 188, 128, 132, 136, 140, 144, 148, 152, 156, 32, 36, 40, 44, 48, 52, 56, 60, 0, 4, 8, 12, 16, 20, 24, 28, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, }, { /* vline perl spot.perl '$x-3' */ 180, 100, 40, 12, 44, 104, 184, 232, 204, 148, 60, 16, 64, 128, 208, 224, 212, 144, 76, 8, 80, 132, 216, 244, 160, 112, 68, 20, 84, 108, 172, 236, 176, 96, 72, 28, 88, 152, 188, 228, 200, 124, 92, 0, 32, 116, 164, 240, 168, 120, 36, 24, 48, 136, 192, 248, 196, 140, 52, 4, 56, 156, 220, 252, }, { /* slashline perl spot.perl '$y+$x-7' */ 248, 232, 224, 192, 140, 92, 52, 28, 240, 220, 196, 144, 108, 60, 12, 64, 216, 180, 148, 116, 76, 20, 80, 128, 204, 152, 104, 44, 16, 72, 100, 160, 164, 96, 68, 24, 56, 112, 168, 176, 124, 40, 8, 36, 88, 136, 184, 212, 84, 4, 32, 120, 156, 188, 228, 236, 0, 48, 132, 172, 200, 208, 244, 252, }, { /* backline perl spot.perl '$y-$x' */ 0, 32, 116, 172, 184, 216, 236, 252, 56, 8, 72, 132, 136, 200, 228, 240, 100, 36, 12, 40, 92, 144, 204, 220, 168, 120, 60, 16, 44, 96, 156, 176, 180, 164, 112, 48, 28, 52, 128, 148, 208, 192, 152, 88, 84, 20, 64, 104, 232, 224, 196, 140, 108, 68, 24, 76, 248, 244, 212, 188, 160, 124, 80, 4, }, { /* tiny good for display, bad for print hand generated */ 0, 128, 32, 192, 8, 136, 40, 200, 224, 64, 160, 112, 232, 72, 168, 120, 48, 144, 16, 208, 56, 152, 24, 216, 176, 96, 240, 80, 184, 104, 248, 88, 12, 140, 44, 204, 4, 132, 36, 196, 236, 76, 172, 124, 228, 68, 164, 116, 60, 156, 28, 220, 52, 148, 20, 212, 188, 108, 252, 92, 180, 100, 244, 84, }, }; static void transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img, i_palidx trans_index) { unsigned char *spot; i_img_dim x, y; i_sample_t *line; int trans_chan = img->channels > 2 ? 3 : 1; if (quant->tr_orddith == od_custom) spot = quant->tr_custom; else spot = orddith_maps[quant->tr_orddith]; line = mymalloc(img->xsize * sizeof(i_sample_t)); for (y = 0; y < img->ysize; ++y) { i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1); for (x = 0; x < img->xsize; ++x) { if (line[x] < spot[(x&7)+(y&7)*8]) data[x+y*img->xsize] = trans_index; } } myfree(line); } libimager-perl-1.004+dfsg.orig/testimg/0000755000175000017500000000000012617614576017254 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/testimg/winrgb8.bmp0000755000175000017500000000270612031434615021324 0ustar gregoagregoaBMÆ6(  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !  ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+0000libimager-perl-1.004+dfsg.orig/testimg/test.raw0000644000175000017500000020365412031434615020740 0ustar gregoagregoa5DLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLD5-j‰˜˜˜˜˜˜˜šŸª¯±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± |55DLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL-LjL‰L˜L˜L˜L˜L˜L˜L˜LŸD¯5ÍÝääääääääääääääääääääääääääääääääääääääääääääääΠD5| ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±5±D±L±L±L±L±L±L±L±] |È5ìýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KD Îäääääääääääääääääääääääääääääääääääääääääääääääääääääääää/Î] ¹Dçýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýäK²²Käýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýûöìçäääääääÎK ²Däýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýä²KK²äýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýûöìçß(Õ<ÀG¶L±L±L±L±L±L±L±G >@FFH556ýýýüüûþþúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©© !!"224335EEE;;; 444889²²²þþýþÿûþÿúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§224PPP<<<&&&224 RRQttr……„•••™™™”””\\\...±±²ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§ggh———³³³­­­yyy)))000iigƒƒ’’ŸŸŸªªª²²²¾¾¾¿¿¿qqq ²²³þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©§ \\\“““´´´ÇÇÆÃÃÁ­­«~~},,, (()lll““‘¦¦¤³³±¸¸·¿¿¿ÄÄÄÑÑÑÁÁÁ¢¢¢RRR ²²²ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©'''¥¥£ÁÁ¿ÒÒÐÑÑÏÊÊÈ­­¬yyy ]]]™™—ÇÇÅââàìììòòòôôôóóóíííØØØ®®®{{{%%%sstýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©OOO¬¬¬ÞÞÜôôòûûùüüúüüúûûûãããDDD((*§§¨ææäýýûþþýþþþíííÎÎÎçççýýýúúúñññ···YYY444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ©©© |||èèèõõõ¢¢¢qqo  žððîýýüüüü“““JJJÉÉÉööôýýûûûú¨¨¨$$& '''ŠŠŠôôôýýýùùù­­­444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ©©ª¯¯±÷÷ù ***===kkkññïýýûÉÉÈ VVWÓÓÓûûùüüúººº888zzzGGGzzzõõõýýýååå777444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«ÄÄÆìëí436:::xxw443›œšýýûÝÝÝ))) ``aÔÕÕûûúóóòIII SSS}}}///ÄÄÄþþþ÷ø÷_`^444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû¨¨¨ÄÇÇÄÃÇ YYUKLHTWVóöõààÝ331 ";;;HDC0,*`^bÒÔ×øüüÈÉË"!YWW/.0ŒŒŽúýýøýùˆ€444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÓÓÓ!ÆÃź¹µ+,*HDF.-.ääáÖÑË(#  '+,³³¶ôôô¶¶º    qnqûøüüøü–’—444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüü,,.À½¼ÉËÅ)+-"%)ØÙ׎ˆ{ &$wrðëæ¸·´   qslüû÷úùö”’444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýý**,«¬¬áäå.//#"²¨†€m%¥ŠáɢȜÍÖ—vrc#¾ÏÌ  –š˜ûýõ÷ùð‚ƒ444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-†ˆŒðñõ‹Š‡  eF ®‚Ëšêµì¸ æ¶ à´ ×¬ÅžÛÖ®#ɦ2йuQF./0/âåâýÿüëëëXVZ444ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-SSTåàäïîïSTV6!‰e±ƒ°|Ú£î¸î» é¼ á¹ Ó­´“ xÆœ è½ä» mV"%'#ÀÅÂúÿþøüýÅÈÊ"!%××Öþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-"!ÃÂÄøöùëæÚzg7šr¿‰ ÖŸç¯ ðµ ñ· ï¹ë½èÁåÀ äÀá¾çÈîÑêÊçÃã¿Í©xo^ Цþùõýûúëíç|z±±°ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,- twxâÝÐϹ‡¬ƒ½ˆÓ™ã­éµì¸ ë¹é¼ç¿ ëÇîÍîÒñÓ+ôÔ/÷Ö0öÕ.øÕ%öÑóÉ î¿ß°È¡*À¡KŰv¦—r*!±±°þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûýýý//02(£‡Vª}!¿† Жܤ ç° ëµ í¹ ì¼ ê¾ êÁ ìÇïÎðÓ ò×/ôØ>÷ÚDöÚ4õØöÕ öÐ ôÍòÇðÆë¿Ú°Á™{W±±±þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûüüü++- YC›xµ„ÊØ›â« ê´ ê´ ë· ì¼ ëÀ ìÆîÌðÑóÕ*õØ>÷ÚA÷Û=ôØ,öÙ÷Øù×øÛù×öÖ÷ÕöÑòÅ+Ö§)bL ±±²ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý,,. L2  u²€¿ˆÔ• â¡ä¯êµì¶ íºë¾ëÄ ìË ìÎïÒôÖ9øÙGùÚBöÙ*õÚõØõ×õ×õØøÙô×ëÎãÂôÇ+î»"“s rrsþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþýªª«…`¶x¿€ÉÛœ ç¦ç± ì¸ ë· í¼ìÂêÇêÍ íÐòÔ/÷ÚAøÙ@öØ-öØöÙ÷ÚôØôØ÷×öÏằ‡­‚Ùª à¯~_445ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«, ”o¸włіޡ è« é´ ë· íºê½ ëÄ êËìÏðÓ'òÓ<õØ7õØ%ó×öØ÷×ö×ôÖóÖìËÇ› µ„ÂŽ Ñ Ø¡ ÏœfL ØØØþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþüþþüþþüþþüþþýªªª( s´} ÈŒ Óœ ߦ ç®î¹ í¹ ì» ë¿ êÅìÌ îÑòÕ+÷Ø=õÖ*õØô×ö×÷Ø õÕôÑܵª„·Šʘӛܠ؛ќdK qqqþþýþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþþþüþþüþþüþþýªªª T>†_ ½ؤà¬ë´ ï·îº í½ ìà íÉíÍïÒóÖ#ô×&öÖ÷Öô×ñÓñÏêÄÄ— «yÁ‘К Õ› Ùœ Ú՚ĒL7 333þþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþþþüþþüþþüþþýªªªZ>S·…Ý®ë·ò·ï¼ îÁ îÅñÍïÏñÓóÖó×öÕõÔíÏ ãÄ¿˜Ÿo±| É’ Õ— ܘ Ýš Ú Î˜Ãc  SSUhhj'')±±°ýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« C)vM€U§ Û®ñ·ï¿îÇñÍóÐ'ôÔ%ñÔïÔïÑèÈÕ´¬‹Œe›m¼‡ Δ Õ™ ×› ÙŸÕÉ”¶ˆ­‰?yfC;;;yyyyyyQQQ**) qqqþþüýþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«("gƒh%~W‹\©{ Ç  Ô±Ù¸Û¼Ò±έœ¨|¡oi«v º‚ÉŒ Ò‘ Ò“ Ñ—З Å »Ž!Ä \ʱ”Ǻ°¸³®QQLccc€€€zzy442××Öýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«³µ«³¨ƒl&•h“i ˜o ¦~ ¥£}¢y§z°º…ÉćÊ Î’ΔÍ’ ÊŒȇ¸„»”M˵—Ê»ÄÃÀ¾½º¿¿¿”–™777}}}€€aa` !pppþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« \ZS¾¾¹¾·³®™ul˜i¢pÀ’Û²Û´׫ÒŸЖÒ•Ï– Ì“ Ê ÈŽÉÁ‹µƒ±…0¾¦~ƼªÅ¹ÊÌÉÈÍÊÂÇÀ½¾¹©§§! "]]]€€€~~}mmm445ÖÖÕþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþþjjl[XZ½¹º½»¾Áº³°—p–išd¬w ȓҞÔÒ˜ Ò”ÏÊŽÃŒ¿‡½~¾| ·´–Q½´™º»¶»½¸¹½¶ÃÆÁÐÑÏÒÑÑÈÆÅ¼º¹TSS;;;oopqqqBBB 000ýýüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýýýü,,. U[W¸º·»½¸»¼ºÂ·®¶šv‘g'“e ¥u¶¾„ À… Á… ½‚ ·y°p°o°w ²„/¼žmÆ»¦»½±¾¹·Á¼¾ÆÉÉÖÛØèèêõï÷õó÷ÛßÛŸ¡ž ,,.®®­þþüýýûüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüújjj OTK¹½¶Âÿ¿¿¸¿½´Áº³º¨Œ“{@ƒd‘hšhžih›i ˜e ˜e šn¬ŽK¿±‹Â½³»º»¿»¹Ã¿ÀÐÌÏçäç÷õûûüýûþøúý÷÷øø×ÖØOOO333þþüýýûüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÓÓÑ b[_ØÔÖÖÔÖÈÅÄÀ½º¼½¼¾¼ºÃ»¬µ¢ƒ ‚V”n4•l%“l"™t0¦„K±™m¼³˜À¿´¾»µ¾º±¾¼µÁÂÁÎÓÌâçáò÷÷ýþýÿýùÿüöþýùýþýö÷÷²²² ®®­þþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúüýøiig%$%ÏÎÏîííáááÌËÌ¿¾¾¼¼¼½¼½À½½Á½¹Â¼´¿¸­¾¶§½µ¤¾¶§Ã»²Ã½¶À¼¹½¼º¼»¹ÁÀ¾ÆÅÄÓÓÓãäáôõòþÿýýþüÿþüþþûþþüþþüýþûôôô[[[""#ÔÔÕýýüýþúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúüüú¨¨¦ŒŒŒúúúöööëëëÖÖÖÁÁÁ¾¾¾¿½¾¿¾¼¾½»¾½º½¼¸À¾¹Á¾ºÁ¾¸À¼¹¿»º¼º¹¿¾¼ÆÅÃÎÎÎÜÜÜçççòòðýýûýýûÿÿýþþüþþüþþüþþüþþüüüüÃÃÃrrsýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÒÒÐ DDEßßßýýýýýýùùùìììÑÑѽ½½¾½¼¾½»¾½»À¿»¿¾º¾½¹¾¼¸¾½¹À½»¿½»ÁÀ¾ÌËÉ××Õääâïïï÷÷÷üüûýýûþþüýýûþþüþþüþþüþþüþþüþþüõõônnnÔÔÒþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýþþþ+++ µµ´÷÷õýýûþþüýýûúúøååãÄľ½º¾½¹¾½»¾¾»¾½¼¾¾»¾¾»¾½»¾½»ÃÂÀÐÏÍàßÝìëéööôûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûûúÎÎÎ&&&---þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüýýýggg nnnïïíýýûþþüþþüþþüýýûóóñÖÖÔÀ¿½¾½»¾½»¿¾¼¾½»¾½»¾¼¼¾¼½ÈÆÅÛÚØèçåóóñúúøûûùüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûøøøkkkªªªþþþýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûýýû¥¥¦))'ÑÑÏýýûýýûþþüþþüþþüþþüûûùììê×ÖÔÆÅÃÂÁ¿½¼º¾½½½½½ÂÂÂÐÐÐâââñññùùøûûùþþüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýÁÁÁÓÓÔýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûÐÐÎ ŒŒŠö÷óþþüÿÿýþþüþþüþþüþþüÿÿýüüúù÷÷íëìÝÛÜÕÕÕ×××ÜÜÜççåòòðùùøþþþýýýýýûþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüôôóJJJkklþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÑÑÏ888ääãýýùþþûþþüþþüþþüþþüþþüþþüþþüÿýþýüýòðñëêëðððøøøûûùûýúýþýþþþýýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüýýýŒŒŒkkjþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýþùüüúýýýeefœœ›ûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúúøööôýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþÿüþþüþþüýýü¼¼¼jjjýýüüüúþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûþþüddd>>>ÛÛÚøøöüüúýýûþþüþþüþþüþþüþþüþþüþþüýýûýýûúúøüüúþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüûûúâââ++-ÓÓÒþþüýýûÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþüþþüýýû¢¢¡ ‰‰‰ççåøøöüüúþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüüüúûûùþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýþþüüüúùùùîîîMMMÑÑÐüüúýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýýûÏÏÏ---²²²æææõõóýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüùù÷ûûùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúùù÷÷÷õñññóó󇇇ÒÒÒüüüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûÏÏÏ???´´´ßßßôôôûûûþþýþþüþþüþþüýýûýýûýýûýýûþþüýýûûûùôôòööôûûùýýûþþüþþüýýûþþüþþüþþüþþüýýûýýûþþüþþüþþüþþüüüúýýûüüúúúøøøöððîêêèììëìììììì°°°ÒÒÒþþþýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû###XXX©©©ÍÍÍìììøøøùùùüüüþþþþþþþþþýýýüüüúúú÷÷÷òòòñññêêêèèèðððöööùùùúúùüüúýýûûûùüüúúúøýýûýýûûûûûûûúúúùùùøøøøøøòòòïïïééçããâÛÛÛÛÛÛÞÞÞää䯯Æ (((üüüþþýþþüþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüaa_ ttt¢¢¢¶¶¶ÐÐÐçççðððñññöööúúúùùùùùùøøøòòòéééâââßßßäääàààßßßåååïïïööõùù÷øøö÷÷õùù÷ùù÷øøöóóñéééåååáááÝÝÝÛÛÛØØØÖÖÖÓÓÓÑÑÑÐÐÐÈÈÈÈÈÈÊÊÊØØØÜÜÜNNN fffüüûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÎÎÌ………žžž¨¨¨ºººÌÌÌÜÜÜäääîîî÷÷÷úúúùùùúúúùùù÷÷÷íííßßßÞÞÞåååïïïñññøøøýýûýýûüüúýýûýýûúúøøøöóóñææåÚÚÚÒÒÒÉÉÉÅÅÅÄÄÄÂÂÂÂÂÂÀÀÀÁÁÁÀÀÀÂÂÂÂÂÂÉÉÉÝÝÛÊÊÉ001££¢þþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüþþþýýýaab&&&ŽŽŽ¡¡¡¯¯¯ÃÃÃÒÒÒààßééçóóñûûùýýûþþüýýûþþüýýýöööåååæææ÷÷÷ýýýþþþþþþþþüýýûþþüþþüýýûþþüþþüýýûööõíííæææÛÛÛÒÒÒÌÌÌÉÉÉÅÅÅÄÄÄÂÂÂÀÀÀÁÁÁÀÀÀÀÀÀÊÊÊåååÇÇÆ""!$$&556%%%ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúýýûþþüýýýÎÎÎ---˜˜˜¶¶¶ÉÉÉßßßííí÷÷öýýûýýûüüúýýûüüúþþüýýûþþþöööèèèôôôýýýþþþþþþþþþÿÿýýýûüüúýýûþþüþþüüüúýýûûûúüüüüüü÷÷÷ôôôìììäääÚÚÚÒÒÒÊÊÊÅÅÅÁÁÁÀÀÀÀÀÀÃÃÃÕÕÕðð¡  ::;@@@""" ££¢üüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüþþþ___aaa¸¸¸ÓÓÓæææööôüüúþþüþþüýýûýýûüüúýýûûûùýýûýýý÷÷÷ëëëõõõüüüýýýûûûûûûüüúûûùýýûûûùüüúüüúþþüýýûþþýþþþþþþúúúýýýýýýüüüúúúñññçççÜÜÜÐÐÐÇÇÇÃÃÃÁÁÁÉÉÉààÞððïlll 222444$$$üüüýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüýýûýýý"""  222¬¬¬ÔÔÔëëëøøöüüúûûùûûùýýûûûùýýûþþüüüúýýûýýûýýûúúøõõóøøöýýûþþüþþüþþüþþüþþüýýûüüúþþüýýûýýûüüúüüúûûùûûùþþüüüúýýûüüúýýûþþýýýý÷÷÷ìììÝÝÝÑÑÑÆÆÆÃÃÃÍÍÍëëëÝÝÝ)))%%%@@@ÏÏÏþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüÍÍÍ668†††ØØØíííúúøþþüýýûþþüûûùþþüýýûúúøýýûþþüýýûýýûüüúüüúûûùýýûûûùúúøýýûýýûûûùüüúüüúýýûüüúûûùýýûüüúûûùýýûüüúýýûþþüþþüýýûûûùþþýýýýþþþüüü÷÷÷èèèÙÙÙÈÈÈÃÃÃÔÔÔôôô”””@@@ccdüüûýýûýýûþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüüüúžžž ??A:::ÑÑÑòòòúúùýýûûûùüüúýýûþþüûûùýýûýýûüüúüüúþþüþþüþþüüüúüüúþþüþþüþþüþþüýýûÿÿýþþüýýûþþüþþüýýûþþüþþüþþüûûùüüúýýûûûùüüúþþüýýûýýûýýûüüúýýûüüúúúøííëÛÛÙÊÊÉÇÇÇáááããã000444ÏÏÎýýûþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüýýû]]] "99;””•ùùùüüûýýûþþüýýûýýûûûùýýûüüúýýûûûùýýûýýûýýûúúøýýûþþüýýûüüúûûùüüúüüúûûùüüúüüúüüúüüúüüúüüúüüúüüúþþüýýûþþüýýûþþüýýûüüúýýûüüúûûùýýûüüúþþüþþüýýûððîÜÜÝÉÉÉÍÍÍïïî ***(((¡¡ üüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúýþûüüú 668668ãããüüüþþüýýûûûùüüúýýûýýûþþüýýûüüúýýûýýûýýûþþüþþüýýûýýûûûùþþüýýûþþüüüúþþüþþüýýûýýûþþüýýûþþüþþüýýûüüúüüúüüúûûùýýûüüúþþüüüúýýûþþüþþüýýûýýûûûùþþüýýûðððÙÙÚËËËÚÚØááá*** !! 888$$$þþüüüúüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûžž777«««ýýüþþüüüúýýûýýûûûùýýûýýûüüúþþüþþüüüúüüúüüúýýûüüúýýûþþüýýûûûùýýûýýûþþüýýûýýûýýûýýûüüúýýûüüúûûùþþüþþüþþüþþüþþüþþüýýûýýûþþüþþüýýûüüúþþüþþüþþüüüúýýûýýûóóñââàÞÞÛññîqqo...<<<000777ÏÏÏýýüüüúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû]]] FFFDDDëëéþþüþþüüüúýýûþþüþþüþþüüüúþþüûûùüüúüüúÿÿýþþüþþüüüúýýûûûùýýûýýûüüúüüúýýûúúøþþüþþüýýûþþüüüúýýûýýûüüúýýûýýûûûùüüúüüúûûùþþüúúøýýûþþüüüúüüúýýûüüúýýûûûùüüúþþüûûùúúöýýû»»¹ 777FFF;;;### 111$$$bbbüüûýýûýýùþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü ==<¨¨¨ûûúýýûýýûüüúýýûûûùýýûüüúüüúþþüýýûþþüýýûûûùüüúüüúýýûûûùüüúûûùýýûüüúþþüþþüþþüúúøýýûûûùþþüþþüþþüþþüüüúþþüüüúýýûúúøþþüüüúýýûýýûýýûþþüüüúüüúüüúþþüþþüþþüüüúýýûýýûþÿûþþûççå000"""999@@@000@@@ ""#þþýüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüœ;;;HHHîîìýýûûûùþþüûûùþþüýýûýýûýýûýýûüüúüüúýýûúúøþþüþþüýýûüüúùù÷øøöýýûûûùýýûüüúüüúþþüþþüþþüþþüûûùýýûüüúþþüýýûýýûþþüýýûþþüüüúþþüýýûüüúüüúýýûþþüüüúüüúûûùüüúüüúýýûüüúûûùýýùüüùùù÷__^%%%### ???(((   ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúþþûþþüýýý^^^<<<¢¢¢ýýûýýûüüúýýûþþüûûùüüúýýûþþüýýûýýûÿÿýýýûþþüüüúüüúûûùööôëëéùù÷ýýûþþüûûùüüúûûùýýûýýûûûùþþüþþüþþüüüúýýûûûùüüúýýûüüúýýûþþüüüúýýûþþüûûùüüúþþüýýûþþüýýûþþüüüúüüúþþüþþüýþúüýúüüú––•  BBBaabþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþùýýûþþüÍÍÌ666###000äääûûùýþúþþüüüúýýûþþüûûùýýûýýûþþüüüúýýûüüúüüúýýûýýûüüúòòðççåóóñýýûýýûýýûüüúÿÿýþþüýýûýýûûûùýýûýýûþþüþþüþþüýýûþþüþþüüüúþþüýýûýýûüüúþþüýýûýýûûûùüüúüüúüüúýýûþþüûûùýýûþþûýýúþþüÇÇÆ  === ""$ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüýøþÿúýýûœœ› AAA „„„úúúþþüýýùþþüþþüüüúþþüýýûýýûýýûüüúüüúüüúýýûüüúýýûýýûüüúïïíååãùù÷þþüüüúþþüýýûýýûýýûþþüüüúýýûûûùýýûýýûýýûýýûûûùýýûüüúþþüûûùýýûýýûýýûûûùýýûûûùþþüýýûþþüýýûüüúûûùþþüýýûýýùüýúýýûååä)));;;žžŸýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúýýúþþü"""000'')ÓÓÓüüüüüúúûöýýûûûùþþüûûùýýûýýûýýûþþüýýûûûùýýûþþüüüúýýûúúøììêééçùù÷þþüýýûüüúýýûüüúüüúüüúþþüþþüýýûûûùþþüýýûÿÿýþþüþþüýýûûûùþþüþþüûûùþþüþþüþþüþþüûûùýýûüüúþþüþþüþþüýýûþþüýýúüýúüüúòòòDDD666***ŸŸ þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýüýýý›››AAC ``_ööôþþüþþüþþüüüúþþüûûùþþüüüúüüúýýûüüúüüúýýûýýûüüúþþüýýûûûùééçííìúúúûûûýýüþþüþþüþþüþþüüüúüüúüüúýýûþþüüüúýýûûûùýýûûûùýýûýýûüüúþþüýýûüüúýýûüüúþþüþþüþþüüüúúúøýýûýýûüüúüüúüüúþþüýýýüüü^^^333)))!!"ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþ CCE ®®­üüúûûùüüúýýûýýûýýûþþüþþüþþüüüúýýûþþüüüúþþüþþüýýûýýûúúøøøöääâçççúúúýýýýýûýýûüüúûûùüüúýýûþþüýýûûûùüüúýýûþþüüüúýýûýýûüüúþþüýýûûûùÿÿýþþüþþüýýûûûùýýûýýûÿÿýýýûþþüüüúüüúþþüýýûûûùûûûüüü~~~445$$$ !þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý™™™--/../ÞÞÜýýûþþüþþüüüúýýûüüúüüúûûùþþüþþüüüúþþüýýûûûùýýûüüúþþüþþüööôââàèèçúúúüüüýýûüüúüüúýýûüüúþþüûûùýýûþþüþþüýýûüüúýýûüüúþþüûûùüüúüüúýýûûûùüüúüüúÿÿýþþüýýûüüúüüúüüúüüúþþüýýûüüúûûùýýûþþþùùù———223ÎÎÎþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ444ZZ[ôôóûûùýýûüüúþþüüüúýýûþþüþþüüüúûûùýýûüüúüüúüüúýýûüüúûûùþþüôôòààÞæææøøøþþþýýüþþüþþüýýûþþüûûùýýûüüúüüúýýûþþüþþüþþüüüúþþüýýûþþüýýûþþüþþüýýûýýûýýûüüúþþüþþüýýûüüúýýûüüúþþüÿÿýþþüûûùýýüýýý¥¥¥--.ŸŸŸþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýþþüýýûýýûZZ[888ˆˆ‰ýýûþþüýýûüüúýýûýýûýýûüüúþþüþþüþþüýýûüüúþþüüüúýýûüüúüüúþþüööôßßÝééé÷÷÷ýýýüüûüüúüüúüüúýýûûûùüüúýýûþþüýýûüüúüüúþþüýýûýýûûûùýýûýýûýýûýýûþþüýýûüüúýýûþþüüüúýýûþþüþþüüüúüüúûûùýýûüüúýýüþþþ¸¸¸223žžžÿÿýýýûüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúýýûËËÉ>>>ÀÀÀûûùýýûýýûþþüþþüýýûþþüþþüûûùüüúýýûýýûýýûýýûþþüüüúýýûûûùýýûòòðßßÝçççøøøýýýýýûþþüþþüýýûüüúþþüþþüüüúýýûúúøþþüüüúýýûýýûþþüþþüýýûûûùýýûüüúûûùþþüýýûþþüþþüþþüûûùýýûýýûüüúüüúýýûþþüþþüüüûýýýÅÅÅ  777___ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüYYW BBB((*ÚÚÚþþüüüúþþüüüúüüúýýûûûùüüúýýûþþüýýûýýûþþüüüúýýûûûùþþüþþüüüúîîìÝÝÛççæ÷÷÷üüüûûúüüúûûùýýûýýûýýûýýûüüúþþüþþüûûùýýûüüúýýûüüúûûùþþüûûùûûùýýûüüúüüúýýûýýûýýûüüúþþüüüúþþüýýûÿÿýýýûúúøýýûüüüýýýÌÌÌ  667 þþüþþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýû——• GGG556ßßßþþüþþüûûùþþüÿÿýûûùþþüþþüüüúýýûþþüýýûýýûþþüýýûþþüýýûþþüþþüððîÝÝÛçççùùùüüüýýûýýûýýûûûùüüúýýûýýûýýûüüúþþüþþüþþüýýûýýûýýûýýûþþüýýûþþüþþüþþüýýûýýûûûùþþüþþüþþüýýûüüúýýûüüúýýûýýûÿÿýþþýþþþÏÏÏ445!!!ýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþFFFFFFèèçúúøýþúÿÿüúúøþþüþþüüüúýýûûûùüüúýýûúúøüüúûûùýýûüüúüüúúúøýýûîîìÝÝÛççæúúúüüüýýûûûùþþüþþüþþüûûùýýûüüúþþüûûùýýûüüúüüúþþüýýûûûùüüúýýûýýûüüúýýûüüúýýûþþüüüúýýûúúøýýûþþüýýûýýûüüúýýûüüúüüûþþþÔÔÔ##%##% þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû———KKK WWWïïíýýûüüøüüúýýûüüúüüúýýûþþüþþüüüúýýûþþüþþüþþüþþüþþüþþüþþüûûùííëÞÞÜëëêúúúþþþþþüþþüûûùüüúýýûþþüüüúýýûûûùþþüýýûýýûýýûüüúûûùþþüýýûûûùüüúýýûýýûþþüûûùýýûýýûþþüýýûûûùüüúþþüþþüþþüýýûýýûýýüýýýÕÕÕ--/  þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû–––,,.PPP888cccññïþþüþþúýýúýýûüüúüüúýýûýýûþþüþþüûûùýýûüüúýýûúúøýýûüüúýýûýýûììêßßÝíííûûûüüüüüúüüúýýûÿÿýúúøþþüýýûýýûûûùýýûüüúüüúýýûýýûþþüûûùþþüþþüýýûüüúýýûûûùýýûýýûýýûüüúýýûþþüýýûýýûüüúýýûýýûüüúþþýüüüÕÕÕ 668 þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüVVV;;=___NNN òòñûûùüüøþþûüüúýýûýýûþþüþþüûûùüüúþþüýýûýýûþþüþþüþþüýýûýýûûûùèèæßßÝíííüüüþþþýýüþþüýýûüüúþþüùù÷ýýûûûùþþüþþüýýûýýûüüúþþüüüúýýûüüúýýûüüúþþüþþüûûùþþüþþüýýûûûùýýûýýûýýûþþüþþüûûùþþüýýûûûûþþþ×××%%% þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüCCCXXX ‚‚‚ôôòýýûþþúþþûþþüüüúýýûûûùþþüþþüûûùüüúýýûýýûüüúýýûûûùüüúýýûüüúêêèÝÝÛìììúúúüüüúúøýýûýýûýýûþþüýýûýýûÿÿýüüúüüúýýûþþüþþüûûùþþüþþüþþüýýûüüúúúøþþüýýûûûùüüúþþüþþüýýûýýûýýûüüúýýûýýûûûùýýûüüüýýýÐÐÐ,,,!!!ýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü JJJ ŠŠŠööôüüúüýùýýúþþüþþüüüúýýûûûùüüúýýûüüúýýûýýûþþüþþüþþüýýûýýûüüúêêèááßïïîúúúþþþþþüýýûýýûûûùüüúþþüüüúüüúüüúýýûüüúýýûûûùþþüüüúüüúûûùýýûýýûýýûûûùýýûýýûüüúûûùýýûüüúüüúýýûüüúüüúýýûþþüþþüúúúþþþÁÁÁ /// þþüþþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü*** ………øøöþþüþÿûþþûüüúüüúýýûûûùþþüýýûýýûýýûüüúüüúýýûúúøýýûýýûüüúýýûêêèââàòòñúúúýýýýýüþþüÿÿýþþüþþüýýûþþüþþüýýûüüúýýûþþüýýûüüúüüúýýûüüúýýûýýûþþüýýûûûùþþüÿÿýýýûþþüþþüþþüþþüþþüþþüûûùýýûþþüþþþýýý¯¯¯///###  ___ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþûþþüþþý  /./212xxxööôûüûüýùýþúþþüþþýýýûþþüüüúüüúûûùüüúýýûþþüþþüþþüüüúüüúüüúýýûëëéààÞññðýýýþþþûûúýýûüüúüüúýýûûûùýýûýýûþþüýýûýýûûûùýýûüüúýýûýýûýýûúúøýýûüüúúúøþþüýýûûûùüüúýýûûûùüüúýýûûûúýüûýýúüýùûüøýýüüüüŒŒ333''' """***&&&žžÿÿþýýûýüùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿýÿþÿùûÿþüþÿ”––#eGžw·Ž¡€YG  96;yywíîíúþþúýùüý÷ýûýþýÿúúùýýûþþüýýûþþüþþüüüúúúøýýûýýûüüúýýûþþüüüüéééàààòòñûûùüüúþþüþþüýýûþþüýýûüüúüüúüüúûûùýýûüüúþþüþþüþþüýýûýýûýýûýýûüüúýýûþþüüüúþþüþþüüüúþþüþþüþþüüýûúýýýýýÿýùýÿ÷ùÿøüþúùúùbdd! ,,-EEEKKK  ›þýþÿýûþÿøýÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúÿôüÿûÿþúýü÷ÿýôcO$«…×¥ï¼ñ¾ñ½æ· šx!HIKÍÊÐúûûûýùþþüþýþýþûüýúýýûüüúüüúýýûþþüþþüýýûüüúýýûþþüýýûýýûüüüëëëàààòòñüüúüüúýýûûûùýýûüüúþþüüüúýýûýýûþþüüüúþþüüüúýýûýýûýýûýýûüüúþþüýýûüüúþþüþþüüüúþþüþþüûûùýýûüüúþþüûþøüûùýùùûúôúýóüýôèâß4.. ZZZbb\ $!"þüþÿüÿÿýúüÿüüÿþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûúÿùýþüÿûÿÿûùë⻵Œ Ú¤ òµô½ õ¿ ú»þ·ðµ¥…  ROSËÊÊùûõýýýúûøùý÷üýúüüúýýûýýûüüúýýûüüúþþüþþüýýûýýûýýûüüúûûûêêêßßßóóñûûùýýûþþüýýûüüúýýûýýûþþüþþüûûùýýûýýûþþüýýûýýûýýûýýûýýûýýûüüúýýûýýûûûùþþüýýûûûùýýûüüúûûùýýûüüúýüôýöÙïÞ®îÛ£íÛ¢îڟθ„5" % 888GG?32. ""&ýþùûÿôþþøýþùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿÿøÿüÿÿüÿýÿøÿýîͱ]Иå®î·ñ¾ ð¾ õ¼ú¼ø¿ê»©‚) :>3¿¿¼úøûýþüýþüþþüýýûüüúýýûþþüþþüýýûüüúþþüýýûüüúýýûþþüýýüêêêàààóóñýýûýýûüüúþþüýýûþþüüüúüüúûûùýýûúúøýýûûûùýýûüüúþþüþþüûûùþþüýýûþþüüüúüüúûûùþþüþþüþþüþþüýýûýýûýüøûíÉÙ³QÞ³ ë¾íÀíÀ廯¢$PB7770,- e`aüþûøÿúûÿýÿýüÿþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüÿüúüþûûþïØË’¼ŠØœ æ¯ ð¸ò¾ ñÀ ñÀ òÂó¿ö½ò¹¬‚% 855´²´õöøþýýüûùþþüýýûüüúýýûüüúýýûþþüûûùüüúýýûûûùýýûûûúèèèßßß÷÷õüüúüüúýýûüüúýýûüüúýýûþþüýýûþþüþþüýýûüüúýýûüüúüüúûûùþþüüüúýýûüüúþþüþþüþþüûûùýýûüüúúúøýýûüüúýûóëÌ|â³ôÉ ÷Ö ôÙöÖõÏå¾#RB """%%%€l×Åyÿýâýýðùÿùûüþÿüþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûÿþüþüúþ÷þûç·.̑ݣï®ö²ø¹÷½ ô½ ö¼÷½ õ¾ ô¾ê´r -.*¢£Ÿöòôýüüúúøýýûþþüþþüþþüüüúüüúüüúüüúýýûüüúþþüûûûëëëàààññïýýûþþüþþüüüúýýûýýûüüúýýûûûùüüúýýûþþüýýûüüúþþüýýûþþüýýûüüúþþüýýûþþüüüúýýûýýûýýûýýûþþüýýûýýûþüôä½k⥠ò· òÂóÍõÐ ÷Ïد?.  <-ƧðÍ"æÊ=õð¹ûþûúÿúüþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûûÿöýýøÿûë˪gÁ‰Ôš à§ ï®÷µ ùº ø¼÷¼÷¼÷¾ ô¿óÁõÀÞµuW "$ƒƒ…íííýýûûûùüüúûûùýýûýýûþþüüüúüüúýýûûûùýýûüüüêêêÜÜÜëëéøøöûûùþþüýýûýýûýýûþþüÿÿýýýûýýûüüúýýûüüúýýûüüúûûùýýûüüúýýûüüúýýûþþüüüúýýûüüúýýûüüúüüúýýûûûùþýõãÃrÜ¥ñ²õ»ò óÈìÅ»˜2$‘qêÆôÍúÓéØkÿýéúýýüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþýþþýþþüþþûþþüþþüþþüþþøþþóþþïþþíþþìþþíþþïÿýéìå¿Ç¥[¿†Ï•Ú£æ¬ î¶ò½ôÀ ó¾ ó¿ò¿ò¿ö¾ ø¾ òÀó½Ñ¡M6 UVUÔÔÒúúøüüúýýûþþüýýûýýûýýûýýûþþüýýûûûùüüüöööêêêííëúúøþþüûûùýýûüüúýýûýýûüüúþþüýýûþþüþþüþþüûûùýýûýýûþþüýýûüüúýýûýýûþþüýýûýýûüüúýýûýýûþþüýýûüüúýüôãÄpÚ£ î±ö¾ ñÂí¿ã¶®…1 `E ݵîÅ îÈ îËäÄ<íè¾üüúÿþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþùýÿøþþÿûÿþÿüýþý÷øÿþÿûöÿüêÏ¿˜ÕÁy°ˆ%¶†¶…±ƒ­€ °€¶‚ËЖ Úž ãª ê± òºó½ ô¾ õ¾ õ¾ ô¾ ô¾ õ¾ õ¾ òÀ ó½ð»´(  ??>ÃÃÁüûùüüøýþùýþúûýúýýûúúøüüúüüúýýûþþþýýýùùùøø÷úúøýýûýýûûûùþþüüüúþþüþþüûûùýýûüüúûûùüüúýýûüüúýýûýýûûûùþþüûûùüüúüüúþþüþþüþþüþþüýýûúúøüüüýýýüúôæÇwÙ¢î²ô¼ ñ¿ î¹ á­µ„B+ 1 º”îÀíÂî ðÀ äµ!ÛÏ—ýþÿÿýþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿøýÿùþÿùýÿûþûÿÿýúýþøçÝ·¯„!¾ŒÍ—ל Úœ ך Ó–Ë É Ï•ÖœÜ  ã¨ ê° òºô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò¾õ½ò¾ß¹ˆj###—–•ñðîýýûüýûýÿüþþüýýûþþüþþüüüúúúùûûûýýýýýüüüúýýûýýûÿÿýþþüýýûüüúýýûþþüþþüüüúþþüüüúýýûýýûþþüýýûþþüýýûþþüýýûýýûýýûüüúýýûýýûþþüýýûøøøîîîãàÚÛºi򣓡 ô»ï» ç±ݦ À‹eC   $šqÝ­ê¼ é» íº ô½ êµÞЖýþüÿýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþþýýÿÿüþþÿùýþöþüúÿùî­‰*Î Ú˜ Ý  á¨á¨ৠݣߤÞ¤ à¦å«é¯î³ó¹ô½ ô½ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ ÷¿÷½ ñÀðÇѨXC }{|éèçûûùþþüûûùüüúûûùüüúþþüýýûþþþýýýüüûüüúýýûüüúüüúûûùþþüýýûüüúýýûýýûüüúýýûþþüþþüýýûüüúûûùýýûûûùýýûýýûûûùýýûþþüýýûüüúþþüûûùáááÉÉÉÇľԳaØ ï²ñ·ì· å®Û¢Á‹ ˜m?'   +ŽcÏ™ ä± æ· ê·îµ ô· å¬ÝÍŽþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûÿÿýýÿÿüýÿþøüýúþýõÒÀ»ˆÓ™ Ü£ ã®ç´è´ê²ê°æ«æ«ì± ñ¶ñ· óº õ½ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ó½òÀ öÇè¿®‹$ ][\ÔÒÒüûùþþüýýûüüúýýûûûùüüúýýûûûùýýûüüúþþüþþüþþüýýûýýûüüúþþüýýûüüúüüúüüúüüúüüúûûùþþüþþüþþüýýûûûùþþüýýûûûùýýûýýûýýûüüúèèæËËÊÅÅůĽӰ_Ù¡ê¬ ï´é³ ä« Ú ÇŽ¯| Že;"   [: Ÿoȑء â¯é· ì· ó¸ ö¹ç°ßΔýþÿýÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûüÿõþÿüÿþûÿþøüþÿþþö¾¢^ÈŠÙ  æ¯ì´ ð¶ ó· óµ ô·ò¶ñ· ôº õ»ö¼õ½õ½õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ¼ò½ ôÀïÇرu]  423µ´³ùù÷ûûùýýûýýûþþüüüúýýûþþüûûùþþüúúøýýûûûùûûùýýûýýûýýûüüúýýûüüúýýûûûùþþüýýûûûùýýûüüúþþüþþüûûùþþüýýûýýûýýûýýûûûùÚÚØÄÄÃÄÄÄÇľѯaÚ¡é¬ ë° è±äª Ý¢Ε»…®{ŸrtP K18%.+5"N3wVœr°|Š Ö Þ©ä°í¶ ó» õ¹ô» ë¹êÙ—ýüúüþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿôþÿúþþÿÿýùüÿûþýòÅ¥VÌÝ¡è­ð² ö¶ øº÷» ó½ ñ¾ ô¼ ö½ õ¾ õ¾ õ½õ½õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ó¾ó» ó¾òÄ éľ™:(‘‘‘òòòûûúüüúýýûýýûüüúýýûÿÿýþþüþþüþþüþþüþþüüüúüüúûûùüüúýýûþþüýýûþþüûûùÿÿýþþüýýûýýûýýûþþüûûùüüúüüúþþüüüúüüúùù÷××ÕÄÄÃÄÄÄÈſЮdÓšã§ è¯ é³å¬ á¥ÔšÅŽ ¾„ »} µz ªx  vŸv¢w¥x ©z¬| ·‚ÆŒ Ô˜ âªè³ ï¹ õº ôº õ»ó¼ð¾Õ¶AÿüÙÿüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþýþÿûÿûÿýûüþÿÿÿì«…(Ê’Þ¤ê° ñ· ôº õ½ ô¾ ò¿ òÀõ¾ õ¾ ô½ ó¾ ó¾ õ¾ õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ õ½ô» ó»ô¾ ðÈ์j|||ïïïýýüüüúýýûýýûüüúýýûûûùýýûýýûýýûýýûýýûþþüþþüþþüýýûüüúûûùþþüûûùýýûþþüüüúýýûýýûûûùþþüþþüýýûüüúüüúüüú÷÷õ××ÕÅÅÅÄÄÄÆÃ¾Ë¨bјá¥ ç¯ ç³ç® ä©ÙŸ Ï—ÉŽƆ Å… Á„ ¼€¼ ¾ Á‚ Æ Ä襅 â¦í±ñ¸óº ÷º ô¼ó½ô¾ó¸æ¶ØÁbÿýåþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýýýþþúÿùÿþüüþúýüñÀ [đݣ ç­ìµ ò» õ½ö¼ø½ø¼ö¾ õ¾ ò½ ó¾ ó¿ õ¾ ö½ ö½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ ö½ õ½ ÷» ô¼ôÄëÈ΢L7 †††ôôóþþüýýûýýûþþüÿÿýþþüýýüýýûýýûûûùýýûüüúüüúüüúþþüþþüþþüûûùþþüýýûþþüýýûüüúþþüþþüüüúûûùúúøýýûýýûýýûööõ××ÕÅÅÅÃÃÃÅýƤ`ÈÜ å­ ç³ è¯ æ«ݤ Ø› Ò• Í“ÇÈ‘ÉÇŒ ÆŒ É Ë‘ Ô• Üžá©é´ ó½ø½ø½ø»ô¾ó¿ ô¾ö¶ ô´Ü®åÚ•þþõþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþüÿþüÿýÿýüýýüþþøÕÁ‰ÂŒÙŸ æ¬ í´ ñ¹ õ½õ½õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ õ¼ ó¼ ñ¿ òÆç»§$°°°úúøþþüûûùüüúüüúýýûûûùüüúýýûüüúýýüýýûüüúüüúýýûûûùþþüþþüüüúýýûûûùýýûüüúûûùüüúýýûþþüþþüþÿûþþûýûüùøúÜÛÜÆÆÅÅÅÃÅüÀ¡]‹Õš á¨ ç° ê° ì¯ â¨Þ¤ ØÔšÓš Ñ—Ï–Ï— ЗÓ˜ØœÜ¡ã¨ ç® ï¸ õ½ ô½ õ½ õ½ô¾ õ¾ õ¾ ô» ò¸ìµÑ®-ðê±ýþ÷úýþþýþÿüÿüÿýûÿûüÿúþÿúþþûûÿýúÿýÿýýÿûüýþûüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýüüÿüýÿüÿþúþýûýý÷ÖÃŽÁŒÙž ã¨ ë² ñ¹ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ô½ ñ¾ ñ òÅÖ­uU [[[ííëúúøþþüþþüþþüýýûüüúüüúþþüýýûüüúþþüüüúûûùýýûüüúüüúýýûýýûýýûýýûÿÿýþþüýýûþþüýýûûûùýýûüýùûüùýýüûûûåååÊÊÉÄÄÂÆÃ¾½Ÿ[»…Ó˜ à¦ å® ì± î² è¯ ä« á¦ Þ£ Û¡ Ú¡ ÙŸ Ú  Ù  Ü¢ ߤåª ç® íµ ó»õ½ ô½ õ¾ õ½õ¾ õ¾ õ¾ ó¼ ñ¹ ñ¹ï³Í¡.ëã±ûþøúÿúÿýüÿúÿþþúûÿùÿýÿÿýýýÿøûÿøþþþÿýüüÿùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýúüÿúýÿúÿÿ÷þþúþýöÖÆ–¼ˆÕš ᦠë±ñ¸ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò½ ô½ õ¾ ö½ õ½ ò½ ð¿ óÄé¿Ú>-***ááßýýûüüúüüúýýûþþüýýûþþüüüúûûùýýûûûùþþüþþüýýûþþüýýûýýûüüúþþüýýûýýûûûùýýûýýûýýûýýûþþüýýûþþüüýúûûùììêÒÑÏÄÃÃÈÿº›W»…ДÞ£å­ î´ ñµ í´ ê² ç® ã©⨠㨠à¦à¦ã¨ ã© å« ç­ ì³ ï¶ ó»ô½ õ¾ õ¾õ½õ¾ õ¾ õ¾ õ¾ ô¼ òº ñ¶î®Ï+ñè·øÿïüÿöÿüýþþûüÿøþþüÿûÿÿýúþÿ÷ýþÿþþüýÿúýÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýúýÿúþÿüþÿøþþúÿþùèß¹¾‹Õ™ Þ¢ è® ð· ô¼ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ó¾ õ¾ õ¾ õ¾ ó½ ò½ ôÀõÇÞ¶˜v !!!××Öüüúýýûþþüüüúüüúûûùþþüþþüÿÿýþþüþþüüüúüüúüüúùù÷ýýûþþüüüúüüúþþüýýûüüúûûùýýûþþüýýûýýûüüûýýûýþùýýøîïêÖÖÓÆÅÄŸš”‡f#¸‚Ò– Þ£å® í³ ò· ð¸ ð· î´ ë° è­æ«å«å¬äªè¯é°ì´ î¶ òº ô¼õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô¾ ï¹í¹ë¸Ù¬,òè³üþóùÿúüÿüûÿøüÿôÿüýÿûÿþþýüþÿýÿüþþýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿýÿùþþþÿýüÿý⼋Ñ• Þ¢é¯î¶ ó»õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ò½ õ¾ õ¾ õ¾ õ¾ ô½ ô¾ ïÁîÅÑ¥bI )))ßßÝþþüýýûýýûþþüýýûþþüûûùýýûýýûüüúýýûþþüþþüýýûþþüüüúýýûþþüüüúüüúþþüýýûþþüûûùüüúýýûüüúüüüþþüýþøüü÷íîêÖÔÔ¹¶´IB:sS·Д Þ£ä¬ ïµ õº òº òºò¸ð¶ ïµ í³ í³ í³ í³ íµ ï· ï· òº òº ô¼ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ î¼ î¾ î¹ä°"ؼkþþßýý÷üüÿúÿúúýúýýÿüþþüÿýýÿûÿýûÿýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿûÿúÿþÿÿýÿÿýíºŠ!Д Ü ç¬ñ¸ó» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¼ õ¾ ô½ õ¾ ô¿ ëÁ óÅ íÀ¿˜8, ƒƒƒ÷÷õýýûýýûüüúýýûüüúüüúýýûýýûüüúüüúüüúýýûûûùûûùüüúþþüüüúüüúûûùýýûýýûüüúýýûýýûýýûüüúüüúýýýüýûûý÷üþùðñðÂÀÁLHDyYº„Ò– Þ¤ å® î´ ô¸ òº ó¼ô¼ó»òºó¹ó¹ó¹ó¹ò¹ ô¼ ó¼ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ô½ õ¾÷¼ öºñºÔ«,ÚÉŒÿüïýüýúþúøþ÷ýÿúýÿúþÿùÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþúýÿýÿýÿúÿ÷þþýÿýþÿþñº‹#Î’ Ûž è®ï¶ ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ö½ ó¼ õ¾ õ¾ ó¼ õ¿ îÂò òÇáµ Žq  ˆˆˆóóóþþüüüúüüúüüúýýûüüúýýûýýûýýûýýûýýûüüúýýûýýûþþüýýûýýûúúøþþüýýûþþüþþüþþüþþüüüúüüúýýûýýûýýüýýûýÿùúüúÈÈÌD@D xX ¸‚ Ò– Ý¢ ä­ ðµ ô¹ òº ô½õ½õ½ õ½ õ½ ö½ ö½ ö½ õ½ ö¿ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½õ¾ ø½÷½ ÷¼ú¼õº ð½æµ ǤCÿûâüýûûÿöþþûÿýüþÿúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿþùþÿûÿýÿúÿ÷þþýÿüûþþò½$Î’ Úž å« ð· ô¼ ô¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ õ¼ ö½ ö½ õ¾ ö¿ ö¿ ô½ ò¿ î¾ôÄðÉϤgH 4,VWR›œ›çççþþþûûüüýûûûùýýüýþûþþüýýûüüúüüúüüúüüúüüúýýûûûùüüúüüúûûùýýûýýûüüúüüúýýûüüúüüúýýûûûùüüúýýûüüúüüúúúøüýùÊËÊ337#~\¶ Ó— Þ¤ ç¯ ð¶ ô¹ ô¼ó¾ ó¿ ó¿ ô¾ õ¾ ö¾ ö¾ ö¾ ö¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½õ½ò¾ôÀ ö¾õ½ òÀ óÀ ÷½õ¸â²æÖ–þüýûþúÿýýÿüÿþþþûþÿýþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþûÿýþûÿýýÿûÿûþÿû÷ýý弌Α Ú æª ò¸óº õ¼ ô¼ô¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ò»ë½êÉ å¿ ¿Ž¬‹Wöôéùýùûýùûûýþüÿþýùþþúúúûûý÷üþùþþüþþüþþüþþüýýûþþüþþüþþüþþüÿÿýþþüûûùþþüþþüûûùýýùüýøýþùþþúýýûýýûýýûýýûýþûø÷ø¯¯­###0†] ¶‚ Ñ™ ߥè® îµ ó» ô» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ð¿ñ¿ ù½ú»õ½ñ¿ ñ¼õ·ê¬ìÕ”üýúüþøþþûþýýÿýýûÿüüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúÿþüüÿüþÿûÿüþþýùçâ¹¾‹Α Úž è­ ó¹ô» ô» õ½ó»õ½ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ¼ ï½ èÁ èÀÚ© yƹ˜üüøûüûüüúüüùüü÷þýúþþþýþûüüùüüúûûùüüúüüúúúøýýûüüúüüúýýûýýûýýûþþüüüúýýûÿÿýþþúýþùýþùüüúüüúûûùüüúüüúóôòƒ„:&‰_ ¶‚ Ñš à¦é® ï¶ ó¼ õ¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ ö½÷½ ö¾ô½ õºó¸ó¹è³ܪç×”üüúþýÿýýþþþýÿþýýþþýþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþÿúþþþûþøÕ„¾‡Ï‘ÛŸ è­ ñ· ô» ô» õ½õ½õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó»ö» õ½ê½ìÂç¹ Èž•w/èÞÒüùûüý÷ýÿôýþùýüýýýýûüüúûùüüúýýûûûùþþüþþüýýûýýûýýûþþüýýûüüúýýûüüúüüúüüúüüúüüúýýûÿÿýüüúýýûýýûáááXYY  D/‰^ ³ Й â§ ê¯ ï¶ ô¼ õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ½õ½õ¾ õ¾ õ¾ ø½÷¾ó¿ ó½ô¹íµ è² ä§ Ò¥-ïê»ýÿýþüÿþþýüÿýþþýþþýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþýÿùÿýüÿþýúýüýþòŤPÀ… ÍÜ¡ é® ó¹ ô» õ¼ ó¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ½ö» ÷» î¼è¾ íà ٬­ƒ˜ƒY÷òîýüûùýóûýøýüþûûûýÿýýýûýýûþþüûûùüüúüüúüüúþþüüüúüüúüüúýýûþþüþþüýýûþþüþþüýýûüüúþþüþþýöööŸŸŸ$$$ J3‡\°|Ϙã¨ ë° ï¶ ó» ô¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ õ¾ó¾îºìµåª Ý¡ Õ—äËŽþýóüÿüþûüþþøûÿûýÿüÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýþÿýÿúÿýþþþÿýþùÿý߸„ Æ Ó–å«ñ¶óº õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ ö¿ õ¾ ó½ ñÀ ó¼ ÷»ï¼æ½è¿ á±Ä‘ ƒe¬›ƒýøùûþûüþúþýþýýþûüøüüùýýûýýûýýûþþüüüúýýûûûùüüúýýûþþüýýûüüúúúøüüúüüúüüúýýûýýüööö¹¹¹BBBQ9‰\±}Ϙã© ë° ð· ó» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ õ¾ ó»öºó·íµâ¦Û™Í” É«mÿúòþýÿýÿüÿýýþþøúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýþÿþþûÿýþþýÿþýïÑÁ„¼ ÉŒ Û  ì²ó¹óº ô» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ ñ¿ ó¾ ô¼ ðºä¶å¹߯ Ë–  xZ>£—’óôõûþûûúûýýýûý÷ýþúüüúýýûüüúýýûýýûüüúþþüþþüýýûýýûþþüüüúüüúüüúýýûýýüûûûËËËSSS W<ˆ[±| Ζâ§ ê¯ ñ¸ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó» óºñ·ïµé®㢠֖Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿüÿþúÿþûýþÿÿý毄(Ɖ Ò— ⨠ñ¸ó¹ óº õ¼ ö¼ö¾õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ô½ õ¼ óºè´â±ܪ Ó›°} wR.\ZWÎÏÎüûøúúùùüøúüùþþüüüúüüúüüúýýûüüúüüúüüúýýûýýûüüúüüúýýûüüúééç­­­SSS Y=Š\²} Ï– á¦ ê¯ ð· ó¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ô¼ð·ì³è­Û¢ ҞŒʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûýÿùÿþùþÿùüÿýäÞ»»†Ç‹Øž â¨ ë² ôº óº ô» õ»ô¼ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¼ ö¼õº÷»ð· â¬Ü¥ Ò™ ¹ bN: SRO¡¡ ÒÔÔìíìøøöûûùýýûûûùûûùüüúüüúùù÷ùù÷ññïßßݼ¼º‰‰‡PPN#\=Ž`´ Ζá¦ é¯ ð· ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ó» óº ô¼ ô½ò¼ ï¸ é± Þ¥ÙŸ љȒ³‡,îâ¿ýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþþúþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúÿúÿþýÿþûÿýúÏÂŒ¼ˆÍŠÕšâ¤ è¬ ïµ ò¹ òº óºôºô¹öº÷¼ ö½ ó¼ ô¼ ö½ ÷½ ÷½ ô½ ó¿ ó¿ õ¾ õ¾ õ¾ õ¾ ö½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ö¿ ô½ õ½ ö½óº ð¸ æ®Ý¥ Óš ¼ƒ˜f iG ' *))GGGaaawww‚‚‚wwwfffXXXPPPEEE$$$ 2!eB–e·€ Ì• ݤ è° ñ· ô» ô¼ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ö½ ø½ ø½ ö½õ¼ôºóµõ¶ó¸î¸è´ á¬ÕžË”¾‰¿¦_èä½ÿüçÿýùýýþþÿûþþûÿýþþþÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿûÿÿþóÿþñÓÄ·…ʆÏ“ ןߨç° é° îµï¶ñ¸ ò¸ ò¶ ò¸ ó» ô¼ô¼ó»ö½ö½ õ½õ½õ¾ õ¾ õ¾ ö½ õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½ö¾ö¾ õ½ö½ôºï¶ è® Û¢ ј »i rL <&  ;( kH™g·€ Ê’ Û£ ç­î´ ö¼õ½ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ö½ õ½ ó½ ï¹ î¶î³ï²ê¯㬠ڢ Д»‚º˜QçÞºÿüçÿýïþýùüüþþÿþþÿúþÿúÿýýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿúÿüÿÿüþÿýöÑ“³džÊ‹Ñ•כݡ ã¦ ã¨ ä« ã®å±è¯ ê¯ ë³ îµ î¸î¸ò¹òºôºôºôºô»õ¼ö½÷½ö¼õ¾ õ¾ õ¾ õ¾ õ¾ ö¾õ½õ½ö½ ÷¾ö½ó¹í³ äª Ú  Ε ¶}šfuLM4   ?) oJ™g¶ ÇŽ ÙŸ åª ï´ óºõ¼ö½ö½ö½ö½ö½ö½ö½ö½ö½ô½ ô»ñ¸ëµ ç±ä¬㩠ঠÙÑ’ À†œs'æÛ¼þýøþþûþý÷ÿüúþýÿüüþüþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûúÿõûþÿýÿøþÿõçÞ½§}&¹}¾‚ ¾† Ä‹ Ì Õ• Ú™ Ûœ ÛŸ ܡޡ à¤ â¦ ã© åª è®ê°î´ñ¶ó¶ô·ó¸ôºò¸ óº ö½õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô½ ô¼ õ½ õ¼ ôºó¹é° ߦ Óš Æ‹ ¯w–bzPY< %B, nH–c²{ ‰ Ô™ ߤë® ò·ó¹ ô» õ¼ ö½ö½ õ¼ ô» óº ò¹ ò¹ ñ·îµé¯ä© ⥠ܟ ך ΔŠ ©{!˸‰þüîüýùúýùûÿüüýýýýþýýÿûüýýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüþþýþÿüÿùþÿùÿûöèÚ¶y% x «z °z·~¹~¿ Â… ĉ ÉŽ Í Ó• Õ—Õ˜ךÜŸ Ý¡ à¥ ä© æ« è­ ê¯ î´ ñ¸òºòº ó» ö¾ó¼ ô½ ô½ õ¾ ô½ ô½ óº õ¼ ó¹ ïµ㪠؞ ɹ€¦p’_zP[> ' @* iD^¬t ¼ƒ Γ Ü  å© î³ñ·ò¹ óº ô» ô» ô» ò¹ ôºó¹ñ¶ë±æ¬ á¥ÞžØ” Ó‘Ç µ‚¶›Tãܺýýôþýúÿþ÷ýÿöúÿùüÿüýÿýýÿüýÿúýÿøþÿùþÿûÿýþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýÿüÿÿüþÿÿóþÿöþýýÿûôÿûéáٸQi—oŸr¦t®w ´z ¸} ½ À„ÈćÆŠ ÈÌ‘ јÕ› ÙŸ Ý£ ߥ ã¨ ç­ ì²ñ·ò·ó¹óº ôº óº ò¹ ôºóº ò¸ï´ç­ Û¢ Δ¾…¬t›e‹[sKV:%=( b@ˆW¥n ³{ ÄŠ Ô™ Ý  æª ë° ïµ ñ· ò¸ óº ó¹ ò¸ ñ¶ë± è­ ã¨Þ¤Ùš Ðƈ·ƒ ©(ɹŒÿüèÿÿòøþøùÿýþýþÿüýÿýüþÿúþÿúþÿùþÿøþÿùþÿúþþýþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýüÿýûÿüÿÿýÿûüùüþýüþûýüúýýöþþòþþëâÙ¼Á¯‚ªŽKe šk¢n ¨s®w ®v³y ³y ¶{ ¸~ º½„Áˆ Æ Ë‘ Ò— Øž Ü£⦠è«ë¯ï´ó¹ñ¶ó¸ò¸ï´ì±ç¬Ý£ј Ä‹ ³{ ¡i’\QiEM7  8& [:€R›e«tºÊ Ö› ߤ äª è® ì³ ì³ ì³ î´ê°ç¬㨠ݡ ՚ϕ È‹º} ¨w–w$èß¼ÿû÷ýüûúþúùþýüþÿþþÿÿýþÿýþÿýýþþûþÿûþÿúþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûûÿøûÿ÷ýþþÿýÿýþøûþúüýþþüüÿýúýýúýýúþþüþýùÿüñÿýå¿´Žª‹I‡]Œ` —g ›h h¡k£l§o©q­t²y·}½‚ĉÌ’ Ò– Ùœ ÚžÞ¢â§ ç« è¬ é®åª ॠٜ Í’ˆ·~¦n”]†SuI^=B- ggg€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€$$& 3# V7|N–a¥o´{À…Ë‘ÖœÝ¢á§ á¨ ãª ä« ãª ß¥ ÛŸ Ö™Д È‹¼ ±yœj †`&äÚÆûýùùþüýýüýûüÿüýþýûþÿúýÿúûÿûýþþÿýÿÿýþÿýþÿýþþþÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþûþþüþþýþþüþþüþþüþþüþþýþþýþþüþþûþþùÿýôþýïÿý庮‰š…SvS„X ‹[ [‘]—bžg¢l§p«v²~º„ ¾ˆ Œȑ Í•Ó˜Ú Û› Õ— Ð’ ÈŠ ¾‚ ±x¢l‘]„TwJfAO5 + ghhåææýûüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþþýþþýþþýþþýþþýýþýþþýþüüãâ ‚‚|QD+N3qG\ h¬t¶|¾† ÇŒΓј Ò™ Óš њљ͔Ȇº³{ ¨q’e¨“hÿýðüþüýþÿþþýþþüþþüþþüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþûýûýþúýüöþþòÿýìÜÕÀ­ž…{PcGoP{W „Y ‹Z—ae¥lªq®u²y ¶} ¹€ ½ƒ ¿†½…¹±y§ošdZ€PvHiBW9?*  ,*(åæåüýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüýûýþûþýûýüýýýÿþþù¥‡G0e@S”a¤l­u³{ ¶~»‚Á…ćň Ĉ Á‡ »„ ³} ®x¨q™hƒ] ¦’hÿûïýüùüýûýþùþÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýüøþþúýþûüþüúþüüýúýþùþý÷þüôÿýñÛÕÀ« xQa@ pG€Q‹X[˜b œe  i £l £o ¡ožlj”aŽ\†V{NpEe=V9 F3…zgêçßýþüüþþþÿýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþýþýüýüùýýüüþþüýøÕÑÁ>,U7pI‡X˜d£l©r ªt ­v²yµz·{ ¶y ´w ®u¥p l“c wS Žfþþñýþûüûüýûþþÿùýÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüÿþüþýüýþýþýüúÿýùÿþùÿþùþýøÿÿúþüøÿüõÿû‰‡uQ`ApKzR ƒV‡WŠY‹ZŠYŠXˆU…S~NwKnH`?W9@/«¥‘ÿýôýýüûýþýþþýþúÿþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýüûÿþûýþûúýüüýúÿýõ¥ŽA. V9mG…V“`œfŸj¢l£p¢o§q¦m¥lŸi “a‡YoJ šˆlþûõøþùúþúýüþþûþýýüýþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûýÿüýÿýýÿþþþþþþþþþþÿýþÿüýÿýûþÿúüÿûüÿýýÿþþþüÿþ÷ÚÖÁ¦š|]H^A hEoFuIzK|KyHtDrG hCY<N6A- ª¤’ÿýöýýüüþÿûÿÿýÿýþÿúÿýúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþÿûýÿúýÿûþþüÿþúÿýö¢‰?/P4d?wL…WŽ^•b˜g –f”d”cŽ_‚X oK `A —ˆmÿüõþüýýþüýþýþþþÿþûþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿùþþøþÿøýÿùüÿùûÿùûÿùûÿúþýþÿýþýÿýüÿýüÿþüÿýýÿúþÿ÷þþ÷þýôÿýï­¢„rVP5Z: a> c>a<_;X8 P5 F2\N6ºµ¥þüõüüûþþÿüýÿýþþýÿûþÿúÿþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþöìêÛXK2G0 R6^>iEoHwLxMuKmHbCS;ƒv[ߨÌýüøûýùÿýýÿûÿÿýýþþüþþþÿþùþÿùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüþÿýþÿýýÿþûþþûþþûýÿúýÿøýÿøýÿùþþýþýÿþýÿÿþýÿþúþþüýýýýüûþþüýü÷ÿý𭣡–|M=>- >,^O6”ïìÜÿûõþýüýüüýüüýüýûûüþÿûþÿùþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûýÿýþþþÿþýÿþüþþüþþýýÿüþþúÿýöëèÛ›“}\N1?- F0I0 I0 E/ …vVž•}ÞÚÌþüøýýþúþýûþúüúúþüþÿþüüÿúüÿýÿþúþþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüÿýüÿýüÿýýÿþþþþÿýþÿýþÿýÿþþÿþþþÿþúÿþøÿþùÿþüþþþþþþÿüüýûúýþûúþúùÿúùþùûþùýþùþþ÷þý÷ÿýöÿüõÿþöþþ÷üþüûýþþýûÿýûþüüþýýÿþúþÿùþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþüýþþþþÿÿþýÿýûþþûýÿýúþûüýüüüüüüüþþûýü÷ÿþöÿüöÿýôþýóþþ÷ýýøþþûýýúþþûýþúüþüüþûýþùüþúüþýüÿ÷ýÿôÿýýþýÿþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþýþþýþþýþþýþþüþþûþþûþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþüþþüþþüþþüþþüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþüþþûþþûþþüþþüþþüþþüþþüþþûþþüþþüþþûþþüþþüþþûþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþülibimager-perl-1.004+dfsg.orig/testimg/bad_asc.pgm0000644000175000017500000000003012031434615021306 0ustar gregoagregoaP2 2 2 255 255 255 255 xlibimager-perl-1.004+dfsg.orig/testimg/bad1oflow.bmp0000644000175000017500000000021612031434615021611 0ustar gregoagregoaBMŽ>(Pë ë ŒR%9žU°€0`$Ð °—p*ðUð¯ðWð_ðð*ßðEÿð-ð[ÿð·ÿðoÿðlibimager-perl-1.004+dfsg.orig/testimg/winrgb4off.bmp0000644000175000017500000000055212031434615022005 0ustar gregoagregoaBMfz(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/pgm.pgm0000644000175000017500000000007412031434615020525 0ustar gregoagregoaP5 # CREATOR: The GIMP's PNM Filter Version 1.0 2 2 255 þýüûlibimager-perl-1.004+dfsg.orig/testimg/maxval.ppm0000644000175000017500000000002312031434615021235 0ustar gregoagregoaP6 3 1 63 ??? libimager-perl-1.004+dfsg.orig/testimg/tootall.ppm0000644000175000017500000000016112263740601021430 0ustar gregoagregoaP6 1 999999999999999999999999999999999999999999999999999999999999999999999999999999 65535 # we don't get this farlibimager-perl-1.004+dfsg.orig/testimg/newgimpgrad.ggr0000644000175000017500000000022212031434615022235 0ustar gregoagregoaGIMP Gradient Name: imager test gradient 1 0.000000 0.500000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 libimager-perl-1.004+dfsg.orig/testimg/badcomp1.bmp0000644000175000017500000000021612031434615021421 0ustar gregoagregoaBMŽ>(Pë ë ŒR%9žU°€0`$Ð °—p*ðUð¯ðWð_ðð*ßðEÿð-ð[ÿð·ÿðoÿðlibimager-perl-1.004+dfsg.orig/testimg/winrgb2.bmp0000755000175000017500000000021612031434615021310 0ustar gregoagregoaBMŽ>(Pë ë ŒR%9žU°€0`$Ð °—p*ðUð¯ðWð_ðð*ßðEÿð-ð[ÿð·ÿðoÿðlibimager-perl-1.004+dfsg.orig/testimg/comp8.bmp0000644000175000017500000001240212031434615020761 0ustar gregoagregoaBM6(––Ì  3f™Ìÿ333f3™3Ì3ÿ3f3fff™fÌfÿf™3™f™™™Ì™ÿ™Ì3ÌfÌ™ÌÌÌÿÌÿ3ÿfÿ™ÿÌÿÿÿ333f3™3Ì3ÿ333333f33™33Ì33ÿ33f33f3ff3™f3Ìf3ÿf3™33™3f™3™™3Ì™3ÿ™3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌ3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿ3f3fff™fÌfÿf3f33ff3f™3fÌ3fÿ3fff3fffff™ffÌffÿff™f3™ff™f™™fÌ™fÿ™fÌf3ÌffÌf™ÌfÌÌfÿÌfÿf3ÿffÿf™ÿfÌÿfÿÿf™3™f™™™Ì™ÿ™3™33™f3™™3™Ì3™ÿ3™f™3f™ff™™f™Ìf™ÿf™™™3™™f™™™™™Ì™™ÿ™™Ì™3Ì™fÌ™™Ì™ÌÌ™ÿÌ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿ™Ì3ÌfÌ™ÌÌÌÿÌ3Ì33Ìf3Ì™3ÌÌ3Ìÿ3ÌfÌ3fÌffÌ™fÌÌfÌÿfÌ™Ì3™Ìf™Ì™™ÌÌ™Ìÿ™ÌÌÌ3ÌÌfÌÌ™ÌÌÌÌÌÿÌÌÿÌ3ÿÌfÿÌ™ÿÌÌÿÌÿÿÌÿ3ÿfÿ™ÿÌÿÿÿ3ÿ33ÿf3ÿ™3ÿÌ3ÿÿ3ÿfÿ3fÿffÿ™fÿÌfÿÿfÿ™ÿ3™ÿf™ÿ™™ÿÌ™ÿÿ™ÿÌÿ3ÌÿfÌÿ™ÌÿÌÌÿÿÌÿÿÿ3ÿÿfÿÿ™ÿÿÌÿÿÿÿÿ––––––––––––––––––––––nm                       q  s ;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .1 ))))(/ -( L'L'L'L'--=.+(((K(Knm’m’m’m’nPU<<<B+ '((KKnn‘n‘‘´‘´‘´‘‘—–rxZZ<(Pë ë ŒR%9žU°€0`$Ð °—p*ðUð¯ðWð_ðð*ßðEÿð-ð[ÿð·ÿðlibimager-perl-1.004+dfsg.orig/testimg/bad4oflow.bmp0000755000175000017500000000054612031434615021625 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/short_asc.ppm0000644000175000017500000000005612031434615021740 0ustar gregoagregoaP3 2 2 255 255 255 255 255 255 255 255 255 255libimager-perl-1.004+dfsg.orig/testimg/bad24wid0.bmp0000644000175000017500000000234612031434615021421 0ustar gregoagregoaBMæ6(°ë ë µ)µ)µ)´* ²/¬3¦9£@B™D”I‘L#‹R'…X)\+|a0xe1sj3qk7ql9µ)µ)µ)´+ ®1ª6¥:¢@šC•G‘K"O&‰S(‚Z*|`.xd2th6pl7lp8kr9µ)´)³+ ±0 «6¦:¢?œC•I‘L"Q&‰T(ƒZ*}`.xd2th6pl8kr9ht;dx?´* ². ®1¬6¦:¢?œC”IŽO"ŒR&‰W(ƒZ*}`.xd2th6pl8jr:dx?bz@a|B²1­2ª6¦:¢?œC”IO"‰S&…W(ƒ[*}`.xd2th6pl8jr:dx?`|A[CZƒG¬7§8¥:¢?œC”IO"‰S&…W([*|`.xd2sh6pl8jr:dx?`|A[CW…GS‰I¤;¢?AšC”IO"‰S&…W([*|`.xd2sh6ml8jr:dx?`|B[CW…GQ‰ILŒJ@›C–G“JO"‰S&…Y)[*|`.xd2rh6ll8hr:cx?`|CZGW…HQ‰IKKH‘O™C•G‘K!O"‰S&…Z*_.|a/xd2rh6ll8hr:bx?\|CYGT…IP‹JJKD‘OC”Q”H‘K"O&‰S'…Z*`.|c0xe2rj6lm8hs:bx?[|CWGS…IOŒKI‘OC”P@•R@™S‘L"Q&‰T(„Z*`.{d1uh2qk6lp8ht:bz?[}CWGS…IOŒKI‘OC•Q?™S:œW9X‹S'‰W(ƒZ*}`.zd2th6pl7jr9du;a{?[€CW‚GR…IOŒKI‘OC•Q?™S9W3¢Y1¤Z…X)ƒ[*}`.xd2th6pl8jr:dx?`|@[CW„GQ†ILŒKI‘OC•Q?™S8žW2¤Z.¦\*ª`\*|`.xd2th6pl8jr:dx?`|A[CW…GQ‰IKŒKG‘OC•Q?™S8žW1¤[+ª`)­a'®b{a/xd2sh6pl8jr:dx?`|A[CW…GQ‰IJKC‘OA•Q?™S8žW1¤[+ª`(®b&²c"³dxe2rj6mm8js:dx?`|B[CW…GQ‰IJKC‘O?•Q:™S7žW1¤[*ª`'®b&²d"µh¶iql7lp8hs:cx?`|CZGW…HQ‰IJKC‘O?•Q:™S6žW0¤[*ª`&®b"´d ·h¼j½kjs:ht;bx?\|CYGT…IP‰JJKC‘O?•Q:™S6W1£Z*ª`&®b"µdºh¾kÃlÄpdy@by@\|CYGS…IO‰JIKC‘O?•R:™S6W2¢Y.§\(­a"³dºh¾lÃpÅqÆrc{Ba|C[GX„IR‰JJŒKD‘O@”R;™W8X3¢Y0¥[+«`'²c!¶h½kÃpÅrÆsÆslibimager-perl-1.004+dfsg.orig/testimg/bad4wid0.bmp0000755000175000017500000000054612031434615021342 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/junk.ppm0000644000175000017500000000000712031434615020716 0ustar gregoagregoaP1 100 libimager-perl-1.004+dfsg.orig/testimg/short8.bmp0000644000175000017500000000270512031434615021167 0ustar gregoagregoaBMÆ6(  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !  ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+000libimager-perl-1.004+dfsg.orig/testimg/bad8comp.bmp0000644000175000017500000000270612031434615021436 0ustar gregoagregoaBMÆ6(  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !  ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+0000libimager-perl-1.004+dfsg.orig/testimg/base.jpg0000644000175000017500000000116712031434615020655 0ustar gregoagregoaÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ùþŠ( ÿÙlibimager-perl-1.004+dfsg.orig/testimg/multiple.ppm0000644000175000017500000025520412031434615021615 0ustar gregoagregoaP1 # test image 2 2 1 0 0 1 P6 # CREATOR: The GIMP's PNM Filter Version 1.0 164 180 255 þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþúýþùýþùýþûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýýûüüúþþüþþüþþüþþüþþüýýûýýûýýûýýûþþüýýûþþüýýûüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýýýýþþþýýýššš€€€€€€€€€€€€%%%€€€   þþþýýýýýýýýýþþýþþüþþüþÿûþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþýýþ××ÙZZ\aabÝÝÞýýýþþýþþüþÿûþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþüýýûþþüþþüýýüþþþ˜˜˜!!"žžžþþüýýûýþúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûýýûýýûþþý×××YYY!!!žžœþþüýýûýýûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüýýüÖÖÖÛÛÚüüúþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþünnnzzyýýüþþýþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû¬¬¬]]`ÜÜÝþþÿþþÿýýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÔÔÒ 333CCC???---"ÚÚÜýýþüüüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý... %%%BBB___cccPPP222xxyýýþýýûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü««ª '''MMMoooyyydddCCC(((wwwýýüýþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýû---+++OOOqqqtttbbbGGG333!!ÙÙØþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüüüúªª¨---OOOggg]]]LLL888///%%%777ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû--,(((AAAFFF<<<---!!! ´´´þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÔÔÒ ***%%%668ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýýªª«  ³³´ýýûþþüýýûþþüþþüþþýþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûûû--.667ýýüüüúüüúþþüþþüþþýþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýý++-ØØØýýüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýý,,.³³³ýýüþþûþþüþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©556üüûýýûþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©    "! 555ýýûýýûþþúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©© ...++- >>@FFH556ýýýüüûþþúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©© !!"224335EEE;;; 444889²²²þþýþÿûþÿúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§224PPP<<<&&&224 RRQttr……„•••™™™”””\\\...±±²ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§ggh———³³³­­­yyy)))000iigƒƒ’’ŸŸŸªªª²²²¾¾¾¿¿¿qqq ²²³þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©§ \\\“““´´´ÇÇÆÃÃÁ­­«~~},,, (()lll““‘¦¦¤³³±¸¸·¿¿¿ÄÄÄÑÑÑÁÁÁ¢¢¢RRR ²²²ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©'''¥¥£ÁÁ¿ÒÒÐÑÑÏÊÊÈ­­¬yyy ]]]™™—ÇÇÅââàìììòòòôôôóóóíííØØØ®®®{{{%%%sstýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©OOO¬¬¬ÞÞÜôôòûûùüüúüüúûûûãããDDD((*§§¨ææäýýûþþýþþþíííÎÎÎçççýýýúúúñññ···YYY444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ©©© |||èèèõõõ¢¢¢qqo  žððîýýüüüü“““JJJÉÉÉööôýýûûûú¨¨¨$$& '''ŠŠŠôôôýýýùùù­­­444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ©©ª¯¯±÷÷ù ***===kkkññïýýûÉÉÈ VVWÓÓÓûûùüüúººº888zzzGGGzzzõõõýýýååå777444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«ÄÄÆìëí436:::xxw443›œšýýûÝÝÝ))) ``aÔÕÕûûúóóòIII SSS}}}///ÄÄÄþþþ÷ø÷_`^444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû¨¨¨ÄÇÇÄÃÇ YYUKLHTWVóöõààÝ331 ";;;HDC0,*`^bÒÔ×øüüÈÉË"!YWW/.0ŒŒŽúýýøýùˆ€444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÓÓÓ!ÆÃź¹µ+,*HDF.-.ääáÖÑË(#  '+,³³¶ôôô¶¶º    qnqûøüüøü–’—444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüü,,.À½¼ÉËÅ)+-"%)ØÙ׎ˆ{ &$wrðëæ¸·´   qslüû÷úùö”’444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýý**,«¬¬áäå.//#"²¨†€m%¥ŠáɢȜÍÖ—vrc#¾ÏÌ  –š˜ûýõ÷ùð‚ƒ444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-†ˆŒðñõ‹Š‡  eF ®‚Ëšêµì¸ æ¶ à´ ×¬ÅžÛÖ®#ɦ2йuQF./0/âåâýÿüëëëXVZ444ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-SSTåàäïîïSTV6!‰e±ƒ°|Ú£î¸î» é¼ á¹ Ó­´“ xÆœ è½ä» mV"%'#ÀÅÂúÿþøüýÅÈÊ"!%××Öþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-"!ÃÂÄøöùëæÚzg7šr¿‰ ÖŸç¯ ðµ ñ· ï¹ë½èÁåÀ äÀá¾çÈîÑêÊçÃã¿Í©xo^ Цþùõýûúëíç|z±±°ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,- twxâÝÐϹ‡¬ƒ½ˆÓ™ã­éµì¸ ë¹é¼ç¿ ëÇîÍîÒñÓ+ôÔ/÷Ö0öÕ.øÕ%öÑóÉ î¿ß°È¡*À¡KŰv¦—r*!±±°þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûýýý//02(£‡Vª}!¿† Жܤ ç° ëµ í¹ ì¼ ê¾ êÁ ìÇïÎðÓ ò×/ôØ>÷ÚDöÚ4õØöÕ öÐ ôÍòÇðÆë¿Ú°Á™{W±±±þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûüüü++- YC›xµ„ÊØ›â« ê´ ê´ ë· ì¼ ëÀ ìÆîÌðÑóÕ*õØ>÷ÚA÷Û=ôØ,öÙ÷Øù×øÛù×öÖ÷ÕöÑòÅ+Ö§)bL ±±²ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý,,. L2  u²€¿ˆÔ• â¡ä¯êµì¶ íºë¾ëÄ ìË ìÎïÒôÖ9øÙGùÚBöÙ*õÚõØõ×õ×õØøÙô×ëÎãÂôÇ+î»"“s rrsþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþýªª«…`¶x¿€ÉÛœ ç¦ç± ì¸ ë· í¼ìÂêÇêÍ íÐòÔ/÷ÚAøÙ@öØ-öØöÙ÷ÚôØôØ÷×öÏằ‡­‚Ùª à¯~_445ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«, ”o¸włіޡ è« é´ ë· íºê½ ëÄ êËìÏðÓ'òÓ<õØ7õØ%ó×öØ÷×ö×ôÖóÖìËÇ› µ„ÂŽ Ñ Ø¡ ÏœfL ØØØþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþüþþüþþüþþüþþýªªª( s´} ÈŒ Óœ ߦ ç®î¹ í¹ ì» ë¿ êÅìÌ îÑòÕ+÷Ø=õÖ*õØô×ö×÷Ø õÕôÑܵª„·Šʘӛܠ؛ќdK qqqþþýþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþþþüþþüþþüþþýªªª T>†_ ½ؤà¬ë´ ï·îº í½ ìà íÉíÍïÒóÖ#ô×&öÖ÷Öô×ñÓñÏêÄÄ— «yÁ‘К Õ› Ùœ Ú՚ĒL7 333þþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþþþüþþüþþüþþýªªªZ>S·…Ý®ë·ò·ï¼ îÁ îÅñÍïÏñÓóÖó×öÕõÔíÏ ãÄ¿˜Ÿo±| É’ Õ— ܘ Ýš Ú Î˜Ãc  SSUhhj'')±±°ýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« C)vM€U§ Û®ñ·ï¿îÇñÍóÐ'ôÔ%ñÔïÔïÑèÈÕ´¬‹Œe›m¼‡ Δ Õ™ ×› ÙŸÕÉ”¶ˆ­‰?yfC;;;yyyyyyQQQ**) qqqþþüýþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«("gƒh%~W‹\©{ Ç  Ô±Ù¸Û¼Ò±έœ¨|¡oi«v º‚ÉŒ Ò‘ Ò“ Ñ—З Å »Ž!Ä \ʱ”Ǻ°¸³®QQLccc€€€zzy442××Öýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«³µ«³¨ƒl&•h“i ˜o ¦~ ¥£}¢y§z°º…ÉćÊ Î’ΔÍ’ ÊŒȇ¸„»”M˵—Ê»ÄÃÀ¾½º¿¿¿”–™777}}}€€aa` !pppþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« \ZS¾¾¹¾·³®™ul˜i¢pÀ’Û²Û´׫ÒŸЖÒ•Ï– Ì“ Ê ÈŽÉÁ‹µƒ±…0¾¦~ƼªÅ¹ÊÌÉÈÍÊÂÇÀ½¾¹©§§! "]]]€€€~~}mmm445ÖÖÕþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþþjjl[XZ½¹º½»¾Áº³°—p–išd¬w ȓҞÔÒ˜ Ò”ÏÊŽÃŒ¿‡½~¾| ·´–Q½´™º»¶»½¸¹½¶ÃÆÁÐÑÏÒÑÑÈÆÅ¼º¹TSS;;;oopqqqBBB 000ýýüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýýýü,,. U[W¸º·»½¸»¼ºÂ·®¶šv‘g'“e ¥u¶¾„ À… Á… ½‚ ·y°p°o°w ²„/¼žmÆ»¦»½±¾¹·Á¼¾ÆÉÉÖÛØèèêõï÷õó÷ÛßÛŸ¡ž ,,.®®­þþüýýûüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüújjj OTK¹½¶Âÿ¿¿¸¿½´Áº³º¨Œ“{@ƒd‘hšhžih›i ˜e ˜e šn¬ŽK¿±‹Â½³»º»¿»¹Ã¿ÀÐÌÏçäç÷õûûüýûþøúý÷÷øø×ÖØOOO333þþüýýûüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÓÓÑ b[_ØÔÖÖÔÖÈÅÄÀ½º¼½¼¾¼ºÃ»¬µ¢ƒ ‚V”n4•l%“l"™t0¦„K±™m¼³˜À¿´¾»µ¾º±¾¼µÁÂÁÎÓÌâçáò÷÷ýþýÿýùÿüöþýùýþýö÷÷²²² ®®­þþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúüýøiig%$%ÏÎÏîííáááÌËÌ¿¾¾¼¼¼½¼½À½½Á½¹Â¼´¿¸­¾¶§½µ¤¾¶§Ã»²Ã½¶À¼¹½¼º¼»¹ÁÀ¾ÆÅÄÓÓÓãäáôõòþÿýýþüÿþüþþûþþüþþüýþûôôô[[[""#ÔÔÕýýüýþúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúüüú¨¨¦ŒŒŒúúúöööëëëÖÖÖÁÁÁ¾¾¾¿½¾¿¾¼¾½»¾½º½¼¸À¾¹Á¾ºÁ¾¸À¼¹¿»º¼º¹¿¾¼ÆÅÃÎÎÎÜÜÜçççòòðýýûýýûÿÿýþþüþþüþþüþþüþþüüüüÃÃÃrrsýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÒÒÐ DDEßßßýýýýýýùùùìììÑÑѽ½½¾½¼¾½»¾½»À¿»¿¾º¾½¹¾¼¸¾½¹À½»¿½»ÁÀ¾ÌËÉ××Õääâïïï÷÷÷üüûýýûþþüýýûþþüþþüþþüþþüþþüþþüõõônnnÔÔÒþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýþþþ+++ µµ´÷÷õýýûþþüýýûúúøååãÄľ½º¾½¹¾½»¾¾»¾½¼¾¾»¾¾»¾½»¾½»ÃÂÀÐÏÍàßÝìëéööôûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûûúÎÎÎ&&&---þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüýýýggg nnnïïíýýûþþüþþüþþüýýûóóñÖÖÔÀ¿½¾½»¾½»¿¾¼¾½»¾½»¾¼¼¾¼½ÈÆÅÛÚØèçåóóñúúøûûùüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûøøøkkkªªªþþþýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûýýû¥¥¦))'ÑÑÏýýûýýûþþüþþüþþüþþüûûùììê×ÖÔÆÅÃÂÁ¿½¼º¾½½½½½ÂÂÂÐÐÐâââñññùùøûûùþþüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýÁÁÁÓÓÔýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûÐÐÎ ŒŒŠö÷óþþüÿÿýþþüþþüþþüþþüÿÿýüüúù÷÷íëìÝÛÜÕÕÕ×××ÜÜÜççåòòðùùøþþþýýýýýûþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüôôóJJJkklþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÑÑÏ888ääãýýùþþûþþüþþüþþüþþüþþüþþüþþüÿýþýüýòðñëêëðððøøøûûùûýúýþýþþþýýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüýýýŒŒŒkkjþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýþùüüúýýýeefœœ›ûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúúøööôýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþÿüþþüþþüýýü¼¼¼jjjýýüüüúþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûþþüddd>>>ÛÛÚøøöüüúýýûþþüþþüþþüþþüþþüþþüþþüýýûýýûúúøüüúþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüûûúâââ++-ÓÓÒþþüýýûÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþüþþüýýû¢¢¡ ‰‰‰ççåøøöüüúþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüüüúûûùþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýþþüüüúùùùîîîMMMÑÑÐüüúýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýýûÏÏÏ---²²²æææõõóýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüùù÷ûûùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúùù÷÷÷õñññóó󇇇ÒÒÒüüüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûÏÏÏ???´´´ßßßôôôûûûþþýþþüþþüþþüýýûýýûýýûýýûþþüýýûûûùôôòööôûûùýýûþþüþþüýýûþþüþþüþþüþþüýýûýýûþþüþþüþþüþþüüüúýýûüüúúúøøøöððîêêèììëìììììì°°°ÒÒÒþþþýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû###XXX©©©ÍÍÍìììøøøùùùüüüþþþþþþþþþýýýüüüúúú÷÷÷òòòñññêêêèèèðððöööùùùúúùüüúýýûûûùüüúúúøýýûýýûûûûûûûúúúùùùøøøøøøòòòïïïééçããâÛÛÛÛÛÛÞÞÞää䯯Æ (((üüüþþýþþüþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüaa_ ttt¢¢¢¶¶¶ÐÐÐçççðððñññöööúúúùùùùùùøøøòòòéééâââßßßäääàààßßßåååïïïööõùù÷øøö÷÷õùù÷ùù÷øøöóóñéééåååáááÝÝÝÛÛÛØØØÖÖÖÓÓÓÑÑÑÐÐÐÈÈÈÈÈÈÊÊÊØØØÜÜÜNNN fffüüûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÎÎÌ………žžž¨¨¨ºººÌÌÌÜÜÜäääîîî÷÷÷úúúùùùúúúùùù÷÷÷íííßßßÞÞÞåååïïïñññøøøýýûýýûüüúýýûýýûúúøøøöóóñææåÚÚÚÒÒÒÉÉÉÅÅÅÄÄÄÂÂÂÂÂÂÀÀÀÁÁÁÀÀÀÂÂÂÂÂÂÉÉÉÝÝÛÊÊÉ001££¢þþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüþþþýýýaab&&&ŽŽŽ¡¡¡¯¯¯ÃÃÃÒÒÒààßééçóóñûûùýýûþþüýýûþþüýýýöööåååæææ÷÷÷ýýýþþþþþþþþüýýûþþüþþüýýûþþüþþüýýûööõíííæææÛÛÛÒÒÒÌÌÌÉÉÉÅÅÅÄÄÄÂÂÂÀÀÀÁÁÁÀÀÀÀÀÀÊÊÊåååÇÇÆ""!$$&556%%%ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúýýûþþüýýýÎÎÎ---˜˜˜¶¶¶ÉÉÉßßßííí÷÷öýýûýýûüüúýýûüüúþþüýýûþþþöööèèèôôôýýýþþþþþþþþþÿÿýýýûüüúýýûþþüþþüüüúýýûûûúüüüüüü÷÷÷ôôôìììäääÚÚÚÒÒÒÊÊÊÅÅÅÁÁÁÀÀÀÀÀÀÃÃÃÕÕÕðð¡  ::;@@@""" ££¢üüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüþþþ___aaa¸¸¸ÓÓÓæææööôüüúþþüþþüýýûýýûüüúýýûûûùýýûýýý÷÷÷ëëëõõõüüüýýýûûûûûûüüúûûùýýûûûùüüúüüúþþüýýûþþýþþþþþþúúúýýýýýýüüüúúúñññçççÜÜÜÐÐÐÇÇÇÃÃÃÁÁÁÉÉÉààÞððïlll 222444$$$üüüýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüýýûýýý"""  222¬¬¬ÔÔÔëëëøøöüüúûûùûûùýýûûûùýýûþþüüüúýýûýýûýýûúúøõõóøøöýýûþþüþþüþþüþþüþþüýýûüüúþþüýýûýýûüüúüüúûûùûûùþþüüüúýýûüüúýýûþþýýýý÷÷÷ìììÝÝÝÑÑÑÆÆÆÃÃÃÍÍÍëëëÝÝÝ)))%%%@@@ÏÏÏþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüÍÍÍ668†††ØØØíííúúøþþüýýûþþüûûùþþüýýûúúøýýûþþüýýûýýûüüúüüúûûùýýûûûùúúøýýûýýûûûùüüúüüúýýûüüúûûùýýûüüúûûùýýûüüúýýûþþüþþüýýûûûùþþýýýýþþþüüü÷÷÷èèèÙÙÙÈÈÈÃÃÃÔÔÔôôô”””@@@ccdüüûýýûýýûþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüüüúžžž ??A:::ÑÑÑòòòúúùýýûûûùüüúýýûþþüûûùýýûýýûüüúüüúþþüþþüþþüüüúüüúþþüþþüþþüþþüýýûÿÿýþþüýýûþþüþþüýýûþþüþþüþþüûûùüüúýýûûûùüüúþþüýýûýýûýýûüüúýýûüüúúúøííëÛÛÙÊÊÉÇÇÇáááããã000444ÏÏÎýýûþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüýýû]]] "99;””•ùùùüüûýýûþþüýýûýýûûûùýýûüüúýýûûûùýýûýýûýýûúúøýýûþþüýýûüüúûûùüüúüüúûûùüüúüüúüüúüüúüüúüüúüüúüüúþþüýýûþþüýýûþþüýýûüüúýýûüüúûûùýýûüüúþþüþþüýýûððîÜÜÝÉÉÉÍÍÍïïî ***(((¡¡ üüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúýþûüüú 668668ãããüüüþþüýýûûûùüüúýýûýýûþþüýýûüüúýýûýýûýýûþþüþþüýýûýýûûûùþþüýýûþþüüüúþþüþþüýýûýýûþþüýýûþþüþþüýýûüüúüüúüüúûûùýýûüüúþþüüüúýýûþþüþþüýýûýýûûûùþþüýýûðððÙÙÚËËËÚÚØááá*** !! 888$$$þþüüüúüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûžž777«««ýýüþþüüüúýýûýýûûûùýýûýýûüüúþþüþþüüüúüüúüüúýýûüüúýýûþþüýýûûûùýýûýýûþþüýýûýýûýýûýýûüüúýýûüüúûûùþþüþþüþþüþþüþþüþþüýýûýýûþþüþþüýýûüüúþþüþþüþþüüüúýýûýýûóóñââàÞÞÛññîqqo...<<<000777ÏÏÏýýüüüúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû]]] FFFDDDëëéþþüþþüüüúýýûþþüþþüþþüüüúþþüûûùüüúüüúÿÿýþþüþþüüüúýýûûûùýýûýýûüüúüüúýýûúúøþþüþþüýýûþþüüüúýýûýýûüüúýýûýýûûûùüüúüüúûûùþþüúúøýýûþþüüüúüüúýýûüüúýýûûûùüüúþþüûûùúúöýýû»»¹ 777FFF;;;### 111$$$bbbüüûýýûýýùþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü ==<¨¨¨ûûúýýûýýûüüúýýûûûùýýûüüúüüúþþüýýûþþüýýûûûùüüúüüúýýûûûùüüúûûùýýûüüúþþüþþüþþüúúøýýûûûùþþüþþüþþüþþüüüúþþüüüúýýûúúøþþüüüúýýûýýûýýûþþüüüúüüúüüúþþüþþüþþüüüúýýûýýûþÿûþþûççå000"""999@@@000@@@ ""#þþýüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüœ;;;HHHîîìýýûûûùþþüûûùþþüýýûýýûýýûýýûüüúüüúýýûúúøþþüþþüýýûüüúùù÷øøöýýûûûùýýûüüúüüúþþüþþüþþüþþüûûùýýûüüúþþüýýûýýûþþüýýûþþüüüúþþüýýûüüúüüúýýûþþüüüúüüúûûùüüúüüúýýûüüúûûùýýùüüùùù÷__^%%%### ???(((   ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúþþûþþüýýý^^^<<<¢¢¢ýýûýýûüüúýýûþþüûûùüüúýýûþþüýýûýýûÿÿýýýûþþüüüúüüúûûùööôëëéùù÷ýýûþþüûûùüüúûûùýýûýýûûûùþþüþþüþþüüüúýýûûûùüüúýýûüüúýýûþþüüüúýýûþþüûûùüüúþþüýýûþþüýýûþþüüüúüüúþþüþþüýþúüýúüüú––•  BBBaabþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþùýýûþþüÍÍÌ666###000äääûûùýþúþþüüüúýýûþþüûûùýýûýýûþþüüüúýýûüüúüüúýýûýýûüüúòòðççåóóñýýûýýûýýûüüúÿÿýþþüýýûýýûûûùýýûýýûþþüþþüþþüýýûþþüþþüüüúþþüýýûýýûüüúþþüýýûýýûûûùüüúüüúüüúýýûþþüûûùýýûþþûýýúþþüÇÇÆ  === ""$ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüýøþÿúýýûœœ› AAA „„„úúúþþüýýùþþüþþüüüúþþüýýûýýûýýûüüúüüúüüúýýûüüúýýûýýûüüúïïíååãùù÷þþüüüúþþüýýûýýûýýûþþüüüúýýûûûùýýûýýûýýûýýûûûùýýûüüúþþüûûùýýûýýûýýûûûùýýûûûùþþüýýûþþüýýûüüúûûùþþüýýûýýùüýúýýûååä)));;;žžŸýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúýýúþþü"""000'')ÓÓÓüüüüüúúûöýýûûûùþþüûûùýýûýýûýýûþþüýýûûûùýýûþþüüüúýýûúúøììêééçùù÷þþüýýûüüúýýûüüúüüúüüúþþüþþüýýûûûùþþüýýûÿÿýþþüþþüýýûûûùþþüþþüûûùþþüþþüþþüþþüûûùýýûüüúþþüþþüþþüýýûþþüýýúüýúüüúòòòDDD666***ŸŸ þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýüýýý›››AAC ``_ööôþþüþþüþþüüüúþþüûûùþþüüüúüüúýýûüüúüüúýýûýýûüüúþþüýýûûûùééçííìúúúûûûýýüþþüþþüþþüþþüüüúüüúüüúýýûþþüüüúýýûûûùýýûûûùýýûýýûüüúþþüýýûüüúýýûüüúþþüþþüþþüüüúúúøýýûýýûüüúüüúüüúþþüýýýüüü^^^333)))!!"ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþ CCE ®®­üüúûûùüüúýýûýýûýýûþþüþþüþþüüüúýýûþþüüüúþþüþþüýýûýýûúúøøøöääâçççúúúýýýýýûýýûüüúûûùüüúýýûþþüýýûûûùüüúýýûþþüüüúýýûýýûüüúþþüýýûûûùÿÿýþþüþþüýýûûûùýýûýýûÿÿýýýûþþüüüúüüúþþüýýûûûùûûûüüü~~~445$$$ !þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý™™™--/../ÞÞÜýýûþþüþþüüüúýýûüüúüüúûûùþþüþþüüüúþþüýýûûûùýýûüüúþþüþþüööôââàèèçúúúüüüýýûüüúüüúýýûüüúþþüûûùýýûþþüþþüýýûüüúýýûüüúþþüûûùüüúüüúýýûûûùüüúüüúÿÿýþþüýýûüüúüüúüüúüüúþþüýýûüüúûûùýýûþþþùùù———223ÎÎÎþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ444ZZ[ôôóûûùýýûüüúþþüüüúýýûþþüþþüüüúûûùýýûüüúüüúüüúýýûüüúûûùþþüôôòààÞæææøøøþþþýýüþþüþþüýýûþþüûûùýýûüüúüüúýýûþþüþþüþþüüüúþþüýýûþþüýýûþþüþþüýýûýýûýýûüüúþþüþþüýýûüüúýýûüüúþþüÿÿýþþüûûùýýüýýý¥¥¥--.ŸŸŸþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýþþüýýûýýûZZ[888ˆˆ‰ýýûþþüýýûüüúýýûýýûýýûüüúþþüþþüþþüýýûüüúþþüüüúýýûüüúüüúþþüööôßßÝééé÷÷÷ýýýüüûüüúüüúüüúýýûûûùüüúýýûþþüýýûüüúüüúþþüýýûýýûûûùýýûýýûýýûýýûþþüýýûüüúýýûþþüüüúýýûþþüþþüüüúüüúûûùýýûüüúýýüþþþ¸¸¸223žžžÿÿýýýûüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúýýûËËÉ>>>ÀÀÀûûùýýûýýûþþüþþüýýûþþüþþüûûùüüúýýûýýûýýûýýûþþüüüúýýûûûùýýûòòðßßÝçççøøøýýýýýûþþüþþüýýûüüúþþüþþüüüúýýûúúøþþüüüúýýûýýûþþüþþüýýûûûùýýûüüúûûùþþüýýûþþüþþüþþüûûùýýûýýûüüúüüúýýûþþüþþüüüûýýýÅÅÅ  777___ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüYYW BBB((*ÚÚÚþþüüüúþþüüüúüüúýýûûûùüüúýýûþþüýýûýýûþþüüüúýýûûûùþþüþþüüüúîîìÝÝÛççæ÷÷÷üüüûûúüüúûûùýýûýýûýýûýýûüüúþþüþþüûûùýýûüüúýýûüüúûûùþþüûûùûûùýýûüüúüüúýýûýýûýýûüüúþþüüüúþþüýýûÿÿýýýûúúøýýûüüüýýýÌÌÌ  667 þþüþþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýû——• GGG556ßßßþþüþþüûûùþþüÿÿýûûùþþüþþüüüúýýûþþüýýûýýûþþüýýûþþüýýûþþüþþüððîÝÝÛçççùùùüüüýýûýýûýýûûûùüüúýýûýýûýýûüüúþþüþþüþþüýýûýýûýýûýýûþþüýýûþþüþþüþþüýýûýýûûûùþþüþþüþþüýýûüüúýýûüüúýýûýýûÿÿýþþýþþþÏÏÏ445!!!ýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþFFFFFFèèçúúøýþúÿÿüúúøþþüþþüüüúýýûûûùüüúýýûúúøüüúûûùýýûüüúüüúúúøýýûîîìÝÝÛççæúúúüüüýýûûûùþþüþþüþþüûûùýýûüüúþþüûûùýýûüüúüüúþþüýýûûûùüüúýýûýýûüüúýýûüüúýýûþþüüüúýýûúúøýýûþþüýýûýýûüüúýýûüüúüüûþþþÔÔÔ##%##% þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû———KKK WWWïïíýýûüüøüüúýýûüüúüüúýýûþþüþþüüüúýýûþþüþþüþþüþþüþþüþþüþþüûûùííëÞÞÜëëêúúúþþþþþüþþüûûùüüúýýûþþüüüúýýûûûùþþüýýûýýûýýûüüúûûùþþüýýûûûùüüúýýûýýûþþüûûùýýûýýûþþüýýûûûùüüúþþüþþüþþüýýûýýûýýüýýýÕÕÕ--/  þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû–––,,.PPP888cccññïþþüþþúýýúýýûüüúüüúýýûýýûþþüþþüûûùýýûüüúýýûúúøýýûüüúýýûýýûììêßßÝíííûûûüüüüüúüüúýýûÿÿýúúøþþüýýûýýûûûùýýûüüúüüúýýûýýûþþüûûùþþüþþüýýûüüúýýûûûùýýûýýûýýûüüúýýûþþüýýûýýûüüúýýûýýûüüúþþýüüüÕÕÕ 668 þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüVVV;;=___NNN òòñûûùüüøþþûüüúýýûýýûþþüþþüûûùüüúþþüýýûýýûþþüþþüþþüýýûýýûûûùèèæßßÝíííüüüþþþýýüþþüýýûüüúþþüùù÷ýýûûûùþþüþþüýýûýýûüüúþþüüüúýýûüüúýýûüüúþþüþþüûûùþþüþþüýýûûûùýýûýýûýýûþþüþþüûûùþþüýýûûûûþþþ×××%%% þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüCCCXXX ‚‚‚ôôòýýûþþúþþûþþüüüúýýûûûùþþüþþüûûùüüúýýûýýûüüúýýûûûùüüúýýûüüúêêèÝÝÛìììúúúüüüúúøýýûýýûýýûþþüýýûýýûÿÿýüüúüüúýýûþþüþþüûûùþþüþþüþþüýýûüüúúúøþþüýýûûûùüüúþþüþþüýýûýýûýýûüüúýýûýýûûûùýýûüüüýýýÐÐÐ,,,!!!ýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü JJJ ŠŠŠööôüüúüýùýýúþþüþþüüüúýýûûûùüüúýýûüüúýýûýýûþþüþþüþþüýýûýýûüüúêêèááßïïîúúúþþþþþüýýûýýûûûùüüúþþüüüúüüúüüúýýûüüúýýûûûùþþüüüúüüúûûùýýûýýûýýûûûùýýûýýûüüúûûùýýûüüúüüúýýûüüúüüúýýûþþüþþüúúúþþþÁÁÁ /// þþüþþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü*** ………øøöþþüþÿûþþûüüúüüúýýûûûùþþüýýûýýûýýûüüúüüúýýûúúøýýûýýûüüúýýûêêèââàòòñúúúýýýýýüþþüÿÿýþþüþþüýýûþþüþþüýýûüüúýýûþþüýýûüüúüüúýýûüüúýýûýýûþþüýýûûûùþþüÿÿýýýûþþüþþüþþüþþüþþüþþüûûùýýûþþüþþþýýý¯¯¯///###  ___ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþûþþüþþý  /./212xxxööôûüûüýùýþúþþüþþýýýûþþüüüúüüúûûùüüúýýûþþüþþüþþüüüúüüúüüúýýûëëéààÞññðýýýþþþûûúýýûüüúüüúýýûûûùýýûýýûþþüýýûýýûûûùýýûüüúýýûýýûýýûúúøýýûüüúúúøþþüýýûûûùüüúýýûûûùüüúýýûûûúýüûýýúüýùûüøýýüüüüŒŒ333''' """***&&&žžÿÿþýýûýüùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿýÿþÿùûÿþüþÿ”––#eGžw·Ž¡€YG  96;yywíîíúþþúýùüý÷ýûýþýÿúúùýýûþþüýýûþþüþþüüüúúúøýýûýýûüüúýýûþþüüüüéééàààòòñûûùüüúþþüþþüýýûþþüýýûüüúüüúüüúûûùýýûüüúþþüþþüþþüýýûýýûýýûýýûüüúýýûþþüüüúþþüþþüüüúþþüþþüþþüüýûúýýýýýÿýùýÿ÷ùÿøüþúùúùbdd! ,,-EEEKKK  ›þýþÿýûþÿøýÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúÿôüÿûÿþúýü÷ÿýôcO$«…×¥ï¼ñ¾ñ½æ· šx!HIKÍÊÐúûûûýùþþüþýþýþûüýúýýûüüúüüúýýûþþüþþüýýûüüúýýûþþüýýûýýûüüüëëëàààòòñüüúüüúýýûûûùýýûüüúþþüüüúýýûýýûþþüüüúþþüüüúýýûýýûýýûýýûüüúþþüýýûüüúþþüþþüüüúþþüþþüûûùýýûüüúþþüûþøüûùýùùûúôúýóüýôèâß4.. ZZZbb\ $!"þüþÿüÿÿýúüÿüüÿþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûúÿùýþüÿûÿÿûùë⻵Œ Ú¤ òµô½ õ¿ ú»þ·ðµ¥…  ROSËÊÊùûõýýýúûøùý÷üýúüüúýýûýýûüüúýýûüüúþþüþþüýýûýýûýýûüüúûûûêêêßßßóóñûûùýýûþþüýýûüüúýýûýýûþþüþþüûûùýýûýýûþþüýýûýýûýýûýýûýýûýýûüüúýýûýýûûûùþþüýýûûûùýýûüüúûûùýýûüüúýüôýöÙïÞ®îÛ£íÛ¢îڟθ„5" % 888GG?32. ""&ýþùûÿôþþøýþùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿÿøÿüÿÿüÿýÿøÿýîͱ]Иå®î·ñ¾ ð¾ õ¼ú¼ø¿ê»©‚) :>3¿¿¼úøûýþüýþüþþüýýûüüúýýûþþüþþüýýûüüúþþüýýûüüúýýûþþüýýüêêêàààóóñýýûýýûüüúþþüýýûþþüüüúüüúûûùýýûúúøýýûûûùýýûüüúþþüþþüûûùþþüýýûþþüüüúüüúûûùþþüþþüþþüþþüýýûýýûýüøûíÉÙ³QÞ³ ë¾íÀíÀ廯¢$PB7770,- e`aüþûøÿúûÿýÿýüÿþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüÿüúüþûûþïØË’¼ŠØœ æ¯ ð¸ò¾ ñÀ ñÀ òÂó¿ö½ò¹¬‚% 855´²´õöøþýýüûùþþüýýûüüúýýûüüúýýûþþüûûùüüúýýûûûùýýûûûúèèèßßß÷÷õüüúüüúýýûüüúýýûüüúýýûþþüýýûþþüþþüýýûüüúýýûüüúüüúûûùþþüüüúýýûüüúþþüþþüþþüûûùýýûüüúúúøýýûüüúýûóëÌ|â³ôÉ ÷Ö ôÙöÖõÏå¾#RB """%%%€l×Åyÿýâýýðùÿùûüþÿüþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûÿþüþüúþ÷þûç·.̑ݣï®ö²ø¹÷½ ô½ ö¼÷½ õ¾ ô¾ê´r -.*¢£Ÿöòôýüüúúøýýûþþüþþüþþüüüúüüúüüúüüúýýûüüúþþüûûûëëëàààññïýýûþþüþþüüüúýýûýýûüüúýýûûûùüüúýýûþþüýýûüüúþþüýýûþþüýýûüüúþþüýýûþþüüüúýýûýýûýýûýýûþþüýýûýýûþüôä½k⥠ò· òÂóÍõÐ ÷Ïد?.  <-ƧðÍ"æÊ=õð¹ûþûúÿúüþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûûÿöýýøÿûë˪gÁ‰Ôš à§ ï®÷µ ùº ø¼÷¼÷¼÷¾ ô¿óÁõÀÞµuW "$ƒƒ…íííýýûûûùüüúûûùýýûýýûþþüüüúüüúýýûûûùýýûüüüêêêÜÜÜëëéøøöûûùþþüýýûýýûýýûþþüÿÿýýýûýýûüüúýýûüüúýýûüüúûûùýýûüüúýýûüüúýýûþþüüüúýýûüüúýýûüüúüüúýýûûûùþýõãÃrÜ¥ñ²õ»ò óÈìÅ»˜2$‘qêÆôÍúÓéØkÿýéúýýüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþýþþýþþüþþûþþüþþüþþüþþøþþóþþïþþíþþìþþíþþïÿýéìå¿Ç¥[¿†Ï•Ú£æ¬ î¶ò½ôÀ ó¾ ó¿ò¿ò¿ö¾ ø¾ òÀó½Ñ¡M6 UVUÔÔÒúúøüüúýýûþþüýýûýýûýýûýýûþþüýýûûûùüüüöööêêêííëúúøþþüûûùýýûüüúýýûýýûüüúþþüýýûþþüþþüþþüûûùýýûýýûþþüýýûüüúýýûýýûþþüýýûýýûüüúýýûýýûþþüýýûüüúýüôãÄpÚ£ î±ö¾ ñÂí¿ã¶®…1 `E ݵîÅ îÈ îËäÄ<íè¾üüúÿþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþùýÿøþþÿûÿþÿüýþý÷øÿþÿûöÿüêÏ¿˜ÕÁy°ˆ%¶†¶…±ƒ­€ °€¶‚ËЖ Úž ãª ê± òºó½ ô¾ õ¾ õ¾ ô¾ ô¾ õ¾ õ¾ òÀ ó½ð»´(  ??>ÃÃÁüûùüüøýþùýþúûýúýýûúúøüüúüüúýýûþþþýýýùùùøø÷úúøýýûýýûûûùþþüüüúþþüþþüûûùýýûüüúûûùüüúýýûüüúýýûýýûûûùþþüûûùüüúüüúþþüþþüþþüþþüýýûúúøüüüýýýüúôæÇwÙ¢î²ô¼ ñ¿ î¹ á­µ„B+ 1 º”îÀíÂî ðÀ äµ!ÛÏ—ýþÿÿýþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿøýÿùþÿùýÿûþûÿÿýúýþøçÝ·¯„!¾ŒÍ—ל Úœ ך Ó–Ë É Ï•ÖœÜ  ã¨ ê° òºô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò¾õ½ò¾ß¹ˆj###—–•ñðîýýûüýûýÿüþþüýýûþþüþþüüüúúúùûûûýýýýýüüüúýýûýýûÿÿýþþüýýûüüúýýûþþüþþüüüúþþüüüúýýûýýûþþüýýûþþüýýûþþüýýûýýûýýûüüúýýûýýûþþüýýûøøøîîîãàÚÛºi򣓡 ô»ï» ç±ݦ À‹eC   $šqÝ­ê¼ é» íº ô½ êµÞЖýþüÿýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþþýýÿÿüþþÿùýþöþüúÿùî­‰*Î Ú˜ Ý  á¨á¨ৠݣߤÞ¤ à¦å«é¯î³ó¹ô½ ô½ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ ÷¿÷½ ñÀðÇѨXC }{|éèçûûùþþüûûùüüúûûùüüúþþüýýûþþþýýýüüûüüúýýûüüúüüúûûùþþüýýûüüúýýûýýûüüúýýûþþüþþüýýûüüúûûùýýûûûùýýûýýûûûùýýûþþüýýûüüúþþüûûùáááÉÉÉÇľԳaØ ï²ñ·ì· å®Û¢Á‹ ˜m?'   +ŽcÏ™ ä± æ· ê·îµ ô· å¬ÝÍŽþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûÿÿýýÿÿüýÿþøüýúþýõÒÀ»ˆÓ™ Ü£ ã®ç´è´ê²ê°æ«æ«ì± ñ¶ñ· óº õ½ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ó½òÀ öÇè¿®‹$ ][\ÔÒÒüûùþþüýýûüüúýýûûûùüüúýýûûûùýýûüüúþþüþþüþþüýýûýýûüüúþþüýýûüüúüüúüüúüüúüüúûûùþþüþþüþþüýýûûûùþþüýýûûûùýýûýýûýýûüüúèèæËËÊÅÅůĽӰ_Ù¡ê¬ ï´é³ ä« Ú ÇŽ¯| Že;"   [: Ÿoȑء â¯é· ì· ó¸ ö¹ç°ßΔýþÿýÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûüÿõþÿüÿþûÿþøüþÿþþö¾¢^ÈŠÙ  æ¯ì´ ð¶ ó· óµ ô·ò¶ñ· ôº õ»ö¼õ½õ½õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ¼ò½ ôÀïÇرu]  423µ´³ùù÷ûûùýýûýýûþþüüüúýýûþþüûûùþþüúúøýýûûûùûûùýýûýýûýýûüüúýýûüüúýýûûûùþþüýýûûûùýýûüüúþþüþþüûûùþþüýýûýýûýýûýýûûûùÚÚØÄÄÃÄÄÄÇľѯaÚ¡é¬ ë° è±äª Ý¢Ε»…®{ŸrtP K18%.+5"N3wVœr°|Š Ö Þ©ä°í¶ ó» õ¹ô» ë¹êÙ—ýüúüþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿôþÿúþþÿÿýùüÿûþýòÅ¥VÌÝ¡è­ð² ö¶ øº÷» ó½ ñ¾ ô¼ ö½ õ¾ õ¾ õ½õ½õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ó¾ó» ó¾òÄ éľ™:(‘‘‘òòòûûúüüúýýûýýûüüúýýûÿÿýþþüþþüþþüþþüþþüüüúüüúûûùüüúýýûþþüýýûþþüûûùÿÿýþþüýýûýýûýýûþþüûûùüüúüüúþþüüüúüüúùù÷××ÕÄÄÃÄÄÄÈſЮdÓšã§ è¯ é³å¬ á¥ÔšÅŽ ¾„ »} µz ªx  vŸv¢w¥x ©z¬| ·‚ÆŒ Ô˜ âªè³ ï¹ õº ôº õ»ó¼ð¾Õ¶AÿüÙÿüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþýþÿûÿûÿýûüþÿÿÿì«…(Ê’Þ¤ê° ñ· ôº õ½ ô¾ ò¿ òÀõ¾ õ¾ ô½ ó¾ ó¾ õ¾ õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ õ½ô» ó»ô¾ ðÈ์j|||ïïïýýüüüúýýûýýûüüúýýûûûùýýûýýûýýûýýûýýûþþüþþüþþüýýûüüúûûùþþüûûùýýûþþüüüúýýûýýûûûùþþüþþüýýûüüúüüúüüú÷÷õ××ÕÅÅÅÄÄÄÆÃ¾Ë¨bјá¥ ç¯ ç³ç® ä©ÙŸ Ï—ÉŽƆ Å… Á„ ¼€¼ ¾ Á‚ Æ Ä襅 â¦í±ñ¸óº ÷º ô¼ó½ô¾ó¸æ¶ØÁbÿýåþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýýýþþúÿùÿþüüþúýüñÀ [đݣ ç­ìµ ò» õ½ö¼ø½ø¼ö¾ õ¾ ò½ ó¾ ó¿ õ¾ ö½ ö½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ ö½ õ½ ÷» ô¼ôÄëÈ΢L7 †††ôôóþþüýýûýýûþþüÿÿýþþüýýüýýûýýûûûùýýûüüúüüúüüúþþüþþüþþüûûùþþüýýûþþüýýûüüúþþüþþüüüúûûùúúøýýûýýûýýûööõ××ÕÅÅÅÃÃÃÅýƤ`ÈÜ å­ ç³ è¯ æ«ݤ Ø› Ò• Í“ÇÈ‘ÉÇŒ ÆŒ É Ë‘ Ô• Üžá©é´ ó½ø½ø½ø»ô¾ó¿ ô¾ö¶ ô´Ü®åÚ•þþõþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþüÿþüÿýÿýüýýüþþøÕÁ‰ÂŒÙŸ æ¬ í´ ñ¹ õ½õ½õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ õ¼ ó¼ ñ¿ òÆç»§$°°°úúøþþüûûùüüúüüúýýûûûùüüúýýûüüúýýüýýûüüúüüúýýûûûùþþüþþüüüúýýûûûùýýûüüúûûùüüúýýûþþüþþüþÿûþþûýûüùøúÜÛÜÆÆÅÅÅÃÅüÀ¡]‹Õš á¨ ç° ê° ì¯ â¨Þ¤ ØÔšÓš Ñ—Ï–Ï— ЗÓ˜ØœÜ¡ã¨ ç® ï¸ õ½ ô½ õ½ õ½ô¾ õ¾ õ¾ ô» ò¸ìµÑ®-ðê±ýþ÷úýþþýþÿüÿüÿýûÿûüÿúþÿúþþûûÿýúÿýÿýýÿûüýþûüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýüüÿüýÿüÿþúþýûýý÷ÖÃŽÁŒÙž ã¨ ë² ñ¹ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ô½ ñ¾ ñ òÅÖ­uU [[[ííëúúøþþüþþüþþüýýûüüúüüúþþüýýûüüúþþüüüúûûùýýûüüúüüúýýûýýûýýûýýûÿÿýþþüýýûþþüýýûûûùýýûüýùûüùýýüûûûåååÊÊÉÄÄÂÆÃ¾½Ÿ[»…Ó˜ à¦ å® ì± î² è¯ ä« á¦ Þ£ Û¡ Ú¡ ÙŸ Ú  Ù  Ü¢ ߤåª ç® íµ ó»õ½ ô½ õ¾ õ½õ¾ õ¾ õ¾ ó¼ ñ¹ ñ¹ï³Í¡.ëã±ûþøúÿúÿýüÿúÿþþúûÿùÿýÿÿýýýÿøûÿøþþþÿýüüÿùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýúüÿúýÿúÿÿ÷þþúþýöÖÆ–¼ˆÕš ᦠë±ñ¸ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò½ ô½ õ¾ ö½ õ½ ò½ ð¿ óÄé¿Ú>-***ááßýýûüüúüüúýýûþþüýýûþþüüüúûûùýýûûûùþþüþþüýýûþþüýýûýýûüüúþþüýýûýýûûûùýýûýýûýýûýýûþþüýýûþþüüýúûûùììêÒÑÏÄÃÃÈÿº›W»…ДÞ£å­ î´ ñµ í´ ê² ç® ã©⨠㨠à¦à¦ã¨ ã© å« ç­ ì³ ï¶ ó»ô½ õ¾ õ¾õ½õ¾ õ¾ õ¾ õ¾ ô¼ òº ñ¶î®Ï+ñè·øÿïüÿöÿüýþþûüÿøþþüÿûÿÿýúþÿ÷ýþÿþþüýÿúýÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýúýÿúþÿüþÿøþþúÿþùèß¹¾‹Õ™ Þ¢ è® ð· ô¼ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ó¾ õ¾ õ¾ õ¾ ó½ ò½ ôÀõÇÞ¶˜v !!!××Öüüúýýûþþüüüúüüúûûùþþüþþüÿÿýþþüþþüüüúüüúüüúùù÷ýýûþþüüüúüüúþþüýýûüüúûûùýýûþþüýýûýýûüüûýýûýþùýýøîïêÖÖÓÆÅÄŸš”‡f#¸‚Ò– Þ£å® í³ ò· ð¸ ð· î´ ë° è­æ«å«å¬äªè¯é°ì´ î¶ òº ô¼õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô¾ ï¹í¹ë¸Ù¬,òè³üþóùÿúüÿüûÿøüÿôÿüýÿûÿþþýüþÿýÿüþþýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿýÿùþþþÿýüÿý⼋Ñ• Þ¢é¯î¶ ó»õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ò½ õ¾ õ¾ õ¾ õ¾ ô½ ô¾ ïÁîÅÑ¥bI )))ßßÝþþüýýûýýûþþüýýûþþüûûùýýûýýûüüúýýûþþüþþüýýûþþüüüúýýûþþüüüúüüúþþüýýûþþüûûùüüúýýûüüúüüüþþüýþøüü÷íîêÖÔÔ¹¶´IB:sS·Д Þ£ä¬ ïµ õº òº òºò¸ð¶ ïµ í³ í³ í³ í³ íµ ï· ï· òº òº ô¼ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ î¼ î¾ î¹ä°"ؼkþþßýý÷üüÿúÿúúýúýýÿüþþüÿýýÿûÿýûÿýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿûÿúÿþÿÿýÿÿýíºŠ!Д Ü ç¬ñ¸ó» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¼ õ¾ ô½ õ¾ ô¿ ëÁ óÅ íÀ¿˜8, ƒƒƒ÷÷õýýûýýûüüúýýûüüúüüúýýûýýûüüúüüúüüúýýûûûùûûùüüúþþüüüúüüúûûùýýûýýûüüúýýûýýûýýûüüúüüúýýýüýûûý÷üþùðñðÂÀÁLHDyYº„Ò– Þ¤ å® î´ ô¸ òº ó¼ô¼ó»òºó¹ó¹ó¹ó¹ò¹ ô¼ ó¼ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ô½ õ¾÷¼ öºñºÔ«,ÚÉŒÿüïýüýúþúøþ÷ýÿúýÿúþÿùÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþúýÿýÿýÿúÿ÷þþýÿýþÿþñº‹#Î’ Ûž è®ï¶ ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ö½ ó¼ õ¾ õ¾ ó¼ õ¿ îÂò òÇáµ Žq  ˆˆˆóóóþþüüüúüüúüüúýýûüüúýýûýýûýýûýýûýýûüüúýýûýýûþþüýýûýýûúúøþþüýýûþþüþþüþþüþþüüüúüüúýýûýýûýýüýýûýÿùúüúÈÈÌD@D xX ¸‚ Ò– Ý¢ ä­ ðµ ô¹ òº ô½õ½õ½ õ½ õ½ ö½ ö½ ö½ õ½ ö¿ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½õ¾ ø½÷½ ÷¼ú¼õº ð½æµ ǤCÿûâüýûûÿöþþûÿýüþÿúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿþùþÿûÿýÿúÿ÷þþýÿüûþþò½$Î’ Úž å« ð· ô¼ ô¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ õ¼ ö½ ö½ õ¾ ö¿ ö¿ ô½ ò¿ î¾ôÄðÉϤgH 4,VWR›œ›çççþþþûûüüýûûûùýýüýþûþþüýýûüüúüüúüüúüüúüüúýýûûûùüüúüüúûûùýýûýýûüüúüüúýýûüüúüüúýýûûûùüüúýýûüüúüüúúúøüýùÊËÊ337#~\¶ Ó— Þ¤ ç¯ ð¶ ô¹ ô¼ó¾ ó¿ ó¿ ô¾ õ¾ ö¾ ö¾ ö¾ ö¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½õ½ò¾ôÀ ö¾õ½ òÀ óÀ ÷½õ¸â²æÖ–þüýûþúÿýýÿüÿþþþûþÿýþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþûÿýþûÿýýÿûÿûþÿû÷ýý弌Α Ú æª ò¸óº õ¼ ô¼ô¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ò»ë½êÉ å¿ ¿Ž¬‹Wöôéùýùûýùûûýþüÿþýùþþúúúûûý÷üþùþþüþþüþþüþþüýýûþþüþþüþþüþþüÿÿýþþüûûùþþüþþüûûùýýùüýøýþùþþúýýûýýûýýûýýûýþûø÷ø¯¯­###0†] ¶‚ Ñ™ ߥè® îµ ó» ô» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ð¿ñ¿ ù½ú»õ½ñ¿ ñ¼õ·ê¬ìÕ”üýúüþøþþûþýýÿýýûÿüüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúÿþüüÿüþÿûÿüþþýùçâ¹¾‹Α Úž è­ ó¹ô» ô» õ½ó»õ½ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ¼ ï½ èÁ èÀÚ© yƹ˜üüøûüûüüúüüùüü÷þýúþþþýþûüüùüüúûûùüüúüüúúúøýýûüüúüüúýýûýýûýýûþþüüüúýýûÿÿýþþúýþùýþùüüúüüúûûùüüúüüúóôòƒ„:&‰_ ¶‚ Ñš à¦é® ï¶ ó¼ õ¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ ö½÷½ ö¾ô½ õºó¸ó¹è³ܪç×”üüúþýÿýýþþþýÿþýýþþýþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþÿúþþþûþøÕ„¾‡Ï‘ÛŸ è­ ñ· ô» ô» õ½õ½õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó»ö» õ½ê½ìÂç¹ Èž•w/èÞÒüùûüý÷ýÿôýþùýüýýýýûüüúûùüüúýýûûûùþþüþþüýýûýýûýýûþþüýýûüüúýýûüüúüüúüüúüüúüüúýýûÿÿýüüúýýûýýûáááXYY  D/‰^ ³ Й â§ ê¯ ï¶ ô¼ õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ½õ½õ¾ õ¾ õ¾ ø½÷¾ó¿ ó½ô¹íµ è² ä§ Ò¥-ïê»ýÿýþüÿþþýüÿýþþýþþýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþýÿùÿýüÿþýúýüýþòŤPÀ… ÍÜ¡ é® ó¹ ô» õ¼ ó¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ½ö» ÷» î¼è¾ íà ٬­ƒ˜ƒY÷òîýüûùýóûýøýüþûûûýÿýýýûýýûþþüûûùüüúüüúüüúþþüüüúüüúüüúýýûþþüþþüýýûþþüþþüýýûüüúþþüþþýöööŸŸŸ$$$ J3‡\°|Ϙã¨ ë° ï¶ ó» ô¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ õ¾ó¾îºìµåª Ý¡ Õ—äËŽþýóüÿüþûüþþøûÿûýÿüÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýþÿýÿúÿýþþþÿýþùÿý߸„ Æ Ó–å«ñ¶óº õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ ö¿ õ¾ ó½ ñÀ ó¼ ÷»ï¼æ½è¿ á±Ä‘ ƒe¬›ƒýøùûþûüþúþýþýýþûüøüüùýýûýýûýýûþþüüüúýýûûûùüüúýýûþþüýýûüüúúúøüüúüüúüüúýýûýýüööö¹¹¹BBBQ9‰\±}Ϙã© ë° ð· ó» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ õ¾ ó»öºó·íµâ¦Û™Í” É«mÿúòþýÿýÿüÿýýþþøúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýþÿþþûÿýþþýÿþýïÑÁ„¼ ÉŒ Û  ì²ó¹óº ô» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ ñ¿ ó¾ ô¼ ðºä¶å¹߯ Ë–  xZ>£—’óôõûþûûúûýýýûý÷ýþúüüúýýûüüúýýûýýûüüúþþüþþüýýûýýûþþüüüúüüúüüúýýûýýüûûûËËËSSS W<ˆ[±| Ζâ§ ê¯ ñ¸ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó» óºñ·ïµé®㢠֖Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿüÿþúÿþûýþÿÿý毄(Ɖ Ò— ⨠ñ¸ó¹ óº õ¼ ö¼ö¾õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ô½ õ¼ óºè´â±ܪ Ó›°} wR.\ZWÎÏÎüûøúúùùüøúüùþþüüüúüüúüüúýýûüüúüüúüüúýýûýýûüüúüüúýýûüüúééç­­­SSS Y=Š\²} Ï– á¦ ê¯ ð· ó¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ô¼ð·ì³è­Û¢ ҞŒʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûýÿùÿþùþÿùüÿýäÞ»»†Ç‹Øž â¨ ë² ôº óº ô» õ»ô¼ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¼ ö¼õº÷»ð· â¬Ü¥ Ò™ ¹ bN: SRO¡¡ ÒÔÔìíìøøöûûùýýûûûùûûùüüúüüúùù÷ùù÷ññïßßݼ¼º‰‰‡PPN#\=Ž`´ Ζá¦ é¯ ð· ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ó» óº ô¼ ô½ò¼ ï¸ é± Þ¥ÙŸ љȒ³‡,îâ¿ýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþþúþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúÿúÿþýÿþûÿýúÏÂŒ¼ˆÍŠÕšâ¤ è¬ ïµ ò¹ òº óºôºô¹öº÷¼ ö½ ó¼ ô¼ ö½ ÷½ ÷½ ô½ ó¿ ó¿ õ¾ õ¾ õ¾ õ¾ ö½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ö¿ ô½ õ½ ö½óº ð¸ æ®Ý¥ Óš ¼ƒ˜f iG ' *))GGGaaawww‚‚‚wwwfffXXXPPPEEE$$$ 2!eB–e·€ Ì• ݤ è° ñ· ô» ô¼ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ö½ ø½ ø½ ö½õ¼ôºóµõ¶ó¸î¸è´ á¬ÕžË”¾‰¿¦_èä½ÿüçÿýùýýþþÿûþþûÿýþþþÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿûÿÿþóÿþñÓÄ·…ʆÏ“ ןߨç° é° îµï¶ñ¸ ò¸ ò¶ ò¸ ó» ô¼ô¼ó»ö½ö½ õ½õ½õ¾ õ¾ õ¾ ö½ õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½ö¾ö¾ õ½ö½ôºï¶ è® Û¢ ј »i rL <&  ;( kH™g·€ Ê’ Û£ ç­î´ ö¼õ½ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ö½ õ½ ó½ ï¹ î¶î³ï²ê¯㬠ڢ Д»‚º˜QçÞºÿüçÿýïþýùüüþþÿþþÿúþÿúÿýýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿúÿüÿÿüþÿýöÑ“³džÊ‹Ñ•כݡ ã¦ ã¨ ä« ã®å±è¯ ê¯ ë³ îµ î¸î¸ò¹òºôºôºôºô»õ¼ö½÷½ö¼õ¾ õ¾ õ¾ õ¾ õ¾ ö¾õ½õ½ö½ ÷¾ö½ó¹í³ äª Ú  Ε ¶}šfuLM4   ?) oJ™g¶ ÇŽ ÙŸ åª ï´ óºõ¼ö½ö½ö½ö½ö½ö½ö½ö½ö½ô½ ô»ñ¸ëµ ç±ä¬㩠ঠÙÑ’ À†œs'æÛ¼þýøþþûþý÷ÿüúþýÿüüþüþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûúÿõûþÿýÿøþÿõçÞ½§}&¹}¾‚ ¾† Ä‹ Ì Õ• Ú™ Ûœ ÛŸ ܡޡ à¤ â¦ ã© åª è®ê°î´ñ¶ó¶ô·ó¸ôºò¸ óº ö½õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô½ ô¼ õ½ õ¼ ôºó¹é° ߦ Óš Æ‹ ¯w–bzPY< %B, nH–c²{ ‰ Ô™ ߤë® ò·ó¹ ô» õ¼ ö½ö½ õ¼ ô» óº ò¹ ò¹ ñ·îµé¯ä© ⥠ܟ ך ΔŠ ©{!˸‰þüîüýùúýùûÿüüýýýýþýýÿûüýýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüþþýþÿüÿùþÿùÿûöèÚ¶y% x «z °z·~¹~¿ Â… ĉ ÉŽ Í Ó• Õ—Õ˜ךÜŸ Ý¡ à¥ ä© æ« è­ ê¯ î´ ñ¸òºòº ó» ö¾ó¼ ô½ ô½ õ¾ ô½ ô½ óº õ¼ ó¹ ïµ㪠؞ ɹ€¦p’_zP[> ' @* iD^¬t ¼ƒ Γ Ü  å© î³ñ·ò¹ óº ô» ô» ô» ò¹ ôºó¹ñ¶ë±æ¬ á¥ÞžØ” Ó‘Ç µ‚¶›Tãܺýýôþýúÿþ÷ýÿöúÿùüÿüýÿýýÿüýÿúýÿøþÿùþÿûÿýþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýÿüÿÿüþÿÿóþÿöþýýÿûôÿûéáٸQi—oŸr¦t®w ´z ¸} ½ À„ÈćÆŠ ÈÌ‘ јÕ› ÙŸ Ý£ ߥ ã¨ ç­ ì²ñ·ò·ó¹óº ôº óº ò¹ ôºóº ò¸ï´ç­ Û¢ Δ¾…¬t›e‹[sKV:%=( b@ˆW¥n ³{ ÄŠ Ô™ Ý  æª ë° ïµ ñ· ò¸ óº ó¹ ò¸ ñ¶ë± è­ ã¨Þ¤Ùš Ðƈ·ƒ ©(ɹŒÿüèÿÿòøþøùÿýþýþÿüýÿýüþÿúþÿúþÿùþÿøþÿùþÿúþþýþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýüÿýûÿüÿÿýÿûüùüþýüþûýüúýýöþþòþþëâÙ¼Á¯‚ªŽKe šk¢n ¨s®w ®v³y ³y ¶{ ¸~ º½„Áˆ Æ Ë‘ Ò— Øž Ü£⦠è«ë¯ï´ó¹ñ¶ó¸ò¸ï´ì±ç¬Ý£ј Ä‹ ³{ ¡i’\QiEM7  8& [:€R›e«tºÊ Ö› ߤ äª è® ì³ ì³ ì³ î´ê°ç¬㨠ݡ ՚ϕ È‹º} ¨w–w$èß¼ÿû÷ýüûúþúùþýüþÿþþÿÿýþÿýþÿýýþþûþÿûþÿúþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûûÿøûÿ÷ýþþÿýÿýþøûþúüýþþüüÿýúýýúýýúþþüþýùÿüñÿýå¿´Žª‹I‡]Œ` —g ›h h¡k£l§o©q­t²y·}½‚ĉÌ’ Ò– Ùœ ÚžÞ¢â§ ç« è¬ é®åª ॠٜ Í’ˆ·~¦n”]†SuI^=B- ggg€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€$$& 3# V7|N–a¥o´{À…Ë‘ÖœÝ¢á§ á¨ ãª ä« ãª ß¥ ÛŸ Ö™Д È‹¼ ±yœj †`&äÚÆûýùùþüýýüýûüÿüýþýûþÿúýÿúûÿûýþþÿýÿÿýþÿýþÿýþþþÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþûþþüþþýþþüþþüþþüþþüþþýþþýþþüþþûþþùÿýôþýïÿý庮‰š…SvS„X ‹[ [‘]—bžg¢l§p«v²~º„ ¾ˆ Œȑ Í•Ó˜Ú Û› Õ— Ð’ ÈŠ ¾‚ ±x¢l‘]„TwJfAO5 + ghhåææýûüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþþýþþýþþýþþýþþýýþýþþýþüüãâ ‚‚|QD+N3qG\ h¬t¶|¾† ÇŒΓј Ò™ Óš њљ͔Ȇº³{ ¨q’e¨“hÿýðüþüýþÿþþýþþüþþüþþüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþûýûýþúýüöþþòÿýìÜÕÀ­ž…{PcGoP{W „Y ‹Z—ae¥lªq®u²y ¶} ¹€ ½ƒ ¿†½…¹±y§ošdZ€PvHiBW9?*  ,*(åæåüýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüýûýþûþýûýüýýýÿþþù¥‡G0e@S”a¤l­u³{ ¶~»‚Á…ćň Ĉ Á‡ »„ ³} ®x¨q™hƒ] ¦’hÿûïýüùüýûýþùþÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýüøþþúýþûüþüúþüüýúýþùþý÷þüôÿýñÛÕÀ« xQa@ pG€Q‹X[˜b œe  i £l £o ¡ožlj”aŽ\†V{NpEe=V9 F3…zgêçßýþüüþþþÿýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþýþýüýüùýýüüþþüýøÕÑÁ>,U7pI‡X˜d£l©r ªt ­v²yµz·{ ¶y ´w ®u¥p l“c wS Žfþþñýþûüûüýûþþÿùýÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüÿþüþýüýþýþýüúÿýùÿþùÿþùþýøÿÿúþüøÿüõÿû‰‡uQ`ApKzR ƒV‡WŠY‹ZŠYŠXˆU…S~NwKnH`?W9@/«¥‘ÿýôýýüûýþýþþýþúÿþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýüûÿþûýþûúýüüýúÿýõ¥ŽA. V9mG…V“`œfŸj¢l£p¢o§q¦m¥lŸi “a‡YoJ šˆlþûõøþùúþúýüþþûþýýüýþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûýÿüýÿýýÿþþþþþþþþþþÿýþÿüýÿýûþÿúüÿûüÿýýÿþþþüÿþ÷ÚÖÁ¦š|]H^A hEoFuIzK|KyHtDrG hCY<N6A- ª¤’ÿýöýýüüþÿûÿÿýÿýþÿúÿýúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþÿûýÿúýÿûþþüÿþúÿýö¢‰?/P4d?wL…WŽ^•b˜g –f”d”cŽ_‚X oK `A —ˆmÿüõþüýýþüýþýþþþÿþûþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿùþþøþÿøýÿùüÿùûÿùûÿùûÿúþýþÿýþýÿýüÿýüÿþüÿýýÿúþÿ÷þþ÷þýôÿýï­¢„rVP5Z: a> c>a<_;X8 P5 F2\N6ºµ¥þüõüüûþþÿüýÿýþþýÿûþÿúÿþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþöìêÛXK2G0 R6^>iEoHwLxMuKmHbCS;ƒv[ߨÌýüøûýùÿýýÿûÿÿýýþþüþþþÿþùþÿùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüþÿýþÿýýÿþûþþûþþûýÿúýÿøýÿøýÿùþþýþýÿþýÿÿþýÿþúþþüýýýýüûþþüýü÷ÿý𭣡–|M=>- >,^O6”ïìÜÿûõþýüýüüýüüýüýûûüþÿûþÿùþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûýÿýþþþÿþýÿþüþþüþþýýÿüþþúÿýöëèÛ›“}\N1?- F0I0 I0 E/ …vVž•}ÞÚÌþüøýýþúþýûþúüúúþüþÿþüüÿúüÿýÿþúþþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüÿýüÿýüÿýýÿþþþþÿýþÿýþÿýÿþþÿþþþÿþúÿþøÿþùÿþüþþþþþþÿüüýûúýþûúþúùÿúùþùûþùýþùþþ÷þý÷ÿýöÿüõÿþöþþ÷üþüûýþþýûÿýûþüüþýýÿþúþÿùþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþüýþþþþÿÿþýÿýûþþûýÿýúþûüýüüüüüüüþþûýü÷ÿþöÿüöÿýôþýóþþ÷ýýøþþûýýúþþûýþúüþüüþûýþùüþúüþýüÿ÷ýÿôÿýýþýÿþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþýþþýþþýþþýþþüþþûþþûþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþüþþüþþüþþüþþüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþüþþûþþûþþüþþüþþüþþüþþüþþûþþüþþüþþûþþüþþüþþûþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüP5 # CREATOR: The GIMP's PNM Filter Version 1.0 2 2 255 þýüûlibimager-perl-1.004+dfsg.orig/testimg/badused4a.bmp0000755000175000017500000000054612031434615021600 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/maxval_256.ppm0000644000175000017500000000011312031434615021631 0ustar gregoagregoaP6 # test image - check we handle 256 maxval correctly 1 2 256 libimager-perl-1.004+dfsg.orig/testimg/bad24comp.bmp0000644000175000017500000000234612031434615021514 0ustar gregoagregoaBMæ6(°ë ë µ)µ)µ)´* ²/¬3¦9£@B™D”I‘L#‹R'…X)\+|a0xe1sj3qk7ql9µ)µ)µ)´+ ®1ª6¥:¢@šC•G‘K"O&‰S(‚Z*|`.xd2th6pl7lp8kr9µ)´)³+ ±0 «6¦:¢?œC•I‘L"Q&‰T(ƒZ*}`.xd2th6pl8kr9ht;dx?´* ². ®1¬6¦:¢?œC”IŽO"ŒR&‰W(ƒZ*}`.xd2th6pl8jr:dx?bz@a|B²1­2ª6¦:¢?œC”IO"‰S&…W(ƒ[*}`.xd2th6pl8jr:dx?`|A[CZƒG¬7§8¥:¢?œC”IO"‰S&…W([*|`.xd2sh6pl8jr:dx?`|A[CW…GS‰I¤;¢?AšC”IO"‰S&…W([*|`.xd2sh6ml8jr:dx?`|B[CW…GQ‰ILŒJ@›C–G“JO"‰S&…Y)[*|`.xd2rh6ll8hr:cx?`|CZGW…HQ‰IKKH‘O™C•G‘K!O"‰S&…Z*_.|a/xd2rh6ll8hr:bx?\|CYGT…IP‹JJKD‘OC”Q”H‘K"O&‰S'…Z*`.|c0xe2rj6lm8hs:bx?[|CWGS…IOŒKI‘OC”P@•R@™S‘L"Q&‰T(„Z*`.{d1uh2qk6lp8ht:bz?[}CWGS…IOŒKI‘OC•Q?™S:œW9X‹S'‰W(ƒZ*}`.zd2th6pl7jr9du;a{?[€CW‚GR…IOŒKI‘OC•Q?™S9W3¢Y1¤Z…X)ƒ[*}`.xd2th6pl8jr:dx?`|@[CW„GQ†ILŒKI‘OC•Q?™S8žW2¤Z.¦\*ª`\*|`.xd2th6pl8jr:dx?`|A[CW…GQ‰IKŒKG‘OC•Q?™S8žW1¤[+ª`)­a'®b{a/xd2sh6pl8jr:dx?`|A[CW…GQ‰IJKC‘OA•Q?™S8žW1¤[+ª`(®b&²c"³dxe2rj6mm8js:dx?`|B[CW…GQ‰IJKC‘O?•Q:™S7žW1¤[*ª`'®b&²d"µh¶iql7lp8hs:cx?`|CZGW…HQ‰IJKC‘O?•Q:™S6žW0¤[*ª`&®b"´d ·h¼j½kjs:ht;bx?\|CYGT…IP‰JJKC‘O?•Q:™S6W1£Z*ª`&®b"µdºh¾kÃlÄpdy@by@\|CYGS…IO‰JIKC‘O?•R:™S6W2¢Y.§\(­a"³dºh¾lÃpÅqÆrc{Ba|C[GX„IR‰JJŒKD‘O@”R;™W8X3¢Y0¥[+«`'²c!¶h½kÃpÅrÆsÆslibimager-perl-1.004+dfsg.orig/testimg/short_bin16.ppm0000644000175000017500000000011412031434615022104 0ustar gregoagregoaP6 # CREATOR: The GIMP's PNM Filter Version 1.0 2 2 65535 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/testimg/toowide.ppm0000644000175000017500000000016112263740601021424 0ustar gregoagregoaP6 999999999999999999999999999999999999999999999999999999999999999999999999999999 1 65535 # we don't get this farlibimager-perl-1.004+dfsg.orig/testimg/comp4.bmp0000644000175000017500000000456212031434615020765 0ustar gregoagregoaBMr v(––ü  DX`f–²Hø3 ¿ž^­.øKý•–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»P»¸0ˆ‹»»<ª¨0fˆ»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§0w U&c.3h»»§,wUU Dfc,3h»»§(wuUDDI™™™”Dc*3h»»§&wuTDI™c(3h»»§$wuTD™‘c&3h»»§$wTD™‘c$3h»»§"wUD™A$3h»»§ wuDI ™f"3h»»§ wTI"™”c 3h»»§wuD&™‘f 3h»»§wTI(™c3h»»§wuD*™‘c3h»»§wTI*™”3h»»§wT.™c3h»»§wuD.™‘c3h»»§wTI.™”3h»»§wT2™3h»»§wuD2™‘c3h»»§wuI2™‘c3h»»§wTI4™3h»»§wT6™3h»»§wT6™c3h»»§wuD6™‘c3h»»§wuD6™‘c3h»»§wuI6™‘c3h»»§wuI6™‘3h»»§wTI8™3h»»§wTI8™3h»»§wT:™3h»»§wT:™3h»»§wT:™3h»»§wT:™3h»»§wT:™3h»»§wT:™3h»»§wT:™3h»»§wTI8™3h»»§wTI8™3h»»§wuI6™‘3h»»§wuI6™‘c3h»»§wuD6™‘c3h»»§wuD6™‘c3h»»§wT6™c3h»»§wT6™3h»»§wTI4™3h»»§wuI2™‘c3h»»§wuD2™‘c3h»»§wT2™3h»»§wTI.™”3h»»§wuD.™‘c3h»»§wT.™c3h»»§wTI*™”3h»»§wuD*™‘c3h»»§wTI(™c3h»»§wuD&™‘f 3h»»§ wTI"™”c 3h»»§ wuDI ™f"3h»»§"wUD™A$3h»»§$wTD™‘c$3h»»§$wuTD™‘c&3h»»§&wuTDI™c(3h»»§(wuUDDI™™™”Dc*3h»»§,wUU Dfc,3h»»§0w U&c.3h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»§:w&03h»»<ª¨0fˆ»P»¸0ˆ‹»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»–»libimager-perl-1.004+dfsg.orig/testimg/bad8wid0.bmp0000644000175000017500000000270612031434615021343 0ustar gregoagregoaBMÆ6(  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !  ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+0000libimager-perl-1.004+dfsg.orig/testimg/maxval_4095_asc.ppm0000644000175000017500000000007012031434615022546 0ustar gregoagregoaP3 3 1 4095 4095 4095 4095 2048 2048 2048 2047 2047 0 libimager-perl-1.004+dfsg.orig/testimg/short8rle.bmp0000644000175000017500000000301712031434615021667 0ustar gregoagregoaBM6(Ú  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !   ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+0libimager-perl-1.004+dfsg.orig/testimg/maxval_0.ppm0000644000175000017500000000007612031434615021464 0ustar gregoagregoaP6 # test image - check we handle 0 maxval correctly 1 1 0 libimager-perl-1.004+dfsg.orig/testimg/longid.tga0000644000175000017500000000024012031434615021201 0ustar gregoagregoa€  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXlibimager-perl-1.004+dfsg.orig/testimg/short_bin.pbm0000644000175000017500000000001312031434615021715 0ustar gregoagregoaP4 16 2 ú€þlibimager-perl-1.004+dfsg.orig/testimg/short_bin.ppm0000644000175000017500000000010112031434615021731 0ustar gregoagregoaP6 # CREATOR: The GIMP's PNM Filter Version 1.0 2 2 255 ÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/testimg/badused4b.bmp0000755000175000017500000000056012031434615021575 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/short_asc.pgm0000644000175000017500000000002712031434615021725 0ustar gregoagregoaP2 2 2 255 255 255 255 libimager-perl-1.004+dfsg.orig/testimg/test.png0000644000175000017500000000437212031434615020727 0ustar gregoagregoa‰PNG  IHDR––³cæµÁIDATxœíÏOI€¿i¶c«jÙXæ@ƒbY1 ì •r‰4‡ù›s)—H–V™˜DHVG¤9à·À%DËN‰Þ=”í8 `~tUò¾D» õ^õêW ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ EðSѸW<ð!æŠîÌÍ9 hÈo}ôß GÅáC„P.º37g P0¼õÑ3+´rÀ— ÿ[¼ˆwޝ™Ïð5Þíüq1¼†øQº9àýÅJBEQºý·õ@Ж£gV@¿AžÎú!÷Íá_йb\==¡ÓxMóÔ…À"”À›åÐ;Fa6aiÖ¹o4(ˆ¯ÎîKGÛmôLÞJî2–`– qŸ=º 9 ÿr:ù//2,q>Ó€·’ïç?ùa…Î# G:(tQè<¢ÐyD¡óˆBç…Î# G:(tQè<ßÕÚÜGd>zŽó‹pΑæ8c¨É­YvqWœW8­­Ì «Ò›'óÑÿXç'gÃ8=VÙ‘Ì¡}²í“»œŒ\U81-pj´…¨*ésv«¤ÙÅ£2=H•Ú“”Lý‡³€´ÆéYà°K÷y!ªB‰Ãiƒ®Ñ¢Îj¤ÁUQ˜g‰Þxem­I«ì>§Û Wå¨N¿‚ Ýé’Âiy«ìEìo²Ó [¥g´•L’ªwÙ¢Ú\£õí3(“lìÖè6ØÙ$Yáóš{"Qè‘›y®É§5ö¶x‘¬°¿À©I§WiûæCrJÃÑêÃÜCûÔÉNhÆ$ï¶Ø[#~FZ# ܰè€ÂIð-s°ÎÇmÚMâU>W臨›˜»ücÇ:CE5eñ˜ÕÏD q“ö6×9Xv#mW8|-:Û´×ù¸ÌÁ]äý9¥!Õ”PQé³tD¨–áhµBão…d“?_ò¶Eç±™öîEÞ7mEaŸú!o_²³Á~dµE{NümñÇ+Þ¼àýýßåæË]泑N_V[´Tá´¿_ùýÞEì?Dð]ÒôT8ú_˜ßä±Ö¢ ô÷µ9AF´ÿÍ/í´h£B]%ÝäÏW¼)ÄŸaÚâ¹¹7O·Á°ôȹëzä!ªIü’·/øwQþF[4wSÓêè§UhS_Æ)´ÁA‹N‹Î2Ýýº4>Áiuhuhd½]ŠmQhRèÏãë÷U¬?ƒ—*š1ÛmTˆªØ•N-R8I¡Û´×ùP%½ôVu!øšjÊúTÈaÝ®tjG/0wÑÖØkÛB§™¤ÓfÌÚ¡]/Ú€- Mšû×kìY’B§1étm­w#‹–̈¶(4!‘D$æLÑ=º_*¢„(±(mQÕ9Üdg…} CÐ`qeŸÍꇗ¬ (+šk‰½ÝNí Aƒ¯Y8¥Ñ¥Ö³åê …>zÓÝ=«Îb.bÎkj=]N­È¥V( ÈþzÙ’UՔ绣[á…c…B³à¥zõ²%«ðõÈâäQT±¯Ð#/3¨Ð¯Ð/3°9‹¼œò€JŸJŸò øé°x…n… Áª@,^¡[¡Áªé°x……w¤x…ç>zž3Ÿ/öO„/ÇÿÂü¾Æ»äõ›ÇíLÁí wF:(tQè<¢ÐyD¡ó¯0gNãŸ1¯y’[П›{è'œÍ£}ò¢·x(þ+ÓøAJ5#г•ùt¦—•^¨½x…Æß.ÏÅ¢»s#Œ¿Ýç#‹ÅR¼B‰Â;R¼Âo@¹O¥Oe@Ùþé0÷”éWèW”‹_MZtû€khUb‰B·¦C«&B,Q¨ñOYèÒèQËlÎ¥¹GЫÑmpº Q8&ÇËzÔº4NY°9—jŸÓº zÖ”Q°  d‡ÔwØÜgEÚˆ¹‡ Ù_agsôrŒ ØòMi|E˜%DŠÐÎ@Ô>*$‰H¢QI°Eaާ÷X{ÇÖk¢ Á½µQ…(Z‘E±G!ã@Üc-¦y@êóssÐ nŽüY‚XõЍ Ęf›íUA5è–fØÜöÐ>i•?ÓÞ&nZ‚X¥Ðø)Õ¬‡¨:‡fe[ák¢L 5µÙ>¬“V- A¬J¤Œ¯.º,whuhÙN')´Ó¢Ó¢»l˵Ä»¢©tú–—feiuKŒ¿d…÷ÿàíKëR¨Á:…ŒÓé“*é…Xœøûc‹7¯ØÙ°.…lThÒé>Ñô/Ùâ´¿ßåÝ/–VïÂN…\°xΜæÉ#TBd\-X…,óþo^Yíkò­Eó4êA둎5w±«|jJ=Òû`bÑ#^»smî¯MŒåõ+ì­òIjsß;9Þ’yÜ'<¤n* ­D·¬ÿÍÇz£çï¦B~²Â¾TÈP¦ÃqŸ•„("¹õ>Þ×M~Ì>½êÔ>ŸWeŸŠ‡dŽŠ°Oå3«»üýv»ÅøçY¨{Q–…Z-æ²[L1L‹ìQ3{6í°q£=›‚A©Ýß’´©ÔÒPöl*#rHI¦T©OvN3:¯ˆÂ“³0N›¯³ÍxÐÊÎiV0qÉx_£óòý ½#]"[lë%?_zô¾> Î+œfZçÕ,BɶG4wáûùO~XD¡óˆBç…Î# G:(tQè<¢ÐyD¡óˆBç…Î# G:Ïwõ°ézrÂ1Ý“iŽà†Ì¶ïS¨AA ÀÓ‚ûò•ˆA1[qù™Ú9ž¯#;"9æõvN¹èÎL€‚„Ù¶x˜Y¡ãù:ô *&Vøš¢‹P~å4d3FáO³6[‚"±h<_ËdÀ+ìxüî̬Ðð±h<_Ëô€wcO AAAAAAAAA„ï•ÿ‡ËcÔ–òúIEND®B`‚libimager-perl-1.004+dfsg.orig/testimg/badplanes.bmp0000755000175000017500000000054612031434615021675 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/test_gimp_pal0000644000175000017500000000007412031434615022007 0ustar gregoagregoaGIMP Palette # test palette 255 250 250 snow (255 250 250) libimager-perl-1.004+dfsg.orig/testimg/bad_asc.pbm0000644000175000017500000000001412031434615021303 0ustar gregoagregoaP1 2 2 10 0xlibimager-perl-1.004+dfsg.orig/testimg/gradbad2.ggr0000644000175000017500000000007212031434615021402 0ustar gregoagregoaGIMP Gradient 1 1 2 3 4 5 6 7 8 9 10 Another invalid file libimager-perl-1.004+dfsg.orig/testimg/short24.bmp0000644000175000017500000000234512031434615021245 0ustar gregoagregoaBMæ6(°ë ë µ)µ)µ)´* ²/¬3¦9£@B™D”I‘L#‹R'…X)\+|a0xe1sj3qk7ql9µ)µ)µ)´+ ®1ª6¥:¢@šC•G‘K"O&‰S(‚Z*|`.xd2th6pl7lp8kr9µ)´)³+ ±0 «6¦:¢?œC•I‘L"Q&‰T(ƒZ*}`.xd2th6pl8kr9ht;dx?´* ². ®1¬6¦:¢?œC”IŽO"ŒR&‰W(ƒZ*}`.xd2th6pl8jr:dx?bz@a|B²1­2ª6¦:¢?œC”IO"‰S&…W(ƒ[*}`.xd2th6pl8jr:dx?`|A[CZƒG¬7§8¥:¢?œC”IO"‰S&…W([*|`.xd2sh6pl8jr:dx?`|A[CW…GS‰I¤;¢?AšC”IO"‰S&…W([*|`.xd2sh6ml8jr:dx?`|B[CW…GQ‰ILŒJ@›C–G“JO"‰S&…Y)[*|`.xd2rh6ll8hr:cx?`|CZGW…HQ‰IKKH‘O™C•G‘K!O"‰S&…Z*_.|a/xd2rh6ll8hr:bx?\|CYGT…IP‹JJKD‘OC”Q”H‘K"O&‰S'…Z*`.|c0xe2rj6lm8hs:bx?[|CWGS…IOŒKI‘OC”P@•R@™S‘L"Q&‰T(„Z*`.{d1uh2qk6lp8ht:bz?[}CWGS…IOŒKI‘OC•Q?™S:œW9X‹S'‰W(ƒZ*}`.zd2th6pl7jr9du;a{?[€CW‚GR…IOŒKI‘OC•Q?™S9W3¢Y1¤Z…X)ƒ[*}`.xd2th6pl8jr:dx?`|@[CW„GQ†ILŒKI‘OC•Q?™S8žW2¤Z.¦\*ª`\*|`.xd2th6pl8jr:dx?`|A[CW…GQ‰IKŒKG‘OC•Q?™S8žW1¤[+ª`)­a'®b{a/xd2sh6pl8jr:dx?`|A[CW…GQ‰IJKC‘OA•Q?™S8žW1¤[+ª`(®b&²c"³dxe2rj6mm8js:dx?`|B[CW…GQ‰IJKC‘O?•Q:™S7žW1¤[*ª`'®b&²d"µh¶iql7lp8hs:cx?`|CZGW…HQ‰IJKC‘O?•Q:™S6žW0¤[*ª`&®b"´d ·h¼j½kjs:ht;bx?\|CYGT…IP‰JJKC‘O?•Q:™S6W1£Z*ª`&®b"µdºh¾kÃlÄpdy@by@\|CYGS…IO‰JIKC‘O?•R:™S6W2¢Y.§\(­a"³dºh¾lÃpÅqÆrc{Ba|C[GX„IR‰JJŒKD‘O@”R;™W8X3¢Y0¥[+«`'²c!¶h½kÃpÅrÆsÆlibimager-perl-1.004+dfsg.orig/testimg/imager.pbm0000644000175000017500000000022112031434615021173 0ustar gregoagregoaP4 62 17 ÀÀÀÆçÀ{°ø<Çÿáÿñþ<Ç(Pë ë ŒR%9žU°€0`$Ð °—p*ðUð¯ðWð_ðð*ßðEÿð-ð[ÿð·ÿðoÿðlibimager-perl-1.004+dfsg.orig/testimg/short_bin16.pgm0000644000175000017500000000010012031434615022066 0ustar gregoagregoaP5 # CREATOR: The GIMP's PNM Filter Version 1.0 2 2 65535 ÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/testimg/alpha16.tga0000644000175000017500000000021212031434615021160 0ustar gregoagregoa !‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|‰€‰|libimager-perl-1.004+dfsg.orig/testimg/filltest.ppm0000644000175000017500000000134312031434615021601 0ustar gregoagregoaP6 22 11 255 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/testimg/scale.ppm0000644000175000017500000007270212031434615021051 0ustar gregoagregoaP6 # CREATOR: XV Version 3.10 Rev: 12/16/94 118 85 255 øøøøøøøøøøøøøøøøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷óæáñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xô¨Tô¨Tô¨Tô¨Tù¨Xú­Qú­Qú­Qú­QfDPùÓ¢÷÷÷÷÷÷øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O­tS=4%=4%=4%=4%=4%=4%ùÓ¢üüüùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qü«TùÓ¢úúúúúúúúúúúúøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷óæáñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ù¨Xñ¤Vô¨Tô¨Tù¨Xô¨Tô¨Tô¨Tù¨Xú­QfDPùÓ¢÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôõõôõõôôôôôôôõõôõõôõõôõõùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O=4%=4%=4%=4%;*"=4%;*"=4%ûûûùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Qú­Qú­Qú­Qú­Qú­Qü«Tù¨Xù¨Xù¨Xü«Tú¹cúúúúúúúúúúúú÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ùÓ¢ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ñ¤Vô¨Tô¨Tô¨Tù¨Xô¨Tô¨TfDPÞª“÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oô¨T9#;*"=4%=4%=4%;*";*"=4%­tSùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Qú­Qü«Tü«Tü«Tù¨Xù¨Xù¨Xù¨XùÓ¢úúúúúúúúúúúú÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ùÓ¢ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ô¨Tô¨Tô¨TfDP­tSôõõôõõ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°OÞH9#9#=4%;*"=4%;*";*";*"=4%ÞHû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Qú­Qú­Qü«Tü«Tù¨Xô¨TùÓ¢úúúúúúúúúûûû÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Þª“ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[fDPfDPôõõôõõôõõôõõôõõôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ùÓ¢ú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oô¨T9#;*"9#;*";*"9#=4%;*";*"ÞHû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Qú­Qú­Qú­Qú­Qü«Tú¹cúúúúúúûûûûûûûûû÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ùÓ¢ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Q9#;*"9#=4%;*";*"9#;*"=4%ÞHû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Qú­Qü«Tü«Tú¹cúúúûûûûûûûûûûûû÷÷÷÷÷÷÷÷÷ôõõ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Þª“ñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPÞª“ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôú¹cû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oô¨T9#;*"9#9#=4%9#;*";*"9#­tSû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Qú­Qú­Qü«Tü«Tü«Tü«TùÓ¢ùùùúúúúúúúúúúúúôõõôõõôõõôõõôõõôõõôõõôõõôõõôõõôõõôõõôõõôôôùÓ¢ó¢[ñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ú¹cú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O­tS;*";*"9#9#9#9#9#9#9#Ø…Jû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tú­Qü«Tü«Tü«Tü«Tô¨TøøøøøøøøøøøøùùùùùùôõõôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ú¹cú­Qú­Qú­Qú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oô¨T=4%;*";*"9#9#9#9#9#;*"fDPû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qü«Tü«Tü«Tü«Tü«Tù¨Xù¨Xù¨XùÓ¢÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷øøøôõõôõõôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñŸZñ¡\fDPfDPÞª“ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ú¹cú­Qü«Tú­Qú­Qú­Qú­Qú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oô¨T;*";*";*"9#9#9#9#9#9#9#;*";*"=4%­tS„+;*"„+ô£Uû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tú­Qü«Tü«Tü«Tü«Tü«Tü«Tù¨Xù¨Xù¨Xù¨Xù¨XùÓ¢ôôôôõõôõõôõõôõõ÷÷÷ôõõôõõôõõôõõôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\fDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ú¹cù¨Xù¨Xù¨Xü«Tü«Tú­Qú­Qú­Qú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oô¨T=4%;*"9#9#9#9#9#9#9#9#=4%;*";*";*"=4%;*";*";*"„+ô£Uû°Oû°Oû°Oû°Oû°Oü«Tû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xâqôôôôôôôôôôôôôôôôôôôôô÷÷÷÷÷÷÷÷÷ôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZó¢[ñŸZñŸZñŸZñŸZñŸZó¢[fDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¡\ó¢[ó¢[ó¢[ù¨Xù¨Xù¨Xù¨Xù¨Xü«Tü«Tú­Qü«Tú­Qú­Qú­Qû°Oô¨T;*";*"9#;*"9#9#9#;*"9#9#Þª“­tS9#9#=4%;*";*"=4%„+„+Ø…Jû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tù¨Xù¨Xù¨Xù¨Xù¨XùÓ¢ôôôôôôôôôôôôôôôôôôôôô÷÷÷÷÷÷÷÷÷ôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZó¢[ó¢[ñŸZñŸZñŸZñŸZfDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xü«Tü«Tú­Qô¨T;*"9#9#9#;*";*"9#9#=4%=4%óæáôôô=4%9#9#9#;*";*"„+„+„+„+û°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tù¨Xù¨Xù¨Xñ¡\ôôôôôôôôôôôôôôôôôôôôôôôô÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôõõôõõôôôôôôôôôôôôôôôôôôùÓ¢ñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZó¢[ó¢[ñŸZñŸZfDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¡\ó¢[ó¢[ñŸZó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xô£U=4%9#;*";*";*";*"9#9#=4%Þª“ôôôôôôùÓ¢9#;*";*"9#=4%;*";*"„+„+ñ¤Vû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tù¨Xù¨XùÓ¢ôôôôôôôôôôôôôôôôôôôôôôõõ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôôôôôôôôôôôôôôôùÓ¢ñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñ¤VñŸZfDPfDPÞª“ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ô£UñŸZô£Uñ¤Vñ¤VñŸZó¢[ó¢[ó¢[ó¢[ù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xñ¤V=4%9#9#9#;*";*";*"9#;*"Þª“ôôôôôôôôôÞª“9#;*";*";*";*";*";*"„+„+û°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tù¨Xôôôôôôôôôôôôôõõôõõôõõ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¤Vñ¤VñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñ¤Vñ¤VñŸZñŸZñ¤VfDPfDPÞª“ôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ó¢[ñ¤Vô£Uñ¤Vô£Uô£Uô£Uù¨Xô£Uô£Uô£Uô£Uó¢[ô£Uô£Uù¨Xù¨Xñ¤V=4%;*"9#;*";*";*";*"9#9#Þª“ôôôôôôôôôôôô=4%9#9#9#9#9#„+„+„+­tSû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«TÞª“ôõõôõõôõõôõõôõõ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñ¤Vñ¤Vñ¤VfDPfDPÞª“ôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ó¢[ô£Uó¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xù¨Xù¨Xù¨Xù¨XñŸZ=4%;*"9#9#;*";*";*";*"9#Þª“ôôôôôôôôôôôôôôô9#;*";*";*";*";*"„+„+„+ÞHü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tù¨Xôõõ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷øøøùùùúúúúúú÷÷÷÷÷÷ôõõôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤VfDPfDPùÓ¢ôôôôôôôôôôôôôôôôôôôôôùÓ¢ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xù¨Xù¨Xù¨XñŸZ=4%9#9#;*";*";*";*"9#9#Þª“ôôôôôôôôôôôôôôôùÓ¢9#;*"9#9#9#;*";*"„+­tSü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tù¨Xü«Tú¹c÷÷÷÷÷÷÷÷÷øøøùùùùùùúúúûûûûûû­tS÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôôôôôôôôôôôôôôôôôôôôôùÓ¢ñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤VfDPfDPÞª“ôôôôôôôôôôôôôôôôôôùÓ¢ó¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xù¨Xù¨Xô£Uô£U9#9#9#9#;*";*";*";*"9#Þª“ôôôôôôôôôôôôôôôôôô­tS9#9#9#9#9#9#=4%„+ü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tù¨Xü«TóæáùùùúúúúúúûûûûûûûûûûûûûûûóæáfDP÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôôôôôôôôôôôôôôôôôôôôôùÓ¢ñŸZñŸZñŸZñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤VfDPfDPÞª“ôôôôôôôôôôôôôôôùÓ¢ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xô£Uù¨Xô£U=4%9#9#;*";*";*";*"9#9#­tSôôôôôôôôôôôôôôôôôôôôôfDP9#9#9#9#9#9#9#­tSü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tó¢[÷÷÷÷÷÷øøøùùùùùùúúúúúúúúúóæá­tSfDP÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôõõôôôôôôôôôùÓ¢ñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VfDPfDP­tSôôôôôôôôôôôôùÓ¢ñ¡\ô£Uñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xô£Uô£U=4%9#;*";*";*";*";*";*"9#­tSôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ùÓ¢óæáóæáùÓ¢ùÓ¢=4%ô£Uü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«TùÓ¢÷÷÷÷÷÷÷÷÷øøøùùùùùùúúúûûûùÓ¢fDPfDPøøøøøøøøøøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ùÓ¢ñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñ¤Vñ¤VñŸZñŸZñŸZñ¤VfDPfDPùÓ¢ôôôôôôôôôùÓ¢ñ¡\ô£UñŸZñ¤Vô£Uó¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xô£Uñ¤V=4%9#9#;*";*";*";*"9#9#­tSôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tâqôôôôõõ÷÷÷÷÷÷øøøøøøùùùúúúúúú­tSfDPfDPúúúùùùùùùùùùøøøøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ùÓ¢ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñ¤Vñ¤VfDPfDPùÓ¢ôôôôôôùÓ¢ñ¤Vñ¤Vó¢[ñ¤Vô£Uó¢[ñ¤Vô£Uñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xñ¤V=4%9#9#;*";*";*";*";*"9#­tSôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôô¨Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«TùÓ¢ôôôôôôôôôôõõ÷÷÷÷÷÷÷÷÷÷÷÷ùÓ¢fDPfDPfDPûûûúúúúúúúúúúúúúúúúúúúúúùùùùùùùùùùùùùùùùùùùÓ¢ñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZó¢[ñŸZñŸZfDPfDPùÓ¢ôôôùÓ¢ñ¡\ñŸZó¢[ñŸZñ¤VñŸZó¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨X=4%9#9#;*";*";*"9#9#9#­tSôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tâqôôôôôôôôôôôôôôôôôôôõõôõõ÷÷÷fDPfDPfDPfDPüüüüüüûûûûûûûûûûûûûûûûûûûûûûûûûûûûûûúúúúúúùÓ¢ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZó¢[ñŸZñŸZfDPfDPùÓ¢ùÓ¢ñŸZñŸZó¢[ó¢[ó¢[ñŸZñ¤Vó¢[ô£Uñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨XØ…J9#;*";*";*";*"9#9#;*"­tSóæáôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ù¨Xü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«TùÓ¢ôôôôôôôôôôôôôôôôôôôõõôõõÞª“fDP­tS­tSfDPþþþþþþþþþþþþþþþýýýýýýýýýýýýüüüüüüüüüüüüýýýùÓ¢ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñ¤Vñ¤VfDPfDPÞª“ñŸZó¢[ñŸZó¢[ñŸZó¢[ñ¤VñŸZô£UñŸZñŸZô£Uô£Uô£Uô£Uô£Uô£Uù¨XÞH9#;*";*";*";*"9#9#;*"­tSóæáôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tú¹côôôôôôôôôôôôôôôôôôôôôôôôóæá­tSfDPfDPfDPfDPÊÄùËÍüËÍüËÍüÿÿÿÿÿÿþþþþþþþþþþþþÿÿÿÿÿÿÿÿÿÿÿÿùÓ¢ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤VfDP­tSñ¤Vñ¤Vñ¤VñŸZó¢[ó¢[ó¢[ñŸZó¢[ô£UñŸZô£Uô£Uô£Uù¨Xô£Uô£Uô£UÞH9#;*";*";*";*";*"9#9#­tSôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôú¹cü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«TùÓ¢ôôôôõõôõõôõõôõõôõõôõõôõõùÓ¢fDPfDPfDPfDP=4%·¸ý·¸ý·¸ý·¸ý¿¿þ·¸ý·¸ý·¸ý·¸ý·¸ý¯®ý¯®ý¯®ý¯®ýùÓ¢ñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤V­tSñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vô£UñŸZô£Uñ¤Vñ¤Vô£Uñ¤Vô£Uô£Uô£Uô£Uô£Uô£U9#;*";*";*"9#9#9#9#­tSôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôùÓ¢ü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«T­tS÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷­tSfDPfDPfDPfDP=4%‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‰‰ÿ‰‰ÿ‰‰ÿ‰‰ÿ‰‰ÿ‘‘ÿ‘‘ÿ‘‘ÿýýØÓïñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vô£Uñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£UñŸZ=4%;*";*";*"9#9#;*";*"fDP÷÷÷÷÷÷÷÷÷ôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôõõóæáü«Tü«Tü«Tû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tû°Oü«Tü«Tü«Tü«Tü«Tü«TùÓ¢øøøøøøøøøøøøùùùùùùùùùùùùôõõfDPfDPfDP=4%=4%;*"mmýmmýrrÿrrÿrrÿrrÿrrÿwwþ||þ……ü‰‰ÿ‘‘ÿ‘‘ÿýÊÄùñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZñ¤VñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vô£Uñ¤Vñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£UñŸZ=4%;*";*";*"9#9#;*";*"­tSùùùùùùøøøøøøøøøøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷øøøøøøøøøøøøøøøøøøú¹cü«Tû°Oü«Tû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tú¹cúúúúúúúúúúúúúúúùùùùùùùùùùùùùÓ¢fDPfDP=4%=4%9#=4%\\þ\\þ^^ÿ^^ÿddþjjýmmýmmýrrÿrrÿwwþ||þ……ü‰‰ÿ·¸ýñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¤VñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vô£Uñ¤Vñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£U=4%;*";*";*";*"9#;*";*"fDPûûûüüüüüüüüüüüüüüüûûûûûûûûûûûûûûûûûûûûûúúúúúúúúúúúúùùùùùùùùùùÓ¢ü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«Tü«TÞHóæáûûûûûûúúúúúúúúúúúúûûûûûûûûû­tSfDP=4%=4%=4%;*"=4%UUÿUUÿUUÿ\\þ^^ÿddþjjýmmýrrÿrrÿwwþwwþwwþwwþ£¢ûñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vô£Uñ¤Vñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uñ¤VfDP;*";*";*";*"9#9#;*"­tSØÓïÿÿÿþþþþþþþþþþþþþþþþþþýýýþþþþþþþþþþþþýýýýýýýýýýýýýýýýýýýýýüüüü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oü«TÞª“üüüýýýýýýýýýýýýüüüüüüüüüüüüüüüÞª“=4%fDPfDP9#9#fDP\\þ^^ÿ^^ÿ^^ÿddþddþddþddþjjýmmýrrÿwwþwwþwwþ—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñ¤Vñ¤VñŸZñ¤Vñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£UfDP;*";*";*"9#9#9#;*"fDP¨¨ý¯®ý·¸ý·¸ý·¸ý·¸ý¿¿þ¿¿þÊÄùÊÄùÊÄùÊÄùÊÄùËÍüËÍüËÍüÿÿÿÿÿÿËÍüþþþþþþú¹cü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O­tSÊÄùËÍüËÍüËÍüËÍüËÍüþþþþþþËÍüËÍüËÍüÞª“;*"=4%9#9#9#9#^^ÿ^^ÿ^^ÿddþddþddþjjýmmýrrÿrrÿwwþrrÿwwþwwþ·¸ýñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZñŸZñŸZó¢[ó¢[ñŸZñŸZñŸZñ¤Vñ¤VñŸZñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uñ¤VfDP;*";*"9#;*"9#9#;*"=4%……ü……ü‰‰ÿ‰‰ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿ‘‘ÿý£¢û£¢û¨¨ý¨¨ýü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oñ¤V—﨨ý¨¨ý£¢û£¢ûýýýý‘‘ÿ‘‘ÿ‰‰ÿ—ï=4%9#=4%9#;*"9#^^ÿ^^ÿddþddþmmýmmýrrÿrrÿwwþwwþ||þwwþwwþwwþÊÄùñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤VñŸZñ¤Vñ¤Vñ¤Vó¢[ñ¤Vô£Uô£Uô£Uô£U­tS;*";*";*"9#;*";*";*";*"cdõddþ^^ÿ^^ÿ^^ÿ^^ÿ\\þ^^ÿ^^ÿ^^ÿ\\þ^^ÿ\\þ\\þ\\þ\\þ\\þ^^ÿ^^ÿddþddþ^^ÿÞª“ü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°OfDP‚úwwþmmýddþ\\þ\\þ\\þ\\þ\\þUUÿUUÿUUÿTTü=4%;*"=4%9#9#=4%^^ÿddþddþddþddþddþddþddþddþjjýmmýmmýmmýrrÿ¯®ýñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZó¢[ó¢[ñŸZñ¤Vó¢[ñ¤Vñ¤VñŸZó¢[ô£U­tS;*";*";*"9#;*";*";*";*"i\ÇTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTýTTýTTýTTþTTþTTþTTþTTþTTþ{|øü«Tü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O­tSFX¾\\þUUÿUUÿUUÿTTþTTþTTþTTþTTþTTþTTþTTþTTþ=4%9#9#=4%9#;*"UUÿUUÿUUÿUUÿ\\þ^^ÿddþjjýmmýrrÿrrÿrrÿwwþwwþ—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZñŸZó¢[ñŸZñŸZó¢[ñŸZñ¤Vñ¤V­tS;*"9#;*"9#;*";*";*"=4%FX¾TTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýjjýù¨Xü«Tü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Q=4%TTþTTþTTþTTþTTþTTþTTþTTþTTþTTýTTýTTýTTýTTýcdõ9#9#9#9#;*"^^ÿ^^ÿddþddþjjýmmýjjýjjýmmýmmýmmýrrÿrrÿrrÿØÓïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZó¢[ó¢[ó¢[ó¢[ñŸZñ¤V;*";*";*";*"9#;*";*";*"FX¾TTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýâqü«Tü«Tú­Qü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O=4%cdõTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTý=4%9#;*"9#=4%mmýmmýmmýmmýrrÿrrÿmmýmmýmmýmmýrrÿmmýmmýmmý—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[­tS;*"9#9#9#;*";*";*"9#i\ÇTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýmmýü«Tü«Tü«Tú­Qú­Qü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°OÞH=4%SSùTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTý\\þ=4%9#9#fDPddþddþjjýmmýmmýmmýmmýrrÿrrÿmmýjjýddþ^^ÿ^^ÿ—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ðŸ\;*";*"9#;*";*";*";*";*"FX¾TTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTþâqü«Tü«Tü«Tü«Tú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O­tS[WæTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTþTTþTTþTTþTTþTTþi\Ç;*"fDPfDPddþddþjjýjjýmmýmmýmmýmmýmmýmmýjjýddþ^^ÿ\\þ‹Šúñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[­tS9#9#9#;*";*";*"fDP;*"TD}TTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTýTTýTTýTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþÊÄùü«Tü«Tü«Tü«Tü«Tú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oô¨TFX¾TTýTTýTTýTTýTTýTTýTTýTTýTTþTTþTTþTTþUUÿUUÿ\\þ^^ÿddþddþjjýi\ÇfDPfDPjjýddþddþddþ^^ÿ^^ÿ^^ÿ\\þ\\þUUÿUUÿUUÿUUÿUUÿ—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ñ¤Vô¨Tô¨Tô¨Tñ¤Vó¢[ó¢[ñŸZ;*";*"=4%=4%;*";*";*";*"fDPTTüUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTý{|øü«Tü«Tü«Tü«Tü«Tü«Tú­Qü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Q;*"SSùTTýTTýTTýTTýTTýTTþTTþTTþUUÿUUÿ^^ÿddþrrÿwwþ……ü‰‰ÿ‘‘ÿ‘‘ÿ‘’üfDPfDPfDPUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿTTþTTþTTþTTþ……üñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ô¨Tô¨Tô¨Tô¨Tù¨Xô¨Tô¨Tù¨Xù¨Xù¨Xù¨Xô¨TfDP9#;*";*";*";*";*";*"TD}TTüUUÿUUÿUUÿUUÿUUÿUUÿUUÿTTþFX¾FX¾##aTD}(&iFX¾RR÷TTþTTþTTþTTþTTþTTýTTýTTýù¨Xü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tû°Oü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O­tSFX¾TTþTTþTTþTTþUUÿ\\þddþjjý||þ‚ú‘‘ÿ‘‘ÿýý¨¨ý¨¨ý·¸ý·¸ý·¸ý·¸ýfDPfDPfDPTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþ……üñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ô¨Tô¨Tô¨Tú­Qú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oú­Qú­Q­tS9#;*";*";*";*";*"9#fDPTTüTTþTTþTTþTTþTTþTTþTTüTD}        TTýTTýTTýTTýTTýTTýTTýÞª“ü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oô¨TyoÎUUÿ\\þ^^ÿmmýrrÿ……ü‘‘ÿý¨¨ý¯®ý·¸ý¿¿þÊÄùËÍüËÍüËÍüËÍüÿÿÿÿÿÿÿÿÿÞª“fDPfDP­tSTTýTTýTTýTTýTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþ‹Šúó¢[ó¢[ó¢[ñ¤Vô¨Tô¨Tô¨Tô¨Tô¨Tú­Qú­Qú­Qú­Qû°Oú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°O­tS=4%9#;*";*";*";*"9#fDPcdõTTþTTþTTþTTþTTþTTþSSù7        FX¾TTýTTýTTýTTýTTýTTý—ïü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O­tSmmýrrÿ‚ú‘‘ÿ‘’ü£¢û¯®ý·¸ý¿¿þËÍüËÍüËÍüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþþþþýýýùùùfDPfDPfDPù¨XTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTý—ïô¨Tô¨Tô¨Tô¨Tú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qû°Oú­Qû°Oû°Oû°Oû°Oû°Oô¨T;*";*";*";*"9#;*"9#;*"SSùTTýTTýTTýTTýTTýTTý[Wæ7    7   7TTýTTýTTýTTýTTýTTýjjýû°Oû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tû°Oû°Oú­QyoÎ||þ‰‰ÿ‘’ü¨¨ý·¸ý¿¿þÊÄùËÍüËÍüËÍüËÍüÿÿÿþþþþþþýýýýýýýýýýýýýýýýýýÞª“fDPfDPðŸ\ù¨XTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTýTTý—ïô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qû°Oû°Oú­QfDP;*";*";*";*"fDP9#;*"cdõrrü‹Šú‹Šú—ú—ï—ï­tSìAZÕ1D„+fDPfDP=4%   QQôTTýTTýTTýTTýTTýTTýú¹cû°Oû°Oû°Oû°Oû°Oû°Oú¹cú¹cû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«TØ…Jý¨¨ý·¸ý¿¿þËÍüËÍüÿÿÿÿÿÿþþþþþþþþþýýýýýýüüüûûûûûûûûûûûûúúúúúúúúúfDPfDPfDPù¨Xù¨XTTýTTýTTýTTýTTýTTýTTüTTüTTüTTüTTüTTü‹Šúó¢[ó¢[ó¢[ô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tù¨Xú­Qú­Qú­QØ…J;*";*";*"9#;*";*";*"ìAZúCXúCXúCXúCXúCXúCXúCXúCXúCXúCXúCXìAZìAZö3Hö3Hö3HÕ1DÕ1D{|øcdõ\\þTTýTTýTTýÞª“û°Oû°Oú¹cû°Oû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cú¹cú¹cû°Oü«Tü«Tü«Tü«Tü«Tü«Tô¨TÞª“ËÍüÿÿÿþþþþþþþþþþþþýýýýýýýýýüüüûûûûûûúúúúúúúúúúúúúúúúúúùùùùùùÞª“fDP=4%ñ¤Vù¨Xù¨XTTýTTýTTüTTüTTüTTüTTüTTüTTüTTüTTürrüñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tù¨Xô¨TÞH=4%;*";*";*"9#;*";*"ìAZö3HúCXö3HúCXúCXúCXúCXúCXö3Hö3HìAZìAZö3Hö3Hö3Hö3Hö3HúCXö3HÕ1DÕ1DìAZìAZyoÎÊÄùû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cû°Oú¹cú¹cú¹cú¹cú¹cú¹cû°Oû°Oü«Tü«Tü«Tü«Tü«TâqËÍüÿÿÿþþþþþþþþþþþþýýýýýýýýýýýýüüüüüüüüüüüüüüüüüüûûûûûûûûûúúú÷÷÷fDPfDP­tSù¨Xù¨Xù¨XTTýTTüTTüTTüTTüTTüTTüTTüTTüTTü—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ô¨Tô¨Tô¨Tó¢[ó¢[ó¢[ñ¤Vó¢[ù¨X­tS=4%;*";*"9#;*"=4%ùÓ¢Þª“âqúCXúCXúCXúCXúCXúCXö3HúCXúCXö3Hö3HìAZìAZö3HÕ1DÕ1D„+„+Õ1DÕ1D„+Õ1DúCXû°Oû°Oû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cû°Oû°Oû°Oû°Oü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tô¨TÊÄùÊÄùÿÿÿÿÿÿþþþþþþþþþþþþþþþþþþþþþþþþýýýüüüûûûûûûúúúùùùøøø÷÷÷÷÷÷Þª“fDPfDPù¨Xù¨Xù¨Xù¨XTTüTTüTTüTTüTTüTTüTTüTTüTTü‚úâqñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ÞH;*";*";*"9#;*";*"fDP­tS­tSâqúCXúCXö3HúCXìAZÕ1Dö3Hö3HìAZÕ1Dö3Hö3HÕ1D„+„+Õ1D„+„+„+„+„+Ø…Jû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cû°OÞª“·¸ý·¸ý¿¿þËÍüÿÿÿþþþýýýýýýüüüûûûúúúùùùùùùøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôôôfDPfDPô¨Tü«Tü«Tü«Tü«TTTüTTüTTüTTüTTüTTüTTüTTü‚úñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\­tS;*";*"9#;*";*"„+ùÓ¢ôôôóæáúCXúCXö3HúCXö3Hö3HìAZÕ1Dö3H„+ö3HÕ1D„+„+„+„+„+„+„+„+„+ÞHû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cØÓïýýýýýýüüüüüüûûûûûûúúúúúúùùùøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ôõõôõõôõõôôôôôô­tSfDP­tSú­Qû°Oü«Tú­Qú­QTTüTTüTTüTTüTTüTTýTTý‚úñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDP;*"9#;*";*";*"úCXúCXúCXúCXúCXö3HúCXúCXìAZÕ1DìAZìAZìAZÕ1D„+„+„+„+„+„+„+„+„+„+Ø…Jú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cùÓ¢úúúùùùùùùøøøøøøøøø÷÷÷÷÷÷÷÷÷ôõõôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôÞª“fDP=4%û°Oû°Oû°Oû°Oû°Oû°OTTüTTüTTüTTýTTýTTý‹Šúñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZ;*"9#=4%;*"„+Õ1Dö3HúCXö3Hö3HúCXö3HúCXö3HÕ1DÕ1DÕ1DÕ1D„+„+„+„+„+„+„+„+„+„+„+Õ1Dù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹cú¹c÷÷÷ôõõôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôóæáfDP=4%ñ¤Vû°Oû°Oû°Oû°Oû°Oû°OTTýTTýTTýTTýTTý—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZ;*"9#;*";*"„+ö3HúCXúCXö3HúCXúCXìAZÕ1Dö3HÕ1DÕ1DìAZÕ1D„+„+„+„+„+„+„+„+9#9#Õ1Dù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oú¹cú¹cú¹cú¹cú¹cú¹cú¹cÞª“ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôÞª“fDPØ…Jû°Oû°Oû°Oû°Oû°Oû°Oû°OTTýTTýTTýTTý……üñ¡\ñ¡\ó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\9#;*";*";*"ìAZö3HìAZö3HúCXö3HúCXìAZ9# 9#„+ìAZÕ1D„+„+„+9#„+„+9#  ÞHù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°Oú¹cú¹cóæáôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôóæáfDPfDPû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°OTTýTTýTTþ—ïñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZ9#;*";*"„+ö3Hö3HìAZö3Hö3Hö3HÕ1DÕ1D    Õ1DÕ1D„+„+„+„+9#  9#ÞHù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xü«Tù¨Xù¨Xü«Tü«Tü«Tû°Oû°Oû°Oû°Oû°OùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôfDP=4%û°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°OTTþTTþrrüñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZ9#;*";*"[WæyoÎÕ1DÕ1Dö3HìAZÕ1DÕ1DÕ1D„+   „+„+„+„+„+9#  9#ñŸZù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tù¨Xü«Tü«Tü«Tü«Tú¹cùÓ¢ôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôÞª“fDPÞHû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°OTTþ……üâqñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZ;*"=4%TD}TTýTTý\\þTD}„+„+„+„+„+„+„+9#9#„+„+9#9#    ÞHô£Uù¨Xù¨Xô£Uô£Uù¨Xô£Uù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tü«Tü«Tü«Tú¹côôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôô÷÷÷÷÷÷ùùùùùùùùù÷÷÷fDP­tSû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°O……üñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZ;*";*"i\ÇTTýTTþTTþTTþTTþcdõTD}9#„+„+„+„+„+„+„+9#9#   Ø…Jô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tü«Tü«Tü«Tù¨Xü«Tù¨Xü«Tü«Tô£UùÓ¢ôôôôôôôôôôôôôõõôõõ÷÷÷÷÷÷÷÷÷øøøøøøùùùùùùùùùùùùúúúûûûüüüüüü­tS­tSô¨Tü«Tü«Tü«Tü«Tù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñŸZñŸZ=4%=4%yoÎ^^ÿjjýjjýwwþ||þ‘‘ÿ‘‘ÿý¨¨ýÊÄù­tS;*"9#9#„+9#   ­tSô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tü«Tô£U÷÷÷÷÷÷÷÷÷øøøøøøùùùúúúúúúûûûËÍüËÍü¿¿þÊÄù¿¿þ¿¿þÊÄùÊÄù¿¿þ¿¿þØÓïfDPô£Uù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDP—﨨ý·¸ý¿¿þËÍüËÍüËÍüËÍüýýýüüüüüüûûûûûûûûûùÓ¢Þª“fDP  ­tSô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xù¨Xù¨Xù¨Xü«Tü«Tü«Tü«Tü«Tü«Tü«Tú¹cýýýËÍüÊÄù·¸ý¨¨ý‘’ü‰‰ÿ……üwwþmmýwwþrrÿrrÿmmýrrÿddþddþddþmmýfDPô£Uù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xô£Uù¨Xó¢[ñ¤Vñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPÞª“úúúúúúùùùùùùùùùøøøøøøøøøøøøøøøøøøøøø÷÷÷÷÷÷÷÷÷÷÷÷fDPÞHô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô¨Tü«Tô£Uô¨Tô¨Tô¨Tô¨Tü«Tü«Tü«TùÓ¢¨¨ýý‰‰ÿ||þmmý^^ÿ\\þ^^ÿ\\þUUÿUUÿTTþTTþTTþTTýTTýTTýTTüfDP­tSô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨X—ïñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñ¡\ñ¡\fDPfDPùÓ¢ôõõôôôôõõôõõôôôôôôôõõôõõôôôôôôôôôôôôôôôôôôôôôùÓ¢ú¹có¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô¨Tü«Tô£Uô¨Tù¨Xô¨Tô¨Tô£U·¸ý||þmmý\\þUUÿTTþTTþTTþTTýTTýTTüTTüTTüTTüSSûSSûSSûSSûTD}­tSô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uñ¡\cdõñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPÞª“ôôôôôôôôôôôôôôôôôôôôôôôôôôôôõõôõõôõõ÷÷÷÷÷÷ùÓ¢ó¢[ñ¤Vó¢[ñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô¨Tô£Uô¨Tô¨Tô¨Tô£Uô£Uô¨T\\þUUÿTTþTTþTTþTTþUUÿUUÿTTþTTþTTþTTþTTþTTýTTýTTýTTýcdõfDPñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£U—ïSSûó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPÞª“÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷øøøùùùùùùùùùùùùúúúúúúúúúùÓ¢ú¹cñ¤Vó¢[ñ¤Vó¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uù¨Xñ¡\TTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTþTTýTTýTTýTTýcdõfDPñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£UTTýTTýñ¡\ñ¡\ñ¡\ó¢[ó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDPfDPùÓ¢ûûûûûûüüüýýýüüüýýýýýýýýýýýýþþþýýýýýýÞª“ó¢[ó¢[ó¢[ó¢[ó¢[ñŸZô£Uô£Uñ¤VñŸZô£Uô£Uô£Uô£Uô£Uñ¤Vô£Uù¨Xô£Uù¨Xô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô¨TÞª“UUÿUUÿUUÿUUÿUUÿUUÿUUÿTTþTTþTTþTTþTTþTTþTTþTTþ\\þfDPÞHô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£U‹Šúwwþ‚úñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ñ¡\ï¡\ÞHó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ï¡\fDPfDP—ï¿¿þ¯®ý¯®ý£¢ûý‘‘ÿ‘‘ÿ……ü‘‘ÿ‘‘ÿ‘‘ÿÞª“ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ñŸZó¢[ó¢[­tS„+ó¢[ù¨Xô£Uù¨Xù¨Xù¨Xù¨Xù¨Xô£Uù¨Xô£Uô£Uô£Uô£Uù¨Xù¨Xù¨Xù¨XÞª“^^ÿ\\þ^^ÿddþddþmmýrrÿmmýmmýddþ^^ÿ\\þ\\þ\\þ\\þ­tS­tSô£Uô£Uô£Uô£Uô£Uô£Uù¨Xô£Uô£Uù¨Xô£Uô£Uô£UÞª“¨¨ýý‰‰ÿñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ï¡\=4%­tSó¢[ñ¤Vñ¤Vô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tñ¤Vñ¤Vô¨Tñ¤Vó¢[fDPfDPcdõ\\þ\\þTTýTTýTTýTTýTTýTTýTTýcdõÞª“ù¨Xù¨Xù¨Xù¨Xñ¤Vó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xù¨Xù¨Xó¢[ù¨XØ…J9#fDPù¨Xó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨XØÓïmmýjjýddþ\\þUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿUUÿyoέtSù¨Xô£Uù¨Xù¨Xù¨Xô£Uù¨Xù¨Xô£Uù¨Xô£Uô£Uó¢[ñ¡\‘‘ÿ‘‘ÿ……ümmýñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ðŸ\fDP=4%­tSñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ô¨Tô¨Tô¨Tô¨Tô¨TfDPfDPi\ÇSSûSSúSSúSSúSSúSSúSSûSSûcdõô¨Tô¨Tô¨Tô¨Tô¨Tô¨Tù¨Xù¨Xù¨Xô¨Tô¨Tú­Qú­Qú­Qú­Qú­Q­tS9#;*"fDPú­Qü«Tú­Qú­Qú­Qú­Qú­Qü«Tù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨X¯®ýUUÿTTþTTþTTþUUÿUUÿUUÿUUÿ^^ÿddþmmýmmýmmýrrü­tSù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ñŸZ¿¿þ¨¨ý¨¨ý£¢ûýñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\„+;*";*"­tSñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vô¨T­tSfDPi\ÇRRøRRøSSùSSùSSùSSùSSú‹Šúô¨Tú­Qú­Qù¨Xú­Qú­Qú­Qô¨Tú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­QØ…J9#;*"9#­tSü«Tú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Q·¸ý‚úrrÿwwþmmýrrÿwwþ‚ú‰‰ÿ‘‘ÿ‘‘ÿýýý­tSñ¤Vù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xù¨Xó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ùÓ¢ûûûûûûüüüüüüËÍüñ¤VñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZ„+;*";*";*"­tSñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ñ¤Vñ¤Vô¨Tô¨Tô¨Tô¨Tï¡\fDPyoÎRRøRRøSSùSSùSSùSSùÞª“ú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Qú­Q­tS;*"9#9#;*"=4%ü«Tü«Tü«Tü«Tù¨Xù¨Xù¨Xü«Tü«Tú­Qú­Qú­Qú­Qú­Qú­Qû°Oú­Qû°Oú¹cÊÄùÊÄùÊÄù¿¿þÊÄùËÍüËÍüËÍüËÍüýýýýýýüüüfDPô¨Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qù¨Xù¨Xù¨Xú¹cûûûûûûûûûûûûüüüýýýñ¤Vñ¤Vñ¤VñŸZñ¤VñŸZñŸZñŸZñŸZ„+;*";*";*";*"fDPñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[­tSi\ÇRRøRRøRRøSSùrrüâqó¢[ó¢[ô¨Tô¨Tô¨Tô¨Tù¨Xô¨Tô¨Tô¨Tô¨Tù¨Xù¨Xù¨Xù¨Xù¨X­tS;*"9#9#fDP=4%­tSù¨Xó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xù¨Xù¨Xù¨Xú­Qú­Qû°Oû°Oú¹cËÍüËÍüËÍüËÍüËÍüËÍü¯®ý¯®ý£¢û¯®ý¨¨ýÞª“ô¨Tû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú¹cóæáýýýþþþþþþþþþýýýýýýñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VñŸZfDP;*"9#9#9#=4%­tSñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\Þª“—ï—ïÞª“Þª“ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xô¨Tù¨Xô¨Tù¨Xó¢[­tS9#9#;*"fDPôõõÞª“fDPó¢[ó¢[ó¢[ó¢[ñŸZó¢[ó¢[ó¢[ù¨Xó¢[ù¨Xó¢[ù¨Xó¢[ó¢[ù¨Xù¨Xó¢[ù¨XÊÄù……ürrÿjjý^^ÿUUÿUUÿ\\þ\\þ\\þ—ïù¨Xü«Tú­Qú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú¹cùÓ¢ýýýüüüüüüûûûûûûüüüüüüñŸZñŸZñŸZñŸZñŸZñ¤VñŸZfDP;*"=4%9#;*";*";*"­tSñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZðŸ\ðŸ\ñŸZñŸZñŸZñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñŸZñŸZñŸZñ¡\ñŸZfDP9#9#;*"=4%óæá÷÷÷Þª“­tSó¢[ó¢[ô£Uô£UñŸZñŸZô£Uô£Uó¢[ù¨Xô£Uù¨Xô£Uô£Uô£Uô£Uô£Uô£Uô£UØÓï^^ÿTTþTTýTTüTTüTTüTTýjjýâqù¨Xù¨Xù¨Xó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ù¨Xü«Tú­Qû°Oú­Qý£¢ûý£¢ûý£¢ûý‘‘ÿ……üñŸZñŸZñŸZñŸZñŸZñŸZ„+9#9#;*";*";*";*";*"­tSñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¤Vñ¡\ñŸZñŸZñŸZñ¤Vñ¤Vñ¤VñŸZñ¡\ñ¡\ñŸZó¢[ñŸZñ¤V­tS=4%;*";*"9#óæáôôôôõõÞª“­tSñŸZñ¤Vô£Uô£Uô£UñŸZñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uù¨Xô£Uô£Uô£Uô£Uô£Uô£U—ïUUÿUUÿTTþTTþjjýÞª“ñ¤Vó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[—ïUUÿ\\þUUÿUUÿTTþTTþTTþTTþTTþñŸZñŸZñŸZñŸZñŸZ=4%9#9#;*";*"9#9#9#9#­tSñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñŸZñŸZñŸZñŸZñ¡\ñŸZñŸZñŸZñ¡\ñ¡\ñŸZó¢[ñŸZ=4%9#;*"9#=4%ôôôøøøùùùùùùùÓ¢­tSñŸZñ¤Vó¢[ñŸZô£Uô£Uñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£UÞª“ØÓïÞª“Þª“ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uñ¤VñŸZñ¤Vñ¤VÞª“TTþTTþTTþTTþTTþTTþTTþUUÿUUÿUUÿñŸZñŸZñŸZñŸZ=4%=4%fDP;*";*"9#9#;*";*"TD}‹ŠúñŸZñŸZñŸZñŸZðŸ\ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZ­tS;*"9#9#fDPóæáùùùøøøùùùùùùùÓ¢­tSó¢[ñŸZñ¤Vô£Uô£Uó¢[ó¢[ô£Uô£UñŸZñ¤Vô£Uñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£UâqddþTTþTTþTTþTTþTTþTTþTTþUUÿUUÿUUÿô¨Tô¨Tñ¤VfDPfDP=4%fDP9#9#9#;*";*"TD}TTý‚úðŸ\ðŸ\ðŸ\ðŸ\ðŸ\ðŸ\ðŸ\ðŸ\ðŸ\ðŸ\ñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñŸZñ¡\ñŸZñŸZñŸZñŸZñŸZ­tS9#9#9#­tSóæáýýýýýýýýýþþþþþþùÓ¢­tSñŸZñŸZó¢[ó¢[ó¢[ñŸZñ¤Vó¢[ó¢[ó¢[ô£Uô£UñŸZñ¤Vñ¤VñŸZñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£UÞHcdõTTþTTýTTýTTýTTýTTýTTýTTýTTýSSùSSùû°Oû°O­tS;*"fDP=4%fDP9#;*";*"9#fDPTTýTTý‹Šúô¨Tô¨Tñ¤Vñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\­tS9#9#;*"fDPËÍüÊÄù·¸ý·¸ý¨¨ý¯®ýýÞª“­tSó¢[ó¢[ñŸZñŸZó¢[ó¢[ó¢[ñŸZñ¤Vñ¤Vó¢[ó¢[ó¢[ó¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£U—ïSSûSSûSSûSSûSSûSSû[Wæ[WæTD}„+Õ1Dö3Hû°O­tS=4%9#9#;*";*"=4%;*"9#TD}TTýTTýTTýTTþú­Qú­Qú­Qô¨Tó¢[ó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\­tS9#9#;*"fDP‘’ü‘‘ÿ‚úwwþrrÿjjý^^ÿ\\þyoÎfDPó¢[ó¢[ó¢[ñŸZñŸZñŸZñŸZó¢[ó¢[ó¢[ñŸZñŸZñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uó¢[ó¢[ô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£U—ïSSùSSùSSùSSùQQôTD}fDP„+„+Õ1Dö3Hö3HúCX­tS;*";*";*";*";*";*"9#=4%TD}SSúSSúSSûTTüTTüû°Oû°Oû°Oú­Qû°Oû°Oû°Oú­Qû°Oû°Oû°Oú­Qú­Qô¨Tó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\­tS9#;*";*";*"\\þUUÿTTþTTýTTýTTýTTýTTýTTý[Wæ=4%ñŸZñŸZñŸZó¢[ó¢[ñŸZñŸZñŸZñŸZó¢[ó¢[ó¢[ó¢[ó¢[ñŸZñŸZô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uñ¤Vñ¤VÞª“RRøRRøRRøRRøTD}9#9#9#„+âqóæáØÓïìAZö3HfDP;*";*"9#9#9#9#;*"TD}RRøRRøRRøRRøRRøRRøâqú­Qú­Qû°Oû°Oû°Oû°Oû°Oú­Qû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oû°Oú­Qû°Oú­Qú­Qô¨Tô¨Tñ¤Vó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\fDP;*";*"9#=4%SSùSSûSSûSSúSSúSSúSSúSSúSSúSSúi\Ç=4%ñŸZñ¡\ñŸZñŸZñŸZñŸZó¢[ó¢[ñŸZó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ñŸZñŸZô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uñ¤Vñ¤Vñ¤Vñ¤Vñ¤VâqTTüTTüTTý\\þfDP9#9#9#„+ö3HÞª“üüüøøøfDPúCX;*"=4%9#fDP;*";*";*"i\ÇRRøRRøRRøRRøRR÷RR÷RR÷‹Šúó¢[ó¢[ó¢[ó¢[ó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ó¢[ñ¤Vñ¤Vó¢[ó¢[ñ¡\­tS9#9#9#=4%SSùTTýTTýTTýTTýTTýTTýTTýTTüTTüTTýcdõ;*"Ø…JñŸZñŸZñŸZñŸZñŸZñŸZó¢[ó¢[ñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vô£Uô£Uô£Uô£Uô£Uô£Uô£Uô£Uó¢[ó¢[ó¢[ó¢[ó¢[ñ¤Vñ¤Vñ¤Vñ¤VÞHcdõ^^ÿ^^ÿddþTD}9#„+9#Õ1Dö3HìAZÞª“ÿÿÿTD} úCX=4%9#=4%;*";*"=4%TD}SSùSSùSSùRRøRR÷RR÷RR÷RR÷rrüñ¤Vñ¤Vñ¤Vó¢[ó¢[ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\ñ¡\­tS9#9#;*"fDPSSùTTýTTþTTþUUÿUUÿTTþTTþTTýTTüTTüSSûcdõ;*"fDPñ¡\ó¢[ñŸZñŸZñŸZñŸZñ¤Vñ¤Vñ¤VñŸZñŸZñŸZñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤Vñ¤VùÓ¢¯®ý·¸ý·¸ý·¸ý=4%9#„+„+Õ1Dö3HìAZúCXóæáýýýÞª“úCXlibimager-perl-1.004+dfsg.orig/testimg/badbits.bmp0000755000175000017500000000054612031434615021354 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/bad8oflow.bmp0000644000175000017500000000270612031434615021626 0ustar gregoagregoaBMÆ6(  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !  ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+0000libimager-perl-1.004+dfsg.orig/testimg/badcomp4.bmp0000755000175000017500000000054612031434615021435 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/winrgb2off.bmp0000644000175000017500000000022212031434615021775 0ustar gregoagregoaBMŽB(Pë ë ŒR%9žU°€0`$Ð °—p*ðUð¯ðWð_ðð*ßðEÿð-ð[ÿð·ÿðoÿðlibimager-perl-1.004+dfsg.orig/testimg/bad4widbig.bmp0000755000175000017500000000054612031434615021744 0ustar gregoagregoaBMfv(€ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/testimg/winrgb24off.bmp0000644000175000017500000000235212031434615022067 0ustar gregoagregoaBMæ:(°ë ë µ)µ)µ)´* ²/¬3¦9£@B™D”I‘L#‹R'…X)\+|a0xe1sj3qk7ql9µ)µ)µ)´+ ®1ª6¥:¢@šC•G‘K"O&‰S(‚Z*|`.xd2th6pl7lp8kr9µ)´)³+ ±0 «6¦:¢?œC•I‘L"Q&‰T(ƒZ*}`.xd2th6pl8kr9ht;dx?´* ². ®1¬6¦:¢?œC”IŽO"ŒR&‰W(ƒZ*}`.xd2th6pl8jr:dx?bz@a|B²1­2ª6¦:¢?œC”IO"‰S&…W(ƒ[*}`.xd2th6pl8jr:dx?`|A[CZƒG¬7§8¥:¢?œC”IO"‰S&…W([*|`.xd2sh6pl8jr:dx?`|A[CW…GS‰I¤;¢?AšC”IO"‰S&…W([*|`.xd2sh6ml8jr:dx?`|B[CW…GQ‰ILŒJ@›C–G“JO"‰S&…Y)[*|`.xd2rh6ll8hr:cx?`|CZGW…HQ‰IKKH‘O™C•G‘K!O"‰S&…Z*_.|a/xd2rh6ll8hr:bx?\|CYGT…IP‹JJKD‘OC”Q”H‘K"O&‰S'…Z*`.|c0xe2rj6lm8hs:bx?[|CWGS…IOŒKI‘OC”P@•R@™S‘L"Q&‰T(„Z*`.{d1uh2qk6lp8ht:bz?[}CWGS…IOŒKI‘OC•Q?™S:œW9X‹S'‰W(ƒZ*}`.zd2th6pl7jr9du;a{?[€CW‚GR…IOŒKI‘OC•Q?™S9W3¢Y1¤Z…X)ƒ[*}`.xd2th6pl8jr:dx?`|@[CW„GQ†ILŒKI‘OC•Q?™S8žW2¤Z.¦\*ª`\*|`.xd2th6pl8jr:dx?`|A[CW…GQ‰IKŒKG‘OC•Q?™S8žW1¤[+ª`)­a'®b{a/xd2sh6pl8jr:dx?`|A[CW…GQ‰IJKC‘OA•Q?™S8žW1¤[+ª`(®b&²c"³dxe2rj6mm8js:dx?`|B[CW…GQ‰IJKC‘O?•Q:™S7žW1¤[*ª`'®b&²d"µh¶iql7lp8hs:cx?`|CZGW…HQ‰IJKC‘O?•Q:™S6žW0¤[*ª`&®b"´d ·h¼j½kjs:ht;bx?\|CYGT…IP‰JJKC‘O?•Q:™S6W1£Z*ª`&®b"µdºh¾kÃlÄpdy@by@\|CYGS…IO‰JIKC‘O?•R:™S6W2¢Y.§\(­a"³dºh¾lÃpÅqÆrc{Ba|C[GX„IR‰JJŒKD‘O@”R;™W8X3¢Y0¥[+«`'²c!¶h½kÃpÅrÆsÆslibimager-perl-1.004+dfsg.orig/testimg/bad8useda.bmp0000644000175000017500000000270612031434615021601 0ustar gregoagregoaBMÆ6(  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !  ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+0000libimager-perl-1.004+dfsg.orig/testimg/bad_asc.ppm0000644000175000017500000000005412031434615021325 0ustar gregoagregoaP3 2 2 255 255 255 255 255 255 255 255 255 xlibimager-perl-1.004+dfsg.orig/testimg/maxval_65536.ppm0000644000175000017500000000010612031434615022007 0ustar gregoagregoaP6 # test image - check we handle 65536 maxval correctly 1 1 65536 libimager-perl-1.004+dfsg.orig/testimg/bad1wid0.bmp0000644000175000017500000000021612031434615021326 0ustar gregoagregoaBMŽ>(Pë ë ŒR%9žU°€0`$Ð °—p*ðUð¯ðWð_ðð*ßðEÿð-ð[ÿð·ÿðoÿðlibimager-perl-1.004+dfsg.orig/testimg/short_asc.pbm0000644000175000017500000000001312031434615021713 0ustar gregoagregoaP1 2 2 01 1libimager-perl-1.004+dfsg.orig/testimg/gimpgrad0000644000175000017500000000033612031434615020753 0ustar gregoagregoaGIMP Gradient 2 0.000000 0.130000 0.546377 0.900000 0.900000 1.000000 1.000000 0.000000 1.000000 0.000000 1.000000 4 1 0.546377 0.773188 1.000000 0.000000 1.000000 0.000000 1.000000 0.200000 0.200000 0.200000 0.000000 0 0 libimager-perl-1.004+dfsg.orig/testimg/winrgb24.bmp0000644000175000017500000000234612031434615021377 0ustar gregoagregoaBMæ6(°ë ë µ)µ)µ)´* ²/¬3¦9£@B™D”I‘L#‹R'…X)\+|a0xe1sj3qk7ql9µ)µ)µ)´+ ®1ª6¥:¢@šC•G‘K"O&‰S(‚Z*|`.xd2th6pl7lp8kr9µ)´)³+ ±0 «6¦:¢?œC•I‘L"Q&‰T(ƒZ*}`.xd2th6pl8kr9ht;dx?´* ². ®1¬6¦:¢?œC”IŽO"ŒR&‰W(ƒZ*}`.xd2th6pl8jr:dx?bz@a|B²1­2ª6¦:¢?œC”IO"‰S&…W(ƒ[*}`.xd2th6pl8jr:dx?`|A[CZƒG¬7§8¥:¢?œC”IO"‰S&…W([*|`.xd2sh6pl8jr:dx?`|A[CW…GS‰I¤;¢?AšC”IO"‰S&…W([*|`.xd2sh6ml8jr:dx?`|B[CW…GQ‰ILŒJ@›C–G“JO"‰S&…Y)[*|`.xd2rh6ll8hr:cx?`|CZGW…HQ‰IKKH‘O™C•G‘K!O"‰S&…Z*_.|a/xd2rh6ll8hr:bx?\|CYGT…IP‹JJKD‘OC”Q”H‘K"O&‰S'…Z*`.|c0xe2rj6lm8hs:bx?[|CWGS…IOŒKI‘OC”P@•R@™S‘L"Q&‰T(„Z*`.{d1uh2qk6lp8ht:bz?[}CWGS…IOŒKI‘OC•Q?™S:œW9X‹S'‰W(ƒZ*}`.zd2th6pl7jr9du;a{?[€CW‚GR…IOŒKI‘OC•Q?™S9W3¢Y1¤Z…X)ƒ[*}`.xd2th6pl8jr:dx?`|@[CW„GQ†ILŒKI‘OC•Q?™S8žW2¤Z.¦\*ª`\*|`.xd2th6pl8jr:dx?`|A[CW…GQ‰IKŒKG‘OC•Q?™S8žW1¤[+ª`)­a'®b{a/xd2sh6pl8jr:dx?`|A[CW…GQ‰IJKC‘OA•Q?™S8žW1¤[+ª`(®b&²c"³dxe2rj6mm8js:dx?`|B[CW…GQ‰IJKC‘O?•Q:™S7žW1¤[*ª`'®b&²d"µh¶iql7lp8hs:cx?`|CZGW…HQ‰IJKC‘O?•Q:™S6žW0¤[*ª`&®b"´d ·h¼j½kjs:ht;bx?\|CYGT…IP‰JJKC‘O?•Q:™S6W1£Z*ª`&®b"µdºh¾kÃlÄpdy@by@\|CYGS…IO‰JIKC‘O?•R:™S6W2¢Y.§\(­a"³dºh¾lÃpÅqÆrc{Ba|C[GX„IR‰JJŒKD‘O@”R;™W8X3¢Y0¥[+«`'²c!¶h½kÃpÅrÆsÆslibimager-perl-1.004+dfsg.orig/testimg/winrgb8off.bmp0000644000175000017500000000271212031434615022011 0ustar gregoagregoaBMÆ:(  ½!µ)­1µ1¥9­9¥9œB¥B”JœJ”J!ŒR!ŒR)„Z)ŒZ){c1„c1sk1kk9sk9cs9ks9c{9Z{Bc{BZ„BR„JZ„JJŒJRŒJJ”JB”RJ”R9œRBœR9œZ1¥Z)­Z)­c!µc)µc!µk½k!½kÆkÆkÆsÆsÎsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ        !  ! # ! #$$ ! #$%%! #$%%'! #$%''' #$%'')( "$%'')** "$%''(*,+ "$%''(,+.0 "$%%'(,+000 $$%%')*+0000libimager-perl-1.004+dfsg.orig/testimg/maxval_asc.ppm0000644000175000017500000000004412031434615022066 0ustar gregoagregoaP3 3 1 63 63 63 63 32 32 32 31 31 0 libimager-perl-1.004+dfsg.orig/testimg/winrgb4.bmp0000755000175000017500000000054612031434615021320 0ustar gregoagregoaBMfv(ð  C•S1§]Ét'µgV„Fgw=Z„JNN˜HŒR)¹' ¦?„Z)ˆZ-c1qo9ªªª»¸ˆ™Þîÿªª«»ˆ‰îÿõªª»¸ˆÞïÿUª«»ˆ™ÝîÿUVª»¸‰ÞïõUf»»ˆ™ÝîÿUVg»¸‰ÞïõUfw»ˆ™ÝîÿUfgpˆ‰îïõVfwˆ™ÞîÿUfgp‰îÿõVfwÞïÿUfgpÝîÿUVdwÞïõUfw3îÿUVgp3ïõUfw33ÿUfgp32õVfw32"Ufgp3""Vfw32""libimager-perl-1.004+dfsg.orig/rendert.h0000644000175000017500000000043412031434615017375 0ustar gregoagregoa#ifndef IMAGER_RENDERT_H #define IMAGER_RENDERT_H #include "imdatatypes.h" struct i_render_tag { int magic; i_img *im; i_img_dim line_width; i_color *line_8; i_fcolor *line_double; i_img_dim fill_width; i_color *fill_line_8; i_fcolor *fill_line_double; }; #endif libimager-perl-1.004+dfsg.orig/gaussian.im0000644000175000017500000000437512263740600017733 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include static double gauss(int x, double std) { return 1.0/(sqrt(2.0*PI)*std)*exp(-(double)(x)*(double)(x)/(2*std*std)); } /* Counters are as follows l: lines i: columns c: filter coeffs ch: channels pc: coeff equalization */ int i_gaussian(i_img *im, double stddev) { int i, c, ch; i_img_dim x, y; double pc; double *coeff; double res[MAXCHANNELS]; i_img *timg; int radius, diameter; dIMCTXim(im); im_log((aIMCTX, 1,"i_gaussian(im %p, stdev %.2f)\n",im,stddev)); i_clear_error(); if (stddev <= 0) { i_push_error(0, "stddev must be positive"); return 0; } /* totally silly cutoff */ if (stddev > 1000) { stddev = 1000; } timg = i_sametype(im, im->xsize, im->ysize); if (im->bits <= 8) radius = ceil(2 * stddev); else radius = ceil(3 * stddev); diameter = 1 + radius * 2; coeff = mymalloc(sizeof(double) * diameter); for(i=0;i <= radius;i++) coeff[radius + i]=coeff[radius - i]=gauss(i, stddev); pc=0; for(i=0; i < diameter; i++) pc+=coeff[i]; for(i=0;i < diameter;i++) coeff[i] /= pc; #code im->bits <= 8 IM_COLOR rcolor; for(y = 0; y < im->ysize; y++) { for(x = 0; x < im->xsize; x++) { pc=0.0; for(ch=0;chchannels;ch++) res[ch]=0; for(c = 0;c < diameter; c++) if (IM_GPIX(im,x+c-radius,y,&rcolor)!=-1) { for(ch=0;chchannels;ch++) res[ch]+= rcolor.channel[ch] * coeff[c]; pc+=coeff[c]; } for(ch=0;chchannels;ch++) { double value = res[ch] / pc; rcolor.channel[ch] = value > IM_SAMPLE_MAX ? IM_SAMPLE_MAX : IM_ROUND(value); } IM_PPIX(timg, x, y, &rcolor); } } for(x = 0;x < im->xsize; x++) { for(y = 0; y < im->ysize; y++) { pc=0.0; for(ch=0; chchannels; ch++) res[ch]=0; for(c=0; c < diameter; c++) if (IM_GPIX(timg, x, y+c-radius, &rcolor)!=-1) { for(ch=0;chchannels;ch++) res[ch]+= rcolor.channel[ch] * coeff[c]; pc+=coeff[c]; } for(ch=0;chchannels;ch++) { double value = res[ch]/pc; rcolor.channel[ch] = value > IM_SAMPLE_MAX ? IM_SAMPLE_MAX : IM_ROUND(value); } IM_PPIX(im, x, y, &rcolor); } } #/code myfree(coeff); i_img_destroy(timg); return 1; } libimager-perl-1.004+dfsg.orig/plug.h0000644000175000017500000000336512263740601016711 0ustar gregoagregoa#include "imdatatypes.h" #include "immacros.h" /* structures for passing data between Imager-plugin and the Imager-module */ #include "ext.h" #define getINT(k,s) (util_table->getint(INP,k,s)) #define getDOUBLE(k,s) (util_table->getdouble(INP,k,s)) #define getVOID(k,s) (util_table->getvoid(INP,k,(void**)s)) #define getSTR(k,s) (util_table->getstr(INP,k,(char**)s)) #define getOBJ(k,t,s) (util_table->getobj(INP,k,t,(void**)s)) #define i_color_set(cl,r,g,b,a) (symbol_table->i_color_set(cl,r,g,b,a)) #define i_color_info(cl) (symbol_table->i_color_info(cl)) #define im_get_context() (symbol_table->im_get_context_f()) #define i_img_empty_ch(im,x,y,ch) ((symbol_table->i_img_empty_ch_f(im_get_context(), im,x,y,ch)) #define i_img_exorcise(im) (symbol_table->i_img_exorcise_f(im)) #define i_img_info(im,info) (symbol_table->i_img_info_f(im,info)) #define i_img_setmask(im,ch_mask) (symbol_table->i_img_setmask_f(im,ch_mask)) #define i_img_getmask(im) (symbol_table->i_img_getmask_f(im)) /* Not needed? The i_gpix() macro in image.h will call the right function directly. #define i_ppix(im,x,y,val) (symbol_table->i_ppix(im,x,y,val)) #define i_gpix(im,x,y,val) (symbol_table->i_gpix(im,x,y,val)) */ #define i_box(im, x1, y1, x2, y2,val) (symbol_table->i_box(im, x1, y1, x2, y2,val)) #define i_draw(im, x1, y1, x2, y2,val) (symbol_table->i_draw(im, x1, y1, x2, y2,val)) #define i_arc(im, x, y, rad, d1, d2,val) (symbol_table->i_arc(im, x, y, rad, d1, d2,val)) #define i_copyto(im,src, x1, y1, x2, y2, tx, ty,trans) (symbol_table->i_copyto(im,src, x1, y1, x2, y2, tx, ty,trans)) #define i_rubthru(im,src, tx, ty) (symbol_table->i_rubthru(im,src, tx, ty)) #ifdef WIN32 extern char __declspec(dllexport) evalstr[]; extern func_ptr __declspec(dllexport) function_list[]; #endif libimager-perl-1.004+dfsg.orig/pnm.c0000644000175000017500000004757412263740601016541 0ustar gregoagregoa#include "imager.h" #include "log.h" #include "iolayer.h" #include "imageri.h" #include #include /* =head1 NAME pnm.c - implements reading and writing ppm/pnm/pbm files, uses io layer. =head1 SYNOPSIS io_glue *ig = io_new_fd( fd ); i_img *im = i_readpnm_wiol(ig, 0); // no limit on how much is read // or io_glue *ig = io_new_fd( fd ); return_code = i_writepnm_wiol(im, ig); =head1 DESCRIPTION pnm.c implements the basic functions to read and write portable anymap files. It uses the iolayer and needs either a seekable source or an entire memory mapped buffer. =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ #define misspace(x) (x==' ' || x=='\n' || x=='\r' || x=='\t' || x=='\f' || x=='\v') #define misnumber(x) (x <= '9' && x>='0') static char *typenames[]={"ascii pbm", "ascii pgm", "ascii ppm", "binary pbm", "binary pgm", "binary ppm"}; /* =item skip_spaces(ig) Advances in stream until it is positioned at a non white space character. (internal) ig - io_glue =cut */ static int skip_spaces(io_glue *ig) { int c; while( (c = i_io_peekc(ig)) != EOF && misspace(c) ) { if ( i_io_getc(ig) == EOF ) break; } if (c == EOF) return 0; return 1; } /* =item skip_comment(ig) Advances in stream over whitespace and a comment if one is found. (internal) ig - io_glue object =cut */ static int skip_comment(io_glue *ig) { int c; if (!skip_spaces(ig)) return 0; if ((c = i_io_peekc(ig)) == EOF) return 0; if (c == '#') { while( (c = i_io_peekc(ig)) != EOF && (c != '\n' && c != '\r') ) { if ( i_io_getc(ig) == EOF ) break; } } if (c == EOF) return 0; return 1; } /* =item gnum(mb, i) Fetches the next number from stream and stores in i, returns true on success else false. mb - buffer object i - integer to store result in =cut */ static int gnum(io_glue *ig, int *i) { int c; *i = 0; if (!skip_spaces(ig)) return 0; if ((c = i_io_peekc(ig)) == EOF) return 0; if (!misnumber(c)) return 0; while( (c = i_io_peekc(ig)) != EOF && misnumber(c) ) { int work = *i * 10 + (c - '0'); if (work < *i) { /* overflow */ i_push_error(0, "integer overflow"); return 0; } *i = work; i_io_getc(ig); } return 1; } static i_img * read_pgm_ppm_bin8(io_glue *ig, i_img *im, int width, int height, int channels, int maxval, int allow_incomplete) { i_color *line, *linep; int read_size; unsigned char *read_buf, *readp; int x, y, ch; int rounder = maxval / 2; line = mymalloc(width * sizeof(i_color)); read_size = channels * width; read_buf = mymalloc(read_size); for(y=0;ytags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", y); return im; } else { i_push_error(0, "short read - file truncated?"); i_img_destroy(im); return NULL; } } if (maxval == 255) { for(x=0; xchannel[ch] = *readp++; } ++linep; } } else { for(x=0; x maxval) sample = maxval; linep->channel[ch] = (sample * 255 + rounder) / maxval; } ++linep; } } i_plin(im, 0, width, y, line); } myfree(read_buf); myfree(line); return im; } static i_img * read_pgm_ppm_bin16(io_glue *ig, i_img *im, int width, int height, int channels, int maxval, int allow_incomplete) { i_fcolor *line, *linep; int read_size; unsigned char *read_buf, *readp; int x, y, ch; double maxvalf = maxval; line = mymalloc(width * sizeof(i_fcolor)); read_size = channels * width * 2; read_buf = mymalloc(read_size); for(y=0;ytags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", y); return im; } else { i_push_error(0, "short read - file truncated?"); i_img_destroy(im); return NULL; } } for(x=0; x maxval) sample = maxval; readp += 2; linep->channel[ch] = sample / maxvalf; } ++linep; } i_plinf(im, 0, width, y, line); } myfree(read_buf); myfree(line); return im; } static i_img * read_pbm_bin(io_glue *ig, i_img *im, int width, int height, int allow_incomplete) { i_palidx *line, *linep; int read_size; unsigned char *read_buf, *readp; int x, y; unsigned mask; line = mymalloc(width * sizeof(i_palidx)); read_size = (width + 7) / 8; read_buf = mymalloc(read_size); for(y = 0; y < height; y++) { if (i_io_read(ig, read_buf, read_size) != read_size) { myfree(line); myfree(read_buf); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", y); return im; } else { i_push_error(0, "short read - file truncated?"); i_img_destroy(im); return NULL; } } linep = line; readp = read_buf; mask = 0x80; for(x = 0; x < width; ++x) { *linep++ = *readp & mask ? 1 : 0; mask >>= 1; if (mask == 0) { ++readp; mask = 0x80; } } i_ppal(im, 0, width, y, line); } myfree(read_buf); myfree(line); return im; } /* unlike pgm/ppm pbm: - doesn't require spaces between samples (bits) - 1 (maxval) is black instead of white */ static i_img * read_pbm_ascii(io_glue *ig, i_img *im, int width, int height, int allow_incomplete) { i_palidx *line, *linep; int x, y; line = mymalloc(width * sizeof(i_palidx)); for(y = 0; y < height; y++) { linep = line; for(x = 0; x < width; ++x) { int c; skip_spaces(ig); if ((c = i_io_getc(ig)) == EOF || (c != '0' && c != '1')) { myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", y); return im; } else { if (c != EOF) i_push_error(0, "invalid data for ascii pnm"); else i_push_error(0, "short read - file truncated?"); i_img_destroy(im); return NULL; } } *linep++ = c == '0' ? 0 : 1; } i_ppal(im, 0, width, y, line); } myfree(line); return im; } static i_img * read_pgm_ppm_ascii(io_glue *ig, i_img *im, int width, int height, int channels, int maxval, int allow_incomplete) { i_color *line, *linep; int x, y, ch; int rounder = maxval / 2; line = mymalloc(width * sizeof(i_color)); for(y=0;ytags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", 1); return im; } else { if (i_io_peekc(ig) != EOF) i_push_error(0, "invalid data for ascii pnm"); else i_push_error(0, "short read - file truncated?"); i_img_destroy(im); return NULL; } } if (sample > maxval) sample = maxval; linep->channel[ch] = (sample * 255 + rounder) / maxval; } ++linep; } i_plin(im, 0, width, y, line); } myfree(line); return im; } static i_img * read_pgm_ppm_ascii_16(io_glue *ig, i_img *im, int width, int height, int channels, int maxval, int allow_incomplete) { i_fcolor *line, *linep; int x, y, ch; double maxvalf = maxval; line = mymalloc(width * sizeof(i_fcolor)); for(y=0;ytags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", y); return im; } else { if (i_io_peekc(ig) != EOF) i_push_error(0, "invalid data for ascii pnm"); else i_push_error(0, "short read - file truncated?"); i_img_destroy(im); return NULL; } } if (sample > maxval) sample = maxval; linep->channel[ch] = sample / maxvalf; } ++linep; } i_plinf(im, 0, width, y, line); } myfree(line); return im; } /* =item i_readpnm_wiol(ig, allow_incomplete) Retrieve an image and stores in the iolayer object. Returns NULL on fatal error. ig - io_glue object allow_incomplete - allows a partial file to be read successfully =cut */ i_img * i_readpnm_wiol( io_glue *ig, int allow_incomplete) { i_img* im; int type; int width, height, maxval, channels; int c; i_clear_error(); mm_log((1,"i_readpnm(ig %p, allow_incomplete %d)\n", ig, allow_incomplete)); c = i_io_getc(ig); if (c != 'P') { i_push_error(0, "bad header magic, not a PNM file"); mm_log((1, "i_readpnm: Could not read header of file\n")); return NULL; } if ((c = i_io_getc(ig)) == EOF ) { mm_log((1, "i_readpnm: Could not read header of file\n")); return NULL; } type = c - '0'; if (type < 1 || type > 6) { i_push_error(0, "unknown PNM file type, not a PNM file"); mm_log((1, "i_readpnm: Not a pnm file\n")); return NULL; } if ( (c = i_io_getc(ig)) == EOF ) { mm_log((1, "i_readpnm: Could not read header of file\n")); return NULL; } if ( !misspace(c) ) { i_push_error(0, "unexpected character, not a PNM file"); mm_log((1, "i_readpnm: Not a pnm file\n")); return NULL; } mm_log((1, "i_readpnm: image is a %s\n", typenames[type-1] )); /* Read sizes and such */ if (!skip_comment(ig)) { i_push_error(0, "while skipping to width"); mm_log((1, "i_readpnm: error reading before width\n")); return NULL; } if (!gnum(ig, &width)) { i_push_error(0, "could not read image width"); mm_log((1, "i_readpnm: error reading width\n")); return NULL; } if (!skip_comment(ig)) { i_push_error(0, "while skipping to height"); mm_log((1, "i_readpnm: error reading before height\n")); return NULL; } if (!gnum(ig, &height)) { i_push_error(0, "could not read image height"); mm_log((1, "i_readpnm: error reading height\n")); return NULL; } if (!(type == 1 || type == 4)) { if (!skip_comment(ig)) { i_push_error(0, "while skipping to maxval"); mm_log((1, "i_readpnm: error reading before maxval\n")); return NULL; } if (!gnum(ig, &maxval)) { i_push_error(0, "could not read maxval"); mm_log((1, "i_readpnm: error reading maxval\n")); return NULL; } if (maxval == 0) { i_push_error(0, "maxval is zero - invalid pnm file"); mm_log((1, "i_readpnm: maxval is zero, invalid pnm file\n")); return NULL; } else if (maxval > 65535) { i_push_errorf(0, "maxval of %d is over 65535 - invalid pnm file", maxval); mm_log((1, "i_readpnm: maxval of %d is over 65535 - invalid pnm file\n", maxval)); return NULL; } } else maxval=1; if ((c = i_io_getc(ig)) == EOF || !misspace(c)) { i_push_error(0, "garbage in header, invalid PNM file"); mm_log((1, "i_readpnm: garbage in header\n")); return NULL; } channels = (type == 3 || type == 6) ? 3:1; if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) { mm_log((1, "i_readpnm: image size exceeds limits\n")); return NULL; } mm_log((1, "i_readpnm: (%d x %d), channels = %d, maxval = %d\n", width, height, channels, maxval)); if (type == 1 || type == 4) { i_color pbm_pal[2]; pbm_pal[0].channel[0] = 255; pbm_pal[1].channel[0] = 0; im = i_img_pal_new(width, height, 1, 256); i_addcolors(im, pbm_pal, 2); } else { if (maxval > 255) im = i_img_16_new(width, height, channels); else im = i_img_8_new(width, height, channels); } switch (type) { case 1: /* Ascii types */ im = read_pbm_ascii(ig, im, width, height, allow_incomplete); break; case 2: case 3: if (maxval > 255) im = read_pgm_ppm_ascii_16(ig, im, width, height, channels, maxval, allow_incomplete); else im = read_pgm_ppm_ascii(ig, im, width, height, channels, maxval, allow_incomplete); break; case 4: /* binary pbm */ im = read_pbm_bin(ig, im, width, height, allow_incomplete); break; case 5: /* binary pgm */ case 6: /* binary ppm */ if (maxval > 255) im = read_pgm_ppm_bin16(ig, im, width, height, channels, maxval, allow_incomplete); else im = read_pgm_ppm_bin8(ig, im, width, height, channels, maxval, allow_incomplete); break; default: mm_log((1, "type %s [P%d] unsupported\n", typenames[type-1], type)); return NULL; } if (!im) return NULL; i_tags_add(&im->tags, "i_format", 0, "pnm", -1, 0); i_tags_setn(&im->tags, "pnm_maxval", maxval); i_tags_setn(&im->tags, "pnm_type", type); return im; } static void free_images(i_img **imgs, int count) { int i; if (count) { for (i = 0; i < count; ++i) i_img_destroy(imgs[i]); myfree(imgs); } } i_img **i_readpnm_multi_wiol(io_glue *ig, int *count, int allow_incomplete) { i_img **results = NULL; i_img *img = NULL; char c = EOF; int result_alloc = 0, value = 0, eof = 0; *count=0; do { mm_log((1, "read image %i\n", 1+*count)); img = i_readpnm_wiol( ig, allow_incomplete ); if( !img ) { free_images( results, *count ); return NULL; } ++*count; if (*count > result_alloc) { if (result_alloc == 0) { result_alloc = 5; results = mymalloc(result_alloc * sizeof(i_img *)); } else { /* myrealloc never fails (it just dies if it can't allocate) */ result_alloc *= 2; results = myrealloc(results, result_alloc * sizeof(i_img *)); } } results[*count-1] = img; if( i_tags_get_int(&img->tags, "i_incomplete", 0, &value ) && value) { eof = 1; } else if( skip_spaces( ig ) && ( c=i_io_peekc( ig ) ) != EOF && c == 'P' ) { eof = 0; } else { eof = 1; } } while(!eof); return results; } static int write_pbm(i_img *im, io_glue *ig, int zero_is_white) { int x, y; i_palidx *line; i_img_dim write_size; unsigned char *write_buf; unsigned char *writep; char header[255]; unsigned mask; sprintf(header, "P4\012# CREATOR: Imager\012%" i_DF " %" i_DF "\012", i_DFc(im->xsize), i_DFc(im->ysize)); if (i_io_write(ig, header, strlen(header)) < 0) { i_push_error(0, "could not write pbm header"); return 0; } write_size = (im->xsize + 7) / 8; line = mymalloc(sizeof(i_palidx) * im->xsize); write_buf = mymalloc(write_size); for (y = 0; y < im->ysize; ++y) { i_gpal(im, 0, im->xsize, y, line); mask = 0x80; writep = write_buf; memset(write_buf, 0, write_size); for (x = 0; x < im->xsize; ++x) { if (zero_is_white ? line[x] : !line[x]) *writep |= mask; mask >>= 1; if (!mask) { ++writep; mask = 0x80; } } if (i_io_write(ig, write_buf, write_size) != write_size) { i_push_error(0, "write failure"); myfree(write_buf); myfree(line); return 0; } } myfree(write_buf); myfree(line); return 1; } static int write_ppm_data_8(i_img *im, io_glue *ig, int want_channels) { size_t write_size = im->xsize * want_channels; size_t buf_size = im->xsize * im->channels; unsigned char *data = mymalloc(buf_size); i_img_dim y = 0; int rc = 1; i_color bg; i_get_file_background(im, &bg); while (y < im->ysize && rc >= 0) { i_gsamp_bg(im, 0, im->xsize, y, data, want_channels, &bg); if (i_io_write(ig, data, write_size) != write_size) { i_push_error(errno, "could not write ppm data"); rc = 0; break; } ++y; } myfree(data); return rc; } static int write_ppm_data_16(i_img *im, io_glue *ig, int want_channels) { size_t line_size = im->channels * im->xsize * sizeof(i_fsample_t); size_t sample_count = want_channels * im->xsize; size_t write_size = sample_count * 2; i_fsample_t *line_buf = mymalloc(line_size); i_fsample_t *samplep; unsigned char *write_buf = mymalloc(write_size); unsigned char *writep; size_t sample_num; i_img_dim y = 0; int rc = 1; i_fcolor bg; i_get_file_backgroundf(im, &bg); while (y < im->ysize) { i_gsampf_bg(im, 0, im->xsize, y, line_buf, want_channels, &bg); samplep = line_buf; writep = write_buf; for (sample_num = 0; sample_num < sample_count; ++sample_num) { unsigned sample16 = SampleFTo16(*samplep++); *writep++ = sample16 >> 8; *writep++ = sample16 & 0xFF; } if (i_io_write(ig, write_buf, write_size) != write_size) { i_push_error(errno, "could not write ppm data"); rc = 0; break; } ++y; } myfree(line_buf); myfree(write_buf); return rc; } undef_int i_writeppm_wiol(i_img *im, io_glue *ig) { char header[255]; int zero_is_white; int wide_data; mm_log((1,"i_writeppm(im %p, ig %p)\n", im, ig)); i_clear_error(); /* Add code to get the filename info from the iolayer */ /* Also add code to check for mmapped code */ if (i_img_is_monochrome(im, &zero_is_white)) { if (!write_pbm(im, ig, zero_is_white)) return 0; } else { int type; int maxval; int want_channels = im->channels; if (want_channels == 2 || want_channels == 4) --want_channels; if (!i_tags_get_int(&im->tags, "pnm_write_wide_data", 0, &wide_data)) wide_data = 0; if (want_channels == 3) { type = 6; } else if (want_channels == 1) { type = 5; } else { i_push_error(0, "can only save 1 or 3 channel images to pnm"); mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels)); return(0); } if (im->bits <= 8 || !wide_data) maxval = 255; else maxval = 65535; sprintf(header,"P%d\n#CREATOR: Imager\n%" i_DF " %" i_DF"\n%d\n", type, i_DFc(im->xsize), i_DFc(im->ysize), maxval); if (i_io_write(ig,header,strlen(header)) != strlen(header)) { i_push_error(errno, "could not write ppm header"); mm_log((1,"i_writeppm: unable to write ppm header.\n")); return(0); } if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type && im->channels == want_channels) { if (i_io_write(ig,im->idata,im->bytes) != im->bytes) { i_push_error(errno, "could not write ppm data"); return 0; } } else if (maxval == 255) { if (!write_ppm_data_8(im, ig, want_channels)) return 0; } else { if (!write_ppm_data_16(im, ig, want_channels)) return 0; } } if (i_io_close(ig)) { i_push_errorf(i_io_error(ig), "Error closing stream: %d", i_io_error(ig)); return 0; } return(1); } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson , Tony Cook , Philip Gwyn . =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/imdatatypes.h0000644000175000017500000006125312614520110020255 0ustar gregoagregoa#ifndef _DATATYPES_H_ #define _DATATYPES_H_ #include #include "imconfig.h" #define MAXCHANNELS 4 /* =item im_context_t =category Data Types Imager's per-thread context. =cut */ typedef struct im_context_tag *im_context_t; /* =item im_slot_t =category Data Types Represents a slot in the context object. =cut */ typedef ptrdiff_t im_slot_t; typedef void (*im_slot_destroy_t)(void *); /* used for palette indices in some internal code (which might be exposed at some point */ typedef unsigned char i_palidx; /* We handle 2 types of sample, this is hopefully the most common, and the smaller of the ones we support */ typedef unsigned char i_sample_t; typedef struct { i_sample_t gray_color; } gray_color; typedef struct { i_sample_t r,g,b; } rgb_color; typedef struct { i_sample_t r,g,b,a; } rgba_color; typedef struct { i_sample_t c,m,y,k; } cmyk_color; typedef int undef_int; /* special value to put in typemaps to retun undef on 0 and 1 on 1 */ /* =item i_img_dim =category Data Types =synopsis i_img_dim x, y; =order 90 A signed integer type that represents an image dimension or ordinate. May be larger than int on some platforms. =cut */ typedef ptrdiff_t i_img_dim; /* =item i_img_dim_u =category Data Types =synopsis i_img_dim_u limit; =order 90 An unsigned variant of L. =cut */ typedef size_t i_img_dim_u; #define i_img_dim_MAX ((i_img_dim)(~(i_img_dim_u)0 >> 1)) /* =item i_color =category Data Types =synopsis i_color black; =synopsis black.rgba.r = black.rgba.g = black.rgba.b = black.rgba.a = 0; Type for 8-bit/sample color. Samples as per; i_color c; i_color is a union of: =over =item * gray - contains a single element gray_color, eg. C =item * C - contains three elements C, C, C, eg. C =item * C - contains four elements C, C, C, C, eg. C =item * C - contains four elements C, C, C, C, eg. C. Note that Imager never uses CMYK colors except when reading/writing files. =item * channels - an array of four channels, eg C. =back =cut */ typedef union { gray_color gray; rgb_color rgb; rgba_color rgba; cmyk_color cmyk; i_sample_t channel[MAXCHANNELS]; unsigned int ui; } i_color; /* this is the larger sample type, it should be able to accurately represent any sample size we use */ typedef double i_fsample_t; typedef struct { i_fsample_t gray_color; } i_fgray_color_t; typedef struct { i_fsample_t r, g, b; } i_frgb_color_t; typedef struct { i_fsample_t r, g, b, a; } i_frgba_color_t; typedef struct { i_fsample_t c, m, y, k; } i_fcmyk_color_t; /* =item i_fcolor =category Data Types This is the double/sample color type. Its layout exactly corresponds to i_color. =cut */ typedef union { i_fgray_color_t gray; i_frgb_color_t rgb; i_frgba_color_t rgba; i_fcmyk_color_t cmyk; i_fsample_t channel[MAXCHANNELS]; } i_fcolor; typedef enum { i_direct_type, /* direct colour, keeps RGB values per pixel */ i_palette_type /* keeps a palette index per pixel */ } i_img_type_t; typedef enum { /* bits per sample, not per pixel */ /* a paletted image might have one bit per sample */ i_8_bits = 8, i_16_bits = 16, i_double_bits = sizeof(double) * 8 } i_img_bits_t; typedef struct { char *name; /* name of a given tag, might be NULL */ int code; /* number of a given tag, -1 if it has no meaning */ char *data; /* value of a given tag if it's not an int, may be NULL */ int size; /* size of the data */ int idata; /* value of a given tag if data is NULL */ } i_img_tag; typedef struct { int count; /* how many tags have been set */ int alloc; /* how many tags have been allocated for */ i_img_tag *tags; } i_img_tags; typedef struct i_img_ i_img; typedef int (*i_f_ppix_t)(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix); typedef int (*i_f_ppixf_t)(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix); typedef i_img_dim (*i_f_plin_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_color *vals); typedef i_img_dim (*i_f_plinf_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_fcolor *vals); typedef int (*i_f_gpix_t)(i_img *im, i_img_dim x, i_img_dim y, i_color *pix); typedef int (*i_f_gpixf_t)(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix); typedef i_img_dim (*i_f_glin_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_color *vals); typedef i_img_dim (*i_f_glinf_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_fcolor *vals); typedef i_img_dim (*i_f_gsamp_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_sample_t *samp, const int *chans, int chan_count); typedef i_img_dim (*i_f_gsampf_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_fsample_t *samp, const int *chan, int chan_count); typedef i_img_dim (*i_f_gpal_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals); typedef i_img_dim (*i_f_ppal_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals); typedef int (*i_f_addcolors_t)(i_img *im, const i_color *colors, int count); typedef int (*i_f_getcolors_t)(i_img *im, int i, i_color *, int count); typedef int (*i_f_colorcount_t)(i_img *im); typedef int (*i_f_maxcolors_t)(i_img *im); typedef int (*i_f_findcolor_t)(i_img *im, const i_color *color, i_palidx *entry); typedef int (*i_f_setcolors_t)(i_img *im, int index, const i_color *colors, int count); typedef void (*i_f_destroy_t)(i_img *im); typedef i_img_dim (*i_f_gsamp_bits_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, unsigned *samp, const int *chans, int chan_count, int bits); typedef i_img_dim (*i_f_psamp_bits_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, unsigned const *samp, const int *chans, int chan_count, int bits); typedef i_img_dim (*i_f_psamp_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_sample_t *samp, const int *chan, int chan_count); typedef i_img_dim (*i_f_psampf_t)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_fsample_t *samp, const int *chan, int chan_count); /* =item i_img =category Data Types =synopsis i_img *img; =order 10 This is Imager's image type. It contains the following members: =over =item * C - the number of channels in the image =item * C, C - the width and height of the image in pixels =item * C - the number of bytes used to store the image data. Undefined where virtual is non-zero. =item * C - a mask of writable channels. eg. if this is 6 then only channels 1 and 2 are writable. There may be bits set for which there are no channels in the image. =item * C - the number of bits stored per sample. Should be one of i_8_bits, i_16_bits, i_double_bits. =item * C - either i_direct_type for direct color images, or i_palette_type for paletted images. =item * C - if zero then this image is-self contained. If non-zero then this image could be an interface to some other implementation. =item * C - the image data. This should not be directly accessed. A new image implementation can use this to store its image data. i_img_destroy() will myfree() this pointer if it's non-null. =item * C - a structure storing the image's tags. This should only be accessed via the i_tags_*() functions. =item * C - a pointer for use internal to an image implementation. This should be freed by the image's destroy handler. =item * C - data internal to Imager. This is initialized by i_img_init(). =item * i_f_ppix, i_f_ppixf, i_f_plin, i_f_plinf, i_f_gpix, i_f_gpixf, i_f_glin, i_f_glinf, i_f_gsamp, i_f_gampf - implementations for each of the required image functions. An image implementation should initialize these between calling i_img_alloc() and i_img_init(). =item * i_f_gpal, i_f_ppal, i_f_addcolors, i_f_getcolors, i_f_colorcount, i_f_maxcolors, i_f_findcolor, i_f_setcolors - implementations for each paletted image function. =item * i_f_destroy - custom image destruction function. This should be used to release memory if necessary. =item * i_f_gsamp_bits - implements i_gsamp_bits() for this image. =item * i_f_psamp_bits - implements i_psamp_bits() for this image. =item * i_f_psamp - implements psamp() for this image. =item * i_f_psampf - implements psamp() for this image. =item * C - image specific data internal to Imager. =item * C - the Imager API context this image belongs to. =back =cut */ struct i_img_ { int channels; i_img_dim xsize,ysize; size_t bytes; unsigned int ch_mask; i_img_bits_t bits; i_img_type_t type; int virtual; /* image might not keep any data, must use functions */ unsigned char *idata; /* renamed to force inspection of existing code */ /* can be NULL if virtual is non-zero */ i_img_tags tags; void *ext_data; /* interface functions */ i_f_ppix_t i_f_ppix; i_f_ppixf_t i_f_ppixf; i_f_plin_t i_f_plin; i_f_plinf_t i_f_plinf; i_f_gpix_t i_f_gpix; i_f_gpixf_t i_f_gpixf; i_f_glin_t i_f_glin; i_f_glinf_t i_f_glinf; i_f_gsamp_t i_f_gsamp; i_f_gsampf_t i_f_gsampf; /* only valid for type == i_palette_type */ i_f_gpal_t i_f_gpal; i_f_ppal_t i_f_ppal; i_f_addcolors_t i_f_addcolors; i_f_getcolors_t i_f_getcolors; i_f_colorcount_t i_f_colorcount; i_f_maxcolors_t i_f_maxcolors; i_f_findcolor_t i_f_findcolor; i_f_setcolors_t i_f_setcolors; i_f_destroy_t i_f_destroy; /* as of 0.61 */ i_f_gsamp_bits_t i_f_gsamp_bits; i_f_psamp_bits_t i_f_psamp_bits; /* as of 0.88 */ i_f_psamp_t i_f_psamp; i_f_psampf_t i_f_psampf; void *im_data; /* 0.91 */ im_context_t context; }; /* ext_data for paletted images */ typedef struct { int count; /* amount of space used in palette (in entries) */ int alloc; /* amount of space allocated for palette (in entries) */ i_color *pal; int last_found; } i_img_pal_ext; /* Helper datatypes The types in here so far are: doubly linked bucket list - pretty efficient octtree - no idea about goodness needed: hashes. */ /* bitmap mask */ struct i_bitmap { i_img_dim xsize,ysize; char *data; }; struct i_bitmap* btm_new(i_img_dim xsize,i_img_dim ysize); void btm_destroy(struct i_bitmap *btm); int btm_test(struct i_bitmap *btm,i_img_dim x,i_img_dim y); void btm_set(struct i_bitmap *btm,i_img_dim x,i_img_dim y); /* Stack/Linked list */ struct llink { struct llink *p,*n; void *data; int fill; /* Number used in this link */ }; struct llist { struct llink *h,*t; int multip; /* # of copies in a single chain */ size_t ssize; /* size of each small element */ int count; /* number of elements on the list */ }; /* Lists */ struct llist *llist_new( int multip, size_t ssize ); void llist_destroy( struct llist *l ); void llist_push( struct llist *l, const void *data ); void llist_dump( struct llist *l ); int llist_pop( struct llist *l,void *data ); /* Octtree */ struct octt { struct octt *t[8]; int cnt; }; struct octt *octt_new(void); int octt_add(struct octt *ct,unsigned char r,unsigned char g,unsigned char b); void octt_dump(struct octt *ct); void octt_count(struct octt *ct,int *tot,int max,int *overflow); void octt_delete(struct octt *ct); void octt_histo(struct octt *ct, unsigned int **col_usage_it_adr); /* font bounding box results */ enum bounding_box_index_t { BBOX_NEG_WIDTH, BBOX_GLOBAL_DESCENT, BBOX_POS_WIDTH, BBOX_GLOBAL_ASCENT, BBOX_DESCENT, BBOX_ASCENT, BBOX_ADVANCE_WIDTH, BBOX_RIGHT_BEARING, BOUNDING_BOX_COUNT }; /* =item i_polygon_t =category Data Types Represents a polygon. Has the following members: =over =item * C, C - arrays of x and y locations of vertices. =item * C - the number of entries in the C and C arrays. =back =cut */ typedef struct i_polygon_tag { const double *x; const double *y; size_t count; } i_polygon_t; /* =item i_poly_fill_mode_t =category Data Types Control how polygons are filled. Has the following values: =over =item * C - simple even-odd fills. =item * C - non-zero winding rule fills. =back =cut */ typedef enum i_poly_fill_mode_tag { i_pfm_evenodd, i_pfm_nonzero } i_poly_fill_mode_t; /* Generic fills */ struct i_fill_tag; typedef void (*i_fill_with_color_f) (struct i_fill_tag *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data); typedef void (*i_fill_with_fcolor_f) (struct i_fill_tag *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data); typedef void (*i_fill_destroy_f)(struct i_fill_tag *fill); /* combine functions modify their target and are permitted to modify the source to prevent having to perform extra copying/memory allocations, etc The out array has I channels. The in array has I channels + an alpha channel if one isn't included in I. */ typedef void (*i_fill_combine_f)(i_color *out, i_color *in, int channels, i_img_dim count); typedef void (*i_fill_combinef_f)(i_fcolor *out, i_fcolor *in, int channels, i_img_dim count); /* fountain fill types */ typedef enum { i_fst_linear, i_fst_curved, i_fst_sine, i_fst_sphere_up, i_fst_sphere_down, i_fst_end } i_fountain_seg_type; typedef enum { i_fc_direct, i_fc_hue_up, i_fc_hue_down, i_fc_end } i_fountain_color; typedef struct { double start, middle, end; i_fcolor c[2]; i_fountain_seg_type type; i_fountain_color color; } i_fountain_seg; typedef enum { i_fr_none, i_fr_sawtooth, i_fr_triangle, i_fr_saw_both, i_fr_tri_both } i_fountain_repeat; typedef enum { i_ft_linear, i_ft_bilinear, i_ft_radial, i_ft_radial_square, i_ft_revolution, i_ft_conical, i_ft_end } i_fountain_type; typedef enum { i_fts_none, i_fts_grid, i_fts_random, i_fts_circle } i_ft_supersample; /* =item i_fill_t =category Data Types =synopsis i_fill_t *fill; This is the "abstract" base type for Imager's fill types. Unless you're implementing a new fill type you'll typically treat this as an opaque type. =cut */ typedef struct i_fill_tag { /* called for 8-bit/sample image (and maybe lower) */ /* this may be NULL, if so call fill_with_fcolor */ i_fill_with_color_f f_fill_with_color; /* called for other sample sizes */ /* this must be non-NULL */ i_fill_with_fcolor_f f_fill_with_fcolor; /* called if non-NULL to release any extra resources */ i_fill_destroy_f destroy; /* if non-zero the caller will fill data with the original data from the image */ i_fill_combine_f combine; i_fill_combinef_f combinef; } i_fill_t; typedef enum { ic_none, ic_normal, ic_multiply, ic_dissolve, ic_add, ic_subtract, ic_diff, ic_lighten, ic_darken, ic_hue, ic_sat, ic_value, ic_color } i_combine_t; /* =item i_mutex_t X =category mutex =synopsis i_mutex_t mutex; Opaque type for Imager's mutex API. =cut */ typedef struct i_mutex_tag *i_mutex_t; /* describes an axis of a MM font. Modelled on FT2's FT_MM_Axis. It would be nice to have a default entry too, but FT2 doesn't support it. */ typedef struct i_font_mm_axis_tag { char const *name; int minimum; int maximum; } i_font_mm_axis; #define IM_FONT_MM_MAX_AXES 4 /* multiple master information for a font, if any modelled on FT2's FT_Multi_Master. */ typedef struct i_font_mm_tag { int num_axis; int num_designs; /* provided but not necessarily useful */ i_font_mm_axis axis[IM_FONT_MM_MAX_AXES]; } i_font_mm; #ifdef HAVE_LIBTT struct TT_Fonthandle_; typedef struct TT_Fonthandle_ TT_Fonthandle; #endif /* =item i_transp =category Data Types An enumerated type for controlling how transparency is handled during quantization. This has the following possible values: =over =item * C - ignore the alpha channel =item * C - simple transparency thresholding. =item * C - use error diffusion to control which pixels are transparent. =item * C - use ordered dithering to control which pixels are transparent. =back =cut */ /* transparency handling for quantized output */ typedef enum i_transp_tag { tr_none, /* ignore any alpha channel */ tr_threshold, /* threshold the transparency - uses tr_threshold */ tr_errdiff, /* error diffusion */ tr_ordered /* an ordered dither */ } i_transp; /* =item i_make_colors =category Data Types An enumerated type used to control the method used for produce the color map: =over =item * C - the user supplied map is used. =item * C - use the classic web map. Any existing fixed colors are ignored. =item * C - use median cut =item * C - use a fixed black and white map. =item * C - 256 step gray map. =item * C - 4 step gray map. =item * C - 16 step gray map. =back =cut */ typedef enum i_make_colors_tag { mc_none, /* user supplied colour map only */ mc_web_map, /* Use the 216 colour web colour map */ mc_addi, /* Addi's algorithm */ mc_median_cut, /* median cut - similar to giflib, hopefully */ mc_mono, /* fixed mono color map */ mc_gray, /* 256 gray map */ mc_gray4, /* four step gray map */ mc_gray16, /* sixteen step gray map */ mc_mask = 0xFF /* (mask for generator) */ } i_make_colors; /* =item i_translate =category Data Types An enumerated type that controls how colors are translated: =over =item * C - obsolete, forces C to use median cut and acts like C. =item * C - always use the closest color. =item * C - add random values to each sample and find the closest color. =item * C - error diffusion dither. =back =cut */ /* controls how we translate the colours */ typedef enum i_translate_tag { pt_giflib, /* get gif lib to do it (ignores make_colours) */ pt_closest, /* just use the closest match within the hashbox */ pt_perturb, /* randomly perturb the data - uses perturb_size*/ pt_errdiff /* error diffusion dither - uses errdiff */ } i_translate; /* =item i_errdiff =category Data Types Controls the type of error diffusion to use: =over =item * C - floyd-steinberg =item * C - Jarvis, Judice and Ninke =item * C - Stucki =item * C - not usable for transparency dithering, allows a custom error diffusion map to be used. =item * C - or with the error diffusion type to use alternate directions on each line of the dither. =back =cut */ /* Which error diffusion map to use */ typedef enum i_errdiff_tag { ed_floyd, /* floyd-steinberg */ ed_jarvis, /* Jarvis, Judice and Ninke */ ed_stucki, /* Stucki */ ed_custom, /* the map found in ed_map|width|height|orig */ ed_mask = 0xFF, /* mask to get the map */ ed_bidir = 0x100 /* change direction for each row */ } i_errdiff; /* =item i_ord_dith =category Data Types Which ordered dither map to use, currently only available for transparency. Values are: =over =item * C - a pre-generated random map. =item * C - large dot dither. =item * C - smaller dot dither =item * C - horizontal line dither. =item * C - vertical line dither. =item * C - C line dither. =item * C - C<\> line dither. =item * C - small checkbox dither =item * C - custom dither map. =back =cut I don't know of a way to do ordered dither of an image against some general palette */ typedef enum i_ord_dith_tag { od_random, /* sort of random */ od_dot8, /* large dot */ od_dot4, od_hline, od_vline, od_slashline, /* / line dither */ od_backline, /* \ line dither */ od_tiny, /* small checkerbox */ od_custom /* custom 8x8 map */ } i_ord_dith; /* =item i_quantize =category Data Types A structure type used to supply image quantization, ie. when converting a direct color image to a paletted image. This has the following members: =over =item * C - how to handle transparency, see L. =item * C - when C is C, this is the alpha level at which pixels become transparent. =item * C - when C is C this controls the type of error diffusion to be done. This may not be C for this member. =item * C - when C is C this controls the patten used for dithering transparency. =item * C - when C is C this is the ordered dither mask. =item * C - the method used to generate the color palette, see L. =item * C - an array of C L entries used to define the fixed colors (controlled by C and to return the generated color list. =item * C - the size of the buffer allocated to C in C units. =item * C - the number of initialized colors in C. =item * C - how RGB colors are translated to palette indexes, see L. =item * C - when C is C this controls the type of error diffusion to be done. =item * C, C, C, C - when C is C this controls the error diffusion map. C is an array of C integers. C is the position of the current pixel in the error diffusion map, always on the top row. =item * C - the amount to perturb pixels when C is C. =back =cut */ typedef struct i_quantize_tag { int version; /* how to handle transparency */ i_transp transp; /* the threshold at which to make pixels opaque */ int tr_threshold; i_errdiff tr_errdiff; i_ord_dith tr_orddith; unsigned char tr_custom[64]; /* how to make the colour map */ i_make_colors make_colors; /* any existing colours mc_existing is an existing colour table mc_count is the number of existing colours mc_size is the total size of the array that mc_existing points at - this must be at least 256 */ i_color *mc_colors; int mc_size; int mc_count; /* how we translate the colours */ i_translate translate; /* the error diffusion map to use if translate is mc_errdiff */ i_errdiff errdiff; /* the following define the error diffusion values to use if errdiff is ed_custom. ed_orig is the column on the top row that represents the current */ int *ed_map; int ed_width, ed_height, ed_orig; /* the amount of perturbation to use for translate is mc_perturb */ int perturb; /* version 2 members after here */ } i_quantize; /* distance measures used by some filters */ enum { i_dmeasure_euclidean = 0, i_dmeasure_euclidean_squared = 1, i_dmeasure_manhatten = 2, i_dmeasure_limit = 2, }; #include "iolayert.h" /* error message information returned by im_errors() */ typedef struct { char *msg; int code; } i_errmsg; typedef struct i_render_tag i_render; /* =item i_color_model_t =category Data Types =order 95 Returned by L to indicate the color model of the image. An enumerated type with the following possible values: =over =item * C - the image has no usable color data. In future versions of Imager this will be returned in a few limited cases, eg. when the source image is CMYK and the user has requested no color translation is done. =item * C - gray scale with no alpha channel. =item * C - gray scale with an alpha channel. =item * C - RGB =item * C - RGB with an alpha channel. =back =cut */ typedef enum { icm_unknown, icm_gray, icm_gray_alpha, icm_rgb, icm_rgb_alpha } i_color_model_t; #ifdef IMAGER_FORMAT_ATTR #define I_FORMAT_ATTR(format_index, va_index) \ __attribute ((format (printf, format_index, va_index))) #else #define I_FORMAT_ATTR(format_index, va_index) #endif #ifdef _MSC_VER # ifndef vsnprintf # define vsnprintf _vsnprintf # endif # ifndef snprintf # define snprintf _snprintf # endif #endif /* =item i_DF =category Data Types =synopsis printf("left %" i_DF "\n", i_DFc(x)); =order 95 This is a constant string that can be used with functions like printf() to format i_img_dim values after they're been cast with i_DFc(). Does not include the leading C<%>. =cut =item i_DFc =category Data Types =order 95 Cast an C value to a type for use with the i_DF format string. =cut =item i_DFp =category Data Types =synopsis printf("point (" i_DFp ")\n", i_DFcp(x, y)); =order 95 Format a pair of C values. This format string I include the leading C<%>. =cut =item i_DFcp =category Data Types =order 95 Casts two C values for use with the i_DF (or i_DFp) format. =cut */ #define i_DFc(x) ((i_dim_format_t)(x)) #define i_DFcp(x, y) i_DFc(x), i_DFc(y) #define i_DFp "%" i_DF ", %" i_DF #endif libimager-perl-1.004+dfsg.orig/rubthru.im0000644000175000017500000001315112263740601017605 0ustar gregoagregoa#include "imager.h" static int rubthru_targ_noalpha(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy) { i_img_dim x, y, tty; int alphachan; int ch; i_img_dim width = src_maxx - src_minx; int want_channels; i_clear_error(); if (im->channels == 3 && (src->channels == 4 || src->channels == 2)) { want_channels = 4; alphachan = 3; } else if (im->channels == 1 && (src->channels == 4 || src->channels == 2)) { want_channels = 2; alphachan = 1; } else { i_copyto(im, src, src_minx, src_miny, src_maxx, src_maxy, tx, ty); return 1; } #code im->bits <= 8 && src->bits <= 8 IM_WORK_T alpha; IM_COLOR *src_line, *dest_line; src_line = mymalloc(sizeof(IM_COLOR) * width); dest_line = mymalloc(sizeof(IM_COLOR) * width); tty = ty; for(y = src_miny; y < src_maxy; y++) { IM_COLOR *srcp = src_line; IM_COLOR *destp = dest_line; IM_GLIN(src, src_minx, src_maxx, y, src_line); IM_GLIN(im, tx, tx + width, tty, dest_line); if (src->channels != want_channels) IM_ADAPT_COLORS(want_channels, src->channels, src_line, width); for(x = src_minx; x < src_maxx; x++) { alpha = srcp->channel[alphachan]; for (ch = 0; ch < im->channels; ++ch) { IM_WORK_T samp = (alpha * srcp->channel[ch] + (IM_SAMPLE_MAX - alpha) * destp->channel[ch])/IM_SAMPLE_MAX; destp->channel[ch] = IM_LIMIT(samp); } ++srcp; ++destp; } IM_PLIN(im, tx, tx + width, tty, dest_line); tty++; } myfree(src_line); myfree(dest_line); #/code return 1; } static int rubthru_targ_alpha(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy) { i_img_dim x, y, ttx, tty; int want_channels; int alphachan; int ch; int targ_alpha_chan; i_img_dim width = src_maxx - src_minx; if (im->channels == 4 && (src->channels == 4 || src->channels == 2)) { alphachan = 3; want_channels = 4; } else if (im->channels == 2 && (src->channels == 4 || src->channels == 2)) { alphachan = 1; want_channels = 2; } else { i_copyto(im, src, src_minx, src_miny, src_maxx, src_maxy, tx, ty); return 1; } targ_alpha_chan = im->channels - 1; #code im->bits <= 8 && src->bits <= 8 IM_WORK_T src_alpha, orig_alpha, dest_alpha, remains; IM_COLOR *src_line, *dest_line; src_line = mymalloc(sizeof(IM_COLOR) * width); dest_line = mymalloc(sizeof(IM_COLOR) * width); tty = ty; for(y = src_miny; y < src_maxy; y++) { i_img_dim min_x, max_x; IM_COLOR *srcp = src_line; IM_COLOR *destp = dest_line; IM_GLIN(src, src_minx, src_maxx, y, src_line); if (src->channels != want_channels) IM_ADAPT_COLORS(want_channels, src->channels, src_line, width); min_x = src_minx; max_x = src_maxx; while (min_x < max_x && srcp->channel[alphachan] == 0) { ++min_x; ++srcp; } while (max_x > min_x && src_line[max_x-1 - src_minx].channel[alphachan] == 0) { --max_x; } if (max_x > min_x) { i_img_dim work_left = tx + min_x - src_minx; i_img_dim work_width = max_x - min_x; ttx = work_left; IM_GLIN(im, work_left, work_left + work_width, tty, dest_line); for(x = min_x; x < max_x; x++) { src_alpha = srcp->channel[alphachan]; if (src_alpha) { remains = IM_SAMPLE_MAX - src_alpha; orig_alpha = destp->channel[targ_alpha_chan]; dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX; for (ch = 0; ch < im->channels-1; ++ch) { IM_WORK_T samp = ( src_alpha * srcp->channel[ch] + remains * destp->channel[ch] * orig_alpha / IM_SAMPLE_MAX ) / dest_alpha; destp->channel[ch] = IM_LIMIT(samp); } /* dest's alpha */ destp->channel[targ_alpha_chan] = dest_alpha; } ++srcp; ++destp; ttx++; } IM_PLIN(im, work_left, work_left + work_width, tty, dest_line); } tty++; } myfree(dest_line); myfree(src_line); #/code return 1; } /* =item i_rubthru(C, C, C, C, C, C, C, C) =category Image Takes the sub image C[C, C)[C, C)> and overlays it at (C,C) on the image object. The alpha channel of each pixel in C is used to control how much the existing color in C is replaced, if it is 255 then the color is completely replaced, if it is 0 then the original color is left unmodified. =cut */ int i_rubthru(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy) { if (src_minx < 0) { tx -= src_minx; src_minx = 0; } if (src_miny < 0) { ty -= src_miny; src_miny = 0; } if (tx < 0) { src_minx -= tx; tx = 0; } if (ty < 0) { src_miny -= ty; ty = 0; } if (src_maxx > src->xsize) { src_maxx = src->xsize; } if (src_maxy > src->ysize) { src_maxy = src->ysize; } if (tx >= im->xsize || ty >= im->ysize || src_minx >= src_maxx || src_miny >= src_maxy) { i_clear_error(); /* just do nothing, attempting to rubthrough outside the target isn't worth being an error */ return 1; } if (im->channels == 1 || im->channels == 3) return rubthru_targ_noalpha(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy); else return rubthru_targ_alpha(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy); } libimager-perl-1.004+dfsg.orig/Flines/0000755000175000017500000000000012617614576017020 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/Flines/Flines.pm0000644000175000017500000000161212263740577020574 0ustar gregoagregoapackage Imager::Filter::Flines; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.03"; require XSLoader; XSLoader::load('Imager::Filter::Flines', $VERSION); } Imager->register_filter(type=>'flines', callsub => sub { my %hsh = @_; flines($hsh{image}) }, defaults => {}, callseq => [ 'image' ] ); 1; __END__ =head1 NAME Imager::Filter::Flines - dim alternate lines to emulate a video display =head1 SYNOPSIS use Imager; use Imager::Filter::Flines; $img->filter(type=>'flines'); =head1 DESCRIPTION This is an adaption of the C dynamically loadable filter provided in dynfilt/ in previous releases of Imager. This filter has no parameters. =head1 AUTHOR Original by Arnar M. Hrafnkelsson. Adapted by Tony Cook =head1 SEE ALSO Imager, Imager::Filters. =cut libimager-perl-1.004+dfsg.orig/Flines/t/0000755000175000017500000000000012617614576017263 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/Flines/t/t00flines.t0000644000175000017500000000156012263740577021254 0ustar gregoagregoa#!perl -w use strict; use blib; use Imager; use Test::More tests => 3; BEGIN { use_ok('Imager::Filter::Flines') } -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t00flines.log"); { my $im = Imager->new(xsize=>150, ysize=>150); $im->box(filled=>1, xmin => 70, ymin=>25, xmax =>130, ymax => 125, color=>'00FF00'); $im->box(filled=>1, xmin=>20, ymin=>25, xmax=>80, ymax=>125, color => '0000FF'); $im->arc(x =>75, y=>75, r=>30, color => 'FF0000'); $im->filter(type=>"conv", coef => [0.1, 0.2, 0.4, 0.2, 0.1]); ok($im->filter(type=>'flines'), "try filter") or print "# ", $im->errstr, "\n"; ok($im->write(file => 'testout/t00flines.ppm'), "save result"); } END { Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink 'testout/t00flines.ppm'; unlink "testout/t00flines.log"; rmdir "testout"; } } libimager-perl-1.004+dfsg.orig/Flines/Makefile.PL0000644000175000017500000000057412567572530020775 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; my %opts = ( NAME => 'Imager::Filter::Flines', VERSION_FROM => 'Flines.pm', OBJECT => 'Flines.o', INC => '-I..' ); my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'Flines Imager filter extension'; } WriteMakefile(%opts); libimager-perl-1.004+dfsg.orig/Flines/Flines.xs0000644000175000017500000000176612263740577020624 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #ifdef __cplusplus } #endif #include "imext.h" #include "imperl.h" unsigned char static saturate(int in) { if (in>255) { return 255; } else if (in>0) return in; return 0; } static void flines(i_img *im) { i_color vl; i_img_dim x,y; for(y = 0; y < im->ysize; y ++) { float yf, mf; if (!(y%2)) { yf = y/(double)im->ysize; } else { yf = (im->ysize-y)/(double)im->ysize; } mf = 1.2-0.8*yf; for(x = 0; x < im->xsize; x ++ ) { i_gpix(im,x,y,&vl); vl.rgb.r = saturate(vl.rgb.r*mf); vl.rgb.g = saturate(vl.rgb.g*mf); vl.rgb.b = saturate(vl.rgb.b*mf); i_ppix(im,x,y,&vl); } } } DEFINE_IMAGER_CALLBACKS; MODULE = Imager::Filter::Flines PACKAGE = Imager::Filter::Flines PROTOTYPES: ENABLE void flines(im) Imager::ImgRaw im BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/context.c0000644000175000017500000001327412614520110017410 0ustar gregoagregoa#include "imageri.h" #include static volatile im_slot_t slot_count = 1; static im_slot_destroy_t *volatile slot_destructors; static volatile i_mutex_t slot_mutex; /* =item im_context_new() Create a new Imager context object. =cut */ im_context_t im_context_new(void) { im_context_t ctx = malloc(sizeof(im_context_struct)); int i; if (!slot_mutex) slot_mutex = i_mutex_new(); if (!ctx) return NULL; ctx->error_sp = IM_ERROR_COUNT-1; for (i = 0; i < IM_ERROR_COUNT; ++i) { ctx->error_alloc[i] = 0; ctx->error_stack[i].msg = NULL; ctx->error_stack[i].code = 0; } #ifdef IMAGER_LOG ctx->log_level = 0; ctx->lg_file = NULL; #endif ctx->max_width = 0; ctx->max_height = 0; ctx->max_bytes = DEF_BYTES_LIMIT; ctx->slot_alloc = slot_count; ctx->slots = calloc(sizeof(void *), ctx->slot_alloc); if (!ctx->slots) { free(ctx); return NULL; } ctx->refcount = 1; #ifdef IMAGER_TRACE_CONTEXT fprintf(stderr, "im_context: created %p\n", ctx); #endif return ctx; } /* =item im_context_refinc(ctx, where) X =section Context objects =synopsis im_context_refinc(aIMCTX, "a description"); Add a new reference to the context. =cut */ void im_context_refinc(im_context_t ctx, const char *where) { ++ctx->refcount; #ifdef IMAGER_TRACE_CONTEXT fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where, ctx, (unsigned long)ctx->refcount); #endif } /* =item im_context_refdec(ctx, where) X =section Context objects =synopsis im_context_refdec(aIMCTX, "a description"); Remove a reference to the context, releasing it if all references have been removed. =cut */ void im_context_refdec(im_context_t ctx, const char *where) { int i; im_slot_t slot; im_assert(ctx->refcount > 0); --ctx->refcount; #ifdef IMAGER_TRACE_CONTEXT fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where, ctx, (unsigned long)ctx->refcount); #endif if (ctx->refcount != 0) return; /* lock here to avoid slot_destructors from being moved under us */ i_mutex_lock(slot_mutex); for (slot = 0; slot < ctx->slot_alloc; ++slot) { if (ctx->slots[slot] && slot_destructors[slot]) slot_destructors[slot](ctx->slots[slot]); } i_mutex_unlock(slot_mutex); free(ctx->slots); for (i = 0; i < IM_ERROR_COUNT; ++i) { if (ctx->error_stack[i].msg) myfree(ctx->error_stack[i].msg); } #ifdef IMAGER_LOG if (ctx->lg_file && ctx->own_log) fclose(ctx->lg_file); #endif free(ctx); } /* =item im_context_clone(ctx) Clone an Imager context object, returning the result. The error stack is not copied from the original context. =cut */ im_context_t im_context_clone(im_context_t ctx, const char *where) { im_context_t nctx = malloc(sizeof(im_context_struct)); int i; if (!nctx) return NULL; nctx->slot_alloc = slot_count; nctx->slots = calloc(sizeof(void *), nctx->slot_alloc); if (!nctx->slots) { free(nctx); return NULL; } nctx->error_sp = IM_ERROR_COUNT-1; for (i = 0; i < IM_ERROR_COUNT; ++i) { nctx->error_alloc[i] = 0; nctx->error_stack[i].msg = NULL; } #ifdef IMAGER_LOG nctx->log_level = ctx->log_level; if (ctx->lg_file) { if (ctx->own_log) { int newfd = dup(fileno(ctx->lg_file)); nctx->own_log = 1; nctx->lg_file = fdopen(newfd, "w"); if (nctx->lg_file) setvbuf(nctx->lg_file, NULL, _IONBF, BUFSIZ); } else { /* stderr */ nctx->lg_file = ctx->lg_file; nctx->own_log = 0; } } else { nctx->lg_file = NULL; } #endif nctx->max_width = ctx->max_width; nctx->max_height = ctx->max_height; nctx->max_bytes = ctx->max_bytes; nctx->refcount = 1; #ifdef IMAGER_TRACE_CONTEXT fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx); #endif return nctx; } /* =item im_context_slot_new(destructor) Allocate a new context-local-storage slot. C will be called when the context is destroyed if the corresponding slot is non-NULL. =cut */ im_slot_t im_context_slot_new(im_slot_destroy_t destructor) { im_slot_t new_slot; im_slot_destroy_t *new_destructors; if (!slot_mutex) slot_mutex = i_mutex_new(); i_mutex_lock(slot_mutex); new_slot = slot_count++; new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count); if (!new_destructors) i_fatal(1, "Cannot allocate memory for slot destructors"); slot_destructors = new_destructors; slot_destructors[new_slot] = destructor; i_mutex_unlock(slot_mutex); return new_slot; } /* =item im_context_slot_set(slot, value) Set the value of a slot. Returns true on success. Aborts if the slot supplied is invalid. If reallocation of slot storage fails, returns false. =cut */ int im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) { if (slot < 0 || slot >= slot_count) { fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n", (int)slot, (int)slot_count-1); abort(); } if (slot >= ctx->slot_alloc) { ssize_t i; size_t new_alloc = slot_count; void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc); if (!new_slots) return 0; for (i = ctx->slot_alloc; i < new_alloc; ++i) new_slots[i] = NULL; ctx->slots = new_slots; ctx->slot_alloc = new_alloc; } ctx->slots[slot] = value; return 1; } /* =item im_context_slot_get(ctx, slot) Retrieve the value previously stored in the given slot of the context object. =cut */ void * im_context_slot_get(im_context_t ctx, im_slot_t slot) { if (slot < 0 || slot >= slot_count) { fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n", (int)slot, (int)slot_count-1); abort(); } if (slot >= ctx->slot_alloc) return NULL; return ctx->slots[slot]; } libimager-perl-1.004+dfsg.orig/flip.im0000644000175000017500000001071712263740600017050 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" static void flip_h(i_img *im); static void flip_v(i_img *im); static void flip_hv(i_img *im); #define XAXIS 0 #define YAXIS 1 #define XYAXIS 2 /* =item i_flipxy(im, axis) Flips the image inplace around the axis specified. Returns 0 if parameters are invalid. im - Image pointer axis - 0 = x, 1 = y, 2 = both =cut */ undef_int i_flipxy(i_img *im, int direction) { dIMCTXim(im); i_clear_error(); im_log((aIMCTX, 1, "i_flipxy(im %p, direction %d)\n", im, direction )); if (!im) return 0; switch (direction) { case XAXIS: /* Horizontal flip */ flip_h(im); break; case YAXIS: /* Vertical flip */ flip_v(im); break; case XYAXIS: /* Horizontal and Vertical flip */ flip_hv(im); break; default: im_log((aIMCTX, 1, "i_flipxy: direction is invalid\n" )); im_push_errorf(aIMCTX, 0, "direction %d invalid", direction); return 0; } return 1; } static void flip_row_pal(i_palidx *row, i_img_dim width) { i_palidx tmp; i_palidx *leftp = row; i_palidx *rightp = row + width - 1; while (leftp < rightp) { tmp = *leftp; *leftp = *rightp; *rightp = tmp; ++leftp; --rightp; } } #code static void IM_SUFFIX(flip_row)(IM_COLOR *row, i_img_dim width) { IM_COLOR tmp; IM_COLOR *leftp = row; IM_COLOR *rightp = row + width - 1; while (leftp < rightp) { tmp = *leftp; *leftp = *rightp; *rightp = tmp; ++leftp; --rightp; } } #/code static void flip_h(i_img *im) { i_img_dim y; if (im->type == i_palette_type) { i_palidx *line = mymalloc(im->xsize * sizeof(i_palidx)); for (y = 0; y < im->ysize; ++y) { i_gpal(im, 0, im->xsize, y, line); flip_row_pal(line, im->xsize); i_ppal(im, 0, im->xsize, y, line); } myfree(line); } else { #code im->bits == i_8_bits IM_COLOR *line = mymalloc(im->xsize * sizeof(IM_COLOR)); for (y = 0; y < im->ysize; ++y) { IM_GLIN(im, 0, im->xsize, y, line); IM_SUFFIX(flip_row)(line, im->xsize); IM_PLIN(im, 0, im->xsize, y, line); } myfree(line); #/code } } static void flip_v(i_img *im) { i_img_dim topy = 0; i_img_dim boty = im->ysize - 1; if (im->type == i_palette_type) { i_palidx *top_line = mymalloc(im->xsize * sizeof(i_palidx)); i_palidx *bot_line = mymalloc(im->xsize * sizeof(i_palidx)); while (topy < boty) { i_gpal(im, 0, im->xsize, topy, top_line); i_gpal(im, 0, im->xsize, boty, bot_line); i_ppal(im, 0, im->xsize, topy, bot_line); i_ppal(im, 0, im->xsize, boty, top_line); ++topy; --boty; } myfree(bot_line); myfree(top_line); } else { #code im->bits == i_8_bits IM_COLOR *top_line = mymalloc(im->xsize * sizeof(IM_COLOR)); IM_COLOR *bot_line = mymalloc(im->xsize * sizeof(IM_COLOR)); while (topy < boty) { IM_GLIN(im, 0, im->xsize, topy, top_line); IM_GLIN(im, 0, im->xsize, boty, bot_line); IM_PLIN(im, 0, im->xsize, topy, bot_line); IM_PLIN(im, 0, im->xsize, boty, top_line); ++topy; --boty; } myfree(top_line); myfree(bot_line); #/code } } static void flip_hv(i_img *im) { i_img_dim topy = 0; i_img_dim boty = im->ysize - 1; if (im->type == i_palette_type) { i_palidx *top_line = mymalloc(im->xsize * sizeof(i_palidx)); i_palidx *bot_line = mymalloc(im->xsize * sizeof(i_palidx)); while (topy < boty) { i_gpal(im, 0, im->xsize, topy, top_line); i_gpal(im, 0, im->xsize, boty, bot_line); flip_row_pal(top_line, im->xsize); flip_row_pal(bot_line, im->xsize); i_ppal(im, 0, im->xsize, topy, bot_line); i_ppal(im, 0, im->xsize, boty, top_line); ++topy; --boty; } myfree(bot_line); myfree(top_line); } else { #code im->bits == i_8_bits IM_COLOR *top_line = mymalloc(im->xsize * sizeof(IM_COLOR)); IM_COLOR *bot_line = mymalloc(im->xsize * sizeof(IM_COLOR)); while (topy < boty) { IM_GLIN(im, 0, im->xsize, topy, top_line); IM_GLIN(im, 0, im->xsize, boty, bot_line); IM_SUFFIX(flip_row)(top_line, im->xsize); IM_SUFFIX(flip_row)(bot_line, im->xsize); IM_PLIN(im, 0, im->xsize, topy, bot_line); IM_PLIN(im, 0, im->xsize, boty, top_line); ++topy; --boty; } if (topy == boty) { IM_GLIN(im, 0, im->xsize, topy, top_line); IM_SUFFIX(flip_row)(top_line, im->xsize); IM_PLIN(im, 0, im->xsize, topy, top_line); } myfree(top_line); myfree(bot_line); #/code } } libimager-perl-1.004+dfsg.orig/stackmach.c0000644000175000017500000000132612031434615017664 0ustar gregoagregoa#include "stackmach.h" double i_op_run(int codes[], size_t code_size, double parms[], size_t parm_size) { double stack[100]; double *sp = stack; while (code_size) { switch (*codes++) { case bcAdd: sp[-2] += sp[-1]; --sp; break; case bcSubtract: sp[-2] -= sp[-1]; --sp; break; case bcDiv: sp[-2] /= sp[-1]; --sp; break; case bcMult: sp[-2] *= sp[-1]; --sp; break; case bcParm: *sp++ = parms[*codes++]; --code_size; break; case bcSin: sp[-1] = sin(sp[-1]); break; case bcCos: sp[-1] = cos(sp[-1]); break; } --code_size; } return sp[-1]; } libimager-perl-1.004+dfsg.orig/mutexnull.c0000644000175000017500000000070512263740601017765 0ustar gregoagregoa/* dummy mutexes, for non-threaded builds */ #include "imageri.h" #include /* documented in mutexwin.c */ struct i_mutex_tag { int dummy; }; i_mutex_t i_mutex_new(void) { i_mutex_t m; m = malloc(sizeof(*m)); if (!m) i_fatal(3, "Cannot allocate mutex object"); return m; } void i_mutex_destroy(i_mutex_t m) { free(m); } void i_mutex_lock(i_mutex_t m) { (void)m; } void i_mutex_unlock(i_mutex_t m) { (void)m; } libimager-perl-1.004+dfsg.orig/SGI/0000755000175000017500000000000012617614576016222 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/SGI/SGI.pm0000644000175000017500000000251412263740600017165 0ustar gregoagregoapackage Imager::File::SGI; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.03"; require XSLoader; XSLoader::load('Imager::File::SGI', $VERSION); } Imager->register_reader ( type=>'sgi', single => sub { my ($im, $io, %hsh) = @_; $im->{IMG} = i_readsgi_wiol($io, $hsh{page} || 0); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, ); Imager->register_writer ( type=>'sgi', single => sub { my ($im, $io, %hsh) = @_; $im->_set_opts(\%hsh, "i_", $im); $im->_set_opts(\%hsh, "sgi_", $im); unless (i_writesgi_wiol($io, $im->{IMG})) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, ); __END__ =head1 NAME Imager::File::ICO - read MS Icon files =head1 SYNOPSIS use Imager; my $img = Imager->new; $img->read(file=>"foo.ico") or die $img->errstr; my @imgs = Imager->read_multi(file => "foo.ico") or die Imager->errstr; $img->write(file => "foo.ico") or die $img->errstr; Imager->write_multi({ file => "foo.ico" }, @imgs) or die Imager->errstr; =head1 DESCRIPTION Imager's MS Icon support is documented in L. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Files. =cut libimager-perl-1.004+dfsg.orig/SGI/testimg/0000755000175000017500000000000012617614576017676 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/SGI/testimg/rle6.rgb0000644000175000017500000000243412031434614021224 0ustar gregoagregoaÚ?no nameàåêïôùþ !&+05:?DINSX]bglqv{€…Š”™ž£¨«®µ¼ÃÊÑØÛÞåìóú ??????????????????????????????????????????????????????libimager-perl-1.004+dfsg.orig/SGI/testimg/verb.rgb0000644000175000017500000000326012031434614021310 0ustar gregoagregoaÚÿtest imageÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/SGI/testimg/rleagr.rgb0000644000175000017500000000235712031434614021634 0ustar gregoagregoaÚÿâÕàଛààviàà@/àà ýààçÚɽ± ƒ{n]QE4#ñåìßζ¥”ˆ€sbVJ9(öêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/SGI/testimg/verb16.rgb0000644000175000017500000000554012031434614021462 0ustar gregoagregoaÚÿÿno nameÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/SGI/testimg/rle.rgb0000644000175000017500000000243412031434614021136 0ustar gregoagregoaÚÿñàϾ­œ‚q`O>-ñàöåÔò¡”‡veTC2!öå ûêÙÈ·¦™Œ{jYH7& ûêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/SGI/testimg/verb6.rgb0000644000175000017500000000326012031434614021376 0ustar gregoagregoaÚ?no name????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????libimager-perl-1.004+dfsg.orig/SGI/testimg/rle16.rgb0000644000175000017500000000313012031434614021277 0ustar gregoagregoaÚÿÿtest image0êôþ&0:DNXblv€Š”ž¨²¼ÆÐÚäîø  *4>HR\fpv|Š˜¦´ÂÐÖÜêø"06<J ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/SGI/testimg/rle12.rgb0000644000175000017500000000313012031434614021273 0ustar gregoagregoaÚÿno nameàêôþ&0:DNXblv€Š”ž¨²¼ÆÐÚäîø  *4>HR\fpv|Š˜¦´ÂÐÖÜêø"06<J ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/SGI/testimg/verb12.rgb0000644000175000017500000000554012031434614021456 0ustar gregoagregoaÚÿno nameÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿlibimager-perl-1.004+dfsg.orig/SGI/imsgi.h0000644000175000017500000000027712031434614017470 0ustar gregoagregoa#ifndef IMAGER_IMICON_H #define IMAGER_IMICON_H #include "imext.h" extern i_img * i_readsgi_wiol(io_glue *ig, int partial); extern int i_writesgi_wiol(i_io_glue_t *ig, i_img *im); #endif libimager-perl-1.004+dfsg.orig/SGI/imsgi.c0000644000175000017500000007350712263740600017473 0ustar gregoagregoa#include "imsgi.h" #include #include #include /* value for imagic */ #define SGI_MAGIC 474 /* values for the storage field */ #define SGI_STORAGE_VERBATIM 0 #define SGI_STORAGE_RLE 1 /* values for the colormap field */ #define SGI_COLORMAP_NORMAL 0 #define SGI_COLORMAP_DITHERED 1 #define SGI_COLORMAP_SCREEN 2 #define SGI_COLORMAP_COLORMAP 3 /* we add that little bit to avoid rounding issues */ #define SampleFTo16(num) ((int)((num) * 65535.0 + 0.01)) /* maximum size of an SGI image */ #define SGI_DIM_LIMIT 0xFFFF typedef struct { unsigned short imagic; unsigned char storagetype; unsigned char BPC; unsigned short dimensions; unsigned short xsize, ysize, zsize; unsigned int pixmin, pixmax; char name[80]; unsigned int colormap; } rgb_header; static i_img * read_rgb_8_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr); static i_img * read_rgb_8_rle(i_img *im, io_glue *ig, rgb_header const *hdr); static i_img * read_rgb_16_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr); static i_img * read_rgb_16_rle(i_img *im, io_glue *ig, rgb_header const *hdr); static int write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2); static int write_sgi_8_rle(i_img *img, io_glue *ig); static int write_sgi_8_verb(i_img *img, io_glue *ig); static int write_sgi_16_rle(i_img *img, io_glue *ig); static int write_sgi_16_verb(i_img *img, io_glue *ig); #define Sample16ToF(num) ((num) / 65535.0) #define _STRING(x) #x #define STRING(x) _STRING(x) /* =head1 NAME rgb.c - implements reading and writing sgi image files, uses io layer. =head1 SYNOPSIS io_glue *ig = io_new_fd( fd ); i_img *im = i_readrgb_wiol(ig, 0); // disallow partial reads // or io_glue *ig = io_new_fd( fd ); return_code = i_writergb_wiol(im, ig); =head1 DESCRIPTION imsgi.c implements the basic functions to read and write portable SGI files. It uses the iolayer and needs either a seekable source or an entire memory mapped buffer. =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ /* =item rgb_header_unpack(header, headbuf) Unpacks the header structure into from buffer and stores in the header structure. header - header structure headbuf - buffer to unpack from =cut */ static void rgb_header_unpack(rgb_header *header, const unsigned char *headbuf) { header->imagic = (headbuf[0]<<8) + headbuf[1]; header->storagetype = headbuf[2]; header->BPC = headbuf[3]; header->dimensions = (headbuf[4]<<8) + headbuf[5]; header->xsize = (headbuf[6]<<8) + headbuf[7]; header->ysize = (headbuf[8]<<8) + headbuf[9]; header->zsize = (headbuf[10]<<8) + headbuf[11]; header->pixmin = (headbuf[12]<<24) + (headbuf[13]<<16)+(headbuf[14]<<8)+headbuf[15]; header->pixmax = (headbuf[16]<<24) + (headbuf[17]<<16)+(headbuf[18]<<8)+headbuf[19]; memcpy(header->name,headbuf+24,80); header->name[79] = '\0'; header->colormap = (headbuf[104]<<24) + (headbuf[105]<<16)+(headbuf[106]<<8)+headbuf[107]; } /* don't make this a macro */ static void store_16(unsigned char *buf, unsigned short value) { buf[0] = value >> 8; buf[1] = value & 0xFF; } static void store_32(unsigned char *buf, unsigned long value) { buf[0] = value >> 24; buf[1] = (value >> 16) & 0xFF; buf[2] = (value >> 8) & 0xFF; buf[3] = value & 0xFF; } /* =item rgb_header_pack(header, headbuf) Packs header structure into buffer for writing. header - header structure headbuf - buffer to pack into =cut */ static void rgb_header_pack(const rgb_header *header, unsigned char headbuf[512]) { memset(headbuf, 0, 512); store_16(headbuf, header->imagic); headbuf[2] = header->storagetype; headbuf[3] = header->BPC; store_16(headbuf+4, header->dimensions); store_16(headbuf+6, header->xsize); store_16(headbuf+8, header->ysize); store_16(headbuf+10, header->zsize); store_32(headbuf+12, header->pixmin); store_32(headbuf+16, header->pixmax); memccpy(headbuf+24, header->name, '\0', 80); store_32(headbuf+104, header->colormap); } /* =item i_readsgi_wiol(ig, partial) Read in an image from the iolayer data source and return the image structure to it. Returns NULL on error. ig - io_glue object length - maximum length to read from data source, before closing it -1 signifies no limit. =cut */ i_img * i_readsgi_wiol(io_glue *ig, int partial) { i_img *img = NULL; int width, height, channels; rgb_header header; unsigned char headbuf[512]; mm_log((1,"i_readsgi(ig %p, partial %d)\n", ig, partial)); i_clear_error(); if (i_io_read(ig, headbuf, 512) != 512) { i_push_error(errno, "SGI image: could not read header"); return NULL; } rgb_header_unpack(&header, headbuf); if (header.imagic != SGI_MAGIC) { i_push_error(0, "SGI image: invalid magic number"); return NULL; } mm_log((1,"imagic: %d\n", header.imagic)); mm_log((1,"storagetype: %d\n", header.storagetype)); mm_log((1,"BPC: %d\n", header.BPC)); mm_log((1,"dimensions: %d\n", header.dimensions)); mm_log((1,"xsize: %d\n", header.xsize)); mm_log((1,"ysize: %d\n", header.ysize)); mm_log((1,"zsize: %d\n", header.zsize)); mm_log((1,"min: %d\n", header.pixmin)); mm_log((1,"max: %d\n", header.pixmax)); mm_log((1,"name [skipped]\n")); mm_log((1,"colormap: %d\n", header.colormap)); if (header.colormap != SGI_COLORMAP_NORMAL) { i_push_errorf(0, "SGI image: invalid value for colormap (%d)", header.colormap); return NULL; } if (header.BPC != 1 && header.BPC != 2) { i_push_errorf(0, "SGI image: invalid value for BPC (%d)", header.BPC); return NULL; } if (header.storagetype != SGI_STORAGE_VERBATIM && header.storagetype != SGI_STORAGE_RLE) { i_push_error(0, "SGI image: invalid storage type field"); return NULL; } if (header.pixmin >= header.pixmax) { i_push_error(0, "SGI image: invalid pixmin >= pixmax"); return NULL; } width = header.xsize; height = header.ysize; channels = header.zsize; switch (header.dimensions) { case 1: channels = 1; height = 1; break; case 2: channels = 1; break; case 3: /* fall through and use all of the dimensions */ break; default: i_push_error(0, "SGI image: invalid dimension field"); return NULL; } if (!i_int_check_image_file_limits(width, height, channels, header.BPC)) { mm_log((1, "i_readsgi_wiol: image size exceeds limits\n")); return NULL; } if (header.BPC == 1) { img = i_img_8_new(width, height, channels); if (!img) goto ErrorReturn; switch (header.storagetype) { case SGI_STORAGE_VERBATIM: img = read_rgb_8_verbatim(img, ig, &header); break; case SGI_STORAGE_RLE: img = read_rgb_8_rle(img, ig, &header); break; default: goto ErrorReturn; } } else { img = i_img_16_new(width, height, channels); if (!img) goto ErrorReturn; switch (header.storagetype) { case SGI_STORAGE_VERBATIM: img = read_rgb_16_verbatim(img, ig, &header); break; case SGI_STORAGE_RLE: img = read_rgb_16_rle(img, ig, &header); break; default: goto ErrorReturn; } } if (!img) goto ErrorReturn; if (*header.name) i_tags_set(&img->tags, "i_comment", header.name, -1); i_tags_setn(&img->tags, "sgi_pixmin", header.pixmin); i_tags_setn(&img->tags, "sgi_pixmax", header.pixmax); i_tags_setn(&img->tags, "sgi_bpc", header.BPC); i_tags_setn(&img->tags, "sgi_rle", header.storagetype == SGI_STORAGE_RLE); i_tags_set(&img->tags, "i_format", "sgi", -1); return img; ErrorReturn: if (img) i_img_destroy(img); return NULL; } /* =item i_writergb_wiol(img, ig) Writes an image in targa format. Returns 0 on error. img - image to store ig - io_glue object =cut */ int i_writesgi_wiol(io_glue *ig, i_img *img) { int rle; int bpc2; i_clear_error(); if (img->xsize > SGI_DIM_LIMIT || img->ysize > SGI_DIM_LIMIT) { i_push_error(0, "image too large for SGI"); return 0; } if (!write_sgi_header(img, ig, &rle, &bpc2)) return 0; mm_log((1, "format rle %d bpc2 %d\n", rle, bpc2)); if (bpc2) { if (rle) return write_sgi_16_rle(img, ig); else return write_sgi_16_verb(img, ig); } else { if (rle) return write_sgi_8_rle(img, ig); else return write_sgi_8_verb(img, ig); } } static i_img * read_rgb_8_verbatim(i_img *img, io_glue *ig, rgb_header const *header) { i_color *linebuf; unsigned char *databuf; int c, y; int savemask; i_img_dim width = i_img_get_width(img); i_img_dim height = i_img_get_height(img); int channels = i_img_getchannels(img); int pixmin = header->pixmin; int pixmax = header->pixmax; int outmax = pixmax - pixmin; linebuf = mymalloc(width * sizeof(i_color)); /* checked 31Jul07 TonyC */ databuf = mymalloc(width); /* checked 31Jul07 TonyC */ savemask = i_img_getmask(img); for(c = 0; c < channels; c++) { i_img_setmask(img, 1<xsize; x++) linebuf[x].channel[c] = databuf[x]; } else { for(x = 0; x < img->xsize; x++) { int sample = databuf[x]; if (sample < pixmin) sample = 0; else if (sample > pixmax) sample = outmax; else sample -= pixmin; linebuf[x].channel[c] = sample * 255 / outmax; } } i_plin(img, 0, width, height-1-y, linebuf); } } i_img_setmask(img, savemask); myfree(linebuf); myfree(databuf); return img; } static int read_rle_tables(io_glue *ig, i_img *img, unsigned long **pstart_tab, unsigned long **plength_tab, unsigned long *pmax_length) { i_img_dim height = i_img_get_height(img); int channels = i_img_getchannels(img); unsigned char *databuf; unsigned long *start_tab, *length_tab; unsigned long max_length = 0; int i; size_t databuf_size = (size_t)height * channels * 4; size_t tab_size = (size_t)height * channels * sizeof(unsigned long); /* assumption: that the lengths are in bytes rather than in pixels */ if (databuf_size / height / channels != 4 || tab_size / height / channels != sizeof(unsigned long)) { i_push_error(0, "SGI image: integer overflow calculating allocation size"); return 0; } databuf = mymalloc(height * channels * 4); /* checked 31Jul07 TonyC */ start_tab = mymalloc(height*channels*sizeof(unsigned long)); length_tab = mymalloc(height*channels*sizeof(unsigned long)); /* Read offset table */ if (i_io_read(ig, databuf, height * channels * 4) != height * channels * 4) { i_push_error(0, "SGI image: short read reading RLE start table"); goto ErrorReturn; } for(i = 0; i < height * channels; i++) start_tab[i] = (databuf[i*4] << 24) | (databuf[i*4+1] << 16) | (databuf[i*4+2] << 8) | (databuf[i*4+3]); /* Read length table */ if (i_io_read(ig, databuf, height*channels*4) != height*channels*4) { i_push_error(0, "SGI image: short read reading RLE length table"); goto ErrorReturn; } for(i=0; i < height * channels; i++) { length_tab[i] = (databuf[i*4] << 24) + (databuf[i*4+1] << 16)+ (databuf[i*4+2] << 8) + (databuf[i*4+3]); if (length_tab[i] > max_length) max_length = length_tab[i]; } mm_log((3, "Offset/length table:\n")); for(i=0; i < height * channels; i++) mm_log((3, "%d: %lu/%lu\n", i, start_tab[i], length_tab[i])); *pstart_tab = start_tab; *plength_tab = length_tab; *pmax_length = max_length; myfree(databuf); return 1; ErrorReturn: myfree(databuf); myfree(start_tab); myfree(length_tab); return 0; } static i_img * read_rgb_8_rle(i_img *img, io_glue *ig, rgb_header const *header) { i_color *linebuf = NULL; unsigned char *databuf = NULL; unsigned long *start_tab, *length_tab; unsigned long max_length; i_img_dim width = i_img_get_width(img); i_img_dim height = i_img_get_height(img); int channels = i_img_getchannels(img); i_img_dim y; int c; int pixmin = header->pixmin; int pixmax = header->pixmax; int outmax = pixmax - pixmin; if (!read_rle_tables(ig, img, &start_tab, &length_tab, &max_length)) { i_img_destroy(img); return NULL; } mm_log((1, "maxlen for an rle buffer: %lu\n", max_length)); if (max_length > (img->xsize + 1) * 2) { i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length); goto ErrorReturn; } linebuf = mymalloc(width*sizeof(i_color)); /* checked 31Jul07 TonyC */ databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */ for(y = 0; y < img->ysize; y++) { for(c = 0; c < channels; c++) { int ci = height * c + y; int datalen = length_tab[ci]; unsigned char *inp; i_color *outp; int data_left = datalen; int pixels_left = width; i_sample_t sample; if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) { i_push_error(0, "SGI image: cannot seek to RLE data"); goto ErrorReturn; } if (i_io_read(ig, databuf, datalen) != datalen) { i_push_error(0, "SGI image: cannot read RLE data"); goto ErrorReturn; } inp = databuf; outp = linebuf; while (data_left) { int code = *inp++; int count = code & 0x7f; --data_left; if (count == 0) break; if (code & 0x80) { /* literal run */ /* sanity checks */ if (count > pixels_left) { i_push_error(0, "SGI image: literal run overflows scanline"); goto ErrorReturn; } if (count > data_left) { i_push_error(0, "SGI image: literal run consumes more data than available"); goto ErrorReturn; } /* copy the run */ pixels_left -= count; data_left -= count; if (pixmin == 0 && pixmax == 255) { while (count-- > 0) { outp->channel[c] = *inp++; ++outp; } } else { while (count-- > 0) { int sample = *inp++; if (sample < pixmin) sample = 0; else if (sample > pixmax) sample = outmax; else sample -= pixmin; outp->channel[c] = sample * 255 / outmax; ++outp; } } } else { /* RLE run */ if (count > pixels_left) { i_push_error(0, "SGI image: RLE run overflows scanline"); mm_log((2, "RLE run overflows scanline (y %" i_DF " chan %d offset %lu len %lu)\n", i_DFc(y), c, start_tab[ci], length_tab[ci])); goto ErrorReturn; } if (data_left < 1) { i_push_error(0, "SGI image: RLE run has no data for pixel"); goto ErrorReturn; } sample = *inp++; if (pixmin != 0 || pixmax != 255) { if (sample < pixmin) sample = 0; else if (sample > pixmax) sample = outmax; else sample -= pixmin; sample = sample * 255 / outmax; } --data_left; pixels_left -= count; while (count-- > 0) { outp->channel[c] = sample; ++outp; } } } /* must have a full scanline */ if (pixels_left) { i_push_error(0, "SGI image: incomplete RLE scanline"); goto ErrorReturn; } /* must have used all of the data */ if (data_left) { i_push_errorf(0, "SGI image: unused RLE data"); goto ErrorReturn; } } i_plin(img, 0, width, height-1-y, linebuf); } myfree(linebuf); myfree(databuf); myfree(start_tab); myfree(length_tab); return img; ErrorReturn: if (linebuf) myfree(linebuf); if (databuf) myfree(databuf); myfree(start_tab); myfree(length_tab); i_img_destroy(img); return NULL; } static i_img * read_rgb_16_verbatim(i_img *img, io_glue *ig, rgb_header const *header) { i_fcolor *linebuf; unsigned char *databuf; int c, y; int savemask; i_img_dim width = i_img_get_width(img); i_img_dim height = i_img_get_height(img); int channels = i_img_getchannels(img); int pixmin = header->pixmin; int pixmax = header->pixmax; int outmax = pixmax - pixmin; linebuf = mymalloc(width * sizeof(i_fcolor)); /* checked 31Jul07 TonyC */ databuf = mymalloc(width * 2); /* checked 31Jul07 TonyC */ savemask = i_img_getmask(img); for(c = 0; c < channels; c++) { i_img_setmask(img, 1<xsize; x++) linebuf[x].channel[c] = (databuf[x*2] * 256 + databuf[x*2+1]) / 65535.0; } else { for(x = 0; x < img->xsize; x++) { int sample = databuf[x*2] * 256 + databuf[x*2+1]; if (sample < pixmin) sample = 0; else if (sample > pixmax) sample = outmax; else sample -= pixmin; linebuf[x].channel[c] = (double)sample / outmax; } } i_plinf(img, 0, width, height-1-y, linebuf); } } i_img_setmask(img, savemask); myfree(linebuf); myfree(databuf); return img; } static i_img * read_rgb_16_rle(i_img *img, io_glue *ig, rgb_header const *header) { i_fcolor *linebuf = NULL; unsigned char *databuf = NULL; unsigned long *start_tab, *length_tab; unsigned long max_length; i_img_dim width = i_img_get_width(img); i_img_dim height = i_img_get_height(img); int channels = i_img_getchannels(img); i_img_dim y; int c; int pixmin = header->pixmin; int pixmax = header->pixmax; int outmax = pixmax - pixmin; if (!read_rle_tables(ig, img, &start_tab, &length_tab, &max_length)) { i_img_destroy(img); return NULL; } mm_log((1, "maxlen for an rle buffer: %lu\n", max_length)); if (max_length > (img->xsize * 2 + 1) * 2) { i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length); goto ErrorReturn; } linebuf = mymalloc(width*sizeof(i_fcolor)); /* checked 31Jul07 TonyC */ databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */ for(y = 0; y < img->ysize; y++) { for(c = 0; c < channels; c++) { int ci = height * c + y; int datalen = length_tab[ci]; unsigned char *inp; i_fcolor *outp; int data_left = datalen; int pixels_left = width; int sample; if (datalen & 1) { i_push_error(0, "SGI image: invalid RLE length value for BPC=2"); goto ErrorReturn; } if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) { i_push_error(0, "SGI image: cannot seek to RLE data"); goto ErrorReturn; } if (i_io_read(ig, databuf, datalen) != datalen) { i_push_error(0, "SGI image: cannot read RLE data"); goto ErrorReturn; } inp = databuf; outp = linebuf; while (data_left > 0) { int code = inp[0] * 256 + inp[1]; int count = code & 0x7f; inp += 2; data_left -= 2; if (count == 0) break; if (code & 0x80) { /* literal run */ /* sanity checks */ if (count > pixels_left) { i_push_error(0, "SGI image: literal run overflows scanline"); goto ErrorReturn; } if (count > data_left) { i_push_error(0, "SGI image: literal run consumes more data than available"); goto ErrorReturn; } /* copy the run */ pixels_left -= count; data_left -= count * 2; if (pixmin == 0 && pixmax == 65535) { while (count-- > 0) { outp->channel[c] = (inp[0] * 256 + inp[1]) / 65535.0; inp += 2; ++outp; } } else { while (count-- > 0) { int sample = inp[0] * 256 + inp[1]; if (sample < pixmin) sample = 0; else if (sample > pixmax) sample = outmax; else sample -= pixmin; outp->channel[c] = (double)sample / outmax; ++outp; inp += 2; } } } else { double fsample; /* RLE run */ if (count > pixels_left) { i_push_error(0, "SGI image: RLE run overflows scanline"); goto ErrorReturn; } if (data_left < 2) { i_push_error(0, "SGI image: RLE run has no data for pixel"); goto ErrorReturn; } sample = inp[0] * 256 + inp[1]; inp += 2; data_left -= 2; if (pixmin != 0 || pixmax != 65535) { if (sample < pixmin) sample = 0; else if (sample > pixmax) sample = outmax; else sample -= pixmin; fsample = (double)sample / outmax; } else { fsample = (double)sample / 65535.0; } pixels_left -= count; while (count-- > 0) { outp->channel[c] = fsample; ++outp; } } } /* must have a full scanline */ if (pixels_left) { i_push_error(0, "SGI image: incomplete RLE scanline"); goto ErrorReturn; } /* must have used all of the data */ if (data_left) { i_push_errorf(0, "SGI image: unused RLE data"); goto ErrorReturn; } } i_plinf(img, 0, width, height-1-y, linebuf); } myfree(linebuf); myfree(databuf); myfree(start_tab); myfree(length_tab); return img; ErrorReturn: if (linebuf) myfree(linebuf); if (databuf) myfree(databuf); myfree(start_tab); myfree(length_tab); i_img_destroy(img); return NULL; } static int write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2) { rgb_header header; unsigned char headbuf[512] = { 0 }; header.imagic = SGI_MAGIC; if (!i_tags_get_int(&img->tags, "sgi_rle", 0, rle)) *rle = 0; header.storagetype = *rle ? SGI_STORAGE_RLE : SGI_STORAGE_VERBATIM; header.pixmin = 0; header.colormap = SGI_COLORMAP_NORMAL; *bpc2 = img->bits > 8; if (*bpc2) { header.BPC = 2; header.pixmax = 65535; } else { header.BPC = 1; header.pixmax = 255; } if (img->channels == 1) { header.dimensions = 2; } else { header.dimensions = 3; } header.xsize = img->xsize; header.ysize = img->ysize; header.zsize = img->channels; memset(header.name, 0, sizeof(header.name)); i_tags_get_string(&img->tags, "i_comment", 0, header.name, sizeof(header.name)); rgb_header_pack(&header, headbuf); if (i_io_write(ig, headbuf, sizeof(headbuf)) != sizeof(headbuf)) { i_push_error(0, "SGI image: cannot write header"); return 0; } return 1; } static int write_sgi_8_verb(i_img *img, io_glue *ig) { i_sample_t *linebuf; i_img_dim width = img->xsize; int c; i_img_dim y; linebuf = mymalloc(width); /* checked 31Jul07 TonyC */ for (c = 0; c < img->channels; ++c) { for (y = img->ysize - 1; y >= 0; --y) { i_gsamp(img, 0, width, y, linebuf, &c, 1); if (i_io_write(ig, linebuf, width) != width) { i_push_error(errno, "SGI image: error writing image data"); myfree(linebuf); return 0; } } } myfree(linebuf); if (i_io_close(ig)) return 0; return 1; } static int write_sgi_8_rle(i_img *img, io_glue *ig) { i_sample_t *linebuf; unsigned char *comp_buf; i_img_dim width = img->xsize; int c; i_img_dim y; unsigned char *offsets; unsigned char *lengths; int offset_pos = 0; size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2; unsigned long start_offset = 512 + offsets_size; unsigned long current_offset = start_offset; int in_left; unsigned char *outp; i_sample_t *inp; size_t comp_size; if (offsets_size / 2 / 4 / img->channels != img->ysize) { i_push_error(0, "SGI image: integer overflow calculating allocation size"); return 0; } linebuf = mymalloc(width); /* checked 31Jul07 TonyC */ comp_buf = mymalloc((width + 1) * 2); /* checked 31Jul07 TonyC */ offsets = mymalloc(offsets_size); memset(offsets, 0, offsets_size); if (i_io_write(ig, offsets, offsets_size) != offsets_size) { i_push_error(errno, "SGI image: error writing offsets/lengths"); goto Error; } lengths = offsets + img->ysize * img->channels * 4; for (c = 0; c < img->channels; ++c) { for (y = img->ysize - 1; y >= 0; --y) { i_gsamp(img, 0, width, y, linebuf, &c, 1); in_left = width; outp = comp_buf; inp = linebuf; while (in_left) { unsigned char *run_start = inp; /* first try for an RLE run */ int run_length = 1; while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) { ++run_length; ++inp; } if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) { ++run_length; ++inp; } if (run_length > 2) { *outp++ = run_length; *outp++ = inp[0]; inp++; in_left -= run_length; } else { inp = run_start; /* scan for a literal run */ run_length = 1; run_start = inp; while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) { ++run_length; ++inp; } ++inp; /* fill out the run if 2 or less samples left and there's space */ if (in_left - run_length <= 2 && in_left <= 127) { run_length = in_left; } in_left -= run_length; *outp++ = run_length | 0x80; while (run_length--) { *outp++ = *run_start++; } } } *outp++ = 0; comp_size = outp - comp_buf; store_32(offsets + offset_pos, current_offset); store_32(lengths + offset_pos, comp_size); offset_pos += 4; current_offset += comp_size; if (i_io_write(ig, comp_buf, comp_size) != comp_size) { i_push_error(errno, "SGI image: error writing RLE data"); goto Error; } } } /* seek back to store the offsets and lengths */ if (i_io_seek(ig, 512, SEEK_SET) != 512) { i_push_error(errno, "SGI image: cannot seek to RLE table"); goto Error; } if (i_io_write(ig, offsets, offsets_size) != offsets_size) { i_push_error(errno, "SGI image: cannot write final RLE table"); goto Error; } myfree(offsets); myfree(comp_buf); myfree(linebuf); if (i_io_close(ig)) return 0; return 1; Error: myfree(offsets); myfree(comp_buf); myfree(linebuf); return 0; } static int write_sgi_16_verb(i_img *img, io_glue *ig) { i_fsample_t *linebuf; unsigned char *encbuf; unsigned char *outp; i_img_dim width = img->xsize; int c; i_img_dim x; i_img_dim y; linebuf = mymalloc(width * sizeof(i_fsample_t)); /* checked 31Jul07 TonyC */ encbuf = mymalloc(width * 2); /* checked 31Jul07 TonyC */ for (c = 0; c < img->channels; ++c) { for (y = img->ysize - 1; y >= 0; --y) { i_gsampf(img, 0, width, y, linebuf, &c, 1); for (x = 0, outp = encbuf; x < width; ++x, outp+=2) { unsigned short samp16 = SampleFTo16(linebuf[x]); store_16(outp, samp16); } if (i_io_write(ig, encbuf, width * 2) != width * 2) { i_push_error(errno, "SGI image: error writing image data"); myfree(linebuf); myfree(encbuf); return 0; } } } myfree(linebuf); myfree(encbuf); if (i_io_close(ig)) return 0; return 1; } static int write_sgi_16_rle(i_img *img, io_glue *ig) { i_fsample_t *sampbuf; unsigned short *linebuf; unsigned char *comp_buf; i_img_dim width = img->xsize; int c; i_img_dim y; unsigned char *offsets; unsigned char *lengths; int offset_pos = 0; size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2; unsigned long start_offset = 512 + offsets_size; unsigned long current_offset = start_offset; int in_left; unsigned char *outp; unsigned short *inp; size_t comp_size; i_img_dim x; if (offsets_size / 4 / 2 / img->channels != img->ysize) { i_push_error(0, "SGI image: integer overflow calculating allocation size"); return 0; } sampbuf = mymalloc(width * sizeof(i_fsample_t)); /* checked 31Jul07 TonyC */ linebuf = mymalloc(width * sizeof(unsigned short)); /* checked 31Jul07 TonyC */ comp_buf = mymalloc((width + 1) * 2 * 2); /* checked 31Jul07 TonyC */ offsets = mymalloc(offsets_size); memset(offsets, 0, offsets_size); if (i_io_write(ig, offsets, offsets_size) != offsets_size) { i_push_error(errno, "SGI image: error writing offsets/lengths"); goto Error; } lengths = offsets + img->ysize * img->channels * 4; for (c = 0; c < img->channels; ++c) { for (y = img->ysize - 1; y >= 0; --y) { i_gsampf(img, 0, width, y, sampbuf, &c, 1); for (x = 0; x < width; ++x) linebuf[x] = (unsigned short)(SampleFTo16(sampbuf[x])); in_left = width; outp = comp_buf; inp = linebuf; while (in_left) { unsigned short *run_start = inp; /* first try for an RLE run */ int run_length = 1; while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) { ++run_length; ++inp; } if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) { ++run_length; ++inp; } if (run_length > 2) { store_16(outp, run_length); store_16(outp+2, inp[0]); outp += 4; inp++; in_left -= run_length; } else { inp = run_start; /* scan for a literal run */ run_length = 1; run_start = inp; while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) { ++run_length; ++inp; } ++inp; /* fill out the run if 2 or less samples left and there's space */ if (in_left - run_length <= 2 && in_left <= 127) { run_length = in_left; } in_left -= run_length; store_16(outp, run_length | 0x80); outp += 2; while (run_length--) { store_16(outp, *run_start++); outp += 2; } } } store_16(outp, 0); outp += 2; comp_size = outp - comp_buf; store_32(offsets + offset_pos, current_offset); store_32(lengths + offset_pos, comp_size); offset_pos += 4; current_offset += comp_size; if (i_io_write(ig, comp_buf, comp_size) != comp_size) { i_push_error(errno, "SGI image: error writing RLE data"); goto Error; } } } /* seek back to store the offsets and lengths */ if (i_io_seek(ig, 512, SEEK_SET) != 512) { i_push_error(errno, "SGI image: cannot seek to RLE table"); goto Error; } if (i_io_write(ig, offsets, offsets_size) != offsets_size) { i_push_error(errno, "SGI image: cannot write final RLE table"); goto Error; } myfree(offsets); myfree(comp_buf); myfree(linebuf); myfree(sampbuf); if (i_io_close(ig)) return 0; return 1; Error: myfree(offsets); myfree(comp_buf); myfree(linebuf); myfree(sampbuf); return 0; } libimager-perl-1.004+dfsg.orig/SGI/t/0000755000175000017500000000000012617614576016465 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/SGI/t/20write.t0000644000175000017500000001562112263740600020134 0ustar gregoagregoa#!perl -w use strict; use Imager; use Test::More tests => 57; use Imager::Test qw(test_image test_image_16 is_image); use IO::Seekable; -d 'testout' or mkdir 'testout', 0777; Imager::init_log('testout/20write.log', 2); { my $im = test_image(); $im->line(x1 => 0, y1 => 0, x2 => 150, y2 => 150, color => 'FF0000'); ok($im->write(file => 'testout/20verb.rgb'), "write 8-bit verbatim") or print "# ", $im->errstr, "\n"; my $im2 = Imager->new; ok($im2->read(file => 'testout/20verb.rgb'), "read it back") or print "# ", $im2->errstr, "\n"; is_image($im, $im2, "compare"); is($im2->tags(name => 'sgi_rle'), 0, "check not rle"); is($im2->tags(name => 'sgi_bpc'), 1, "check bpc"); is($im2->tags(name => 'i_comment'), undef, "no namestr"); ok($im->write(file => 'testout/20rle.rgb', sgi_rle => 1, i_comment => "test"), "write 8-bit rle") or print "# ", $im->errstr, "\n"; my $im3 = Imager->new; ok($im3->read(file => 'testout/20rle.rgb'), "read it back") or print "# ", $im3->errstr, "\n"; is_image($im, $im3, "compare"); is($im3->tags(name => 'sgi_rle'), 1, "check not rle"); is($im3->tags(name => 'sgi_bpc'), 1, "check bpc"); is($im3->tags(name => 'i_comment'), 'test', "check i_comment set"); } { my $im = test_image_16(); $im->line(x1 => 0, y1 => 0, x2 => 150, y2 => 150, color => 'FF0000'); ok($im->write(file => 'testout/20verb16.rgb'), "write 16-bit verbatim") or print "# ", $im->errstr, "\n"; my $im2 = Imager->new; ok($im2->read(file => 'testout/20verb16.rgb'), "read it back") or print "# ", $im2->errstr, "\n"; is_image($im, $im2, "compare"); is($im2->tags(name => 'sgi_rle'), 0, "check not rle"); is($im2->tags(name => 'sgi_bpc'), 2, "check bpc"); is($im2->tags(name => 'i_comment'), undef, "no namestr"); ok($im->write(file => 'testout/20rle16.rgb', sgi_rle => 1, i_comment => "test"), "write 16-bit rle") or print "# ", $im->errstr, "\n"; my $im3 = Imager->new; ok($im3->read(file => 'testout/20rle16.rgb'), "read it back") or print "# ", $im3->errstr, "\n"; is_image($im, $im3, "compare"); is($im3->tags(name => 'sgi_rle'), 1, "check not rle"); is($im3->tags(name => 'sgi_bpc'), 2, "check bpc"); is($im3->tags(name => 'i_comment'), 'test', "check i_comment set"); my $imbig = Imager->new(xsize => 300, ysize => 300, bits => 16); $imbig->paste(src => $im, tx => 0, ty => 0); $imbig->paste(src => $im, tx => 150, ty => 0); $imbig->paste(src => $im, tx => 0, ty => 150); $imbig->paste(src => $im, tx => 150, ty => 150); for my $t (0 .. 74) { $imbig->line(x1 => $t*4, y1 => 0, x2 => 3+$t*4, y2 => 299, color => [ 255 - $t, 0, 0 ]); } my $data; ok($imbig->write(data => \$data, type => 'sgi', sgi_rle => 1), "write larger image"); cmp_ok(length($data), '>', 0x10000, "check output large enough for test"); print "# ", length $data, "\n"; my $imbigcmp = Imager->new; ok($imbigcmp->read(data => $data), "read larger image"); is_image($imbig, $imbigcmp, "check large image matches"); } { # grey scale check my $im = test_image()->convert(preset=>'grey'); ok($im->write(file => 'testout/20vgray8.bw'), "write 8-bit verbatim grey") or print "# ", $im->errstr, "\n"; my $im2 = Imager->new; ok($im2->read(file => 'testout/20vgray8.bw'), "read it back") or print "# ", $im2->errstr, "\n"; is_image($im, $im2, "compare"); is($im2->tags(name => 'i_format'), 'sgi', "check we saved as SGI"); is($im2->tags(name => 'sgi_rle'), 0, "check not rle"); is($im2->tags(name => 'sgi_bpc'), 1, "check bpc"); is($im2->tags(name => 'i_comment'), undef, "no namestr"); } { # write failure tests my $rgb8 = test_image(); my $rgb16 = test_image_16(); my $rgb8rle = $rgb8->copy; $rgb8rle->settag(name => 'sgi_rle', value => 1); my $grey8 = $rgb8->convert(preset => 'grey'); my $grey16 = $rgb16->convert(preset => 'grey'); my $grey16rle = $grey16->copy; $grey16rle->settag(name => 'sgi_rle', value => 1); my @tests = ( # each entry is: image, limit, expected msg, description [ $rgb8, 500, 'SGI image: cannot write header', 'writing header' ], [ $rgb8, 1024, 'SGI image: error writing image data', '8-bit image data' ], [ $grey8, 513, 'SGI image: error writing image data', '8-bit image data (grey)' ], [ $rgb8rle, 513, 'SGI image: error writing offsets/lengths', 'rle tables, 8 bit', ], [ $rgb8rle, 4112, 'SGI image: error writing RLE data', '8-bit rle data', ], [ $rgb8rle, 14707, 'SGI image: cannot write final RLE table', '8-bit rewrite RLE table', ], [ $rgb16, 513, 'SGI image: error writing image data', '16-bit image data', ], [ $grey16rle, 513, 'SGI image: error writing offsets/lengths', 'rle tables, 16 bit', ], [ $grey16rle, 1713, 'SGI image: error writing RLE data', '16-bit rle data', ], [ $grey16rle, 10871, 'SGI image: cannot write final RLE table', '16-bit rewrite RLE table', ], ); for my $test (@tests) { my ($im, $limit, $expected_msg, $desc) = @$test; my $io = limited_write_io($limit); ok(!$im->write(type => 'sgi', io => $io), "write should fail - $desc"); is($im->errstr, "$expected_msg: limit reached", "check error - $desc"); } } { # check close failures are handled correctly my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; ok(!$im->write(type => "sgi", callback => sub { 1 }, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } sub limited_write_io { my ($limit) = @_; my ($writecb, $seekcb) = limited_write($limit); my $io = Imager::io_new_cb($writecb, undef, $seekcb, undef, 1); $io->set_buffered(0); return $io; } sub limited_write { my ($limit) = @_; my $pos = 0; my $written = 0; return ( # write callback sub { my ($data) = @_; # limit total written so we can fail the offset table write for RLE $written += length $data; if ($written <= $limit) { $pos += length $data; print "# write of ", length $data, " bytes successful (", $limit - $written, " left)\n"; return 1; } else { print "# write of ", length $data, " bytes failed\n"; Imager::i_push_error(0, "limit reached"); return; } }, # seek cb sub { my ($position, $whence) = @_; if ($whence == SEEK_SET) { $pos = $position; print "# seek to $pos\n"; } elsif ($whence == SEEK_END) { die "SEEK_END not supported\n"; } elsif ($whence == SEEK_CUR) { die "SEEK_CUR not supported\n"; } else { die "Invalid seek whence $whence"; } $pos; } ) } libimager-perl-1.004+dfsg.orig/SGI/t/30limit.t0000644000175000017500000000316412263740600020120 0ustar gregoagregoa#!perl -w use Imager; use Test::More tests => 14; use Imager::Test qw(is_image); { # SGI files are limited to 0xFFFF x 0xFFFF pixels { my $im = Imager->new(xsize => 0x10000, ysize => 1); my $data = ''; ok(!$im->write(data => \$data, type => "sgi"), "fail to write too wide an image"); is($im->errstr, "image too large for SGI", "check error message"); } SKIP: { my $im = Imager->new(xsize => 0xFFFF, ysize => 1); $im->box(fill => { hatch => "check4x4" }); my $data = ''; ok($im->write(data => \$data, type => "sgi"), "write image at width limit"); my $im2 = Imager->new(data => $data, ftype => "sgi"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is_image($im, $im2, "check we read what we wrote"); is($im->getwidth, 0xffff, "check width"); is($im->getheight, 1, "check height"); } { my $im = Imager->new(xsize => 1, ysize => 0x10000); my $data = ''; ok(!$im->write(data => \$data, type => "sgi"), "fail to write too tall an image"); is($im->errstr, "image too large for SGI", "check error message"); } SKIP: { my $im = Imager->new(xsize => 1, ysize => 0xFFFF); $im->box(fill => { hatch => "check2x2" }); my $data = ''; ok($im->write(data => \$data, type => "sgi"), "write image at width limit"); my $im2 = Imager->new(data => $data, ftype => "sgi"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is_image($im, $im2, "check we read what we wrote"); is($im->getwidth, 1, "check width"); is($im->getheight, 0xffff, "check height"); } } libimager-perl-1.004+dfsg.orig/SGI/t/10read.t0000644000175000017500000002175612031434614017720 0ustar gregoagregoa#!perl -w use strict; use Imager; use Imager::Test qw(is_image is_color3); use Test::More tests => 103; -d 'testout' or mkdir 'testout', 0777; Imager::init_log('testout/10read.log', 2); { my $im_verb = Imager->new; ok($im_verb->read(file => 'testimg/verb.rgb'), "read verbatim") or print "# ", $im_verb->errstr, "\n"; is($im_verb->getchannels, 3, "check channels"); is($im_verb->getwidth, 20, "check width"); is($im_verb->getheight, 20, "check height"); is_color3($im_verb->getpixel(x => 0, 'y' => 0), 255, 0, 0, "check 0,0"); is_color3($im_verb->getpixel(x => 1, 'y' => 2), 255, 255, 0, "check 0,2"); is_color3($im_verb->getpixel(x => 2, 'y' => 4), 0, 255, 255, "check 2,5"); is($im_verb->tags(name => 'i_format'), 'sgi', "check i_format tag"); is($im_verb->tags(name => 'sgi_rle'), 0, "check sgi_rgb"); is($im_verb->tags(name => 'sgi_pixmin'), 0, "check pixmin"); is($im_verb->tags(name => 'sgi_pixmax'), 255, "check pixmax"); is($im_verb->tags(name => 'sgi_bpc'), 1, "check bpc"); is($im_verb->tags(name => 'i_comment'), 'test image', "check name string"); my $im_rle = Imager->new; ok($im_rle->read(file => 'testimg/rle.rgb'), "read rle") or print "# ", $im_rle->errstr, "\n"; is($im_rle->tags(name => 'sgi_rle'), 1, "check sgi_rgb"); my $im_rleagr = Imager->new; ok($im_rleagr->read(file => 'testimg/rleagr.rgb'), "read rleagr") or print "# ", $im_rleagr->errstr, "\n"; my $im6 = Imager->new; ok($im6->read(file => 'testimg/verb6.rgb'), "read verbatim 6-bit") or print "# ", $im6->errstr, "\n"; is($im6->tags(name => 'sgi_pixmax'), 63, "check pixmax"); is_image($im_verb, $im_rle, "compare verbatim to rle"); is_image($im_verb, $im_rleagr, "compare verbatim to rleagr"); is_image($im_verb, $im6, "compare verbatim to verb 6-bit"); my $im_verb12 = Imager->new; ok($im_verb12->read(file => 'testimg/verb12.rgb'), "read verbatim 12") or print "# ", $im_verb12->errstr, "\n"; is($im_verb12->bits, 16, "check bits on verb12"); is($im_verb12->tags(name => 'sgi_pixmax'), 4095, "check pixmax"); my $im_verb16 = Imager->new; ok($im_verb16->read(file => 'testimg/verb16.rgb'), "read verbatim 16") or print "# ", $im_verb16->errstr, "\n"; is($im_verb16->bits, 16, "check bits on verb16"); is($im_verb16->tags(name => 'sgi_pixmax'), 65535, "check pixmax"); is_image($im_verb, $im_verb12, "compare verbatim to verb12"); is_image($im_verb, $im_verb16, "compare verbatim to verb16"); my $im_rle6 = Imager->new; ok($im_rle6->read(file => 'testimg/rle6.rgb'), "read rle 6 bit"); is($im_rle6->tags(name => 'sgi_pixmax'), 63, 'check pixmax'); is_image($im_verb, $im_rle6, 'compare verbatim to rle6'); my $im_rle12 = Imager->new; ok($im_rle12->read(file => 'testimg/rle12.rgb'), 'read rle 12 bit') or print "# ", $im_rle12->errstr, "\n"; is($im_rle12->tags(name => 'sgi_pixmax'), 4095, 'check pixmax'); is_image($im_verb, $im_rle12, 'compare verbatim to rle12'); my $im_rle16 = Imager->new; ok($im_rle16->read(file => 'testimg/rle16.rgb'), 'read rle 16 bit') or print "# ", $im_rle16->errstr, "\n"; is($im_rle16->tags(name => 'sgi_pixmax'), 65535, 'check pixmax'); is($im_rle16->tags(name => 'sgi_bpc'), 2, "check bpc"); is_image($im_verb, $im_rle16, 'compare verbatim to rle16'); } { # short read tests, each is source file, limit, match, description my @tests = ( [ 'verb.rgb', 100, 'SGI image: could not read header', 'header', ], [ 'verb.rgb', 512, 'SGI image: cannot read image data', 'verbatim image data' ], [ 'rle.rgb', 512, 'SGI image: short read reading RLE start table', 'rle start table' ], [ 'rle.rgb', 752, 'SGI image: short read reading RLE length table', 'rle length table' ], [ 'rle.rgb', 0x510, "SGI image: cannot read RLE data", 'read rle data' ], [ 'rle.rgb', 0x50E, "SGI image: cannot seek to RLE data", 'seek rle data' ], [ 'verb16.rgb', 512, 'SGI image: cannot read image data', 'read image data (16-bit)' ], [ 'rle16.rgb', 512, 'SGI image: short read reading RLE start table', 'rle start table (16-bit)', ], [ 'rle16.rgb', 0x42f, 'SGI image: cannot seek to RLE data', 'seek RLE data (16-bit)' ], [ 'rle16.rgb', 0x64A, 'SGI image: cannot read RLE data', 'read rle image data (16-bit)' ], ); for my $test (@tests) { my ($src, $size, $match, $desc) = @$test; open SRC, "< testimg/$src" or die "Cannot open testimg/$src: $!"; binmode SRC; my $data; read(SRC, $data, $size) == $size or die "Could not read $size bytes from $src"; close SRC; my $im = Imager->new; ok(!$im->read(data => $data, type => 'sgi'), "read: $desc"); is($im->errstr, $match, "error match: $desc"); } } { # each entry is: source file, patches, expected error, description my @tests = ( [ 'verb.rgb', { 0 => '00 00' }, 'SGI image: invalid magic number', 'bad magic', ], [ 'verb.rgb', { 104 => '00 00 00 01' }, 'SGI image: invalid value for colormap (1)', 'invalid colormap field', ], [ 'verb.rgb', { 3 => '03' }, 'SGI image: invalid value for BPC (3)', 'invalid bpc field', ], [ 'verb.rgb', { 2 => '03' }, 'SGI image: invalid storage type field', 'invalid storage type field', ], [ 'verb.rgb', { 4 => '00 04' }, 'SGI image: invalid dimension field', 'invalid dimension field', ], [ 'rle.rgb', { 0x2f0 => '00 00 00 2b' }, 'SGI image: ridiculous RLE line length 43', 'invalid rle length', ], [ 'rle.rgb', { 0x3E0 => '95' }, 'SGI image: literal run overflows scanline', 'literal run overflow scanline', ], [ 'rle.rgb', { 0x3E0 => '87' }, 'SGI image: literal run consumes more data than available', 'literal run consuming too much data', ], [ 'rle.rgb', { 0x3E0 => '15' }, 'SGI image: RLE run overflows scanline', 'RLE run overflows scanline', ], [ 'rle.rgb', { 0x3E0 => '81 FF 12 00 01' }, 'SGI image: RLE run has no data for pixel', 'RLE run has no data for pixel', ], [ 'rle.rgb', { 0x3E0 => '81 FF 12 00' }, 'SGI image: incomplete RLE scanline', 'incomplete RLE scanline', ], [ 'rle.rgb', { 0x2F0 => '00 00 00 06' }, 'SGI image: unused RLE data', 'unused RLE data', ], [ 'verb.rgb', { 0x0c => '00 00 00 FF 00 00 00 00' }, 'SGI image: invalid pixmin >= pixmax', 'bad pixmin/pixmax', ], [ 'rle16.rgb', { 0x2f0 => '00 00 00 0B' }, 'SGI image: invalid RLE length value for BPC=2', 'bad RLE table (length) (bpc=2)' ], [ 'rle16.rgb', { 0x2f0 => '00 00 00 53' }, 'SGI image: ridiculous RLE line length 83', 'way too big RLE line length (16-bit)' ], [ 'rle16.rgb', { 0x426 => '00 95' }, 'SGI image: literal run overflows scanline', 'literal overflow scanline (bpc=2)' ], [ 'rle16.rgb', { 0x426 => '00 93' }, 'SGI image: literal run consumes more data than available', 'literal overflow data (bpc=2)' ], [ 'rle16.rgb', { 0x3EA => '00 15' }, 'SGI image: RLE run overflows scanline', 'rle overflow scanline (bpc=2)' ], [ 'rle16.rgb', { 0x3EA => '00 15' }, 'SGI image: RLE run overflows scanline', 'rle overflow scanline (bpc=2)' ], [ 'rle16.rgb', { 0x3EA => '00 83 ff ff ff ff ff ff 00 01' }, 'SGI image: RLE run has no data for pixel', 'rle code no argument (bpc=2)' ], [ 'rle16.rgb', { 0x3EA => '00 14 ff ff 00 00' }, 'SGI image: unused RLE data', 'unused RLE data (bpc=2)' ], [ 'rle16.rgb', { 0x3EA => '00 12 ff ff' }, 'SGI image: incomplete RLE scanline', 'incomplete rle scanline (bpc=2)' ], ); # invalid file tests - take our original files and patch them a # little to make them invalid my $test_index = 0; for my $test (@tests) { my ($filename, $patches, $error, $desc) = @$test; my $data = load_patched_file("testimg/$filename", $patches); my $im = Imager->new; ok(!$im->read(data => $data, type=>'sgi'), "$test_index - $desc:should fail to read"); is($im->errstr, $error, "$test_index - $desc:check message"); ++$test_index; } } sub load_patched_file { my ($filename, $patches) = @_; open IMDATA, "< $filename" or die "Cannot open $filename: $!"; binmode IMDATA; my $data = do { local $/; }; for my $offset (keys %$patches) { (my $hdata = $patches->{$offset}) =~ tr/ //d; my $pdata = pack("H*", $hdata); substr($data, $offset, length $pdata) = $pdata; } return $data; } libimager-perl-1.004+dfsg.orig/SGI/t/00load.t0000644000175000017500000000011712031434614017707 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 1; use_ok('Imager::File::SGI'); libimager-perl-1.004+dfsg.orig/SGI/SGI.xs0000644000175000017500000000067312031434614017205 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "imsgi.h" #include "ppport.h" DEFINE_IMAGER_CALLBACKS; MODULE = Imager::File::SGI PACKAGE = Imager::File::SGI PROTOTYPES: DISABLE Imager::ImgRaw i_readsgi_wiol(ig, partial) Imager::IO ig int partial int i_writesgi_wiol(ig, im) Imager::IO ig Imager::ImgRaw im BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/SGI/Makefile.PL0000644000175000017500000000062612567572530020175 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; my %opts = ( NAME => 'Imager::File::SGI', VERSION_FROM => 'SGI.pm', OBJECT => 'SGI.o imsgi.o', INC => '-I..', clean => { FILES => 'testout' }, ); my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'SGI Image file support'; } WriteMakefile(%opts); libimager-perl-1.004+dfsg.orig/Changes.old0000644000175000017500000021415712031434613017640 0ustar gregoagregoaRevision history for Perl extension Imager. 0.01 Thu May 6 15:25:03 1999 - original version; created by h2xs 1.18 0.02 Mon May 10 20:20:20 1999 - Added PPM writer, and a new return type to be used to return undef() from a function returning (int)0. 0.03 Thu May 20 23:23:23 1999 - Added Pseudo image handling thingies, now you can use your own get and put pixel routines. 0.04 Mon May 24 22:14:55 1999 - Rewrote parts of jpeg support. 0.05 Tue May 25 23:40:01 1999 - Added png support with libpng fixed error reporting and return types from some format routines. 0.06 Wed May 26 19:05:39 1999 - Fixed Data::Dumper being used when it shouldn't have added feature checking to see at run time if certain formats are avaliable. removed some ancient C++ style comments that hadn't been properly removed, some out of bounds errors in ppm.c fixed tests so missing features are skipped. 0.07 Thu May 27 03:15:00 1999 - Fixed the typemap for i_img and i_color so that you can pass a null pointer to them without getting a warning when warnings are enabled. Maybe this is counter perl but it greatly increases the usability of the functions. 0.08 Fri May 28 14:13:21 1999 - Added support for gif via, giflib or libungif. gif is so ridden with patent issues but the user can decide which library to use since they have the same include files and calling interface. 0.09 Mon May 31 17:52:32 1999 - Added image scaling per axis - faster than doing both axes at the same time. The current method uses lancoz kernel and filtering. But more types should be added - including: nearest neighbor, linear, and bicubic. 0.10 Mon Jun 7 03:25:54 1999 - Added T1 postscript font handling. It's very primitive at the moment but creative people can do nice stuff with it. Currently it is not possible to have it generate an image of the correct size for a given string but that is on the way. 0.11 Mon Jun 7 14:43:35 1999 - Added T1 features for direct to image rendering in a single color. fixed some debug messages going to stderr instead of a log file. 0.12 Tue Jun 8 02:58:43 1999 - Fixed bugs in jpeg.c when loading images. Also specified prototype behaviour to on in the Imager.xs file. The Makefile.PL step doesn't complain anymore so that is hopefully fixed. 0.13 Wed Jun 9 06:55:58 1999 - Fixed Imager.xs for init_log call. Minor fixes here and there. 0.14 Thu Jun 10 14:11:22 1999 - Rewrote most of the logging stuff so that it is now possible to remove all logging from the XS part of the module. Also some primitive check of memory usage was added. Claes Jacobsson sent in some filters, inverter, contrast and a noise filter. 0.15 Mon Jun 14 08:13:29 1999 - Wrote minor enhancement on the calling syntax list. Started on the object interface - added better support for quering avaliable filetypes. Fixed memory leaks in most loaders. New filters from Claes in this version are bumpmap, postlevels and mosaic. 0.16 Wed Jun 16 20:54:33 1999 - Added fixes to the BEGIN and END parts, added writer function for the OO interface. Also added basic IPTC reading support for jpegs. Also a few filters have been added to the OO interface. 0.17 Thu Jun 24 11:09:15 1999 - Added dynamic loading stuff - It's still missing a nice global symbol table. This will be fixed in next release. also calling the plugins is not all to easy at the moment. 0.18 Mon Jun 28 12:31:33 1999 - Added global symbol table - plugins now need a symbol table pointer in them. When the module is loaded it is set to point at the global symbol table. Also some barebones Makefile.PL has been made in the dynfilt directory - it works on my system - I hope it does on yours. 0.19 Fri Jul 1 15:00:03 1999 - Added a way new scaling method for creating easy previews. It only uses nearest neighbor, so it's doesn't look very nice but it may be better for applications like remote sensing. 0.20 Mon Jul 5 10:15:37 1999 - Added and rewrote documentation. 0.21 Mon Jul 6 19:15:37 1999 - Fixed a bug in the scaling routine - it wasn't handling 0< cases. 0.22 Sat Oct 9 07:04:14 1999 - Added a new method to write gif images - now it is possible to have a part of a palette fixed. this is very usefull if one needs to make sure that some color like white is in the pallete. This method also allows some ditherding and gives better colormap than the mediancut from the gif libraries. It does need much more cpu power though. Hopefully later versions will be faster. 0.23 **************** Internal release only - Fixed the %instances bug - caused ALL memory to be leaked. Added real noise function - need feedback on how it should be used. Also box(), and polyline are now in place. Polygon is missing but antialiased line drawing with integer endpoints are done but should be replaced with a version that can have floating point endvalues. Two noise filters addded. 0.24 **************** Internal release only - Converted i_color into an object from a reference, so now it's giving an object instead of a void ptr or an integer or something. 0.25 **************** Internal release only - Added basic Truetype functionality - still needs a rewrite to be decent. Currently it's a port of a demo program that uses an awful amount of global variables and there is much IO since no caching of glyphs is done. 0.26 Tue Nov 23 03:57:00 1999 > Development release < - Added transformations so that an image can be wrapped. To achive decent speed a C based stackmachine is included. As a result transformations need to be specified in rpn (postfix) notation. It also can use the Affix::Infix2Postfix class to do the conversion for it. 0.27 Tue Dec 28 03:57:00 1999 > CPAN release < - This is a bugfix version mostly, thanks to claes for pointing out the problems - fixed palette saving wasn't working correctly after version 0.24 - rather surprised this didn't crash everything. Also fixed that for t1 fonts the bounding box wasn't being reported unless the font had been used before. This is either a bug in t1lib or a mistake in it's documentation. Another lingering bug since 0.24 what that $img->box() wasn't creating it's default color properly. Added i_tt_text() method and more debuging to the truetype routines. truetype testcase fixed and old debug rubish removed. 0.28 Tue Jan 4 05:25:58 2000 > CPAN release < - Only fixes to truetype test and transformation tests. Thanks to schinder of cpan testers for testing and reporting. 0.29 Tue Jan 4 21:49:57 2000 > CPAN release < - fixes to get rid of warnings under pre 5.005, Fixed broken preproccessor directives to work on non gnu compilers. Fixed DSO test on HPUX - both code errors and HPUX creates .sl instead of .so so the tests were failing. 0.30 Sun Jan 7 05:00:06 2000 > Bunch of Alpha releases < - An attempt to automate installation. 0.31 Sat Jan 15 03:58:29 2000 > Fixes fixes fixes < - Fixed a bug pointed out by Leolo where loading gifs skips the first line of the imageload() has been by read() - for now load is an alias for read. It will be removed in the future. Also, fixes dynamic loading on systems that prepend an underscore to symbols. At the present the only system that I know of that needs this is OpenBSD. BUT YOU MUST RECOMPILE ALL OF YOUR OLD MODULES AGAINST THIS BUILD. Added getchannels() method ( How did I manage to delay this untill now ). Some document changes but nothing substantial. Also fixed the png read/write routines to handle all colorspaces and images with alpha information. Also now it's possible to have Imager guess the format of the files to load or save when passing files to read or save from the filename. Also all of the tests except dynamic loading now pass on OS/2. 0.32 Tue Feb 29 17:26:00 2000 CPAN RELEASE - Added the getcolorcount method. Fixed interlace handling on png images. Fixed the missing channel count in crop() method. Rewrote most of t1lib database stuff - created color and font classes. T1 stuff is mostly done - TT things were rewritten too and now include most of what is needed for pixmap caching. Added documentation for fonts. Comments have been added to some of the relevant c-routines. Added a copy() function in Imager.xs and a corresponding method name. Changed the underlying data type for the raw XS images from pointers to objects - this will hopefully catch the most basic errors and keep the segfaulting down. This means that all of the underlying XS calls for readjpeg, readgif, readpng and readraw do not take the first parameter any more. Made fixes to keep it not spewing warning on 5.004 perl. **** If you had any code that didn't use the OO interface **** **** It will probably not work any longer **** 0.33 Beta -- No final - Fixed the end message from Imager 0.32. Destroy called on an empty image. Did some work on the polygon method. Some clean up in the Makefile.PL script. Fixed a buffer overrun in the t_transform in Imager.XS. Fixed the error handling in the jpeg loader. It now correctly returns undef if a load on an image fails. It also sends the error messages to the log file. Added errstr() method to the image object. Added a new way to read() objects from scalars. So far this is only implemented for jpeg, png and gif. ppm and raw soon - as always if someone wants to do an overhaul on the ppm stuff feel free. It seems like such a basic format that interfacing with a library is more work than implementing all of the needed routines instead. 0.34 Beta -- No final - Bunch of documentation fixes, backed out ppm code. Put in TonyC's giant transform2 patch. Fixed the patch to make it ansi compliant. Fixed a bunch of bugs in the Freetype code with regard to vertical and horizontal positioning and bounding boxes. Cleaned up a lot of the code so it runs under -Wall. Code that is still in development such as the polygon converter do not compile cleanly. Fixed the non antialiased versions of truetype dump to image routines. Also removed the FIXME for the hardcoding of antialias in the Imager string method. Fixed sign error and a missing cache of the bounding box calculation for the rasterize function. Removed some debugging code I forgot to remove. Added iolayer.h and iolayer.c but they don't do anything for now. 0.35 pre2 -- No time yet - Fixed some compile warnings for various files under -Wall. Added functionality for jpeg reading of seekable files, it's not really working yet. This version is pretty much *not* working. Do not install unless you intend to do a lot of development. Repeat - it doesn't even pass tests (but it compiles). Ok now reading jpegs works from scalars, my guess is that it also works from non seeking sources such as sockets or pipes. 0.35 pre3 - No time yet - Added the *right* patch from Tony which combines the common code from i_readgif and i_readgif_scalar into i_readgif_low. Added tiff reading support through iolayer. 0.35 pre4 - No time yet - Added tiff writing (no options) support through iolayer. Also made some small fixes for the iolayer reading (was always doing two reads when one was needed). Patched the Imager::read() call so that it now uses a mixture of old and new functions. 0.35 pre5 - No time yet - Fixed various gnu'isms in the c code (some bugs in the link list implmentation). Fixed missing #skip codes when gif format is not present in any form. Added fixes for 5.004_04 in the transform2 function. Made sure it compiles cleanly with sun's cc. Switched from a .jpeg for transform2 check to a .ppm file so it runs when jpeg is not present. Added a test for tiff files in t10formats.t. 0.35 pre6 - No time yet - Fixes to Makefile.PL. Should find freetype includes on more distributions now. Ran tests on Solaris and Hpux, minor fixes. Compiles with some warnings on with both hpux and solaris' cc. Made some minor changes to the documentation. Fixes to tiff.c log code. 0.35 pre7 - No time yet - Fixes 64 bit bug on freebsd. While libtiff mirrors the effects of lseek it's toff_t is a uint32, while lseek uses off_t which can be a 64 bit quantity. Added the IM_LFLAGS environment variable to help people with broken libgifs (that want to link with X). 0.35 Sun Jan 28 19:42:59 EST 2001 - More makefile fixes, fixed a few signedness warnings. Checked to see if it compiled cleanly on Solaris and HPUX. Fixed a 5.004_04 warning and added more ENV flags for makefile. 0.36 Mon Jan 29 09:36:11 EST 2001 - String as 0 or "" caused an error in $img->string(). Fixed a documentation error invoving string() method syntax. Merged a patch for non antialised truetype fonts. Fixed an error in the Makefile.PL which caused a makefile to be generated that bombed with sgi's make. 0.37 Mon Tue 30 09:36:11 EST 2001 - Several documentation fixes. Pod documentation for almost every function in image.c. Added sys/types.h include in iolayer which was causing problems on various linux systems. 0.38 pre1 - No time yet - Fixed a braindamaged fix on the Makefile.PL file. Moved the code for Imager::Color into lib/Imager/Color.pm. Wrote some pod about how it works. Made the names of Imager::Color XS routines all begin with ICL_ and used the prefix rules of XS to get nice names in perl. Found a bug (not fixed) in how XS handles returning an object to an object it had as a parameter (double free). 0.38 pre2 - No time yet - Fixes lots of for documentation, patch for freetype bounding box handling. Split put code for Imager::Font into Font.pm and added more documentation for Font.pm. Added string local ascender and descender for tt fonts. Note that this needs to be added to t1 fonts before 0.38 final. 0.38 pre3 - No time yet - Fixed an in consistency in the bounding box functions for t1 fonts. Now both versions get the 6 argument bounding_box method described in Imager::Font. Started converting the comments in font.c so that they are viewable by doco.perl. Added two examples of filters. Need to make them more usefull and then add more notes than are in compile.txt. 0.38 pre4 - No time yet - Completed adding pod comments to font.c, tiff.c and iolayer.c. Those along with image.c should now have every single function described in pod format. 0.38 pre5 - No time yet - Replaced ppm.c with pnm.c which adds support for pbm/pgm/ppm files ascii and binary formats. Added patches for the gif routines. Patched some of the color quantizing routines (Leolo and TonyC). There is one bomb and one warning in this test, and frankly I don't see why they are suddenly there. 0.38 pre6 - No time yet - Patch from Tony that fixes infix when Parse::RecDescent is present. Checked some cases where malloc/free were used instead of mymalloc/myfree. Added bufchain iolayer code. You can now write to a chain of buffers and later slurp it all into a single perl scalar. Found some oddity of t/t10 test not giving the right return value when malloc debugging was enabled. Fixed some of the logging code and the malloc debugging options. Added more tests for tiffs. 0.38 pre7 - No time yet - Added i_gradgen code and put it into the filters hash. Think a seperate pod for filters would be a good idea. Also removed some of the debugging code from the iolayer. Added pod comments to filters.c and looked over the code. 0.38 pre8 - No time yet - limited Win32 support, Imager installs and builds using VC++, but there's no image/font format support yet. 0.38 pre9 - No time yet - Added lots of color quantization code from Tony with benchmarks. Also fixes ugly stack overrun in old version. Added fixes for the lmfixed problem. Four of them, let's see which is fastest. This version adds some voronoi partitioning - it's dog slow but it's a reference implementation to check if faster algorithms are doing the right thing [tm]. Added a check for giflib 3. - Win32 support for libpng - fixed set_internal creating 2 refs to one object - Win32 support for jpeg - Win32 support for tiff - base level error reporting code added, I still need to modify older code to use it - fix translate=>'giflib' handling of single-colour images. Previously a single colour image would cause an error in MakeMapObject(). - fix t/t10formats.t tests against giflib3 - added test for transparent gifs - minor doc fixes for transparent gifs - make it less error-prone to write transparent gifs - documented the options for reading raw images - Changes switched to use spaces for formatting - switch gif.c to new error reporting with related changes to Imager.xs, Imager.pm - each of the image formats now have their own test file, extracted from t10formats.t, usually with som extra tests - Added flip() and docs to Imager.pm and i_flipxy to image.c. Added testcases too. - Fixed an overflow bug in png.c - added the colors parameter to Imager::read() which receives the arrayref of colours that i_readgif(_scalar) returns - fixed a problem in makemap_addi in quant.c where only the first image was compared against the palette when the palette was being refined. I screwed up on this originally (TC). This is the other half of a fix for Leolo's lmfixed problem . - makemap_addi() now only puts colours into the palette that it found while optimizing the palette (so we don't get 256 colour palettes for 2 colour images :) - initial implementation of a row-based interface to low-level images (for performance) - changed Imager::read() for GIF so that the arrayref pointed to by the ref supplied in colors contains Imager::Color objects instead of more arrayrefs, keep this interface stable until we can make an informed choice about i_readgif() - incorporated Micksa's faxable tiff support, treating as a type of tiff rather than a separate format - t/t70newgif.t now checks for gif support - added the convert() method - Added support for transparent to alpha conversion during loading of png files. Note that libpng 1.0.1 is broken in handling this, we know that 1.0.5 works. - support for writing PGM (portable gray map) files - Fix for i_gifread_low() for images with only a local and no global colormap and an abort if no colormap is present (which is legal in gif). - several fixes to i_readgif_low() - Fixed crop() method so that it is consistent with documentation. - make clean now removes the testout directory - added tests for the OO interface for tiff, added an option to choose the resolution for fax tiffs, removed some unused code, fixed minor problems with Imager::write() handling of image types - changed README note on libgif bug to refer to t105gif.t instead of t10formats.t 0.39 pre1 - split Imager::Font into a base, *::Type1 and *::Truetype - writing faxable tiff now allows 2 and 4 channel images - virtual image interface - 8-bit/sample images - paletted images - 16-bit/sample images - masked images - writing non-8bit images to raw - writing '' '' to tiff - i_convert support for high-bit images and paletted images - i_copy for high-bit and paletted images - tests for rubthru - rubthru can now rub a 2 channel image over a 1 or 3 channel image - rubthru for high-bit images - i_readgif_multi functions, which return all the frames from a GIF file, along with a bunch of meta-information as tag - OO interface to tags - OO interface read_multi() to read multi-image files (just GIF so far) - documentation for the multi-image GIF reading and tags - rotate() method with rotate by steps of 90 degrees (and docs) - fixed a bug in i_img_pal_new_low() - added gaussian to the filters list - documented the individual filters - fixed the right-hand side of bounding boxes for TT fonts where the last character overlaps the advance width (eg. italic fonts) - added rotation by exact amounts in degrees or radians, implemented using the matrix idea from Addi. The procedural matrix transformer is exposed, but still needs testing (as XS) and needs an OO interface, hopefully with some helper tools, like the preset interface with ->convert(). - MY::postamble() in Makefile.PL included a broken rule (Makefile.PL 1.13.2.5) - support for GDI fonts under Win32 - made that work for cygwin too (needs the w32api package) - freetype1 support under Win32 - t1lib support under Win32 - fixed a minor bug in font.c (invalid font files caused a SEGV) - checked cygwin for both t1lib and freetype1 - freetype 2 support - exposed the matrix_transform() function to the OO interface - added Imager::Matrix2d convenience class - support for setting the resolution when writing to PNG - retrieve physical resolution to tags when reading from PNG - found an XS bug in the interface to i_tags_add() - fixed handling of writing text to a channel with freetype2 (sometimes the edge of a character would damage the edge of the previous character) - some utf8 support for freetype2 - some vertical layout support for freetype2 - named parameters for specifying colors, with quite a few options. - glyph size issues for freetyp2 - minor problem in handling of canon option - low-level bmp writing (moving it to laptop) - Windows BMP reading and writing - added OO interfaces for the mosaic, bumpmap, postlevels and watermark filters - added t/t61filters.t to test the filters - fixed some problems in jpeg handling from the exp_represent merge - fixed buffer flushing for wiol jpeg code - added some tests that will hopefully catch it in the future - added the OO interfaces to the mosaic, bumpmap, postlevels and watermark filters, and documented them - fixed a sample size conversion problem in i_gpixf_d() etc. - added simple color representation conversion functions (used in i_fountain().) - added the fountain filter: - creates gradients similar to paint software - 90% support for GIMP gradient files - OO interface and documentation - Imager::Fountain for building/loading fill definitions - named value translation for filters - added a generic fill mechanism - created versions of i_box() and i_arc() that can fill using generic fills - solid generic fills (with alpha blending if asked for) - hatched generic fills (with some options) - fountain generic fills - sample code to generate an examples page - improved the scale* hatches a bit - add the flood_fill() method (using the existing i_flood_fill) - implement i_flood_cfill() based on i_flood_fill, and add general fills to the flood_fill() method - generalize the combine parameter to get different ways of combining the fill with the target - the tt driver (freetype 1) didn't handle the first character hanging off the left of the character cell - the tt driver produces some artifacts when characters overlapped - error handling for writing jpeg images - writing paletted images to GIF now uses the image palette if it's small enough - $img->arc() now calls i_circle_aa() if a complete circle is being drawn in a plain color - image based fills - unsharp mask - make i_conv() clamp the bottom end of the samples range too (makes it useful for sharpening) - adjust ascender/descender values for FT1.x to avoid losing descenders (specifically the bottom of "g" in ImUgly.ttf or arial.ttf at 14pixels) - added tga.c to read targa images - added i_bumpmap_complex to do more accurate bumpmapping - added an image type with doubles as samples - change i_copy() and i_sametype() to handle double/sample images - added basic POD to trans2.c - transform2 now uses the error interface - myrealloc() is implemented for malloc debug mode - now buffer chains are freed when destructor for Imager::IO is called - adjusted the Lanczos window width for the scaling code and added code to normalize the filter generated to preserve intensity scaling. - constant edge extension for scaling operations - better error checking of automatic fill conversions - fix some range checking for the fountain fill segment type 0.39 pre2 - A few scattered mymalloc/free fixes - io_buffer implemented as a source for io layer and XS and perl OO code added. - Test for iolayer t/t07iolayer.t implemented. - Fixed known memory leaks. - gif screen was wasn't being calculated correctly 0.39 Released: Nov 2 2001. 0.40 pre1 - anti-aliased polygon fill - add general fill to polygon fill - make color values smarter for the drawing functions - implemented reading and writing the TIFF text tags - added prototypes for some of the derivative tags functions - read paletted tiff images into Imager paletted images - on partial tiff image reads, set the i_incomplete tag - tiff reading now uses the error stack - use the error stack value from reading bmp files - fix an error message in bmp.c - added has_chars() method to Imager::Font::FreeType2 - freetype 2 bounding box function didn't know UTF8 (doh!) - write paletted images as paletted to tiff - initialize counter for packing 4 bit data - don't allocate hashboxes as locals since it overflows the stack by default in Darwin - applied T1 afm patch from Claes Jacobsson - split IM_INCPATH and IM_LIBPATH with $Config{path_sep}, so they work on Windows - Added memory pools for easy cleanup of temp buffers - Added read support for sgi .rgb files. - io_new_fd() now creates a FDSEEK io object - implemented i_readgif_wiol() - Imager->read() now uses i_readgif_wiol(); - extend callback iolayers at C and Perl levels - implemented i_writegif_wiol() - split out Perl iolayer initialization into private methods - add tests for each type of iolayer in t50basicoo.t - read/write multi-image tiff files - tests in t50basicoo.t for multi-image/file - ASCII PBM files were reading white as dark gray (255 vs 1) - modify the Freetype2 font code to pick it's own encoding rather than using whatever strange translation FT2 happens to pick - modify the FT1 font code to use the first encoding as a default if we don't find a unicode encoding - use the glyph bbox to calculate the glyph bitmaps for rendering with FT1 rather than the global ascender/descender. This helps with fonts that have broken metrics. - fix calculation of descender for FT2, it was calculating the minimum decent rather than the maximum for the characters in the string - didn't set default for bounding_box() utf8 parameter (caused a warning when calling bounding_box() on a FT2 font with no utf8 parameter) - Added lib/Imager/Draw.pod documentation of primitives. - Added lib/Imager/Transformations.pod, some docs of simple transforms. - Added lib/Imager/ImageTypes.pod, draft of ImageType pod. - Added lib/Imager/Filters.pod, draft of Filters pod. - Added lib/Imager/Engines.pod, draft of Engines pod. - added getpixel() and setpixel() methods - added Artur's OSX dlload() emulation, with minor changes - modified _color() to work around a 5.6.0 bug - replaced old gif options with tags - we now log which memory block is being freed before giving an error on it being re-freed - fixed stupid bug in deleting tags - fixed minor pod errors involving > 0.40pre2 - make t1log optional, defaulting to off. You can enable the log with Imager::init(t1log=>1) (Ticket #369) - quote a few hash key strings to prevent warnings on 5.004 - modify quantization code to handle 1 channel images correctly (Ticket #365) - make channel pointer to i_gsamp() const int * so we can pass const arrays - handle the presence of the default broken giflib better, by giving them some more prose about the problem, and skipping all but the first test that fails with the broken giflib - i_box_cfill() went into an infinite loop on fountain fills or fills on images with more than 8-bits/sample - hide more of our Darwin dlload emulation to prevent runtime symbol conflicts - use INT2PTR() and PTR2IV() macros instead of direct casts to prevent pointer vs int size warnings on 64-bit builds of perl. - add our own INT2PTR and PTR2IV definitions when perl doesn't supply them - difference() method - hide (with static) or rename many symbols that could possibly cause conflicts with other libraries or perl - Fix runaway cache problem for freetype1 font cache. - Added version logging when log is started. 0.40 - difference() wasn't setting an alpha channel when the input image didn't have one - improve crop() documentation, see http://perlmonks.org/index.pl?lastnode_id=155767&node_id=155428 - handle the first "buggy giflib" test more portably. Previously it used fork() which caused problems on systems that didn't have a real fork(). 0.41 - skip() in testtools should be skipn() and it should use the loop variable for the test number 0.42 - quote the 'min' parameter to scale in Imager::Transformations and at least mention it in the docs beyond the examples - document the values for the read() and write() method type parameter - support UTF8 text with Freetype 1.x - second parameter to SvPV() must be of type STRLEN - Doc pathces from cogent. - Fixed out of bounds access on bitmap for flood fills. - some char * vs unsigned char * casts missing on OSF1 v4.0 - some enums had , on the last item in datatypes.h, which OSF1 didn't like - Compaq C 6.4 (OSF1) claims to be C99 but doesn't provide stdint.h, don't try to use it under OSF - fix missing initialization in tags.c - Change i_draw to i_line and have it use Bresenham's line drawing algorithm. - support has_chars() method for Freetype 1.x - fixed log message for i_ft2_has_chars() - fixed some broken checking for UTF8 in FT2 code - handle UTF8 strings passed to T1 low-level functions - handle flags for underline, strikethrough and overline for T1 low-level output functions - OO interfaces to UTF8 and flags, for now leaving the flags as specific to Imager::Font::Type1 - mc_web_map was storing colors with an alpha of 0 - update the URLs for libpng and zlib - Fixed empty string handling for tt font driver. - Fixed tiff handling of images all contained in a single strip (rowsperstrip = -1) and added a hack for images missing the rowsperstrip tag. - Fixed default parameters for crop() - Added Preliminary specialized scaling code. - Added image type detection. - added smoke test for win32 font bounding_box() method, and fixed the problem reported in ticket #1748. - update t37w32font.t to use i_line() instead of i_draw() - replaced non-portable call to rint() with (int)(dy+0.5) (so we can build on Win32) - the default tifflib warning handler was crashing on Win32 under ActivePerl, when an unrecognized tag was read from the file. For now we'll just drop the warnings in the bit bucket. (Ticket #1513) - the code to read multiple tiffs didn't handle files with more than five images correctly, causing a memory overrun. - fix some minor test code hiccups - implemented i_t1_has_chars(), tests for same - added ExistenceTest.{pfb,afm,ttf} for testing $font->has_chars - tests for Imager::Font::Type1::has_chars(); - tests for Imager::Font::Truetype::has_chars(); - internal and external bounding box calculations now use the same hint flags as text output for Freetype 2.x - made the i_foo_bbox() interface more expandable by using symbolic constants for the sizes and array offsets - added a / character to the ExistenceTest.foo fonts that overlaps the right side of the character cell, to test the advance width reporting. - added advance width to the i_foo_bbox() interface, and implemented it for FT2, FT1 and Type 1 - Imager::Font::bounding_box() now returns an Imager::Font::BBox object in scalar context. - implemented $font->align() text output method, for simple output of aligned text - created Imager::Font::Wrap::wrap_text to perform simple text wrapping - FT1, FT2 and T1 fonts now support the face_name method - FT1, FT2 and T1 now support the glyph_names() method - Debian woody supplied FT2.0.9, which didn't support FT_Has_PS_Names(), so we use the FT_HAS_GLYPH_NAMES() macro instead. - some older FT1 don't define TT_MS_LANGID_ENGLISH_GENERAL, which we use, define it if freetype doesn't. - Added extra options to rubthrough() so only a subpart of source image is used. - the image fills didn't handle filling with source images of less than four channels correctly - added comment support the postfix transform2() expression parser - transform2() can now produce images with other than 3 channels. - added a correct T_AVREF input mapping to the typemap to simplify parameter lists - shut off one of the align subtests in the ft2 test. The triggering is likely an ft2 bug. - removed some half written scaling optimization code. - added /sw/lib and /sw/include to the Makefile.PL code for osX. - removed all references to the www.eecs.umich.edu page and changed them to imager.perl.org ones. 0.43 - added log() and exp() functions to transform2() - change the getpN() functions in transform2() to set a reasonable alpha if the input image has no alpha - document the constants that transform2() defines - skip the right number of tests when FT2 isn't available - This version pushed to CPAN because of skip problem in FT2 test. 0.43_01 Fri 8 Oct 2004 - only call FT_Get_Postscript_Name() on FT 2.0.6 and later - put the IM_LIBPATH and IM_INCPATH values first in the search path so the builder gets their local versions if desired rather than the system versions they might be trying to avoid - document the exp() and log() transform2() functions - document the constants normally set by transform2(). - refer the user to appropriate documents in the example in Imager.pm - change the list of documents in Imager.pm to move the document names out of the =item lines so we can make them into links - the scale() method now produces a warning when called in void context. - font.c now only uses the defined T1Lib error codes - update ppport.h and remove the duplicate definitions from Imager.xs. Had to mangle ppport.h to prevent duplicate global function definitions. - newer versions of tifflib require that all of the function pointers passed to TIFFClientOpen be non-NULL, the mmap() and munmap() pointers were always NULL and the sizeproc was sometimes NULL. - there would be a link or load time error on m_init_log() if Imager was built with IM_NOLOG, fixed by renamed init_log() to m_init_log() in log.c (thanks to Takumi Yamani) - moved some variable definitions to the right place - the Win32 font driver bounding box function now returns the right number of values (both thanks to Takumi Yamani) - the Win32 font driver now uses DEFAULT_CHARSET rather than ANSI_CHARSET are the lfCharSet value for the LOGFONT, as suggested by Takumi Yamani. - fontfiles/ExistenceTest.{pfb,ttf} weren't marked as binary in the CVS repository (caused test failures if you built from CVS on Win32) - Makefile.PL should now handle INCLUDE or LIB with spaces in them correctly on Win32. - the pnm reader read maxval for ppm/pgm files and then ignored it, it's now validated (0 < maxval < 65536) and used to scale samples. Note that binary ppm/pgm files (P6/P5) with maxval > 255 result in an error, since I didn't want to add new features just yet, just get the code that's there working correctly. Thanks to Elthek on rhizo for reporting this and help in tracking it down. Resolves https://rt.cpan.org/Ticket/Display.html?id=7465 - added a bunch of tests for reading pnm files. - previously, if you supplied to_paletted and empty color map and set make_colors to 'none', quant_translate() would segfault. This was because it was making the reasonable assumption that you'd have colors to map to. quant_translate() now checks there is at least one color and return NULL if there isn't. - i_img_to_pal() now does error checking of the value returned by quant_translate(). - Imager::to_paletted() now checks for success/failure of i_img_to_pal() correctly and does appropriate error handling. - i_writegif_low() did no error checking on the result of quant_translate(), it now does - we now test that trying to write a GIF image with no palette allowable by the quant options is a failure. - Imager::write() was doing nothing with the result of the call to i_writegif_gen(), in particular it wasn't returning () on failure. - added tests for paletted image handling and the methods specific to those images - the XS for i_setcolors() was missing the OUTPUT clause for RETVAL, and hence wasn't returning failure on failure. - supplying a sufficiently small scaling value could make the scale() method return an image with zero height or width. Several of the above together resolve https://rt.cpan.org/Ticket/Display.html?id=7467 - the void context warning for scale() now includes the callers filename/line (instead of the default of Imager.pm line 15xx) - Imager->new will now return undef if the dimensions or number of channels specified for an image are out of range. An error message can be retrieved with Imager->errstr. - added the C color specifier and the Imager::Color::Table class which defines those colors. Resolves https://rt.cpan.org/Ticket/Display.html?id=2593 - added the equals() method to Imager::Color. Resolves https://rt.cpan.org/Ticket/Display.html?id=2238 - prevent a test warning introduced by the above - the rotate() and matrix_transform() methods now accept a 'back' parameter specifying a background color. This is only used where there is no source data (think of the corners around an image rotated 45 degrees) and it not combined with transparent pixels from the source image. Resolves https://rt.cpan.org/Ticket/Display.html?id=6140 - removed a warning generated by the new matrix_transform() test - added a method index to Imager.pm - corrected "flood fill" to "flood_fill" in Imager/Draw.pod - removed compose() method from Imager/Transformations.pod since it isn't implemented yet - the image resulting from a crop is now the same type as the source image (paletted vs direct, bits/sample) Resolves https://rt.cpan.org/Ticket/Display.html?id=7578 - the parameters to crop() weren't handled correctly in most cases other than supplying left,top,right,bottom. - clarified the documentation for crop() providing more detail and more examples - the edges of the cropped area are now cropped against the edges of the source image - cropping to zero width/height is treated as an error (no image is returned and $src->errstr has a message) Resolves https://rt.cpan.org/Ticket/Display.html?id=7581 - built 0.43_01 for testing 0.43_02 Mon 26 Oct 2004 - the changes to scale() had some problems with integer vs floating point calculations (only caught in tests under perl 5.8.5 ) - the FT2 glyph_names() method didn't do correct error handling when the string parameter wasn't supplied - i_ft2_glyph_name() accepted only an unsigned char as the character code to get the name for, which meant it didn't work for unicode characters \x{100} or above - the XS for i_ft2_glyph_name() had a similar problem - added NameTest.ttf to be used in checking unicode glyph names - added reliable_only optional parameter to the glyph_names() method so you can ignore theresult of FT_Has_PS_Glyph_Names() - handle errors given by i_ft2_glyph_name() a bit more correctly - the FT1 glyph_names() method didn't do correct error handling when the string parameter wasn't supplied - some memory allocated when creating a callback IO object (io_new_cb) wasn't being released (detected with valgrind) - the testtools.pl match[nx]() functions escapes the test string on test failure a bit better - the XS code for i_tt_glyph_name() used unsigned char to store a unicode character when it should have used unsigned long. - the XS code for i_t1_glyph_name() used unsigned char to store a unicode character when it should have used unsigned long. - resolves https://rt.cpan.org/Ticket/Display.html?id=7949 - the type 1 glyph_names() method didn't do correct error handling when the string parameter wasn't supplied - renamed io.h to imio.h to prevent problems building under cygwin. resolve https://rt.cpan.org/Ticket/Display.html?id=7948 - i_writegif_low() wasn't setting the returned global palette, which meant a rubbish palette was returned to the user (detected with valgrind) - built 0.43_02 for testing 0.43_03 Wed 8 Dec 2004 - change the "double-include" protection macro that imio.h uses. - updated download locations for the various libraries that Imager depends on. Added some advice for cygwin. - more information on gif library versions in README and Makefile.PL - creating an image where the size of the allocated image buffer would overflow an integer would cause too small a buffer to be allocated. This could potentially be a security hole. partly resolves https://rt.cpan.org/Ticket/Display.html?id=8213 - set i_format to jpeg for jpeg files and test for it - set i_format to png when reading png files and test for it - i_yres was being set to the xres when reading a png file - added many bad BMP files to test various code paths in bmp.c, and made many minor fixes to bmp.c to make them work: - it was possible for various types of read failures to SEGV, both as NULL pointer dereferences and buffer overflows - some errors, like palettes being too large for the number of bits per pixel, were not being caught - failing to read all of a packed data structure would not cause a read failure - invalid compression types were not always caught - error messages are more consistent (still not always great messages, but one step at a time) - added bmp_compression_name, bmp_used_colors, bmp_filesize, bmp_bit_count tags on reading a BMP file - added tools/imager to the distribution. This is still very experimental and untested. Patches welcome, if you write tests to go with them. - the BMP reader now validates the bfOffBits value from the BMP header and skips to that offset before reading image data. Previously this value was read but otherwise ignored. - added --palette action to tools/imager - i_img_pal_new() now releases the image object memory if creation fails. - set i_format to gif when reading gif files and test for it - set i_format to pnm when reading pnm files and test for it - set i_format to tga when reading tga files and test for it - handle image creation failures when reading tga files - set i_format to tiff when reading tiff images and test for it - handle image creation failures when reading tiff files - test t/t35ttfont.t no longer requires TTFONTTEST to be set (and hasn't for a long time,) removed that requirement from README - updated home page URLs throughout the .pods - added information on reporting bugs to the SUPPORT section of Imager.pm - regops.perl now sorts the dumped data structure to produce minimal diffs - quant.c now checks for integer overflow allocating its image data - i_readraw_wiol() now checks for image creation failure - i_readrgb_wiol() now checks for image creation failure - i_writergb_wiol() was an empty stub, it now pushes an error message and explicitly returns failure. - i_readrgb_wiol() now sets i_format to rgb. - set i_format to raw when reading tga files and test for it - document i_format tag - some tests were using $Config{ivsize} when they should have been using $Config{intsize} Resolves: https://rt.cpan.org/Ticket/Display.html?id=8645 - tools/imager has been removed from the MANIFEST, it's way too late to test/debug for 0.44. - image.h had no prototype for i_ft2_bbox_r() and it was being called from Imager.xs - giflib 4.1.3 still doesn't have all the bugs fixed, update the notes in README and in the buggy_giflib.txt file that t105gif.t produces - make the inclusion of NO_META dependent on the version of EU::MM. I was going to include a META.yml but EU::MM's generation is too simplistic (and misses the leading document header too). For now I'll leave it out. - built 0.43_03 for testing 0.44 Wed 15 Dec 2004 - modify the default include directories list to include the location FreeBSD keeps freetype1 headers after the freetype2 locations. This ensures that the -I options are generated with freetype2 locations first, so that those directories are searched before the freetype1 directories. This prevents problems compiling font.c on FreeBSD. Resolves: http://rt-cpan.fsck.com/Ticket/Display.html?id=1723 - finish off a sentence in the "Producing an image from a CGI script" example in Imager::Files - method index didn't include errstr() - document that you don't want the FT2 freetype.h in the include path 0.44_01 Tue 24 May 2005 - the plugins Makefile has long produced an error after all tests were complete on Win32, finally tracked down why - Makefile.PL now checks the directories specified by $Config{locincpth} and $Config{loclibpth} for includes and libraries respectively. Resolves: https://rt.cpan.org/Ticket/Display.html?id=2942 - we were undefing the wrong macro (used as an include guard) when building the error code translation function for freetype 2. This meant most errors came out as numbers. - add a note to the README on how to get font suitcases and dfont files working on OS X. - add dfont to the list of extensions supported by ft2 - document Imager::Font->new()'s index parameter - added concept index to Imager.pm's POD - the gradgen filter now does the same color value conversion that Imager's drawing functions do. - added trivial multiple master support via the FT2 driver - added .pcf and .pcf.gz to the list of extensions supported by ft2 - the tiff reader now puts warning messages produced during reading into the i_warning tag. Resolves: https://rt.cpan.org/Ticket/Display.html?id=8722 - the i_xres and i_yres tags are now stored in a resolution similar to their source. Resolves: https://rt.cpan.org/Ticket/Display.html?id=8520 - added tiff_resolutionunit_name tag when reading tiff files - Makefile.PL now attempts to use freetype-config to configure freetype 2 and pkg-config to configure libpng. - avoid complaining about include/lib directories we pull from perl's config or we have built-in - Makefile.PL now builds imconfig.h with #defines for libraries present (and for the GIF library version) rather than putting them into CFLAGS - scanning for required include files is now down by directory rather than by file, using -e to check for the existence for a file rather than doing an eq against every filename in the directory. - previously we only checked a candidate include directory for freetype.h to consider it a valid FT1.x include directory. We now check if it contains fterrors.h too, if it does, then it's from a FT2 installation and we ignore it. - Makefile.PL now accepts command-line options to set include and library directories and to enable/disable drivers. - added simple examples to most of the filters documented in Imager::Filters - explicitly document there are no PNG specific tags. - more examples in Imager::Draw - minor cleanup of Imager::Fill - eliminate unused variables and static functions - simplify some XS code by adding another typemap entry - the right-side bearing used to adjust the final width wasn't being calculated correctly, this would cause the bounding_box() function for freetype 2.x to return a larger than expected text width. http://rt.cpan.org/NoAuth/Bug.html?id=11291 - add scaleX/scaleY to the method index and gives them some examples http://rt.cpan.org/NoAuth/Bug.html?id=11328 - call read() instead of open() in the example code in Imager.pm, and mention that open() is an alias for read(). http://rt.cpan.org/NoAuth/Bug.html?id=11431 - added reference list of crop() parameters. http://rt.cpan.org/NoAuth/Bug.html?id=11430 - reading a tga image with an idstring of 128 or more bytes would result in an allocation error, if the platform char type was signed - tests now check that tga tags are set - calling the read() method for a format not included in the Imager build, for example, JPEG with no libjpeg installed, would crash with an undefined function error (modified by DynaLoaders dependence on AutoLoader.) http://rt.cpan.org/NoAuth/Bug.html?id=9618 - some test scripts have been modified to use Test::More, which is now included under the t directory. Eventually all will be modified to use Test::More and the duplicates in t/testtools.pl will be removed - the convert, crop, rotate, copy, matrix_transform, to_paletted, to_rgb8, scaleX and scaleY methods now warn when called in void context. http://rt.cpan.org/NoAuth/Bug.html?id=9672 - correct email addresses in the README file, and include bug reporting information there too - added README for samples directory, describes interleave.pl and anaglyph.pl to start. - the XS for the internal i_glin() function wasn't copying the pixel values across to the returned color objects. http://rt.cpan.org/NoAuth/Bug.html?id=11860 - Imager::Cookbook wasn't included in the MANIFEST - added samp-form.cgi and samp-image.cgi to the samples directory to demonstrate displaying a generated image on a HTML page. - Makefile.PL now adds rules to generate a suitable META.yml to the generated Makefile. - added sample code for handling images uploaded via a HTML form. - saving a GIMP gradiant file with Imager::Fountain->save has always been broken. Fixed it and added tests. - newer versions of GIMP add a line to gradient files before the segment count giving a descriptive name of the gradient. Imager::Fountain can now read and write such gradient files. The interface is a bit indirect, but I'd like to preserve Imager::Fountain as a blessed array ref for now. - the segments parameter supplied to the fountain filter and the fountain fill contructor now accepts color names or other descriptions as other functions do. - fix a few compiler warnings - document the Imager::Font::BBox advance_width() method - Imager::Font::BBox advance_width() method was falling back to the wrong value when the font driver's low level function didn't return the advance width. - the FT 1.x was comparing versus an uninitialized variable when checking the end of string when calculating the right side bearing used to adjust pos_width for glyphs that overlap the right side of the advance width. - Imager::Font::BBox objects now have right_bearing() and display_width() methods. Hopefully this and the advance_width() method fills out the Imager bounding box interface to a useful state. Implemented for all four font drivers. - Win32 font bounding_box() method now supports the advance width and right bearing values. - Imager::Matrix2d->rotate() would only rotate around the supplied centre point if both 'x' and 'y' were non-zero. - the internal i_tags_get_string() function now acts correctly for integer only tags. - the FT1.x driver now supports the align parameter correctly. Tests were added to each driver to check correct handling of the align parameter. - the Win32 font driver bounding_box() method now puts accurate values in the ascent and descent values, previously they were set to the font ascent/descent rather than the values specific to the string. - supplying align=>0 to the win32 font driver string() function now aligns in the same way as the other drivers. - removed the bug reporting email address to prevent spammers stripping it. The URL is still there and if someone knows how rt.cpan.org works they can still figure out the email. - the internal function used to probe file formats if the type parameter wasn't passed to the read() method would produce diagnostics on stdout, precluding use in web applications. Silenced it. - the setcolors() had a fencepost error making it impossible to use it to set the last color in the palette. http://rt.cpan.org/NoAuth/Bug.html?id=12676 - fix the filter examples in Imager::Filter so they don't indicate that a new image is returned (the filter() method works in-place) - add examples for the fountain filter - prevent warnings from Makefile.PL when there's no libraries found - Imager no longer assumes that MSVC is the only native Win32 compiler, MinGW can be used to build Imager. - fixed an inverted condition checking the giflib version, and replaced a manual test skip in t/t105gif.t - add tests to exercise hatch fills for floating images. This code is mis-generated with the gcc 4.0 that ships with OS X 10.4 - work around junk that pkg-config sends to stderr on FreeBSD 4.10 - testimg/base.jpg was missing from the MANIFEST, causing test failures - use a temp file to avoid messing with echo on Win32 when building META.yml - add some Mac OS X notes to the README 0.45 Mon 30 May 2005 - t/t105gif.t wasn't handling buggy giflibs correctly 0.45_01 Mon 12 Dec 2005 - give the colorcount() and maxcolors() methods their own entries and add them to the method index. - added tiff_bitspersample and tiff_photometric tags to tiff images when read - loading filter DLLs/DSOs had an off-by-one error allocating a buffer for the filename of the library (does anyone use this functionality?) - remove old #if 0 code from Imager.xs - convert t/t15color.t to Test::More - prevent warnings when looking up a GIMP color with no palette parameter and $ENV{HOME} not set. Resolves: http://rt.cpan.org/NoAuth/Bug.html?id=13143 - added VERSION numbers to most .pms - convert t/t104ppm.t to Test::More - convert t/t107bmp.t to Test::More - convert t/t108tga.t to Test::More - error messages generated reading JPEG or PNG images are now available via errstr() - implement/test/document set_file_limits()/get_file_limits() methods, which allow limits on the size of image files read. - new example for convert() method based on Leolo's query - implement getscanline(), setscanline() and getsamples() methods. These are low level methods for fast access to image data, based on existing C functions that Imager uses internally. - limit limits.c to C89 - the gif tests weren't skipping enough when there was no gif support - move include t1lib out of image.h to font.c, since nothing it provides is needed elsewhere. - minor POD fixes - added a brief tutorial - Imager::Font->new() for the tt (Freetype 1.x) driver now correctly handles errors from i_tt_new(), and passed error messages now generated by i_tt_new(). Resolves: http://rt.cpan.org/NoAuth/Bug.html?id=14804 - renamed lib/Imager/Cookbook.pm to lib/Imager/Cookbook.pod - CPANTS complains about it not having 'use strict;' - add samples/replace_color.pl - you can now supply a page parameter to read() to read a given page from a TIFF file. - added samples/border.pl, and notes on adding a border in Imager::Cookbook. - added sampled/slant_text.pl, and notes on shearing/rotating text in Imager::Cookbook. - INCOMPATIBLE CHANGE: reading a gif file will now read the first image from the file rather than the a consolidated image. If you want the old behaviour supply C<< gif_consolidate=>1 >> to the read() method. Older versions of Imager will accept this parameter and produce the same result. - you can now supply a page parameter to read() to read a given page from a GIF file. - reading a multi-image GIF was leaking memory (a line buffer per file) - maxcolors now must be at least 1 when creating a paletted image. - converted t/t022double.t to use Test::More - t1 library re-initialization modified to support T1Lib 5.1.0 - setmask() now returns true on success and reports a missing mask parameter. - double per sample images were ignoring the channel mask. - converted t/t021sixteen.t to use Test::More - 16-bit per sample images were ignoring the channel mask - added t/t91pod.t - expand Imager::ImageTypes: - make all methods into =items - document parameters - more examples - add AUTHOR/REVISION/SEE ALSO - add samples/tk-photo.pl - fixes to verbose mode in Makefile.PL, also added a -v switch so you can enable it via the command-line Resolves: http://rt.cpan.org/NoAuth/Bug.html?id=16094 - arc(..., fill=> ...) wasn't handling concave areas correctly - arc(..., color=>...) wasn't properly filling it's area - added experimental antialiased support to arc() - the order of the returned values for Imager::Font's align() method was incorrect. - check the correct directory when adding the cygwin Win32 API include path (Makefile.PL). This was a later response to #16094 Resolves: http://rt.cpan.org/NoAuth/Bug.html?id=16094 - add --nolog command-line switch to Makefile.PL to disable logging - filled polygons using a complex fill with combine != 0 (none) didn't correctly handle polygons that crossed a given scanline more than once. - the straight edges of filled arcs weren't being drawn correctly, causing minor artifacts at the inner and external corners - implemented valign=>'end' for Imager::Font->align - added $img->align_string() as a way to call Imager::Font->align - added samples/align-string.pl - improved missing argument handling a little for the string() method - linkify Imager.pm a bit more - expand Imager::Draw: - make all methods items - document parameters - more examples - add AUTHOR, REVISION. - add smoke test for nearest_color filter - added integer overflow checks to many memory allocation calls - added experimental EXIF decoding when reading JPEG files. - read/write i_xres, i_yres, i_aspect only tage with JPEG files, and read/write jpeg_density_unit (+_name) tag - save the jpeg_comment tag when writing - the has_chars() method now checks the font objects utf8 flag as well as the utf8 parameter. - clean up Imager::Font documentation: - string now documented in Imager::Draw - add parameter list documentation - document the utf8 parameter for bounding_box(), has_chars() Resolves: http://rt.cpan.org/NoAuth/Bug.html?id=13508 - decode the EXIF GPS IFD as well - minor documentation touchups - bump version 0.45_01 0.45_02 Mon 12 Dec 2005 - some test scripts weren't fixing @INC correctly - t/t101jpeg.t wasn't skipping enough when there was no jpeg support - bump version to 0.45_02 0.46 Tue 20 Dec 2005 - change the use in t/t91.pod to require version 1.00 of Test::Pod - minor changes to Imager::Transformations - bump version to 0.46 0.46_01 Fri 30 Dec 2005 - switched to subversion - changed $VERSION that was based on Revision tag to be manually handled. - outputting a single space using the Freetype 1.x driver (type=>'tt') was producing a divide by zero error. - bump to 0.46_01 for testing 0.47 Fri 30 Dec 2005 - bump to 0.47 0.47_01 Tue 21 Feb 2006 - set the locale to "C" properly when testing ft1.x error messages - don't destroy image before creating it in error handling in bmp.c - extra concept index entries - Imager::Draw - align_string()'s valign parameter was invalid in the synopsis - start of external Imager API access: - rename headers to avoid conflicts: - image.h to imager.h - imagei.h to imageri.h - datatypes.h to imdatatypes.h - config.h to imconfig.h (created by Makefile.PL) - moved all public types defined in imager.h to imdatatypes.h - supply the PM parameter to WriteMakefile(), to install headers under Imager/include, and the Imager typemap in Imager/typemap. We scan the MANIFEST for files to add to PM. - add "i_" prefix on some functions useful as public at the C level. - moved the typedefs that support the typemap from Imager.xs to imperl.h - set the global callbacks hook in the Imager.xs BOOT section - API cleanup: - define i_tags_set(), i_tags_setn() - we might not allow multiple values for a tag in the future - i_copy() now returns a new image instead of doing horrible inplace things to an existing image - provide actual functions for all of the macros we define in imager.h so we can put them in the global callbacks structure - define global functions structure (imexttypes.h) and initialize it (imext.c) - add API include header with macros to setup the define and initialize the local callbacks pointer, and macros to call the API functions. - build Imager::APIRef from C sources, including updating the sources to include documentation for each API function. - convert dyntest and mandelbrot dynfilts into XS modules (too easy) - simple Imager::CountColor example - support Inline::C : - typemap changes to accept Imager or Imager::ImgRaw objects as image parameters - define Imager output type for trivial cases of returning an i_img as a full Imager object - Inline WITH hook to filter Imager XS types into types Inline::C can accept, supply appropriate headers and initialization. - test script t/t82inline.t - try to use XSLoader instead of DynaLoader (but fallback if necessary) - paste() can now paste a subset of the source image. - paste() now has better tests - paste() should now be faster for larger pastes - added sample files missing from MANIFEST - added t/t92samples.t to check samples/README against MANIFEST - added inline_replace_color.pl to samples - constify the Imager API - document Imager::Filter::Mandelbrot - convert dynfilt/flines.c to Imager::Filter::Flines - minor changes for older perl/ExtUtils::MM - deal with freetype-config --cflags returning the directories in the wrong order (Freetype 2.1.4 and earlier) Thanks to David Wheeler for his help in tracking this down. - reword and provide an example for non-proportionally scaling an image. Wording from Simon Cozens. - error messages when writing TIFF images were always 'Could not write to buffer', more useful messages are now reported. - error messages when writing PNM images were always 'unable to write pnm image', more useful messages are now reported. - convert t/t103raw.t to Test::More - reading a raw image no longer exits on a short read or read error, and returns an appropriate error message in $im->errstr - write failures when writing a raw image now return a useful message in $im->errstr - added typemap type names to types in Imager::API. - make skip when Inline::C not available less verbose - convert t/t07iolayer.t to Test::More - handle the possibility of strerror() returning NULL. - supply C parameter to filters so we can register filters implemented in perl. - document register_filter() and add test for it - add example to SYNOPSIS of samples/inline_replace_color.pl - minor POD fix in Imager::Color::Table - eliminate many -Wall warnings - update README to match unbuggy giflib - document index parameter of Imager::Font->new() - change faxable output to use a more fax natural PHOTOMETRIC_MINISWHITE, since T.4 normally works that way, and MINISBLACK confuses some readers. - clean up scale() method for readability - make scale() fail if an invalid type is supplied (previously documented as undefined behaviour) - add error handling tests for scale() - smarter warning removal - handle effects of byte ordering when testing tiff error messages - scale() can now expect an Image::Math::Constrain object as a scaling constraint via the constrain parameter. - added tests for the various ways we can specify scaling size - documented scale()'s scalefactor parameter - sick of $opts{scalefactor} in scale(), give it a scalar to call it's own. - check $Config{ldflags} and $Config{ccflags} for places to search for headers and libraries. This deals with the way the fink build of perl puts -L/sw/lib in ldflags rather than using loclibpth - eliminate some of the duplication of -I and -L options in LIBS and INC - Makefile.PL now uses strict. - the search for freetype1.x headers is now smarter - add tests for scaleX()/scaleY() - expand documentation of scaleX()/scaleY() - rotate()s back parameter now accepts color names like other methods - convert t/t69rubthru.t to Test::More - minor clean up of rubthrough() method - error handling tests for rubthrough() - expand Imager::Transformations: - document parameters more explicitly - document return values - add examples - add AUTHOR, SEE ALSO, REVISION - eliminate sign warning from image.c - make TIFF detection stricter - more memory allocation integer overflow auditing - IM_DEBUG_MALLOC wasn't interacting well with the API - make win32.c const happy - make raw.c C89 compliant - added version/level to the API function table structure - fix/simplify META.yml generation - we now generate META.yml at Makefile.PL time, since trying to work with EU::MM to generate a custom META.yml was a waste. - bump to 0.47_01 0.48 Fri 3 Mar 2006 - removed unused hashinfo() function from Imager.xs - added =items for various methods, so Pod::Coverage will pick them up (Pod::Coverage tests to be added in 0.49) - bump to 0.48 0.49 - handle short EXIF user_comment fields correctly, previously Imager would read (and potentially) write beyond the end of an allocated block, or through a NULL pointer if the EXIF user_comment field was less than 8 bytes long. https://rt.cpan.org/Ticket/Display.html?id=17981 - tifflib 3.8.0 with MDI (Microsoft(tm) TIFF) support produces a different error when it reads a file with a bad magic number. Update the test to handle the possible messages. - some jpeg.c logging calls didn't include parameters enough to match the supplied format string. (detected by valgrind) - in some cases memory wasn't being freed during error handling when reading jpeg images (detected by valgrind) - free the TIFF object correctly when reading a TIFF image and the page number is out of range. (detected by valgrind) - i_gsampf() (used to implement getsamples() for floating point samples) was leaking memory. (detected by valgrind) - writing to a PNG file was leaking one memory block (detected by valgrind) - some error paths when reading GIF images weren't closing the GIF read object. (detected by valgrind) - bump to 0.49 (to get #17981 fix out) ================================================================= For latest versions check the Imager-devel pages: http://imager.perl.org/ ================================================================= libimager-perl-1.004+dfsg.orig/imextpl.h0000644000175000017500000000231412263740601017415 0ustar gregoagregoa#ifndef IMAGER_IMEXTPL_H_ #define IMAGER_IMEXTPL_H_ #include "imextpltypes.h" #include "immacros.h" extern im_pl_ext_funcs *imager_perl_function_ext_table; #define DEFINE_IMAGER_PERL_CALLBACKS im_pl_ext_funcs *imager_perl_function_ext_table #ifndef IMAGER_MIN_PL_API_LEVEL #define IMAGER_MIN_PL_API_LEVEL IMAGER_PL_API_LEVEL #endif #define PERL_INITIALIZE_IMAGER_PERL_CALLBACKS \ do { \ imager_perl_function_ext_table = INT2PTR(im_pl_ext_funcs *, SvIV(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1))); \ if (!imager_perl_function_ext_table) \ croak("Imager Perl API function table not found!"); \ if (imager_perl_function_ext_table->version != IMAGER_PL_API_VERSION) \ croak("Imager Perl API version incorrect"); \ if (imager_perl_function_ext_table->level < IMAGER_MIN_PL_API_LEVEL) \ croak("perl API level %d below minimum of %d", imager_perl_function_ext_table->level, IMAGER_MIN_PL_API_LEVEL); \ } while (0) /* just for use here */ #define im_exttpl imager_perl_function_ext_table #define ip_handle_quant_opts (im_exttpl->f_ip_handle_quant_opts) #define ip_cleanup_quant_opts (im_exttpl->f_ip_cleanup_quant_opts) #define ip_copy_colors_back (im_exttpl->f_ip_copy_colors_back) #endif libimager-perl-1.004+dfsg.orig/datatypes.c0000644000175000017500000001653712263740600017737 0ustar gregoagregoa#include #include #include #define IMAGER_NO_CONTEXT #include "imager.h" /* 2d bitmask with test and set operations */ struct i_bitmap* btm_new(i_img_dim xsize,i_img_dim ysize) { size_t bytes; struct i_bitmap *btm; btm=(struct i_bitmap*)mymalloc(sizeof(struct i_bitmap)); /* checked 4jul05 tonyc */ bytes = (xsize*ysize+8)/8; if (bytes * 8 / ysize < xsize-1) { /* this is kind of rough */ fprintf(stderr, "Integer overflow allocating bitmap (" i_DFp ")", i_DFcp(xsize, ysize)); exit(3); } btm->data=(char*)mymalloc(bytes); /* checked 4jul05 tonyc */ btm->xsize=xsize; btm->ysize=ysize; memset(btm->data, 0, bytes); return btm; } void btm_destroy(struct i_bitmap *btm) { myfree(btm->data); myfree(btm); } int btm_test(struct i_bitmap *btm,i_img_dim x,i_img_dim y) { i_img_dim btno; if (x<0 || x>btm->xsize-1 || y<0 || y>btm->ysize-1) return 0; btno=btm->xsize*y+x; return (1<<(btno%8))&(btm->data[btno/8]); } void btm_set(struct i_bitmap *btm,i_img_dim x,i_img_dim y) { i_img_dim btno; if (x<0 || x>btm->xsize-1 || y<0 || y>btm->ysize-1) abort(); btno=btm->xsize*y+x; btm->data[btno/8]|=1<<(btno%8); } /* Bucketed linked list - stack type */ static struct llink * llink_new(struct llink* p,size_t size); static int llist_llink_push(struct llist *lst, struct llink *lnk,const void *data); static void llink_destroy(struct llink* l); /* =item llist_new() =synopsis struct llist *l = llist_new(100, sizeof(foo); Create a new stack structure. Implemented as a linked list of pools. Parameters: =over =item * multip - number of entries in each pool =item * ssize - size of the objects being pushed/popped =back =cut */ struct llist * llist_new(int multip, size_t ssize) { struct llist *l; l = mymalloc(sizeof(struct llist)); /* checked 4jul05 tonyc */ l->h = NULL; l->t = NULL; l->multip = multip; l->ssize = ssize; l->count = 0; return l; } /* =item llist_push() =synopsis llist_push(l, &foo); Push an item on the stack. =cut */ void llist_push(struct llist *l,const void *data) { size_t ssize = l->ssize; int multip = l->multip; /* fprintf(stderr,"llist_push: data=0x%08X\n",data); fprintf(stderr,"Chain size: %d\n", l->count); */ if (l->t == NULL) { l->t = l->h = llink_new(NULL,ssize*multip); /* Tail is empty - list is empty */ /* fprintf(stderr,"Chain empty - extended\n"); */ } else { /* Check for overflow in current tail */ if (l->t->fill >= l->multip) { struct llink* nt = llink_new(l->t, ssize*multip); l->t->n=nt; l->t=nt; /* fprintf(stderr,"Chain extended\n"); */ } } /* fprintf(stderr,"0x%08X\n",l->t); */ if (llist_llink_push(l,l->t,data)) { dIMCTX; im_fatal(aIMCTX, 3, "out of memory\n"); } } /* =item llist_pop() Pop an item off the list, storing it at C which must have enough room for an object of the size supplied to llist_new(). returns 0 if the list is empty =cut */ int llist_pop(struct llist *l,void *data) { /* int ssize=l->ssize; int multip=l->multip;*/ if (l->t == NULL) return 0; l->t->fill--; l->count--; memcpy(data,(char*)(l->t->data)+l->ssize*l->t->fill,l->ssize); if (!l->t->fill) { /* This link empty */ if (l->t->p == NULL) { /* and it's the only link */ llink_destroy(l->t); l->h = l->t = NULL; } else { l->t=l->t->p; llink_destroy(l->t->n); } } return 1; } void llist_dump(struct llist *l) { int j; int i=0; struct llink *lnk; lnk=l->h; while(lnk != NULL) { for(j=0;jfill;j++) { /* memcpy(&k,(char*)(lnk->data)+l->ssize*j,sizeof(void*));*/ /*memcpy(&k,(char*)(lnk->data)+l->ssize*j,sizeof(void*));*/ printf("%d - %p\n",i,*(void **)((char *)(lnk->data)+l->ssize*j)); i++; } lnk=lnk->n; } } /* =item llist_destroy() Destroy a linked-list based stack. =cut */ void llist_destroy(struct llist *l) { struct llink *t,*lnk = l->h; while( lnk != NULL ) { t=lnk; lnk=lnk->n; myfree(t); } myfree(l); } /* Links */ static struct llink * llink_new(struct llink* p,size_t size) { struct llink *l; l = mymalloc(sizeof(struct llink)); /* checked 4jul05 tonyc */ l->n = NULL; l->p = p; l->fill = 0; l->data = mymalloc(size); /* checked 4jul05 tonyc - depends on caller to llist_push */ return l; } /* free's the data pointer, itself, and sets the previous' next pointer to null */ static void llink_destroy(struct llink* l) { if (l->p != NULL) { l->p->n=NULL; } myfree(l->data); myfree(l); } /* if it returns true there wasn't room for the item on the link */ static int llist_llink_push(struct llist *lst, struct llink *lnk, const void *data) { /* fprintf(stderr,"llist_llink_push: data=0x%08X -> 0x%08X\n",data,*(int*)data); fprintf(stderr,"ssize = %d, multip = %d, fill = %d\n",lst->ssize,lst->multip,lnk->fill); */ if (lnk->fill == lst->multip) return 1; /* memcpy((char*)(lnk->data)+lnk->fill*lst->ssize,data,lst->ssize); */ memcpy((char*)(lnk->data)+lnk->fill*lst->ssize,data,lst->ssize); /* printf("data=%X res=%X\n",*(int*)data,*(int*)(lnk->data));*/ lnk->fill++; lst->count++; return 0; } /* Oct-tree implementation */ struct octt * octt_new() { int i; struct octt *t; t=(struct octt*)mymalloc(sizeof(struct octt)); /* checked 4jul05 tonyc */ for(i=0;i<8;i++) t->t[i]=NULL; t->cnt=0; return t; } /* returns 1 if the colors wasn't in the octtree already */ int octt_add(struct octt *ct,unsigned char r,unsigned char g,unsigned char b) { struct octt *c; int i,cm; int ci; int rc; rc=0; c=ct; /* printf("[r,g,b]=[%d,%d,%d]\n",r,g,b); */ for(i=7;i>-1;i--) { cm=1<t[ci] == NULL) { c->t[ci]=octt_new(); rc=1; } c=c->t[ci]; } c->cnt++; /* New. The only thing really needed (I think) */ return rc; } void octt_delete(struct octt *ct) { int i; for(i=0;i<8;i++) if (ct->t[i] != NULL) octt_delete(ct->t[i]); /* do not free instance here because it will free itself */ myfree(ct); } void octt_dump(struct octt *ct) { int i; /* printf("node [0x%08X] -> (%d)\n",ct,ct->cnt); */ for(i=0;i<8;i++) if (ct->t[i] != NULL) printf("[ %d ] -> %p\n", i, (void *)ct->t[i]); for(i=0;i<8;i++) if (ct->t[i] != NULL) octt_dump(ct->t[i]); } /* note that all calls of octt_count are operating on the same overflow variable so all calls will know at the same time if an overflow has occured and stops there. */ void octt_count(struct octt *ct,int *tot,int max,int *overflow) { int i,c; c=0; if (!(*overflow)) return; for(i=0;i<8;i++) if (ct->t[i]!=NULL) { octt_count(ct->t[i],tot,max,overflow); c++; } if (!c) (*tot)++; if ( (*tot) > (*overflow) ) *overflow=0; } /* This whole function is new */ /* walk through the tree and for each colour, store its seen count in the space pointed by *col_usage_it_adr */ void octt_histo(struct octt *ct, unsigned int **col_usage_it_adr) { int i,c; c = 0; for(i = 0; i < 8; i++) if (ct->t[i] != NULL) { octt_histo(ct->t[i], col_usage_it_adr); c++; } if (!c) { *(*col_usage_it_adr)++ = ct->cnt; } } i_img_dim i_abs(i_img_dim x) { return x < 0 ? -x : x; } libimager-perl-1.004+dfsg.orig/feat.h0000644000175000017500000000057712031434614016660 0ustar gregoagregoa#include "imager.h" static char *i_format_list[]={ #ifdef HAVE_LIBJPEG "jpeg", #endif #ifdef HAVE_LIBTIFF "tiff", #endif #ifdef HAVE_LIBPNG "png", #endif #ifdef HAVE_LIBGIF "gif", #endif #ifdef HAVE_LIBT1 "t1", #endif #ifdef HAVE_LIBTT "tt", #endif #ifdef HAVE_WIN32 "w32", #endif #ifdef HAVE_FT2 "ft2", #endif "raw", "pnm", "bmp", "tga", "ifs", NULL}; libimager-perl-1.004+dfsg.orig/README0000644000175000017500000000507312263740600016446 0ustar gregoagregoa================================================================ Copyright (c) 1999-2004 Arnar M. Hrafnkelsson. All rights reserved. Copyright (c) 2004-2013 Anthony Cook. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. A test font, FT2/fontfiles/MMOne.pfb contains Postscript code copyrighted by Adobe. See adobe.txt for license information. ================================================================ >> THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY WHATSOEVER << If you like or hate Imager, please let me know by sending mail to tonyc@cpan.org - I love feedback. ================================================================ ======================== 1. Patent infringements? ======================== Imager as such contains no patented algorithms. The external libraries (which are not written by me) may or may not contain patented algorithms. YOU ARE SOLELY RESPONSIBLE FOR OBTAINING LICENSE(S) TO USE SUCH LIBRARIES SHOULD YOU NEED ANY. ======================== 2. Compiling and testing ======================== For details on the this process, including library and platform specific details, see Imager::Install, either by using: perldoc lib/Imager/Install.pod or at: http://imager.perl.org/docs/Imager/Install.html The basic installation process is similar to most other CPAN modules: perl Makefile.PL make make test make install ======================= 3. General information ======================= The Imager module homepage is currently at: http://imager.perl.org/ You can report bugs by pointing your browser at: https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager ======================== 4. Thanks ======================== Thanks go to: Tony Cook ( TonyC ) Claes Jacobson ( Claes ) Philip Gwyn ( Leolo ) Michael Slade ( Micksa ) ( Cogent ) Brad Murray ( HalfJack ) Nicholas Dronen ( Veblen ) Michael G Schwern ( Schwern ) Rocco Caputo ( Dngor ) Graham barr ( Gbarr ) Mark-Jason Dominus ( Mjd ) Jerome Jason Alexander ( Jalex ) Randal R. Schwartz ( Merlyn ) Tkil ( ) Artur Bergman ( Sky ) Luc St-Louis ( Lucs ) PerlJam ( ) Roderick Schertler ( Roderick ) Nathan Torkington ( gnat ) Gabriel Vasseur kmx Nicolas Roggli Justin Davis Maurice Height Krzysztof WojtaÅ› David Cantrell Eleneldil G. Arilou Slaven Rezic Richard Fairhurst Nikita Dedik (and just to play it safe) all those I forgot to mention. libimager-perl-1.004+dfsg.orig/mutexpthr.c0000644000175000017500000000122012263740601017761 0ustar gregoagregoa/* pthreads mutexes */ #include "imageri.h" #include #include /* documented in mutexwin.c */ struct i_mutex_tag { pthread_mutex_t mutex; }; i_mutex_t i_mutex_new(void) { i_mutex_t m; m = malloc(sizeof(*m)); if (!m) i_fatal(3, "Cannot allocate mutex object"); if (pthread_mutex_init(&m->mutex, NULL) != 0) { i_fatal(3, "Error initializing mutex %d", errno); } return m; } void i_mutex_destroy(i_mutex_t m) { pthread_mutex_destroy(&(m->mutex)); free(m); } void i_mutex_lock(i_mutex_t m) { pthread_mutex_lock(&(m->mutex)); } void i_mutex_unlock(i_mutex_t m) { pthread_mutex_unlock(&m->mutex); } libimager-perl-1.004+dfsg.orig/perlio.c0000644000175000017500000000552212376611507017233 0ustar gregoagregoa/* perlio.c - Imager's interface to PerlIO */ #define IMAGER_NO_CONTEXT #include "imager.h" #include "EXTERN.h" #include "perl.h" #include "imperlio.h" static ssize_t perlio_reader(void *handle, void *buf, size_t count); static ssize_t perlio_writer(void *handle, const void *buf, size_t count); static off_t perlio_seeker(void *handle, off_t offset, int whence); static int perlio_closer(void *handle); static void perlio_destroy(void *handle); /* my_strerror is defined since perl 5.21.x */ #undef my_strerror static const char *my_strerror(pTHX_ int err); #ifndef tTHX #define tTHX PerlInterpreter * #endif typedef struct { PerlIO *handle; pIMCTX; #ifdef MULTIPLICITY tTHX my_perl; #endif } im_perlio; #define dIMCTXperlio(state) dIMCTXctx(state->aIMCTX) /* =item im_io_new_perlio(PerlIO *) Create a new perl I/O object that reads/writes/seeks on a PerlIO handle. The close() handle flushes output but does not close the handle. =cut */ i_io_glue_t * im_io_new_perlio(pTHX_ PerlIO *handle) { im_perlio *state = mymalloc(sizeof(im_perlio)); dIMCTX; state->handle = handle; #ifdef MULTIPLICITY state->aTHX = aTHX; #endif state->aIMCTX = aIMCTX; return io_new_cb(state, perlio_reader, perlio_writer, perlio_seeker, perlio_closer, perlio_destroy); } static ssize_t perlio_reader(void *ctx, void *buf, size_t count) { im_perlio *state = ctx; dTHXa(state->my_perl); dIMCTXperlio(state); ssize_t result = PerlIO_read(state->handle, buf, count); if (result == 0 && PerlIO_error(state->handle)) { im_push_errorf(aIMCTX, errno, "read() failure (%s)", my_strerror(aTHX_ errno)); return -1; } return result; } static ssize_t perlio_writer(void *ctx, const void *buf, size_t count) { im_perlio *state = ctx; dTHXa(state->my_perl); dIMCTXperlio(state); ssize_t result; result = PerlIO_write(state->handle, buf, count); if (result == 0) { im_push_errorf(aIMCTX, errno, "write() failure (%s)", my_strerror(aTHX_ errno)); } return result; } static off_t perlio_seeker(void *ctx, off_t offset, int whence) { im_perlio *state = ctx; dTHXa(state->my_perl); dIMCTXperlio(state); if (whence != SEEK_CUR || offset != 0) { if (PerlIO_seek(state->handle, offset, whence) < 0) { im_push_errorf(aIMCTX, errno, "seek() failure (%s)", my_strerror(aTHX_ errno)); return -1; } } return PerlIO_tell(state->handle); } static int perlio_closer(void *ctx) { im_perlio *state = ctx; dTHXa(state->my_perl); dIMCTXperlio(state); if (PerlIO_flush(state->handle) < 0) { im_push_errorf(aIMCTX, errno, "flush() failure (%s)", my_strerror(aTHX_ errno)); return -1; } return 0; } static void perlio_destroy(void *ctx) { myfree(ctx); } static const char *my_strerror(pTHX_ int err) { const char *result = strerror(err); if (!result) result = "Unknown error"; return result; } libimager-perl-1.004+dfsg.orig/imext.h0000644000175000017500000003435312507371373017100 0ustar gregoagregoa#ifndef IMAGER_IMEXT_H_ #define IMAGER_IMEXT_H_ #include "imexttypes.h" #include "immacros.h" extern im_ext_funcs *imager_function_ext_table; #define DEFINE_IMAGER_CALLBACKS im_ext_funcs *imager_function_ext_table #ifndef IMAGER_MIN_API_LEVEL #define IMAGER_MIN_API_LEVEL IMAGER_API_LEVEL #endif #define PERL_INITIALIZE_IMAGER_CALLBACKS_NAME(name) \ do { \ imager_function_ext_table = INT2PTR(im_ext_funcs *, SvIV(get_sv(PERL_FUNCTION_TABLE_NAME, 1))); \ if (!imager_function_ext_table) \ croak("Imager API function table not found!"); \ if (imager_function_ext_table->version != IMAGER_API_VERSION) { \ croak("Imager API version incorrect loaded %d vs expected %d in %s", \ imager_function_ext_table->version, IMAGER_API_VERSION, (name)); \ } \ if (imager_function_ext_table->level < IMAGER_MIN_API_LEVEL) \ croak("API level %d below minimum of %d in %s", imager_function_ext_table->level, IMAGER_MIN_API_LEVEL, (name)); \ } while (0) #define PERL_INITIALIZE_IMAGER_CALLBACKS PERL_INITIALIZE_IMAGER_CALLBACKS_NAME(__FILE__) /* just for use here */ #define im_extt imager_function_ext_table #define im_get_context() ((im_extt->f_im_get_context)()) #define im_context_refinc(ctx, where) ((im_extt->f_im_context_refinc)((ctx), (where))) #define im_context_refdec(ctx, where) ((im_extt->f_im_context_refdec)((ctx), (where))) #ifdef IMAGER_DEBUG_MALLOC #define mymalloc(size) ((im_extt->f_mymalloc_file_line)((size), __FILE__, __LINE__)) #define myrealloc(ptr, size) ((im_extt->f_myrealloc_file_line)((ptr), (size), __FILE__, __LINE__)) #define myfree(ptr) ((im_extt->f_myfree_file_line)((ptr), __FILE__, __LINE__)) #else #define mymalloc(size) ((im_extt->f_mymalloc)(size)) #define myfree(size) ((im_extt->f_myfree)(size)) #define myrealloc(block, newsize) ((im_extt->f_myrealloc)((block), (newsize))) #endif #define im_img_8_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_8_new)((ctx), (xsize), (ysize), (channels))) #define im_img_16_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_16_new)((ctx), (xsize), (ysize), (channels))) #define im_img_double_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_double_new)((ctx), (xsize), (ysize), (channels))) #define im_img_pal_new(ctx, xsize, ysize, channels, maxpal) ((im_extt->f_im_img_pal_new)((ctx), (xsize), (ysize), (channels), (maxpal))) #define i_img_destroy(im) ((im_extt->f_i_img_destroy)(im)) #define i_sametype(im, xsize, ysize) ((im_extt->f_i_sametype)((im), (xsize), (ysize))) #define i_sametype_chans(im, xsize, ysize, channels) ((im_extt->f_i_sametype_chans)((im), (xsize), (ysize), (channels))) #define i_img_info(im, info) ((im_extt->f_i_img_info)((im), (info))) #ifndef IMAGER_DIRECT_IMAGE_CALLS #define IMAGER_DIRECT_IMAGE_CALLS 1 #endif #if !IMAGER_DIRECT_IMAGE_CALLS #define i_ppix(im, x, y, val) ((im_extt->f_i_ppix)((im), (x), (y), (val))) #define i_gpix(im, x, y, val) ((im_extt->f_i_gpix)((im), (x), (y), (val))) #define i_ppixf(im, x, y, val) ((im_extt->f_i_ppixf)((im), (x), (y), (val))) #define i_gpixf(im, x, y, val) ((im_extt->f_i_gpixf)((im), (x), (y), (val))) #define i_plin(im, l, r, y, val) ((im_extt->f_i_plin)((im), (l), (r), (y), (val))) #define i_glin(im, l, r, y, val) ((im_extt->f_i_glin)((im), (l), (r), (y), (val))) #define i_plinf(im, l, r, y, val) ((im_extt->f_i_plinf)((im), (l), (r), (y), (val))) #define i_glinf(im, l, r, y, val) ((im_extt->f_i_glinf)((im), (l), (r), (y), (val))) #define i_gsamp(im, l, r, y, samps, chans, count) \ ((im_extt->f_i_gsamp)((im), (l), (r), (y), (samps), (chans), (count))) #define i_gsampf(im, l, r, y, samps, chans, count) \ ((im_extt->f_i_gsampf)((im), (l), (r), (y), (samps), (chans), (count))) #endif #define i_gsamp_bits(im, l, r, y, samps, chans, count, bits) \ (((im)->i_f_gsamp_bits) ? ((im)->i_f_gsamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1) #define i_psamp_bits(im, l, r, y, samps, chans, count, bits) \ (((im)->i_f_psamp_bits) ? ((im)->i_f_psamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1) #define i_new_fill_solid(c, combine) ((im_extt->f_i_new_fill_solid)((c), (combine))) #define i_new_fill_solidf(c, combine) ((im_extt->f_i_new_fill_solidf)((c), (combine))) #define i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy) \ ((im_extt->f_i_new_fill_hatch)((fg), (bg), (combine), (hatch), (cust_hatch), (dx), (dy))) #define i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy) \ ((im_extt->f_i_new_fill_hatchf)((fg), (bg), (combine), (hatch), (cust_hatch), (dx), (dy))) #define i_new_fill_image(im, matrix, xoff, yoff, combine) \ ((im_extt->f_i_new_fill_image)((im), (matrix), (xoff), (yoff), (combine))) #define i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs) \ ((im_extt->f_i_new_fill_fount)((xa), (ya), (xb), (yb), (type), (repeat), (combine), (super_sample), (ssample_param), (count), (segs))) #define i_fill_destroy(fill) ((im_extt->f_i_fill_destroy)(fill)) #define i_quant_makemap(quant, imgs, count) \ ((im_extt->f_i_quant_makemap)((quant), (imgs), (count))) #define i_quant_translate(quant, img) \ ((im_extt->f_i_quant_translate)((quant), (img))) #define i_quant_transparent(quant, indices, img, trans_index) \ ((im_extt->f_i_quant_transparent)((quant), (indices), (img), (trans_index))) #define im_clear_error(ctx) ((im_extt->f_im_clear_error)(ctx)) #define im_push_error(ctx, code, msg) ((im_extt->f_im_push_error)((ctx), (code), (msg))) #define i_push_errorf (im_extt->f_i_push_errorf) #define im_push_errorvf(ctx, code, fmt, list) \ ((im_extt->f_im_push_errorvf)((ctx), (code), (fmt), (list))) #define i_tags_new(tags) ((im_extt->f_i_tags_new)(tags)) #define i_tags_set(tags, name, data, size) \ ((im_extt->f_i_tags_set)((tags), (name), (data), (size))) #define i_tags_setn(tags, name, idata) \ ((im_extt->f_i_tags_setn)((tags), (name), (idata))) #define i_tags_destroy(tags) ((im_extt->f_i_tags_destroy)(tags)) #define i_tags_find(tags, name, start, entry) \ ((im_extt->f_i_tags_find)((tags), (name), (start), (entry))) #define i_tags_findn(tags, code, start, entry) \ ((im_extt->f_i_tags_findn)((tags), (code), (start), (entry))) #define i_tags_delete(tags, entry) \ ((im_extt->f_i_tags_delete)((tags), (entry))) #define i_tags_delbyname(tags, name) \ ((im_extt->f_i_tags_delbyname)((tags), (name))) #define i_tags_delbycode(tags, code) \ ((im_extt->f_i_tags_delbycode)((tags), (code))) #define i_tags_get_float(tags, name, code, value) \ ((im_extt->f_i_tags_get_float)((tags), (name), (code), (value))) #define i_tags_set_float(tags, name, code, value) \ ((im_extt->f_i_tags_set_float)((tags), (name), (code), (value))) #define i_tags_set_float2(tags, name, code, value, places) \ ((im_extt->f_i_tags_set_float2)((tags), (name), (code), (value), (places))) #define i_tags_get_int(tags, name, code, value) \ ((im_extt->f_i_tags_get_int)((tags), (name), (code), (value))) #define i_tags_get_string(tags, name, code, value, value_size) \ ((im_extt->f_i_tags_get_string)((tags), (name), (code), (value), (value_size))) #define i_tags_get_color(tags, name, code, value) \ ((im_extt->f_i_tags_get_color)((tags), (name), (code), (value))) #define i_tags_set_color(tags, name, code, value) \ ((im_extt->f_i_tags_set_color)((tags), (name), (code), (value))) #define i_box(im, x1, y1, x2, y2, val) ((im_extt->f_i_box)((im), (x1), (y1), (x2), (y2), (val))) #define i_box_filled(im, x1, y1, x2, y2, val) ((im_extt->f_i_box_filled)((im), (x1), (y1), (x2), (y2), (val))) #define i_box_cfill(im, x1, y1, x2, y2, fill) ((im_extt->f_i_box_cfill)((im), (x1), (y1), (x2), (y2), (fill))) #define i_line(im, x1, y1, x2, y2, val, endp) ((im_extt->f_i_line)((im), (x1), (y1), (x2), (y2), (val), (endp))) #define i_line_aa(im, x1, y1, x2, y2, val, endp) ((im_extt->f_i_line_aa)((im), (x1), (y1), (x2), (y2), (val), (endp))) #define i_arc(im, x, y, rad, d1, d2, val) ((im_extt->f_i_arc)((im), (x), (y), (rad), (d1), (d2), (val))) #define i_arc_aa(im, x, y, rad, d1, d2, val) ((im_extt->f_i_arc_aa)((im), (x), (y), (rad), (d1), (d2), (val))) #define i_arc_cfill(im, x, y, rad, d1, d2, fill) ((im_extt->f_i_arc_cfill)((im), (x), (y), (rad), (d1), (d2), (fill))) #define i_arc_aa_cfill(im, x, y, rad, d1, d2, fill) ((im_extt->f_i_arc_aa_cfill)((im), (x), (y), (rad), (d1), (d2), (fill))) #define i_circle_aa(im, x, y, rad, val) ((im_extt->f_i_circle_aa)((im), (x), (y), (rad), (val))) #define i_flood_fill(im, seedx, seedy, dcol) ((im_extt->f_i_flood_fill)((im), (seedx), (seedy), (dcol))) #define i_flood_cfill(im, seedx, seedy, fill) ((im_extt->f_i_flood_cfill)((im), (seedx), (seedy), (fill))) #define i_flood_fill_border(im, seedx, seedy, dcol, border) ((im_extt->f_i_flood_fill_border)((im), (seedx), (seedy), (dcol), (border))) #define i_flood_cfill_border(im, seedx, seedy, fill, border) ((im_extt->f_i_flood_cfill_border)((im), (seedx), (seedy), (fill), (border))) #define i_poly_aa_m(im, count, x, y, mode, c) ((im_extt->f_i_poly_aa_m)((im), (count), (x), (y), (mode), (c))) #define i_poly_aa_cfill_m(im, count, x, y, mode, fill) ((im_extt->f_i_poly_aa_m)((im), (count), (x), (y), (mode), (fill))) #define i_poly_poly_aa(im, count, polys, mode, c) ((im_extt->f_i_poly_poly_aa)((im), (count), (polys), (mode), (c))) #define i_poly_poly_aa_cfill(im, count, polys, mode, fill) ((im_extt->f_i_poly_poly_aa_cfill)((im), (count), (polys), (mode), (fill))) #define i_copyto(im, src, x1, y1, x2, y2, tx, ty) \ ((im_extt->f_i_copyto)((im), (src), (x1), (y1), (x2), (y2), (tx), (ty))) #define i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans) \ ((im_extt->f_i_copyto_trans)((im), (src), (x1), (y1), (x2), (y2), (tx), (ty), (trans))) #define i_copy(im) ((im_extt->f_i_copy)(im)) #define i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy) \ ((im_extt->f_i_rubthru)((im), (src), (tx), (ty), (src_minx), (src_miny), (src_maxx), (src_maxy))) #define im_set_image_file_limits(ctx, max_width, max_height, max_bytes) \ ((im_extt->f_im_set_image_file_limits)((max_width), (max_height), (max_bytes))) #define im_get_image_file_limits(ctx, pmax_width, pmax_height, pmax_bytes) \ ((im_extt->f_im_get_image_file_limits)((ctx), (pmax_width), (pmax_height), (pmax_bytes))) #define im_int_check_image_file_limits(ctx, width, height, channels, sample_size) \ ((im_extt->f_im_int_check_image_file_limits)((ctx), (width), (height), (channels), (sample_size))) #define i_img_setmask(img, mask) ((im_extt->f_i_img_setmask)((img), (mask))) #define i_img_getmask(img) ((im_extt->f_i_img_getmask)(img)) #define i_img_getchannels(img) ((im_extt->f_i_img_getchannels)(img)) #define i_img_get_width(img) ((im_extt->f_i_img_get_width)(img)) #define i_img_get_height(img) ((im_extt->f_i_img_get_height)(img)) #define i_lhead(file, line) ((im_extt->f_i_lhead)((file), (line))) #define i_loog (im_extt->f_i_loog) #define im_lhead(ctx, file, line) ((im_extt->f_im_lhead)((ctx), (file), (line))) #define im_loog (im_extt->f_im_loog) #define im_img_alloc(ctx) ((im_extt->f_im_img_alloc)(ctx)) #define im_img_init(ctx, img) ((im_extt->fm_i_img_init)((ctx), (img))) #define i_img_is_monochrome(img, zero_is_white) ((im_extt->f_i_img_is_monochrome)((img), (zero_is_white))) #define i_gsamp_bg(im, l, r, y, samples, out_channels, bg) \ ((im_extt->f_i_gsamp_bg)((im), (l), (r), (y), (samples), (out_channels), (bg))) #define i_gsampf_bg(im, l, r, y, samples, out_channels, bg) \ ((im_extt->f_i_gsampf_bg)((im), (l), (r), (y), (samples), (out_channels), (bg))) #define i_get_file_background(im, bg) \ ((im_extt->f_i_get_file_background)((im), (bg))) #define i_get_file_backgroundf(im, bg) \ ((im_extt->f_i_get_file_backgroundf)((im), (bg))) #define i_utf8_advance(p, s) ((im_extt->f_i_utf8_advance)((p), (s))) #define i_render_new(im, width) ((im_extt->f_i_render_new)((im), (width))) #define i_render_delete(r) ((im_extt->f_i_render_delete)(r)) #define i_render_color(r, x, y, width, src, color) \ ((im_extt->f_i_render_color)((r), (x), (y), (width), (src), (color))) #define i_render_fill(r, x, y, width, src, fill) \ ((im_extt->f_i_render_fill)((r), (x), (y), (width), (src), (fill))) #define i_render_line(r, x, y, width, src, line, combine) \ ((im_extt->f_i_render_line)((r), (x), (y), (width), (src), (line), (combine))) #define i_render_linef(r, x, y, width, src, line, combine) \ ((im_extt->f_i_render_linef)((r), (x), (y), (width), (src), (line), (combine))) #define i_io_getc_imp (im_extt->f_i_io_getc_imp) #define i_io_peekc_imp (im_extt->f_i_io_peekc_imp) #define i_io_peekn (im_extt->f_i_io_peekn) #define i_io_putc_imp (im_extt->f_i_io_putc_imp) #define i_io_read (im_extt->f_i_io_read) #define i_io_write (im_extt->f_i_io_write) #define i_io_seek (im_extt->f_i_io_seek) #define i_io_flush (im_extt->f_i_io_flush) #define i_io_close (im_extt->f_i_io_close) #define i_io_set_buffered (im_extt->f_i_io_set_buffered) #define i_io_gets (im_extt->f_i_io_gets) #define im_io_new_fd(ctx, fd) ((im_extt->f_im_io_new_fd)(ctx, fd)) #define im_io_new_bufchain(ctx) ((im_extt->f_im_io_new_bufchain)(ctx)) #define im_io_new_buffer(ctx, data, len, closecb, closedata) \ ((im_extt->f_im_io_new_buffer)((ctx), (data), (len), (closecb), (closedata))) #define im_io_new_cb(ctx, p, readcb, writecb, seekcb, closecb, destroycb) \ ((im_extt->f_im_io_new_cb)((ctx), (p), (readcb), (writecb), (seekcb), (closecb), (destroycb))) #define io_slurp(ig, datap) ((im_extt->f_io_slurp)((ig), (datap))) #define io_glue_destroy(ig) ((im_extt->f_io_glue_destroy)(ig)) #define i_mutex_new() ((im_extt->f_i_mutex_new)()) #define i_mutex_destroy(m) ((im_extt->f_i_mutex_destroy)(m)) #define i_mutex_lock(m) ((im_extt->f_i_mutex_lock)(m)) #define i_mutex_unlock(m) ((im_extt->f_i_mutex_unlock)(m)) #define im_context_slot_new(destructor) ((im_extt->f_im_context_slot_new)(destructor)) #define im_context_slot_get(ctx, slot) ((im_extt->f_im_context_slot_get)((ctx), (slot))) #define im_context_slot_set(ctx, slot, value) ((im_extt->f_im_context_slot_set)((ctx), (slot), (value))) #define im_push_errorf (im_extt->f_im_push_errorf) #define i_img_alpha_channel(im, channel) ((im_extt->f_i_img_alpha_channel)((im), (channel))) #define i_img_color_model(im) ((im_extt->f_i_img_color_model)((im))) #define i_img_color_channels(im) ((im_extt->f_i_img_color_channels)((im))) #ifdef IMAGER_LOG #ifndef IMAGER_NO_CONTEXT #define mm_log(x) { i_lhead(__FILE__,__LINE__); i_loog x; } #endif #define im_log(x) { im_lhead(aIMCTX, __FILE__,__LINE__); im_loog x; } #else #define mm_log(x) #endif #endif libimager-perl-1.004+dfsg.orig/mutexwin.c0000644000175000017500000000235312263740601017611 0ustar gregoagregoa/* =head1 NAME mutex.c - Imager's mutex API. =head1 FUNCTIONS =over =cut */ #include "imageri.h" #include struct i_mutex_tag { CRITICAL_SECTION section; }; /* =item i_mutex_new() =category Mutex functions =synopsis i_mutex_t m = i_mutex_new(); =order 10 Create a mutex. If a critical section cannot be created for whatever reason, Imager will abort. =cut */ i_mutex_t i_mutex_new(void) { i_mutex_t m; m = malloc(sizeof(*m)); if (!m) i_fatal(3, "Cannot allocate mutex object"); InitializeCriticalSection(&(m->section)); return m; } /* =item i_mutex_destroy(m) =category Mutex functions =synopsis i_mutex_destroy(m); Destroy a mutex. =cut */ void i_mutex_destroy(i_mutex_t m) { DeleteCriticalSection(&(m->section)); free(m); } /* =item i_mutex_lock(m) =category Mutex functions =synopsis i_mutex_lock(m); Lock the mutex, waiting if another thread has the mutex locked. =cut */ void i_mutex_lock(i_mutex_t m) { EnterCriticalSection(&(m->section)); } /* =item i_mutex_unlock(m) =category Mutex functions =synopsis i_mutex_unlock(m); Release the mutex. The behavior of releasing a mutex you don't hold is unspecified. =cut */ void i_mutex_unlock(i_mutex_t m) { LeaveCriticalSection(&(m->section)); } libimager-perl-1.004+dfsg.orig/dynaload.c0000644000175000017500000001756112263740600017532 0ustar gregoagregoa#if defined(OS_hpux) #include typedef shl_t minthandle_t; #elif defined(WIN32) #define WIN32_LEAN_AND_MEAN #include typedef HMODULE minthandle_t; #undef WIN32_LEAN_AND_MEAN #else #include typedef void *minthandle_t; #endif #include "ext.h" struct DSO_handle_tag { minthandle_t handle; char *filename; func_ptr *function_list; }; #include "imager.h" #include "dynaload.h" /* #include "XSUB.h" so we can compile on threaded perls */ #include "imageri.h" static im_context_t do_get_context(void) { return im_get_context(); } static symbol_table_t symbol_table= { i_has_format, ICL_set_internal, ICL_info, do_get_context, im_img_empty_ch, i_img_exorcise, i_img_info, i_img_setmask, i_img_getmask, i_box, i_line, i_arc, i_copyto, i_copyto_trans, i_rubthru }; /* Dynamic loading works like this: dynaload opens the shared object and loads all the functions into an array of functions it returns a string from the dynamic function that can be supplied to the parser for evaling. */ void DSO_call(DSO_handle *handle,int func_index,HV* hv) { mm_log((1,"DSO_call(handle %p, func_index %d, hv %p)\n", handle, func_index, hv)); (handle->function_list[func_index].iptr)((void*)hv); } func_ptr * DSO_funclist(DSO_handle *handle) { return handle->function_list; } #if defined( OS_hpux ) void* DSO_open(char* file,char** evalstring) { shl_t tt_handle; void *d_handle,**plugin_symtab,**plugin_utiltab; int rc,*iptr, (*fptr)(int); func_ptr *function_list; DSO_handle *dso_handle; void (*f)(void *s,void *u); /* these will just have to be void for now */ int i; *evalstring=NULL; mm_log( (1,"DSO_open(file '%s' (0x%08X), evalstring 0x%08X)\n",file,file,evalstring) ); if ( (tt_handle = shl_load(file, BIND_DEFERRED,0L)) == NULL) return NULL; if ( (shl_findsym(&tt_handle, I_EVALSTR,TYPE_UNDEFINED,(void*)evalstring))) return NULL; /* if ( (shl_findsym(&tt_handle, "symbol_table",TYPE_UNDEFINED,(void*)&plugin_symtab))) return NULL; if ( (shl_findsym(&tt_handle, "util_table",TYPE_UNDEFINED,&plugin_utiltab))) return NULL; (*plugin_symtab)=&symbol_table; (*plugin_utiltab)=&i_UTIL_table; */ if ( (shl_findsym(&tt_handle, I_INSTALL_TABLES ,TYPE_UNDEFINED, &f ))) return NULL; mm_log( (1,"Calling install_tables\n") ); f(&symbol_table,&i_UTIL_table); mm_log( (1,"Call ok.\n") ); if ( (shl_findsym(&tt_handle, I_FUNCTION_LIST ,TYPE_UNDEFINED,(func_ptr*)&function_list))) return NULL; if ( (dso_handle=(DSO_handle*)malloc(sizeof(DSO_handle))) == NULL) /* checked 17jul05 tonyc */ return NULL; dso_handle->handle=tt_handle; /* needed to close again */ dso_handle->function_list=function_list; if ( (dso_handle->filename=(char*)malloc(strlen(file)+1)) == NULL) { /* checked 17jul05 tonyc */ free(dso_handle); return NULL; } strcpy(dso_handle->filename,file); mm_log((1,"DSO_open <- (0x%X)\n",dso_handle)); return (void*)dso_handle; } undef_int DSO_close(void *ptr) { DSO_handle *handle=(DSO_handle*) ptr; mm_log((1,"DSO_close(ptr 0x%X)\n",ptr)); return !shl_unload((handle->handle)); } #elif defined(WIN32) void * DSO_open(char *file, char **evalstring) { HMODULE d_handle; func_ptr *function_list; DSO_handle *dso_handle; void (*f)(void *s,void *u); /* these will just have to be void for now */ mm_log( (1,"DSO_open(file '%s' (%p), evalstring %p)\n",file,file,evalstring) ); *evalstring = NULL; if ((d_handle = LoadLibrary(file)) == NULL) { mm_log((1, "DSO_open: LoadLibrary(%s) failed: %lu\n", file, GetLastError())); return NULL; } if ( (*evalstring = (char *)GetProcAddress(d_handle, I_EVALSTR)) == NULL) { mm_log((1,"DSO_open: GetProcAddress didn't fine '%s': %lu\n", I_EVALSTR, GetLastError())); FreeLibrary(d_handle); return NULL; } if ((f = (void (*)(void *, void*))GetProcAddress(d_handle, I_INSTALL_TABLES)) == NULL) { mm_log((1, "DSO_open: GetProcAddress didn't find '%s': %lu\n", I_INSTALL_TABLES, GetLastError())); FreeLibrary(d_handle); return NULL; } mm_log((1, "Calling install tables\n")); f(&symbol_table, &i_UTIL_table); mm_log((1, "Call ok\n")); if ( (function_list = (func_ptr *)GetProcAddress(d_handle, I_FUNCTION_LIST)) == NULL) { mm_log((1, "DSO_open: GetProcAddress didn't find '%s': %lu\n", I_FUNCTION_LIST, GetLastError())); FreeLibrary(d_handle); return NULL; } if ( (dso_handle = (DSO_handle*)malloc(sizeof(DSO_handle))) == NULL) { /* checked 17jul05 tonyc */ mm_log( (1, "DSO_Open: out of memory\n") ); FreeLibrary(d_handle); return NULL; } dso_handle->handle=d_handle; /* needed to close again */ dso_handle->function_list=function_list; if ( (dso_handle->filename=(char*)malloc(strlen(file)+1)) == NULL) { /* checked 17jul05 tonyc */ free(dso_handle); FreeLibrary(d_handle); return NULL; } strcpy(dso_handle->filename,file); mm_log( (1,"DSO_open <- %p\n",dso_handle) ); return (void*)dso_handle; } undef_int DSO_close(void *ptr) { DSO_handle *handle = (DSO_handle *)ptr; BOOL result = FreeLibrary(handle->handle); free(handle->filename); free(handle); return result; } #else /* OS/2 has no dlclose; Perl doesn't provide one. */ #ifdef __EMX__ /* OS/2 */ int dlclose(minthandle_t h) { return DosFreeModule(h) ? -1 : 0; } #endif /* __EMX__ */ void* DSO_open(char* file,char** evalstring) { void *d_handle; func_ptr *function_list; DSO_handle *dso_handle; void (*f)(void *s,void *u); /* these will just have to be void for now */ *evalstring=NULL; mm_log( (1,"DSO_open(file '%s' (%p), evalstring %p)\n", file, file, evalstring) ); if ( (d_handle = dlopen(file, RTLD_LAZY)) == NULL) { mm_log( (1,"DSO_open: dlopen failed: %s.\n",dlerror()) ); return NULL; } if ( (*evalstring = (char *)dlsym(d_handle, I_EVALSTR)) == NULL) { mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_EVALSTR,dlerror()) ); return NULL; } /* I'll just leave this thing in here for now if I need it real soon mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_SYMBOL_TABLE )); if ( (plugin_symtab = dlsym(d_handle, I_SYMBOL_TABLE)) == NULL) { mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_SYMBOL_TABLE,dlerror()) ); return NULL; } mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_UTIL_TABLE )); if ( (plugin_utiltab = dlsym(d_handle, I_UTIL_TABLE)) == NULL) { mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_UTIL_TABLE,dlerror()) ); return NULL; } */ f = (void(*)(void *s,void *u))dlsym(d_handle, I_INSTALL_TABLES); mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_INSTALL_TABLES )); if ( (f = (void(*)(void *s,void *u))dlsym(d_handle, I_INSTALL_TABLES)) == NULL) { mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_INSTALL_TABLES,dlerror()) ); return NULL; } mm_log( (1,"Calling install_tables\n") ); f(&symbol_table,&i_UTIL_table); mm_log( (1,"Call ok.\n") ); /* (*plugin_symtab)=&symbol_table; (*plugin_utiltab)=&i_UTIL_table; */ mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_FUNCTION_LIST )); if ( (function_list=(func_ptr *)dlsym(d_handle, I_FUNCTION_LIST)) == NULL) { mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_FUNCTION_LIST,dlerror()) ); return NULL; } if ( (dso_handle=(DSO_handle*)malloc(sizeof(DSO_handle))) == NULL) /* checked 17jul05 tonyc */ return NULL; dso_handle->handle=d_handle; /* needed to close again */ dso_handle->function_list=function_list; if ( (dso_handle->filename=(char*)malloc(strlen(file)+1)) == NULL) { /* checked 17jul05 tonyc */ free(dso_handle); return NULL; } strcpy(dso_handle->filename,file); mm_log( (1,"DSO_open <- %p\n",dso_handle) ); return (void*)dso_handle; } undef_int DSO_close(void *ptr) { DSO_handle *handle; mm_log((1,"DSO_close(ptr %p)\n",ptr)); handle=(DSO_handle*) ptr; return !dlclose(handle->handle); } #endif libimager-perl-1.004+dfsg.orig/img16.c0000644000175000017500000005245112614520110016647 0ustar gregoagregoa/* =head1 NAME img16.c - implements 16-bit images =head1 SYNOPSIS i_img *im = i_img_16_new(i_img_dim x, i_img_dim y, int channels); # use like a normal image =head1 DESCRIPTION Implements 16-bit/sample images. This basic implementation is required so that we have some larger sample image type to work with. =over =cut */ #define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val); static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val); static i_img_dim i_glin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals); static i_img_dim i_plin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals); static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val); static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val); static i_img_dim i_glinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals); static i_img_dim i_plinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals); static i_img_dim i_gsamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int const *chans, int chan_count); static i_img_dim i_gsampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, int const *chans, int chan_count); static i_img_dim i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps, int const *chans, int chan_count, int bits); static i_img_dim i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned const *samps, int const *chans, int chan_count, int bits); static i_img_dim i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count); static i_img_dim i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count); /* =item IIM_base_16bit_direct Base structure used to initialize a 16-bit/sample image. Internal. =cut */ static i_img IIM_base_16bit_direct = { 0, /* channels set */ 0, 0, 0, /* xsize, ysize, bytes */ ~0U, /* ch_mask */ i_16_bits, /* bits */ i_direct_type, /* type */ 0, /* virtual */ NULL, /* idata */ { 0, 0, NULL }, /* tags */ NULL, /* ext_data */ i_ppix_d16, /* i_f_ppix */ i_ppixf_d16, /* i_f_ppixf */ i_plin_d16, /* i_f_plin */ i_plinf_d16, /* i_f_plinf */ i_gpix_d16, /* i_f_gpix */ i_gpixf_d16, /* i_f_gpixf */ i_glin_d16, /* i_f_glin */ i_glinf_d16, /* i_f_glinf */ i_gsamp_d16, /* i_f_gsamp */ i_gsampf_d16, /* i_f_gsampf */ NULL, /* i_f_gpal */ NULL, /* i_f_ppal */ NULL, /* i_f_addcolors */ NULL, /* i_f_getcolors */ NULL, /* i_f_colorcount */ NULL, /* i_f_maxcolors */ NULL, /* i_f_findcolor */ NULL, /* i_f_setcolors */ NULL, /* i_f_destroy */ i_gsamp_bits_d16, i_psamp_bits_d16, i_psamp_d16, i_psampf_d16 }; /* it's possible some platforms won't have a 16-bit integer type, so we check for one otherwise we work by bytes directly We do assume 8-bit char "Compaq C V6.4-009 on Compaq Tru64 UNIX V5.1A (Rev. 1885)" says it supports C99, but doesn't supply stdint.h, which is required for both hosted and freestanding implementations. So guard against it. */ #if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf) /* C99 should define something useful */ #include #ifdef UINT16_MAX typedef uint16_t i_sample16_t; #define GOT16 #endif #endif /* check out unsigned short */ #ifndef GOT16 #include #if USHRT_MAX == 65535 typedef unsigned short i_sample16_t; #define GOT16 #endif #endif #ifdef GOT16 /* we have a real 16-bit unsigned integer */ #define STORE16(bytes, offset, word) \ (((i_sample16_t *)(bytes))[offset] = (word)) #define STORE8as16(bytes, offset, byte) \ (((i_sample16_t *)(bytes))[offset] = (byte) * 256 + (byte)) #define GET16(bytes, offset) \ (((i_sample16_t *)(bytes))[offset]) #else /* we have to do this the hard way */ #define STORE16(bytes, offset, word) \ ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \ (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF)) #define STORE8as16(bytes, offset, byte) \ ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \ (((unsigned char *)(bytes))[(offset)*2+1] = (byte))) #define GET16(bytes, offset) \ (((unsigned char *)(bytes))[(offset)*2] * 256 \ + ((unsigned char *)(bytes))[(offset)*2+1]) #endif #define GET16as8(bytes, offset) \ ((((i_sample16_t *)(bytes))[offset]+127) / 257) /* =item im_img_16_new(ctx, x, y, ch) XX =category Image creation/destruction =synopsis i_img *img = im_img_16_new(aIMCTX, width, height, channels); =synopsis i_img *img = i_img_16_new(width, height, channels); Create a new 16-bit/sample image. Returns the image on success, or NULL on failure. Also callable as C =cut */ i_img * im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) { i_img *im; size_t bytes, line_bytes; im_log((aIMCTX, 1,"i_img_16_new(x %" i_DF ", y %" i_DF ", ch %d)\n", i_DFc(x), i_DFc(y), ch)); if (x < 1 || y < 1) { im_push_error(aIMCTX, 0, "Image sizes must be positive"); return NULL; } if (ch < 1 || ch > MAXCHANNELS) { im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS); return NULL; } bytes = x * y * ch * 2; if (bytes / y / ch / 2 != x) { im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation"); return NULL; } /* basic assumption: we can always allocate a buffer representing a line from the image, otherwise we're going to have trouble working with the image */ line_bytes = sizeof(i_fcolor) * x; if (line_bytes / x != sizeof(i_fcolor)) { im_push_error(aIMCTX, 0, "integer overflow calculating scanline allocation"); return NULL; } im = im_img_alloc(aIMCTX); *im = IIM_base_16bit_direct; i_tags_new(&im->tags); im->xsize = x; im->ysize = y; im->channels = ch; im->bytes = bytes; im->ext_data = NULL; im->idata = mymalloc(im->bytes); memset(im->idata, 0, im->bytes); im_img_init(aIMCTX, im); return im; } /* =item i_img_to_rgb16(im) =category Image creation Returns a 16-bit/sample version of the supplied image. Returns the image on success, or NULL on failure. =cut */ i_img * i_img_to_rgb16(i_img *im) { i_img *targ; i_fcolor *line; i_img_dim y; dIMCTXim(im); targ = im_img_16_new(aIMCTX, im->xsize, im->ysize, im->channels); if (!targ) return NULL; line = mymalloc(sizeof(i_fcolor) * im->xsize); for (y = 0; y < im->ysize; ++y) { i_glinf(im, 0, im->xsize, y, line); i_plinf(targ, 0, im->xsize, y, line); } myfree(line); return targ; } static int i_ppix_d16(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; if (I_ALL_CHANNELS_WRITABLE(im)) { for (ch = 0; ch < im->channels; ++ch) STORE8as16(im->idata, off+ch, val->channel[ch]); } else { for (ch = 0; ch < im->channels; ++ch) if (im->ch_mask & (1 << ch)) STORE8as16(im->idata, off+ch, val->channel[ch]); } return 0; } static int i_gpix_d16(i_img *im, i_img_dim x, i_img_dim y, i_color *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; for (ch = 0; ch < im->channels; ++ch) val->channel[ch] = GET16as8(im->idata, off+ch); return 0; } static int i_ppixf_d16(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; if (I_ALL_CHANNELS_WRITABLE(im)) { for (ch = 0; ch < im->channels; ++ch) STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch])); } else { for (ch = 0; ch < im->channels; ++ch) if (im->ch_mask & (1 << ch)) STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch])); } return 0; } static int i_gpixf_d16(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) { i_img_dim off; int ch; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; off = (x + y * im->xsize) * im->channels; for (ch = 0; ch < im->channels; ++ch) val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch)); return 0; } static i_img_dim i_glin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { vals[i].channel[ch] = GET16as8(im->idata, off); ++off; } } return count; } else { return 0; } } static i_img_dim i_plin_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; if (I_ALL_CHANNELS_WRITABLE(im)) { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { STORE8as16(im->idata, off, vals[i].channel[ch]); ++off; } } } else { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { if (im->ch_mask & (1 << ch)) STORE8as16(im->idata, off, vals[i].channel[ch]); ++off; } } } return count; } else { return 0; } } static i_img_dim i_glinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off)); ++off; } } return count; } else { return 0; } } static i_img_dim i_plinf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) { int ch; i_img_dim count, i; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; count = r - l; if (I_ALL_CHANNELS_WRITABLE(im)) { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch])); ++off; } } } else { for (i = 0; i < count; ++i) { for (ch = 0; ch < im->channels; ++ch) { if (im->ch_mask & (1 << ch)) STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch])); ++off; } } } return count; } else { return 0; } } static i_img_dim i_gsamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int const *chans, int chan_count) { int ch; i_img_dim count, i, w; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return 0; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = GET16as8(im->idata, off+chans[ch]); ++count; } off += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return 0; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = GET16as8(im->idata, off+ch); ++count; } off += im->channels; } } return count; } else { return 0; } } static i_img_dim i_gsampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps, int const *chans, int chan_count) { int ch; i_img_dim count, i, w; i_img_dim off; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return 0; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch])); ++count; } off += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return 0; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = Sample16ToF(GET16(im->idata, off+ch)); ++count; } off += im->channels; } } return count; } else { return 0; } } static i_img_dim i_gsamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps, int const *chans, int chan_count, int bits) { int ch; i_img_dim count, i, w; i_img_dim off; if (bits != 16) { return i_gsamp_bits_fb(im, l, r, y, samps, chans, chan_count, bits); } if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = GET16(im->idata, off+chans[ch]); ++count; } off += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); i_push_error(0, "Invalid channel count"); return -1; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = GET16(im->idata, off+ch); ++count; } off += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } static i_img_dim i_psamp_bits_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned const *samps, int const *chans, int chan_count, int bits) { int ch; i_img_dim count, i, w; i_img_dim off; if (bits != 16) { dIMCTXim(im); i_push_error(0, "Invalid bits for 16-bit image"); return -1; } if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; off = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << ch)) STORE16(im->idata, off+chans[ch], *samps); ++samps; ++count; } off += im->channels; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); i_push_error(0, "Invalid channel count"); return -1; } for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << ch)) STORE16(im->idata, off+ch, *samps); ++samps; ++count; } off += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =item i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, int *chans, int chan_count) Writes sample values to im for the horizontal line (l, y) to (r-1,y) for the channels specified by chans, an array of int with chan_count elements. Returns the number of samples written (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_psamp_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { i_img_dim offset; if (r > im->xsize) r = im->xsize; offset = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ /* and test if all channels specified are in the mask */ int all_in_mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } if (!((1 << chans[ch]) & im->ch_mask)) all_in_mask = 0; } if (all_in_mask) { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { STORE8as16(im->idata, offset + chans[ch], *samps); ++samps; ++count; } offset += im->channels; } } else { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << (chans[ch]))) STORE8as16(im->idata, offset + chans[ch], *samps); ++samps; ++count; } offset += im->channels; } } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } for (i = 0; i < w; ++i) { unsigned mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & mask) STORE8as16(im->idata, offset + ch, *samps); ++samps; ++count; mask <<= 1; } offset += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =item i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, int *chans, int chan_count) Writes sample values to im for the horizontal line (l, y) to (r-1,y) for the channels specified by chans, an array of int with chan_count elements. Returns the number of samples written (which should be (r-l) * bits_set(chan_mask) =cut */ static i_img_dim i_psampf_d16(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count) { int ch; i_img_dim count, i, w; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { i_img_dim offset; if (r > im->xsize) r = im->xsize; offset = (l+y*im->xsize) * im->channels; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ /* and test if all channels specified are in the mask */ int all_in_mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } if (!((1 << chans[ch]) & im->ch_mask)) all_in_mask = 0; } if (all_in_mask) { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { unsigned samp16 = SampleFTo16(*samps); STORE16(im->idata, offset + chans[ch], samp16); ++samps; ++count; } offset += im->channels; } } else { for (i = 0; i < w; ++i) { for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & (1 << (chans[ch]))) { unsigned samp16 = SampleFTo16(*samps); STORE16(im->idata, offset + chans[ch], samp16); } ++samps; ++count; } offset += im->channels; } } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } for (i = 0; i < w; ++i) { unsigned mask = 1; for (ch = 0; ch < chan_count; ++ch) { if (im->ch_mask & mask) { unsigned samp16 = SampleFTo16(*samps); STORE16(im->idata, offset + ch, samp16); } ++samps; ++count; mask <<= 1; } offset += im->channels; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/maskimg.c0000644000175000017500000004251212263740601017362 0ustar gregoagregoa/* =head1 NAME maskimg.c - implements masked images/image subsets =head1 SYNOPSIS =head1 DESCRIPTION =over =cut */ #define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" #include /* =item i_img_mask_ext A pointer to this type of object is kept in the ext_data of a masked image. =cut */ typedef struct { i_img *targ; i_img *mask; i_img_dim xbase, ybase; i_sample_t *samps; /* temp space */ } i_img_mask_ext; #define MASKEXT(im) ((i_img_mask_ext *)((im)->ext_data)) static void i_destroy_masked(i_img *im); static int i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix); static int i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix); static i_img_dim i_plin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals); static i_img_dim i_plinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals); static int i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix); static int i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix); static i_img_dim i_glin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals); static i_img_dim i_glinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals); static i_img_dim i_gsamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp, int const *chans, int chan_count); static i_img_dim i_gsampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, int const *chans, int chan_count); static i_img_dim i_gpal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals); static i_img_dim i_ppal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals); static i_img_dim psamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samples, const int *chans, int chan_count); static i_img_dim psampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samples, const int *chans, int chan_count); /* =item IIM_base_masked The basic data we copy into a masked image. =cut */ static i_img IIM_base_masked = { 0, /* channels set */ 0, 0, 0, /* xsize, ysize, bytes */ ~0U, /* ch_mask */ i_8_bits, /* bits */ i_palette_type, /* type */ 1, /* virtual */ NULL, /* idata */ { 0, 0, NULL }, /* tags */ NULL, /* ext_data */ i_ppix_masked, /* i_f_ppix */ i_ppixf_masked, /* i_f_ppixf */ i_plin_masked, /* i_f_plin */ i_plinf_masked, /* i_f_plinf */ i_gpix_masked, /* i_f_gpix */ i_gpixf_masked, /* i_f_gpixf */ i_glin_masked, /* i_f_glin */ i_glinf_masked, /* i_f_glinf */ i_gsamp_masked, /* i_f_gsamp */ i_gsampf_masked, /* i_f_gsampf */ i_gpal_masked, /* i_f_gpal */ i_ppal_masked, /* i_f_ppal */ i_addcolors_forward, /* i_f_addcolors */ i_getcolors_forward, /* i_f_getcolors */ i_colorcount_forward, /* i_f_colorcount */ i_maxcolors_forward, /* i_f_maxcolors */ i_findcolor_forward, /* i_f_findcolor */ i_setcolors_forward, /* i_f_setcolors */ i_destroy_masked, /* i_f_destroy */ NULL, /* i_f_gsamp_bits */ NULL, /* i_f_psamp_bits */ psamp_masked, /* i_f_psamp */ psampf_masked /* i_f_psampf */ }; /* =item i_img_masked_new(i_img *targ, i_img *mask, i_img_dim xbase, i_img_dim ybase, i_img_dim w, i_img_dim h) Create a new masked image. The image mask is optional, in which case the image is just a view of a rectangular portion of the image. The mask only has an effect of writing to the image, the entire view of the underlying image is readable. pixel access to mimg(x,y) is translated to targ(x+xbase, y+ybase), as long as (0 <= x < w) and (0 <= y < h). For a pixel to be writable, the pixel mask(x,y) must have non-zero in it's first channel. No scaling of the pixel is done, the channel sample is treated as boolean. =cut */ i_img * i_img_masked_new(i_img *targ, i_img *mask, i_img_dim x, i_img_dim y, i_img_dim w, i_img_dim h) { i_img *im; i_img_mask_ext *ext; dIMCTXim(targ); im_clear_error(aIMCTX); if (x >= targ->xsize || y >= targ->ysize) { im_push_error(aIMCTX, 0, "subset outside of target image"); return NULL; } if (mask) { if (w > mask->xsize) w = mask->xsize; if (h > mask->ysize) h = mask->ysize; } if (x+w > targ->xsize) w = targ->xsize - x; if (y+h > targ->ysize) h = targ->ysize - y; im = im_img_alloc(aIMCTX); memcpy(im, &IIM_base_masked, sizeof(i_img)); i_tags_new(&im->tags); im->xsize = w; im->ysize = h; im->channels = targ->channels; im->bits = targ->bits; im->type = targ->type; ext = mymalloc(sizeof(*ext)); ext->targ = targ; ext->mask = mask; ext->xbase = x; ext->ybase = y; ext->samps = mymalloc(sizeof(i_sample_t) * im->xsize); im->ext_data = ext; im_img_init(aIMCTX, im); return im; } /* =item i_destroy_masked(i_img *im) The destruction handler for masked images. Releases the ext_data. Internal function. =cut */ static void i_destroy_masked(i_img *im) { myfree(MASKEXT(im)->samps); myfree(im->ext_data); } /* =item i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix) Write a pixel to a masked image. Internal function. =cut */ static int i_ppix_masked(i_img *im, i_img_dim x, i_img_dim y, const i_color *pix) { i_img_mask_ext *ext = MASKEXT(im); int result; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; if (ext->mask) { i_sample_t samp; if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp) return 0; /* pretend it was good */ } result = i_ppix(ext->targ, x + ext->xbase, y + ext->ybase, pix); im->type = ext->targ->type; return result; } /* =item i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) Write a pixel to a masked image. Internal function. =cut */ static int i_ppixf_masked(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) { i_img_mask_ext *ext = MASKEXT(im); int result; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; if (ext->mask) { i_sample_t samp; if (i_gsamp(ext->mask, x, x+1, y, &samp, NULL, 1) && !samp) return 0; /* pretend it was good */ } result = i_ppixf(ext->targ, x + ext->xbase, y + ext->ybase, pix); im->type = ext->targ->type; return result; } /* =item i_plin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) Write a row of data to a masked image. Internal function. =cut */ static i_img_dim i_plin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; if (ext->mask) { i_img_dim i; int simple = 0; i_sample_t *samps = ext->samps; i_img_dim w = r - l; i_gsamp(ext->mask, l, r, y, samps, NULL, 1); if (w < 10) simple = 1; else { /* the idea is to make a fast scan to see how often the state changes */ i_img_dim changes = 0; for (i = 0; i < w-1; ++i) if (!samps[i] != !samps[i+1]) ++changes; if (changes > w/3) /* just rough */ simple = 1; } if (simple) { /* we'd be calling a usually more complicated i_plin function almost as often as the usually simple i_ppix(), so just do a simple scan */ for (i = 0; i < w; ++i) { if (samps[i]) i_ppix(ext->targ, l + i + ext->xbase, y + ext->ybase, vals + i); } im->type = ext->targ->type; return r-l; } else { /* the scan above indicates there should be some contiguous regions, look for them and render */ i_img_dim start; i = 0; while (i < w) { while (i < w && !samps[i]) ++i; start = i; while (i < w && samps[i]) ++i; if (i != start) i_plin(ext->targ, l + start + ext->xbase, l + i + ext->xbase, y + ext->ybase, vals + start); } im->type = ext->targ->type; return w; } } else { i_img_dim result = i_plin(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, vals); im->type = ext->targ->type; return result; } } else { return 0; } } /* =item i_plinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) Write a row of data to a masked image. Internal function. =cut */ static i_img_dim i_plinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; if (ext->mask) { i_img_dim i; int simple = 0; i_sample_t *samps = ext->samps; i_img_dim w = r - l; i_gsamp(ext->mask, l, r, y, samps, NULL, 1); if (w < 10) simple = 1; else { /* the idea is to make a fast scan to see how often the state changes */ i_img_dim changes = 0; for (i = 0; i < w-1; ++i) if (!samps[i] != !samps[i+1]) ++changes; if (changes > w/3) /* just rough */ simple = 1; } if (simple) { /* we'd be calling a usually more complicated i_plin function almost as often as the usually simple i_ppix(), so just do a simple scan */ for (i = 0; i < w; ++i) { if (samps[i]) i_ppixf(ext->targ, l + i + ext->xbase, y + ext->ybase, vals+i); } im->type = ext->targ->type; return r-l; } else { /* the scan above indicates there should be some contiguous regions, look for them and render */ i_img_dim start; i = 0; while (i < w) { while (i < w && !samps[i]) ++i; start = i; while (i < w && samps[i]) ++i; if (i != start) i_plinf(ext->targ, l + start + ext->xbase, l + i + ext->xbase, y + ext->ybase, vals + start); } im->type = ext->targ->type; return w; } } else { i_img_dim result = i_plinf(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, vals); im->type = ext->targ->type; return result; } } else { return 0; } } /* =item i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix) Read a pixel from a masked image. Internal. =cut */ static int i_gpix_masked(i_img *im, i_img_dim x, i_img_dim y, i_color *pix) { i_img_mask_ext *ext = MASKEXT(im); if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; return i_gpix(ext->targ, x + ext->xbase, y + ext->ybase, pix); } /* =item i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) Read a pixel from a masked image. Internal. =cut */ static int i_gpixf_masked(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) { i_img_mask_ext *ext = MASKEXT(im); if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; return i_gpixf(ext->targ, x + ext->xbase, y + ext->ybase, pix); } static i_img_dim i_glin_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; return i_glin(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, vals); } else { return 0; } } static i_img_dim i_glinf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; return i_glinf(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, vals); } else { return 0; } } static i_img_dim i_gsamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp, int const *chans, int chan_count) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; return i_gsamp(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, samp, chans, chan_count); } else { return 0; } } static i_img_dim i_gsampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, int const *chans, int chan_count) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; return i_gsampf(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, samp, chans, chan_count); } else { return 0; } } static i_img_dim i_gpal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; return i_gpal(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, vals); } else { return 0; } } static i_img_dim i_ppal_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; if (ext->mask) { i_img_dim i; i_sample_t *samps = ext->samps; i_img_dim w = r - l; i_img_dim start; i_gsamp(ext->mask, l, r, y, samps, NULL, 1); i = 0; while (i < w) { while (i < w && !samps[i]) ++i; start = i; while (i < w && samps[i]) ++i; if (i != start) i_ppal(ext->targ, l+start+ext->xbase, l+i+ext->xbase, y+ext->ybase, vals+start); } return w; } else { return i_ppal(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, vals); } } else { return 0; } } /* =item psamp_masked() i_psamp() implementation for masked images. =cut */ static i_img_dim psamp_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samples, const int *chans, int chan_count) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { unsigned old_ch_mask = ext->targ->ch_mask; i_img_dim result = 0; ext->targ->ch_mask = im->ch_mask; if (r > im->xsize) r = im->xsize; if (ext->mask) { i_img_dim w = r - l; i_img_dim i = 0; i_img_dim x = ext->xbase + l; i_img_dim work_y = y + ext->ybase; i_sample_t *mask_samps = ext->samps; i_gsamp(ext->mask, l, r, y, mask_samps, NULL, 1); /* not optimizing this yet */ while (i < w) { if (mask_samps[i]) { /* found a set mask value, try to do a run */ i_img_dim run_left = x; const i_sample_t *run_samps = samples; ++i; ++x; samples += chan_count; while (i < w && mask_samps[i]) { ++i; ++x; samples += chan_count; } result += i_psamp(ext->targ, run_left, x, work_y, run_samps, chans, chan_count); } else { ++i; ++x; samples += chan_count; result += chan_count; /* pretend we wrote masked off pixels */ } } } else { result = i_psamp(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, samples, chans, chan_count); im->type = ext->targ->type; } ext->targ->ch_mask = old_ch_mask; return result; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =item psampf_masked() i_psampf() implementation for masked images. =cut */ static i_img_dim psampf_masked(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samples, const int *chans, int chan_count) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { i_img_dim result = 0; unsigned old_ch_mask = ext->targ->ch_mask; ext->targ->ch_mask = im->ch_mask; if (r > im->xsize) r = im->xsize; if (ext->mask) { i_img_dim w = r - l; i_img_dim i = 0; i_img_dim x = ext->xbase + l; i_img_dim work_y = y + ext->ybase; i_sample_t *mask_samps = ext->samps; i_gsamp(ext->mask, l, r, y, mask_samps, NULL, 1); /* not optimizing this yet */ while (i < w) { if (mask_samps[i]) { /* found a set mask value, try to do a run */ i_img_dim run_left = x; const i_fsample_t *run_samps = samples; ++i; ++x; samples += chan_count; while (i < w && mask_samps[i]) { ++i; ++x; samples += chan_count; } result += i_psampf(ext->targ, run_left, x, work_y, run_samps, chans, chan_count); } else { ++i; ++x; samples += chan_count; result += chan_count; /* pretend we wrote masked off pixels */ } } } else { result = i_psampf(ext->targ, l + ext->xbase, r + ext->xbase, y + ext->ybase, samples, chans, chan_count); im->type = ext->targ->type; } ext->targ->ch_mask = old_ch_mask; return result; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/imageri.h0000644000175000017500000001117312614520110017342 0ustar gregoagregoa/* Declares utility functions useful across various files which aren't meant to be available externally */ #ifndef IMAGEI_H_ #define IMAGEI_H_ #include "imager.h" #include /* wrapper functions that implement the floating point sample version of a function in terms of the 8-bit sample version */ extern int i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix); extern int i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix); extern i_img_dim i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *pix); extern i_img_dim i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix); extern i_img_dim i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, int const *chans, int chan_count); /* wrapper functions that forward palette calls to the underlying image, assuming the underlying image is the first pointer in whatever ext_data points at */ extern int i_addcolors_forward(i_img *im, const i_color *, int count); extern int i_getcolors_forward(i_img *im, int i, i_color *, int count); extern int i_colorcount_forward(i_img *im); extern int i_maxcolors_forward(i_img *im); extern int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry); extern int i_setcolors_forward(i_img *im, int index, const i_color *colors, int count); /* fallback handler for gsamp_bits */ extern i_img_dim i_gsamp_bits_fb(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, unsigned *samp, const int *chans, int chan_count, int bits); #define SampleFTo16(num) ((int)((num) * 65535.0 + 0.5)) /* we add that little bit to avoid rounding issues */ #define Sample16ToF(num) ((num) / 65535.0) #define SampleFTo8(num) ((int)((num) * 255.0 + 0.5)) #define Sample8ToF(num) ((num) / 255.0) #define Sample16To8(num) (((num)+128) / 257) #define Sample8To16(num) ((num) * 257) extern void i_get_combine(int combine, i_fill_combine_f *, i_fill_combinef_f *); #define im_min(a, b) ((a) < (b) ? (a) : (b)) #define im_max(a, b) ((a) > (b) ? (a) : (b)) #include "ext.h" extern UTIL_table_t i_UTIL_table; /* test if all channels are writable */ #define I_ALL_CHANNELS_WRITABLE(im) (((im)->ch_mask & 0xF) == 0xf) typedef struct i_int_hline_seg_tag { i_img_dim minx, x_limit; } i_int_hline_seg; typedef struct i_int_hline_entry_tag { i_img_dim count; size_t alloc; i_int_hline_seg segs[1]; } i_int_hline_entry; /* represents a set of horizontal line segments to be filled in later */ typedef struct i_int_hlines_tag { i_img_dim start_y, limit_y; i_img_dim start_x, limit_x; i_int_hline_entry **entries; } i_int_hlines; extern void i_int_init_hlines( i_int_hlines *hlines, i_img_dim start_y, i_img_dim count_y, i_img_dim start_x, i_img_dim width_x ); extern void i_int_init_hlines_img(i_int_hlines *hlines, i_img *img); extern void i_int_hlines_add(i_int_hlines *hlines, i_img_dim y, i_img_dim minx, i_img_dim width); extern void i_int_hlines_destroy(i_int_hlines *hlines); extern void i_int_hlines_fill_color(i_img *im, i_int_hlines *hlines, const i_color *val); extern void i_int_hlines_fill_fill(i_img *im, i_int_hlines *hlines, i_fill_t *fill); #define I_LIMIT_8(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x)) #define I_LIMIT_DOUBLE(x) ((x) < 0.0 ? 0.0 : (x) > 1.0 ? 1.0 : (x)) #define IM_STRING(x) #x /* I considered using assert.h here, but perl does it's own thing with assert() and the NDEBUG test is opposite to the direction I prefer */ #ifdef IM_ASSERT extern void im_assert_fail(char const *, int, char const *); #define im_assert(x) ((x) ? (void)(0) : im_assert_fail(__FILE__, __LINE__, IM_STRING(x))) #else #define im_assert(x) (void)(0) #endif i_img_dim i_minx(i_img_dim a, i_img_dim b); i_img_dim i_maxx(i_img_dim x, i_img_dim y); i_img_dim i_abs(i_img_dim x); #define i_min(a, b) i_minx((a), (b)) #define i_max(a, b) i_maxx((a), (b)) #define color_to_grey(col) ((col)->rgb.r * 0.222 + (col)->rgb.g * 0.707 + (col)->rgb.b * 0.071) #define IM_ERROR_COUNT 20 typedef struct im_context_tag { int error_sp; size_t error_alloc[IM_ERROR_COUNT]; i_errmsg error_stack[IM_ERROR_COUNT]; #ifdef IMAGER_LOG /* the log file and level for this context */ FILE *lg_file; int log_level; /* whether we own the lg_file, false for stderr and for cloned contexts */ int own_log; /* values supplied by lhead */ const char *filename; int line; #endif /* file size limits */ i_img_dim max_width, max_height; size_t max_bytes; /* per context storage */ size_t slot_alloc; void **slots; ptrdiff_t refcount; } im_context_struct; #define DEF_BYTES_LIMIT 0x40000000 #endif libimager-perl-1.004+dfsg.orig/regops.perl0000644000175000017500000000566712370401737017766 0ustar gregoagregoa#!perl -w use strict; use Data::Dumper; my $in = shift or die "No input name"; my $out = shift or die "No output name"; open(IN, $in) or die "Cannot open input $in: $!"; open(OUT, "> $out") or die "Cannot create $out: $!"; binmode OUT; print OUT <<'EOS'; # AUTOMATICALLY GENERATED BY regops.perl package Imager::Regops; use strict; require Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK %Attr $MaxOperands $PackCode); @ISA = qw(Exporter); @EXPORT_OK = qw(%Attr $MaxOperands $PackCode); EOS my @ops; my %attr; my $opcode = 0; my $max_opr = 0; my $reg_pack; while () { if (/^\s*rbc_(\w+)/) { my $op = $1; push(@ops, uc "RBC_$op"); # each line has a comment with the registers used - find the maximum # I could probably do this as one line, but let's not my @parms = /\b([rp][a-z])\b/g; $max_opr = @parms if @parms > $max_opr; my $types = join("", map {substr($_,0,1)} @parms); my ($result) = /->\s*([rp])/; $attr{$op} = { parms=>scalar @parms, types=>$types, func=>/\w+\(/?1:0, opcode=>$opcode, result=>$result }; print OUT "use constant RBC_\U$op\E => $opcode;\n"; ++$opcode; } if (/^\#define RM_WORD_PACK \"(.)\"/) { $reg_pack = $1; } } print OUT "\n\@EXPORT = qw(@ops);\n\n"; # previously we used Data::Dumper, with Sortkeys() # to make sure the generated code only changed when the data # changed. Unfortunately Sortkeys isn't supported in some versions of # perl we try to support, so we now generate this manually print OUT "%Attr =\n (\n"; for my $opname (sort keys %attr) { my $op = $attr{$opname}; print OUT " '$opname' =>\n {\n"; for my $attrname (sort keys %$op) { my $attr = $op->{$attrname}; print OUT " '$attrname' => "; if (defined $attr) { if ($attr =~ /^\d+$/) { print OUT $attr; } else { print OUT "'$attr'"; } } else { print OUT "undef"; } print OUT ",\n"; } print OUT " },\n"; } print OUT " );\n"; print OUT "\$MaxOperands = $max_opr;\n"; print OUT qq/\$PackCode = "$reg_pack";\n/; print OUT <<'EOS'; 1; __END__ =head1 NAME Imager::Regops - generated information about the register based virtual machine =head1 SYNOPSIS use Imager::Regops; $Imager::Regops::Attr{$opname}->{opcode} # opcode for given operator $Imager::Regops::Attr{$opname}->{parms} # number of parameters $Imager::Regops::Attr{$opname}->{types} # types of parameters $Imager::Regops::Attr{$opname}->{func} # operator is a function $Imager::Regops::Attr{$opname}->{result} # r for numeric, p for pixel result $Imager::Regops::MaxOperands; # maximum number of operands =head1 DESCRIPTION This module is generated automatically from F so we don't need to maintain the same information in at least one extra place. At least that's the idea. =head1 AUTHOR Tony Cook, tony@develop-help.com =head1 SEE ALSO perl(1), Imager(3), http://imager.perl.org/ =cut EOS close(OUT) or die "Cannot close $out: $!"; close IN; libimager-perl-1.004+dfsg.orig/paste.im0000644000175000017500000002232312263740601017227 0ustar gregoagregoa#include "imager.h" #include "imageri.h" /* =item i_copyto(C, C, C, C, C, C, C, C) =category Image Copies image data from the area (C,C)-[C,C] in the source image to a rectangle the same size with it's top-left corner at (C,C) in the destination image. If C > C or C > C then the corresponding co-ordinates are swapped. =cut */ void i_copyto(i_img *im, i_img *src, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_img_dim tx, i_img_dim ty) { i_img_dim y, t, tty; if (x2= 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, p1(" i_DFp "), p2(" i_DFp "), t(" i_DFp "))\n", im, src, i_DFcp(x1, y1), i_DFcp(x2, y2), i_DFcp(tx, ty))); #code im->bits == i_8_bits IM_COLOR *row = mymalloc(sizeof(IM_COLOR) * (x2-x1)); tty = ty; for(y=y1; ychannels != im->channels) IM_ADAPT_COLORS(im->channels, src->channels, row, x2-x1); IM_PLIN(im, tx, tx+x2-x1, tty, row); tty++; } myfree(row); #/code } #code void #ifdef IM_EIGHT_BIT i_adapt_colors #else i_adapt_fcolors #endif (int out_channels, int in_channels, IM_COLOR *colors, size_t count) { if (out_channels == in_channels) return; if (count == 0) return; switch (out_channels) { case 1: { switch (in_channels) { case 2: /* apply alpha against a black background */ while (count) { colors->channel[0] = colors->channel[0] * colors->channel[1] / IM_SAMPLE_MAX; ++colors; --count; } return; case 3: /* convert to grey */ while (count) { colors->channel[0] = IM_ROUND(color_to_grey(colors)); ++colors; --count; } return; case 4: while (count) { colors->channel[0] = IM_ROUND(color_to_grey(colors) * colors->channel[3] / IM_SAMPLE_MAX); ++colors; --count; } return; default: i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); return; /* avoid warnings */ } } case 2: { switch (in_channels) { case 1: while (count) { colors->channel[1] = IM_SAMPLE_MAX; ++colors; --count; } return; case 3: while (count) { colors->channel[0] = IM_ROUND(color_to_grey(colors)); colors->channel[1] = IM_SAMPLE_MAX; ++colors; --count; } return; case 4: while (count) { colors->channel[0] = IM_ROUND(color_to_grey(colors)); colors->channel[1] = colors->channel[3]; ++colors; --count; } return; default: i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); return; /* avoid warnings */ } } case 3: { switch (in_channels) { case 1: while (count) { colors->channel[1] = colors->channel[2] = colors->channel[0]; ++colors; --count; } return; case 2: while (count) { int alpha = colors->channel[1]; colors->channel[0] = colors->channel[1] = colors->channel[2] = IM_ROUND(colors->channel[0] * alpha / IM_SAMPLE_MAX); ++colors; --count; } return; case 4: while (count) { int alpha = colors->channel[3]; colors->channel[0] = IM_ROUND(colors->channel[0] * alpha / IM_SAMPLE_MAX); colors->channel[1] = IM_ROUND(colors->channel[1] * alpha / IM_SAMPLE_MAX); colors->channel[2] = IM_ROUND(colors->channel[2] * alpha / IM_SAMPLE_MAX); ++colors; --count; } return; default: i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); return; /* avoid warnings */ } } case 4: { switch (in_channels) { case 1: while (count) { colors->channel[1] = colors->channel[2] = colors->channel[0]; colors->channel[3] = IM_SAMPLE_MAX; ++colors; --count; } return; case 2: while (count) { colors->channel[3] = colors->channel[1]; colors->channel[1] = colors->channel[2] = colors->channel[0]; ++colors; --count; } return; case 3: while (count) { colors->channel[3] = IM_SAMPLE_MAX; ++colors; --count; } return; default: i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); return; /* avoid warnings */ } } default: i_fatal(3, "i_adapt_colors: out_channels of %d invalid\n", out_channels); return; /* avoid warnings */ } } void #ifdef IM_EIGHT_BIT i_adapt_colors_bg #else i_adapt_fcolors_bg #endif (int out_channels, int in_channels, IM_COLOR *colors, size_t count, IM_COLOR const *bg) { if (out_channels == in_channels) return; if (count == 0) return; switch (out_channels) { case 2: case 4: IM_ADAPT_COLORS(out_channels, in_channels, colors, count); return; case 1: switch (in_channels) { case 3: IM_ADAPT_COLORS(out_channels, in_channels, colors, count); return; case 2: { /* apply alpha against our given background */ IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg)); while (count) { colors->channel[0] = (colors->channel[0] * colors->channel[1] + grey_bg * (IM_SAMPLE_MAX - colors->channel[1])) / IM_SAMPLE_MAX; ++colors; --count; } } break; case 4: { IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg)); while (count) { IM_WORK_T src_grey = IM_ROUND(color_to_grey(colors)); colors->channel[0] = (src_grey * colors->channel[3] + grey_bg * (IM_SAMPLE_MAX - colors->channel[3])) / IM_SAMPLE_MAX; ++colors; --count; } } break; } break; case 3: switch (in_channels) { case 1: IM_ADAPT_COLORS(out_channels, in_channels, colors, count); return; case 2: { while (count) { int ch; IM_WORK_T src_grey = colors->channel[0]; IM_WORK_T src_alpha = colors->channel[1]; for (ch = 0; ch < 3; ++ch) { colors->channel[ch] = (src_grey * src_alpha + bg->channel[ch] * (IM_SAMPLE_MAX - src_alpha)) / IM_SAMPLE_MAX; } ++colors; --count; } } break; case 4: { while (count) { int ch; IM_WORK_T src_alpha = colors->channel[3]; for (ch = 0; ch < 3; ++ch) { colors->channel[ch] = (colors->channel[ch] * src_alpha + bg->channel[ch] * (IM_SAMPLE_MAX - src_alpha)) / IM_SAMPLE_MAX; } ++colors; --count; } } break; } break; } } /* =item i_gsamp_bg(im, l, r, y, samples, out_channels, background) =category Drawing Like C but applies the source image color over a supplied background color. This is intended for output to image formats that don't support alpha channels. =cut =item i_gsampf_bg(im, l, r, y, samples, out_channels, background) =category Drawing Like C but applies the source image color over a supplied background color. This is intended for output to image formats that don't support alpha channels. =cut */ int #ifdef IM_EIGHT_BIT i_gsamp_bg #else i_gsampf_bg #endif (i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, IM_SAMPLE_T *samples, int out_channels, IM_COLOR const *bg) { if (out_channels == im->channels) return IM_GSAMP(im, l, r, y, samples, NULL, im->channels); switch (out_channels) { case 1: switch (im->channels) { case 2: { i_img_dim x; IM_SAMPLE_T *inp = samples, *outp = samples; IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg)); i_img_dim count; count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels); if (!count) return 0; for (x = l; x < r; ++x) { *outp++ = ( inp[0] * inp[1] + grey_bg * (IM_SAMPLE_MAX - inp[1])) / IM_SAMPLE_MAX; inp += 2; } return count; } break; default: i_fatal(0, "i_gsamp_bg() can only remove alpha channels"); break; } break; case 3: switch (im->channels) { case 1: { int channels[3] = { 0, 0, 0 }; return IM_GSAMP(im, l, r, y, samples, channels, out_channels); } case 2: { i_img_dim x; int ch; IM_SAMPLE_T *inp = samples, *outp = samples; i_img_dim count; int channels[4] = { 0, 0, 0, 1 }; count = IM_GSAMP(im, l, r, y, samples, channels, im->channels); if (!count) return 0; for (x = l; x < r; ++x) { IM_WORK_T alpha = inp[3]; for (ch = 0; ch < 3; ++ch) { *outp++ = ( *inp++ * alpha + bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX; } ++inp; } return count; } case 4: { i_img_dim x; int ch; IM_SAMPLE_T *inp = samples, *outp = samples; i_img_dim count; count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels); if (!count) return 0; for (x = l; x < r; ++x) { IM_WORK_T alpha = inp[3]; for (ch = 0; ch < 3; ++ch) { *outp++ = ( *inp++ * alpha + bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX; } ++inp; } return count; } break; default: i_fatal(0, "i_gsamp_bg() can only remove alpha channels"); break; } break; default: i_fatal(0, "i_gsamp_bg() can only remove alpha channels"); } return 0; } #/code libimager-perl-1.004+dfsg.orig/ppport.h0000644000175000017500000055600212370401737017272 0ustar gregoagregoa#if 0 <<'SKIP'; #endif /* ---------------------------------------------------------------------- ppport.h -- Perl/Pollution/Portability Version 3.21 Automatically created by Devel::PPPort running under perl 5.020000. Do NOT edit this file directly! -- Edit PPPort_pm.PL and the includes in parts/inc/ instead. Use 'perldoc ppport.h' to view the documentation below. ---------------------------------------------------------------------- SKIP =pod =head1 NAME ppport.h - Perl/Pollution/Portability version 3.21 =head1 SYNOPSIS perl ppport.h [options] [source files] Searches current directory for files if no [source files] are given --help show short help --version show version --patch=file write one patch file with changes --copy=suffix write changed copies with suffix --diff=program use diff program and options --compat-version=version provide compatibility with Perl version --cplusplus accept C++ comments --quiet don't output anything except fatal errors --nodiag don't show diagnostics --nohints don't show hints --nochanges don't suggest changes --nofilter don't filter input files --strip strip all script and doc functionality from ppport.h --list-provided list provided API --list-unsupported list unsupported API --api-info=name show Perl API portability information =head1 COMPATIBILITY This version of F is designed to support operation with Perl installations back to 5.003, and has been tested up to 5.11.5. =head1 OPTIONS =head2 --help Display a brief usage summary. =head2 --version Display the version of F. =head2 --patch=I If this option is given, a single patch file will be created if any changes are suggested. This requires a working diff program to be installed on your system. =head2 --copy=I If this option is given, a copy of each file will be saved with the given suffix that contains the suggested changes. This does not require any external programs. Note that this does not automagially add a dot between the original filename and the suffix. If you want the dot, you have to include it in the option argument. If neither C<--patch> or C<--copy> are given, the default is to simply print the diffs for each file. This requires either C or a C program to be installed. =head2 --diff=I Manually set the diff program and options to use. The default is to use C, when installed, and output unified context diffs. =head2 --compat-version=I Tell F to check for compatibility with the given Perl version. The default is to check for compatibility with Perl version 5.003. You can use this option to reduce the output of F if you intend to be backward compatible only down to a certain Perl version. =head2 --cplusplus Usually, F will detect C++ style comments and replace them with C style comments for portability reasons. Using this option instructs F to leave C++ comments untouched. =head2 --quiet Be quiet. Don't print anything except fatal errors. =head2 --nodiag Don't output any diagnostic messages. Only portability alerts will be printed. =head2 --nohints Don't output any hints. Hints often contain useful portability notes. Warnings will still be displayed. =head2 --nochanges Don't suggest any changes. Only give diagnostic output and hints unless these are also deactivated. =head2 --nofilter Don't filter the list of input files. By default, files not looking like source code (i.e. not *.xs, *.c, *.cc, *.cpp or *.h) are skipped. =head2 --strip Strip all script and documentation functionality from F. This reduces the size of F dramatically and may be useful if you want to include F in smaller modules without increasing their distribution size too much. The stripped F will have a C<--unstrip> option that allows you to undo the stripping, but only if an appropriate C module is installed. =head2 --list-provided Lists the API elements for which compatibility is provided by F. Also lists if it must be explicitly requested, if it has dependencies, and if there are hints or warnings for it. =head2 --list-unsupported Lists the API elements that are known not to be supported by F and below which version of Perl they probably won't be available or work. =head2 --api-info=I Show portability information for API elements matching I. If I is surrounded by slashes, it is interpreted as a regular expression. =head1 DESCRIPTION In order for a Perl extension (XS) module to be as portable as possible across differing versions of Perl itself, certain steps need to be taken. =over 4 =item * Including this header is the first major one. This alone will give you access to a large part of the Perl API that hasn't been available in earlier Perl releases. Use perl ppport.h --list-provided to see which API elements are provided by ppport.h. =item * You should avoid using deprecated parts of the API. For example, using global Perl variables without the C prefix is deprecated. Also, some API functions used to have a C prefix. Using this form is also deprecated. You can safely use the supported API, as F will provide wrappers for older Perl versions. =item * If you use one of a few functions or variables that were not present in earlier versions of Perl, and that can't be provided using a macro, you have to explicitly request support for these functions by adding one or more C<#define>s in your source code before the inclusion of F. These functions or variables will be marked C in the list shown by C<--list-provided>. Depending on whether you module has a single or multiple files that use such functions or variables, you want either C or global variants. For a C function or variable (used only in a single source file), use: #define NEED_function #define NEED_variable For a global function or variable (used in multiple source files), use: #define NEED_function_GLOBAL #define NEED_variable_GLOBAL Note that you mustn't have more than one global request for the same function or variable in your project. Function / Variable Static Request Global Request ----------------------------------------------------------------------------------------- PL_parser NEED_PL_parser NEED_PL_parser_GLOBAL PL_signals NEED_PL_signals NEED_PL_signals_GLOBAL eval_pv() NEED_eval_pv NEED_eval_pv_GLOBAL grok_bin() NEED_grok_bin NEED_grok_bin_GLOBAL grok_hex() NEED_grok_hex NEED_grok_hex_GLOBAL grok_number() NEED_grok_number NEED_grok_number_GLOBAL grok_numeric_radix() NEED_grok_numeric_radix NEED_grok_numeric_radix_GLOBAL grok_oct() NEED_grok_oct NEED_grok_oct_GLOBAL load_module() NEED_load_module NEED_load_module_GLOBAL my_snprintf() NEED_my_snprintf NEED_my_snprintf_GLOBAL my_sprintf() NEED_my_sprintf NEED_my_sprintf_GLOBAL my_strlcat() NEED_my_strlcat NEED_my_strlcat_GLOBAL my_strlcpy() NEED_my_strlcpy NEED_my_strlcpy_GLOBAL newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL newRV_noinc() NEED_newRV_noinc NEED_newRV_noinc_GLOBAL newSV_type() NEED_newSV_type NEED_newSV_type_GLOBAL newSVpvn_flags() NEED_newSVpvn_flags NEED_newSVpvn_flags_GLOBAL newSVpvn_share() NEED_newSVpvn_share NEED_newSVpvn_share_GLOBAL pv_display() NEED_pv_display NEED_pv_display_GLOBAL pv_escape() NEED_pv_escape NEED_pv_escape_GLOBAL pv_pretty() NEED_pv_pretty NEED_pv_pretty_GLOBAL sv_2pv_flags() NEED_sv_2pv_flags NEED_sv_2pv_flags_GLOBAL sv_2pvbyte() NEED_sv_2pvbyte NEED_sv_2pvbyte_GLOBAL sv_catpvf_mg() NEED_sv_catpvf_mg NEED_sv_catpvf_mg_GLOBAL sv_catpvf_mg_nocontext() NEED_sv_catpvf_mg_nocontext NEED_sv_catpvf_mg_nocontext_GLOBAL sv_pvn_force_flags() NEED_sv_pvn_force_flags NEED_sv_pvn_force_flags_GLOBAL sv_setpvf_mg() NEED_sv_setpvf_mg NEED_sv_setpvf_mg_GLOBAL sv_setpvf_mg_nocontext() NEED_sv_setpvf_mg_nocontext NEED_sv_setpvf_mg_nocontext_GLOBAL vload_module() NEED_vload_module NEED_vload_module_GLOBAL vnewSVpvf() NEED_vnewSVpvf NEED_vnewSVpvf_GLOBAL warner() NEED_warner NEED_warner_GLOBAL To avoid namespace conflicts, you can change the namespace of the explicitly exported functions / variables using the C macro. Just C<#define> the macro before including C: #define DPPP_NAMESPACE MyOwnNamespace_ #include "ppport.h" The default namespace is C. =back The good thing is that most of the above can be checked by running F on your source code. See the next section for details. =head1 EXAMPLES To verify whether F is needed for your module, whether you should make any changes to your code, and whether any special defines should be used, F can be run as a Perl script to check your source code. Simply say: perl ppport.h The result will usually be a list of patches suggesting changes that should at least be acceptable, if not necessarily the most efficient solution, or a fix for all possible problems. If you know that your XS module uses features only available in newer Perl releases, if you're aware that it uses C++ comments, and if you want all suggestions as a single patch file, you could use something like this: perl ppport.h --compat-version=5.6.0 --cplusplus --patch=test.diff If you only want your code to be scanned without any suggestions for changes, use: perl ppport.h --nochanges You can specify a different C program or options, using the C<--diff> option: perl ppport.h --diff='diff -C 10' This would output context diffs with 10 lines of context. If you want to create patched copies of your files instead, use: perl ppport.h --copy=.new To display portability information for the C function, use: perl ppport.h --api-info=newSVpvn Since the argument to C<--api-info> can be a regular expression, you can use perl ppport.h --api-info=/_nomg$/ to display portability information for all C<_nomg> functions or perl ppport.h --api-info=/./ to display information for all known API elements. =head1 BUGS If this version of F is causing failure during the compilation of this module, please check if newer versions of either this module or C are available on CPAN before sending a bug report. If F was generated using the latest version of C and is causing failure of this module, please file a bug report using the CPAN Request Tracker at L. Please include the following information: =over 4 =item 1. The complete output from running "perl -V" =item 2. This file. =item 3. The name and version of the module you were trying to build. =item 4. A full log of the build that failed. =item 5. Any other information that you think could be relevant. =back For the latest version of this code, please get the C module from CPAN. =head1 COPYRIGHT Version 3.x, Copyright (c) 2004-2013, Marcus Holland-Moritz. Version 2.x, Copyright (C) 2001, Paul Marquess. Version 1.x, Copyright (C) 1999, Kenneth Albanowski. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO See L. =cut use strict; # Disable broken TRIE-optimization BEGIN { eval '${^RE_TRIE_MAXBUF} = -1' if $] >= 5.009004 && $] <= 5.009005 } my $VERSION = 3.21; my %opt = ( quiet => 0, diag => 1, hints => 1, changes => 1, cplusplus => 0, filter => 1, strip => 0, version => 0, ); my($ppport) = $0 =~ /([\w.]+)$/; my $LF = '(?:\r\n|[\r\n])'; # line feed my $HS = "[ \t]"; # horizontal whitespace # Never use C comments in this file! my $ccs = '/'.'*'; my $cce = '*'.'/'; my $rccs = quotemeta $ccs; my $rcce = quotemeta $cce; eval { require Getopt::Long; Getopt::Long::GetOptions(\%opt, qw( help quiet diag! filter! hints! changes! cplusplus strip version patch=s copy=s diff=s compat-version=s list-provided list-unsupported api-info=s )) or usage(); }; if ($@ and grep /^-/, @ARGV) { usage() if "@ARGV" =~ /^--?h(?:elp)?$/; die "Getopt::Long not found. Please don't use any options.\n"; } if ($opt{version}) { print "This is $0 $VERSION.\n"; exit 0; } usage() if $opt{help}; strip() if $opt{strip}; if (exists $opt{'compat-version'}) { my($r,$v,$s) = eval { parse_version($opt{'compat-version'}) }; if ($@) { die "Invalid version number format: '$opt{'compat-version'}'\n"; } die "Only Perl 5 is supported\n" if $r != 5; die "Invalid version number: $opt{'compat-version'}\n" if $v >= 1000 || $s >= 1000; $opt{'compat-version'} = sprintf "%d.%03d%03d", $r, $v, $s; } else { $opt{'compat-version'} = 5; } my %API = map { /^(\w+)\|([^|]*)\|([^|]*)\|(\w*)$/ ? ( $1 => { ($2 ? ( base => $2 ) : ()), ($3 ? ( todo => $3 ) : ()), (index($4, 'v') >= 0 ? ( varargs => 1 ) : ()), (index($4, 'p') >= 0 ? ( provided => 1 ) : ()), (index($4, 'n') >= 0 ? ( nothxarg => 1 ) : ()), } ) : die "invalid spec: $_" } qw( AvFILLp|5.004050||p AvFILL||| BhkDISABLE||5.019003| BhkENABLE||5.019003| BhkENTRY_set||5.019003| BhkENTRY||| BhkFLAGS||| CALL_BLOCK_HOOKS||| CLASS|||n CPERLscope|5.005000||p CX_CURPAD_SAVE||| CX_CURPAD_SV||| CopFILEAV|5.006000||p CopFILEGV_set|5.006000||p CopFILEGV|5.006000||p CopFILESV|5.006000||p CopFILE_set|5.006000||p CopFILE|5.006000||p CopSTASHPV_set|5.006000||p CopSTASHPV|5.006000||p CopSTASH_eq|5.006000||p CopSTASH_set|5.006000||p CopSTASH|5.006000||p CopyD|5.009002|5.004050|p Copy||5.004050| CvPADLIST||5.008001| CvSTASH||| CvWEAKOUTSIDE||| DEFSV_set|5.010001||p DEFSV|5.004050||p END_EXTERN_C|5.005000||p ENTER||| ERRSV|5.004050||p EXTEND||| EXTERN_C|5.005000||p F0convert|||n FREETMPS||| GIMME_V||5.004000|n GIMME|||n GROK_NUMERIC_RADIX|5.007002||p G_ARRAY||| G_DISCARD||| G_EVAL||| G_METHOD|5.006001||p G_NOARGS||| G_SCALAR||| G_VOID||5.004000| GetVars||| GvAV||| GvCV||| GvHV||| GvSVn|5.009003||p GvSV||| Gv_AMupdate||5.011000| HEf_SVKEY||5.004000| HeHASH||5.004000| HeKEY||5.004000| HeKLEN||5.004000| HePV||5.004000| HeSVKEY_force||5.004000| HeSVKEY_set||5.004000| HeSVKEY||5.004000| HeUTF8||5.010001| HeVAL||5.004000| HvENAMELEN||5.015004| HvENAMEUTF8||5.015004| HvENAME||5.013007| HvNAMELEN_get|5.009003||p HvNAMELEN||5.015004| HvNAMEUTF8||5.015004| HvNAME_get|5.009003||p HvNAME||| INT2PTR|5.006000||p IN_LOCALE_COMPILETIME|5.007002||p IN_LOCALE_RUNTIME|5.007002||p IN_LOCALE|5.007002||p IN_PERL_COMPILETIME|5.008001||p IS_NUMBER_GREATER_THAN_UV_MAX|5.007002||p IS_NUMBER_INFINITY|5.007002||p IS_NUMBER_IN_UV|5.007002||p IS_NUMBER_NAN|5.007003||p IS_NUMBER_NEG|5.007002||p IS_NUMBER_NOT_INT|5.007002||p IVSIZE|5.006000||p IVTYPE|5.006000||p IVdf|5.006000||p LEAVE||| LINKLIST||5.013006| LVRET||| MARK||| MULTICALL||5.019003| MY_CXT_CLONE|5.009002||p MY_CXT_INIT|5.007003||p MY_CXT|5.007003||p MoveD|5.009002|5.004050|p Move||5.004050| NOOP|5.005000||p NUM2PTR|5.006000||p NVTYPE|5.006000||p NVef|5.006001||p NVff|5.006001||p NVgf|5.006001||p Newxc|5.009003||p Newxz|5.009003||p Newx|5.009003||p Nullav||| Nullch||| Nullcv||| Nullhv||| Nullsv||| OP_CLASS||5.013007| OP_DESC||5.007003| OP_NAME||5.007003| ORIGMARK||| PAD_BASE_SV||| PAD_CLONE_VARS||| PAD_COMPNAME_FLAGS||| PAD_COMPNAME_GEN_set||| PAD_COMPNAME_GEN||| PAD_COMPNAME_OURSTASH||| PAD_COMPNAME_PV||| PAD_COMPNAME_TYPE||| PAD_RESTORE_LOCAL||| PAD_SAVE_LOCAL||| PAD_SAVE_SETNULLPAD||| PAD_SETSV||| PAD_SET_CUR_NOSAVE||| PAD_SET_CUR||| PAD_SVl||| PAD_SV||| PERLIO_FUNCS_CAST|5.009003||p PERLIO_FUNCS_DECL|5.009003||p PERL_ABS|5.008001||p PERL_BCDVERSION|5.019002||p PERL_GCC_BRACE_GROUPS_FORBIDDEN|5.008001||p PERL_HASH|5.004000||p PERL_INT_MAX|5.004000||p PERL_INT_MIN|5.004000||p PERL_LONG_MAX|5.004000||p PERL_LONG_MIN|5.004000||p PERL_MAGIC_arylen|5.007002||p PERL_MAGIC_backref|5.007002||p PERL_MAGIC_bm|5.007002||p PERL_MAGIC_collxfrm|5.007002||p PERL_MAGIC_dbfile|5.007002||p PERL_MAGIC_dbline|5.007002||p PERL_MAGIC_defelem|5.007002||p PERL_MAGIC_envelem|5.007002||p PERL_MAGIC_env|5.007002||p PERL_MAGIC_ext|5.007002||p PERL_MAGIC_fm|5.007002||p PERL_MAGIC_glob|5.019002||p PERL_MAGIC_isaelem|5.007002||p PERL_MAGIC_isa|5.007002||p PERL_MAGIC_mutex|5.019002||p PERL_MAGIC_nkeys|5.007002||p PERL_MAGIC_overload_elem|5.019002||p PERL_MAGIC_overload_table|5.007002||p PERL_MAGIC_overload|5.019002||p PERL_MAGIC_pos|5.007002||p PERL_MAGIC_qr|5.007002||p PERL_MAGIC_regdata|5.007002||p PERL_MAGIC_regdatum|5.007002||p PERL_MAGIC_regex_global|5.007002||p PERL_MAGIC_shared_scalar|5.007003||p PERL_MAGIC_shared|5.007003||p PERL_MAGIC_sigelem|5.007002||p PERL_MAGIC_sig|5.007002||p PERL_MAGIC_substr|5.007002||p PERL_MAGIC_sv|5.007002||p PERL_MAGIC_taint|5.007002||p PERL_MAGIC_tiedelem|5.007002||p PERL_MAGIC_tiedscalar|5.007002||p PERL_MAGIC_tied|5.007002||p PERL_MAGIC_utf8|5.008001||p PERL_MAGIC_uvar_elem|5.007003||p PERL_MAGIC_uvar|5.007002||p PERL_MAGIC_vec|5.007002||p PERL_MAGIC_vstring|5.008001||p PERL_PV_ESCAPE_ALL|5.009004||p PERL_PV_ESCAPE_FIRSTCHAR|5.009004||p PERL_PV_ESCAPE_NOBACKSLASH|5.009004||p PERL_PV_ESCAPE_NOCLEAR|5.009004||p PERL_PV_ESCAPE_QUOTE|5.009004||p PERL_PV_ESCAPE_RE|5.009005||p PERL_PV_ESCAPE_UNI_DETECT|5.009004||p PERL_PV_ESCAPE_UNI|5.009004||p PERL_PV_PRETTY_DUMP|5.009004||p PERL_PV_PRETTY_ELLIPSES|5.010000||p PERL_PV_PRETTY_LTGT|5.009004||p PERL_PV_PRETTY_NOCLEAR|5.010000||p PERL_PV_PRETTY_QUOTE|5.009004||p PERL_PV_PRETTY_REGPROP|5.009004||p PERL_QUAD_MAX|5.004000||p PERL_QUAD_MIN|5.004000||p PERL_REVISION|5.006000||p PERL_SCAN_ALLOW_UNDERSCORES|5.007003||p PERL_SCAN_DISALLOW_PREFIX|5.007003||p PERL_SCAN_GREATER_THAN_UV_MAX|5.007003||p PERL_SCAN_SILENT_ILLDIGIT|5.008001||p PERL_SHORT_MAX|5.004000||p PERL_SHORT_MIN|5.004000||p PERL_SIGNALS_UNSAFE_FLAG|5.008001||p PERL_SUBVERSION|5.006000||p PERL_SYS_INIT3||5.010000| PERL_SYS_INIT||5.010000| PERL_SYS_TERM||5.019003| PERL_UCHAR_MAX|5.004000||p PERL_UCHAR_MIN|5.004000||p PERL_UINT_MAX|5.004000||p PERL_UINT_MIN|5.004000||p PERL_ULONG_MAX|5.004000||p PERL_ULONG_MIN|5.004000||p PERL_UNUSED_ARG|5.009003||p PERL_UNUSED_CONTEXT|5.009004||p PERL_UNUSED_DECL|5.007002||p PERL_UNUSED_VAR|5.007002||p PERL_UQUAD_MAX|5.004000||p PERL_UQUAD_MIN|5.004000||p PERL_USE_GCC_BRACE_GROUPS|5.009004||p PERL_USHORT_MAX|5.004000||p PERL_USHORT_MIN|5.004000||p PERL_VERSION|5.006000||p PL_DBsignal|5.005000||p PL_DBsingle|||pn PL_DBsub|||pn PL_DBtrace|||pn PL_Sv|5.005000||p PL_bufend|5.019002||p PL_bufptr|5.019002||p PL_check||5.006000| PL_compiling|5.004050||p PL_comppad_name||5.017004| PL_comppad||5.008001| PL_copline|5.019002||p PL_curcop|5.004050||p PL_curpad||5.005000| PL_curstash|5.004050||p PL_debstash|5.004050||p PL_defgv|5.004050||p PL_diehook|5.004050||p PL_dirty|5.004050||p PL_dowarn|||pn PL_errgv|5.004050||p PL_error_count|5.019002||p PL_expect|5.019002||p PL_hexdigit|5.005000||p PL_hints|5.005000||p PL_in_my_stash|5.019002||p PL_in_my|5.019002||p PL_keyword_plugin||5.011002| PL_last_in_gv|||n PL_laststatval|5.005000||p PL_lex_state|5.019002||p PL_lex_stuff|5.019002||p PL_linestr|5.019002||p PL_modglobal||5.005000|n PL_na|5.004050||pn PL_no_modify|5.006000||p PL_ofsgv|||n PL_opfreehook||5.011000|n PL_parser|5.009005|5.009005|p PL_peepp||5.007003|n PL_perl_destruct_level|5.004050||p PL_perldb|5.004050||p PL_ppaddr|5.006000||p PL_rpeepp||5.013005|n PL_rsfp_filters|5.019002||p PL_rsfp|5.019002||p PL_rs|||n PL_signals|5.008001||p PL_stack_base|5.004050||p PL_stack_sp|5.004050||p PL_statcache|5.005000||p PL_stdingv|5.004050||p PL_sv_arenaroot|5.004050||p PL_sv_no|5.004050||pn PL_sv_undef|5.004050||pn PL_sv_yes|5.004050||pn PL_tainted|5.004050||p PL_tainting|5.004050||p PL_tokenbuf|5.019002||p POP_MULTICALL||5.019003| POPi|||n POPl|||n POPn|||n POPpbytex||5.007001|n POPpx||5.005030|n POPp|||n POPs|||n PTR2IV|5.006000||p PTR2NV|5.006000||p PTR2UV|5.006000||p PTR2nat|5.009003||p PTR2ul|5.007001||p PTRV|5.006000||p PUSHMARK||| PUSH_MULTICALL||5.019003| PUSHi||| PUSHmortal|5.009002||p PUSHn||| PUSHp||| PUSHs||| PUSHu|5.004000||p PUTBACK||| PadARRAY||5.019003| PadMAX||5.019003| PadlistARRAY||5.019003| PadlistMAX||5.019003| PadlistNAMESARRAY||5.019003| PadlistNAMESMAX||5.019003| PadlistNAMES||5.019003| PadlistREFCNT||5.017004| PadnameIsOUR||| PadnameIsSTATE||| PadnameLEN||5.019003| PadnameOURSTASH||| PadnameOUTER||| PadnamePV||5.019003| PadnameSV||5.019003| PadnameTYPE||| PadnameUTF8||5.019003| PadnamelistARRAY||5.019003| PadnamelistMAX||5.019003| PerlIO_clearerr||5.007003| PerlIO_close||5.007003| PerlIO_context_layers||5.009004| PerlIO_eof||5.007003| PerlIO_error||5.007003| PerlIO_fileno||5.007003| PerlIO_fill||5.007003| PerlIO_flush||5.007003| PerlIO_get_base||5.007003| PerlIO_get_bufsiz||5.007003| PerlIO_get_cnt||5.007003| PerlIO_get_ptr||5.007003| PerlIO_read||5.007003| PerlIO_seek||5.007003| PerlIO_set_cnt||5.007003| PerlIO_set_ptrcnt||5.007003| PerlIO_setlinebuf||5.007003| PerlIO_stderr||5.007003| PerlIO_stdin||5.007003| PerlIO_stdout||5.007003| PerlIO_tell||5.007003| PerlIO_unread||5.007003| PerlIO_write||5.007003| Perl_signbit||5.009005|n PoisonFree|5.009004||p PoisonNew|5.009004||p PoisonWith|5.009004||p Poison|5.008000||p READ_XDIGIT||5.017006| RETVAL|||n Renewc||| Renew||| SAVECLEARSV||| SAVECOMPPAD||| SAVEPADSV||| SAVETMPS||| SAVE_DEFSV|5.004050||p SPAGAIN||| SP||| START_EXTERN_C|5.005000||p START_MY_CXT|5.007003||p STMT_END|||p STMT_START|||p STR_WITH_LEN|5.009003||p ST||| SV_CONST_RETURN|5.009003||p SV_COW_DROP_PV|5.008001||p SV_COW_SHARED_HASH_KEYS|5.009005||p SV_GMAGIC|5.007002||p SV_HAS_TRAILING_NUL|5.009004||p SV_IMMEDIATE_UNREF|5.007001||p SV_MUTABLE_RETURN|5.009003||p SV_NOSTEAL|5.009002||p SV_SMAGIC|5.009003||p SV_UTF8_NO_ENCODING|5.008001||p SVfARG|5.009005||p SVf_UTF8|5.006000||p SVf|5.006000||p SVt_INVLIST||5.019002| SVt_IV||| SVt_NULL||| SVt_NV||| SVt_PVAV||| SVt_PVCV||| SVt_PVFM||| SVt_PVGV||| SVt_PVHV||| SVt_PVIO||| SVt_PVIV||| SVt_PVLV||| SVt_PVMG||| SVt_PVNV||| SVt_PV||| SVt_REGEXP||5.011000| Safefree||| Slab_Alloc||| Slab_Free||| Slab_to_ro||| Slab_to_rw||| StructCopy||| SvCUR_set||| SvCUR||| SvEND||| SvGAMAGIC||5.006001| SvGETMAGIC|5.004050||p SvGROW||| SvIOK_UV||5.006000| SvIOK_notUV||5.006000| SvIOK_off||| SvIOK_only_UV||5.006000| SvIOK_only||| SvIOK_on||| SvIOKp||| SvIOK||| SvIVX||| SvIV_nomg|5.009001||p SvIV_set||| SvIVx||| SvIV||| SvIsCOW_shared_hash||5.008003| SvIsCOW||5.008003| SvLEN_set||| SvLEN||| SvLOCK||5.007003| SvMAGIC_set|5.009003||p SvNIOK_off||| SvNIOKp||| SvNIOK||| SvNOK_off||| SvNOK_only||| SvNOK_on||| SvNOKp||| SvNOK||| SvNVX||| SvNV_nomg||5.013002| SvNV_set||| SvNVx||| SvNV||| SvOK||| SvOOK_offset||5.011000| SvOOK||| SvPOK_off||| SvPOK_only_UTF8||5.006000| SvPOK_only||| SvPOK_on||| SvPOKp||| SvPOK||| SvPVX_const|5.009003||p SvPVX_mutable|5.009003||p SvPVX||| SvPV_const|5.009003||p SvPV_flags_const_nolen|5.009003||p SvPV_flags_const|5.009003||p SvPV_flags_mutable|5.009003||p SvPV_flags|5.007002||p SvPV_force_flags_mutable|5.009003||p SvPV_force_flags_nolen|5.009003||p SvPV_force_flags|5.007002||p SvPV_force_mutable|5.009003||p SvPV_force_nolen|5.009003||p SvPV_force_nomg_nolen|5.009003||p SvPV_force_nomg|5.007002||p SvPV_force|||p SvPV_mutable|5.009003||p SvPV_nolen_const|5.009003||p SvPV_nolen|5.006000||p SvPV_nomg_const_nolen|5.009003||p SvPV_nomg_const|5.009003||p SvPV_nomg_nolen|5.013007||p SvPV_nomg|5.007002||p SvPV_renew|5.009003||p SvPV_set||| SvPVbyte_force||5.009002| SvPVbyte_nolen||5.006000| SvPVbytex_force||5.006000| SvPVbytex||5.006000| SvPVbyte|5.006000||p SvPVutf8_force||5.006000| SvPVutf8_nolen||5.006000| SvPVutf8x_force||5.006000| SvPVutf8x||5.006000| SvPVutf8||5.006000| SvPVx||| SvPV||| SvREFCNT_dec_NN||5.017007| SvREFCNT_dec||| SvREFCNT_inc_NN|5.009004||p SvREFCNT_inc_simple_NN|5.009004||p SvREFCNT_inc_simple_void_NN|5.009004||p SvREFCNT_inc_simple_void|5.009004||p SvREFCNT_inc_simple|5.009004||p SvREFCNT_inc_void_NN|5.009004||p SvREFCNT_inc_void|5.009004||p SvREFCNT_inc|||p SvREFCNT||| SvROK_off||| SvROK_on||| SvROK||| SvRV_set|5.009003||p SvRV||| SvRXOK||5.009005| SvRX||5.009005| SvSETMAGIC||| SvSHARED_HASH|5.009003||p SvSHARE||5.007003| SvSTASH_set|5.009003||p SvSTASH||| SvSetMagicSV_nosteal||5.004000| SvSetMagicSV||5.004000| SvSetSV_nosteal||5.004000| SvSetSV||| SvTAINTED_off||5.004000| SvTAINTED_on||5.004000| SvTAINTED||5.004000| SvTAINT||| SvTHINKFIRST||| SvTRUE_nomg||5.013006| SvTRUE||| SvTYPE||| SvUNLOCK||5.007003| SvUOK|5.007001|5.006000|p SvUPGRADE||| SvUTF8_off||5.006000| SvUTF8_on||5.006000| SvUTF8||5.006000| SvUVXx|5.004000||p SvUVX|5.004000||p SvUV_nomg|5.009001||p SvUV_set|5.009003||p SvUVx|5.004000||p SvUV|5.004000||p SvVOK||5.008001| SvVSTRING_mg|5.009004||p THIS|||n UNDERBAR|5.009002||p UTF8_MAXBYTES|5.009002||p UVSIZE|5.006000||p UVTYPE|5.006000||p UVXf|5.007001||p UVof|5.006000||p UVuf|5.006000||p UVxf|5.006000||p WARN_ALL|5.006000||p WARN_AMBIGUOUS|5.006000||p WARN_ASSERTIONS|5.019002||p WARN_BAREWORD|5.006000||p WARN_CLOSED|5.006000||p WARN_CLOSURE|5.006000||p WARN_DEBUGGING|5.006000||p WARN_DEPRECATED|5.006000||p WARN_DIGIT|5.006000||p WARN_EXEC|5.006000||p WARN_EXITING|5.006000||p WARN_GLOB|5.006000||p WARN_INPLACE|5.006000||p WARN_INTERNAL|5.006000||p WARN_IO|5.006000||p WARN_LAYER|5.008000||p WARN_MALLOC|5.006000||p WARN_MISC|5.006000||p WARN_NEWLINE|5.006000||p WARN_NUMERIC|5.006000||p WARN_ONCE|5.006000||p WARN_OVERFLOW|5.006000||p WARN_PACK|5.006000||p WARN_PARENTHESIS|5.006000||p WARN_PIPE|5.006000||p WARN_PORTABLE|5.006000||p WARN_PRECEDENCE|5.006000||p WARN_PRINTF|5.006000||p WARN_PROTOTYPE|5.006000||p WARN_QW|5.006000||p WARN_RECURSION|5.006000||p WARN_REDEFINE|5.006000||p WARN_REGEXP|5.006000||p WARN_RESERVED|5.006000||p WARN_SEMICOLON|5.006000||p WARN_SEVERE|5.006000||p WARN_SIGNAL|5.006000||p WARN_SUBSTR|5.006000||p WARN_SYNTAX|5.006000||p WARN_TAINT|5.006000||p WARN_THREADS|5.008000||p WARN_UNINITIALIZED|5.006000||p WARN_UNOPENED|5.006000||p WARN_UNPACK|5.006000||p WARN_UNTIE|5.006000||p WARN_UTF8|5.006000||p WARN_VOID|5.006000||p WIDEST_UTYPE|5.015004||p XCPT_CATCH|5.009002||p XCPT_RETHROW|5.009002|5.007001|p XCPT_TRY_END|5.009002|5.004000|p XCPT_TRY_START|5.009002|5.004000|p XPUSHi||| XPUSHmortal|5.009002||p XPUSHn||| XPUSHp||| XPUSHs||| XPUSHu|5.004000||p XSPROTO|5.010000||p XSRETURN_EMPTY||| XSRETURN_IV||| XSRETURN_NO||| XSRETURN_NV||| XSRETURN_PV||| XSRETURN_UNDEF||| XSRETURN_UV|5.008001||p XSRETURN_YES||| XSRETURN|||p XST_mIV||| XST_mNO||| XST_mNV||| XST_mPV||| XST_mUNDEF||| XST_mUV|5.008001||p XST_mYES||| XS_APIVERSION_BOOTCHECK||5.013004| XS_EXTERNAL||5.019003| XS_INTERNAL||5.019003| XS_VERSION_BOOTCHECK||| XS_VERSION||| XSprePUSH|5.006000||p XS||| XopDISABLE||5.019003| XopENABLE||5.019003| XopENTRY_set||5.019003| XopENTRY||5.019003| XopFLAGS||5.013007| ZeroD|5.009002||p Zero||| _aMY_CXT|5.007003||p _add_range_to_invlist||| _append_range_to_invlist||| _core_swash_init||| _get_swash_invlist||| _invlist_array_init||| _invlist_contains_cp||| _invlist_contents||| _invlist_dump||| _invlist_intersection_maybe_complement_2nd||| _invlist_intersection||| _invlist_invert_prop||| _invlist_invert||| _invlist_len||| _invlist_populate_swatch||| _invlist_search||| _invlist_subtract||| _invlist_union_maybe_complement_2nd||| _invlist_union||| _is_uni_FOO||5.017008| _is_uni_perl_idcont||5.017008| _is_uni_perl_idstart||5.017007| _is_utf8_FOO||5.017008| _is_utf8_mark||5.017008| _is_utf8_perl_idcont||5.017008| _is_utf8_perl_idstart||5.017007| _new_invlist_C_array||| _new_invlist||| _pMY_CXT|5.007003||p _swash_inversion_hash||| _swash_to_invlist||| _to_fold_latin1||| _to_uni_fold_flags||5.013011| _to_upper_title_latin1||| _to_utf8_fold_flags||5.015006| _to_utf8_lower_flags||5.015006| _to_utf8_title_flags||5.015006| _to_utf8_upper_flags||5.015006| aMY_CXT_|5.007003||p aMY_CXT|5.007003||p aTHXR_|5.019002||p aTHXR|5.019002||p aTHX_|5.006000||p aTHX|5.006000||p aassign_common_vars||| add_cp_to_invlist||| add_data|||n add_utf16_textfilter||| addmad||| adjust_size_and_find_bucket|||n adjust_stack_on_leave||| alloc_maybe_populate_EXACT||| alloccopstash||| allocmy||| amagic_call||| amagic_cmp_locale||| amagic_cmp||| amagic_deref_call||5.013007| amagic_i_ncmp||| amagic_is_enabled||| amagic_ncmp||| anonymise_cv_maybe||| any_dup||| ao||| append_madprops||| apply_attrs_my||| apply_attrs_string||5.006001| apply_attrs||| apply||| assert_uft8_cache_coherent||| atfork_lock||5.007003|n atfork_unlock||5.007003|n av_arylen_p||5.009003| av_clear||| av_create_and_push||5.009005| av_create_and_unshift_one||5.009005| av_delete||5.006000| av_exists||5.006000| av_extend_guts||| av_extend||| av_fetch||| av_fill||| av_iter_p||5.011000| av_len||| av_make||| av_pop||| av_push||| av_reify||| av_shift||| av_store||| av_tindex||5.017009| av_top_index||5.017009| av_undef||| av_unshift||| ax|||n bad_type_gv||| bad_type_pv||| bind_match||| block_end||| block_gimme||5.004000| block_start||| blockhook_register||5.013003| boolSV|5.004000||p boot_core_PerlIO||| boot_core_UNIVERSAL||| boot_core_mro||| bytes_cmp_utf8||5.013007| bytes_from_utf8||5.007001| bytes_to_uni|||n bytes_to_utf8||5.006001| call_argv|5.006000||p call_atexit||5.006000| call_list||5.004000| call_method|5.006000||p call_pv|5.006000||p call_sv|5.006000||p caller_cx||5.013005| calloc||5.007002|n cando||| cast_i32||5.006000| cast_iv||5.006000| cast_ulong||5.006000| cast_uv||5.006000| check_locale_boundary_crossing||| check_type_and_open||| check_uni||| check_utf8_print||| checkcomma||| ckWARN|5.006000||p ck_entersub_args_core||| ck_entersub_args_list||5.013006| ck_entersub_args_proto_or_list||5.013006| ck_entersub_args_proto||5.013006| ck_warner_d||5.011001|v ck_warner||5.011001|v ckwarn_common||| ckwarn_d||5.009003| ckwarn||5.009003| cl_and|||n cl_anything|||n cl_init|||n cl_is_anything|||n cl_or|||n clear_placeholders||| clone_params_del|||n clone_params_new|||n closest_cop||| compute_EXACTish||| convert||| cop_fetch_label||5.015001| cop_free||| cop_hints_2hv||5.013007| cop_hints_fetch_pvn||5.013007| cop_hints_fetch_pvs||5.013007| cop_hints_fetch_pv||5.013007| cop_hints_fetch_sv||5.013007| cop_store_label||5.015001| cophh_2hv||5.013007| cophh_copy||5.013007| cophh_delete_pvn||5.013007| cophh_delete_pvs||5.013007| cophh_delete_pv||5.013007| cophh_delete_sv||5.013007| cophh_fetch_pvn||5.013007| cophh_fetch_pvs||5.013007| cophh_fetch_pv||5.013007| cophh_fetch_sv||5.013007| cophh_free||5.013007| cophh_new_empty||5.019003| cophh_store_pvn||5.013007| cophh_store_pvs||5.013007| cophh_store_pv||5.013007| cophh_store_sv||5.013007| core_prototype||| core_regclass_swash||| coresub_op||| could_it_be_a_POSIX_class||| cr_textfilter||| create_eval_scope||| croak_memory_wrap||5.019003|n croak_no_mem|||n croak_no_modify||5.013003|n croak_nocontext|||vn croak_popstack|||n croak_sv||5.013001| croak_xs_usage||5.010001|n croak|||v csighandler||5.009003|n curmad||| current_re_engine||| curse||| custom_op_desc||5.007003| custom_op_name||5.007003| custom_op_register||5.013007| custom_op_xop||5.013007| cv_ckproto_len_flags||| cv_clone_into||| cv_clone||| cv_const_sv_or_av||| cv_const_sv||5.004000| cv_dump||| cv_forget_slab||| cv_get_call_checker||5.013006| cv_set_call_checker||5.013006| cv_undef||| cvgv_set||| cvstash_set||| cx_dump||5.005000| cx_dup||| cxinc||| dAXMARK|5.009003||p dAX|5.007002||p dITEMS|5.007002||p dMARK||| dMULTICALL||5.009003| dMY_CXT_SV|5.007003||p dMY_CXT|5.007003||p dNOOP|5.006000||p dORIGMARK||| dSP||| dTHR|5.004050||p dTHXR|5.019002||p dTHXa|5.006000||p dTHXoa|5.006000||p dTHX|5.006000||p dUNDERBAR|5.009002||p dVAR|5.009003||p dXCPT|5.009002||p dXSARGS||| dXSI32||| dXSTARG|5.006000||p deb_curcv||| deb_nocontext|||vn deb_stack_all||| deb_stack_n||| debop||5.005000| debprofdump||5.005000| debprof||| debstackptrs||5.007003| debstack||5.007003| debug_start_match||| deb||5.007003|v defelem_target||| del_sv||| delete_eval_scope||| delimcpy||5.004000|n deprecate_commaless_var_list||| despatch_signals||5.007001| destroy_matcher||| die_nocontext|||vn die_sv||5.013001| die_unwind||| die|||v dirp_dup||| div128||| djSP||| do_aexec5||| do_aexec||| do_aspawn||| do_binmode||5.004050| do_chomp||| do_close||| do_delete_local||| do_dump_pad||| do_eof||| do_exec3||| do_execfree||| do_exec||| do_gv_dump||5.006000| do_gvgv_dump||5.006000| do_hv_dump||5.006000| do_ipcctl||| do_ipcget||| do_join||| do_magic_dump||5.006000| do_msgrcv||| do_msgsnd||| do_ncmp||| do_oddball||| do_op_dump||5.006000| do_op_xmldump||| do_open9||5.006000| do_openn||5.007001| do_open||5.004000| do_pmop_dump||5.006000| do_pmop_xmldump||| do_print||| do_readline||| do_seek||| do_semop||| do_shmio||| do_smartmatch||| do_spawn_nowait||| do_spawn||| do_sprintf||| do_sv_dump||5.006000| do_sysseek||| do_tell||| do_trans_complex_utf8||| do_trans_complex||| do_trans_count_utf8||| do_trans_count||| do_trans_simple_utf8||| do_trans_simple||| do_trans||| do_vecget||| do_vecset||| do_vop||| docatch||| doeval||| dofile||| dofindlabel||| doform||| doing_taint||5.008001|n dooneliner||| doopen_pm||| doparseform||| dopoptoeval||| dopoptogiven||| dopoptolabel||| dopoptoloop||| dopoptosub_at||| dopoptowhen||| doref||5.009003| dounwind||| dowantarray||| dump_all_perl||| dump_all||5.006000| dump_eval||5.006000| dump_exec_pos||| dump_fds||| dump_form||5.006000| dump_indent||5.006000|v dump_mstats||| dump_packsubs_perl||| dump_packsubs||5.006000| dump_sub_perl||| dump_sub||5.006000| dump_sv_child||| dump_trie_interim_list||| dump_trie_interim_table||| dump_trie||| dump_vindent||5.006000| dumpuntil||| dup_attrlist||| emulate_cop_io||| eval_pv|5.006000||p eval_sv|5.006000||p exec_failed||| expect_number||| fbm_compile||5.005000| fbm_instr||5.005000| feature_is_enabled||| filter_add||| filter_del||| filter_gets||| filter_read||| finalize_optree||| finalize_op||| find_and_forget_pmops||| find_array_subscript||| find_beginning||| find_byclass||| find_hash_subscript||| find_in_my_stash||| find_lexical_cv||| find_runcv_where||| find_runcv||5.008001| find_rundefsv2||| find_rundefsvoffset||5.009002| find_rundefsv||5.013002| find_script||| find_uninit_var||| first_symbol|||n foldEQ_latin1||5.013008|n foldEQ_locale||5.013002|n foldEQ_utf8_flags||5.013010| foldEQ_utf8||5.013002| foldEQ||5.013002|n fold_constants||| forbid_setid||| force_ident_maybe_lex||| force_ident||| force_list||| force_next||| force_strict_version||| force_version||| force_word||| forget_pmop||| form_nocontext|||vn form_short_octal_warning||| form||5.004000|v fp_dup||| fprintf_nocontext|||vn free_global_struct||| free_tied_hv_pool||| free_tmps||| gen_constant_list||| get_and_check_backslash_N_name||| get_aux_mg||| get_av|5.006000||p get_context||5.006000|n get_cvn_flags|5.009005||p get_cvs|5.011000||p get_cv|5.006000||p get_db_sub||| get_debug_opts||| get_hash_seed||| get_hv|5.006000||p get_invlist_iter_addr||| get_invlist_offset_addr||| get_invlist_previous_index_addr||| get_mstats||| get_no_modify||| get_num||| get_op_descs||5.005000| get_op_names||5.005000| get_opargs||| get_ppaddr||5.006000| get_re_arg||| get_sv|5.006000||p get_vtbl||5.005030| getcwd_sv||5.007002| getenv_len||| glob_2number||| glob_assign_glob||| glob_assign_ref||| gp_dup||| gp_free||| gp_ref||| grok_bin|5.007003||p grok_bslash_N||| grok_bslash_c||| grok_bslash_o||| grok_bslash_x||| grok_hex|5.007003||p grok_number|5.007002||p grok_numeric_radix|5.007002||p grok_oct|5.007003||p group_end||| gv_AVadd||| gv_HVadd||| gv_IOadd||| gv_SVadd||| gv_add_by_type||5.011000| gv_autoload4||5.004000| gv_autoload_pvn||5.015004| gv_autoload_pv||5.015004| gv_autoload_sv||5.015004| gv_check||| gv_const_sv||5.009003| gv_dump||5.006000| gv_efullname3||5.004000| gv_efullname4||5.006001| gv_efullname||| gv_ename||| gv_fetchfile_flags||5.009005| gv_fetchfile||| gv_fetchmeth_autoload||5.007003| gv_fetchmeth_pv_autoload||5.015004| gv_fetchmeth_pvn_autoload||5.015004| gv_fetchmeth_pvn||5.015004| gv_fetchmeth_pv||5.015004| gv_fetchmeth_sv_autoload||5.015004| gv_fetchmeth_sv||5.015004| gv_fetchmethod_autoload||5.004000| gv_fetchmethod_pv_flags||5.015004| gv_fetchmethod_pvn_flags||5.015004| gv_fetchmethod_sv_flags||5.015004| gv_fetchmethod||| gv_fetchmeth||| gv_fetchpvn_flags|5.009002||p gv_fetchpvs|5.009004||p gv_fetchpv||| gv_fetchsv|5.009002||p gv_fullname3||5.004000| gv_fullname4||5.006001| gv_fullname||| gv_handler||5.007001| gv_init_pvn||5.015004| gv_init_pv||5.015004| gv_init_svtype||| gv_init_sv||5.015004| gv_init||| gv_magicalize_isa||| gv_name_set||5.009004| gv_stashpvn|5.004000||p gv_stashpvs|5.009003||p gv_stashpv||| gv_stashsv||| gv_try_downgrade||| handle_regex_sets||| he_dup||| hek_dup||| hfree_next_entry||| hfreeentries||| hsplit||| hv_assert||| hv_auxinit||| hv_backreferences_p||| hv_clear_placeholders||5.009001| hv_clear||| hv_common_key_len||5.010000| hv_common||5.010000| hv_copy_hints_hv||5.009004| hv_delayfree_ent||5.004000| hv_delete_common||| hv_delete_ent||5.004000| hv_delete||| hv_eiter_p||5.009003| hv_eiter_set||5.009003| hv_ename_add||| hv_ename_delete||| hv_exists_ent||5.004000| hv_exists||| hv_fetch_ent||5.004000| hv_fetchs|5.009003||p hv_fetch||| hv_fill||5.013002| hv_free_ent_ret||| hv_free_ent||5.004000| hv_iterinit||| hv_iterkeysv||5.004000| hv_iterkey||| hv_iternext_flags||5.008000| hv_iternextsv||| hv_iternext||| hv_iterval||| hv_kill_backrefs||| hv_ksplit||5.004000| hv_magic_check|||n hv_magic||| hv_name_set||5.009003| hv_notallowed||| hv_placeholders_get||5.009003| hv_placeholders_p||| hv_placeholders_set||5.009003| hv_rand_set||5.017011| hv_riter_p||5.009003| hv_riter_set||5.009003| hv_scalar||5.009001| hv_store_ent||5.004000| hv_store_flags||5.008000| hv_stores|5.009004||p hv_store||| hv_undef_flags||| hv_undef||| ibcmp_locale||5.004000| ibcmp_utf8||5.007003| ibcmp||| incline||| incpush_if_exists||| incpush_use_sep||| incpush||| ingroup||| init_argv_symbols||| init_constants||| init_dbargs||| init_debugger||| init_global_struct||| init_i18nl10n||5.006000| init_i18nl14n||5.006000| init_ids||| init_interp||| init_main_stash||| init_perllib||| init_postdump_symbols||| init_predump_symbols||| init_stacks||5.005000| init_tm||5.007002| inplace_aassign||| instr|||n intro_my||| intuit_method||| intuit_more||| invert||| invlist_array||| invlist_clone||| invlist_extend||| invlist_highest||| invlist_is_iterating||| invlist_iterfinish||| invlist_iterinit||| invlist_iternext||| invlist_max||| invlist_previous_index||| invlist_set_len||| invlist_set_previous_index||| invlist_trim||| invoke_exception_hook||| io_close||| isALNUMC|5.006000||p isALNUM_lazy||| isALPHANUMERIC||5.017008| isALPHA||| isASCII|5.006000|5.006000|p isBLANK|5.006001||p isCNTRL|5.006000|5.006000|p isDIGIT||| isFOO_lc||| isFOO_utf8_lc||| isGRAPH|5.006000||p isGV_with_GP|5.009004||p isIDCONT||5.017008| isIDFIRST_lazy||| isIDFIRST||| isLOWER||| isOCTAL||5.013005| isPRINT|5.004000||p isPSXSPC|5.006001||p isPUNCT|5.006000||p isSPACE||| isUPPER||| isWORDCHAR||5.013006| isXDIGIT|5.006000||p is_an_int||| is_ascii_string||5.011000|n is_cur_LC_category_utf8||| is_handle_constructor|||n is_list_assignment||| is_lvalue_sub||5.007001| is_uni_alnum_lc||5.006000| is_uni_alnumc_lc||5.017007| is_uni_alnumc||5.017007| is_uni_alnum||5.006000| is_uni_alpha_lc||5.006000| is_uni_alpha||5.006000| is_uni_ascii_lc||5.006000| is_uni_ascii||5.006000| is_uni_blank_lc||5.017002| is_uni_blank||5.017002| is_uni_cntrl_lc||5.006000| is_uni_cntrl||5.006000| is_uni_digit_lc||5.006000| is_uni_digit||5.006000| is_uni_graph_lc||5.006000| is_uni_graph||5.006000| is_uni_idfirst_lc||5.006000| is_uni_idfirst||5.006000| is_uni_lower_lc||5.006000| is_uni_lower||5.006000| is_uni_print_lc||5.006000| is_uni_print||5.006000| is_uni_punct_lc||5.006000| is_uni_punct||5.006000| is_uni_space_lc||5.006000| is_uni_space||5.006000| is_uni_upper_lc||5.006000| is_uni_upper||5.006000| is_uni_xdigit_lc||5.006000| is_uni_xdigit||5.006000| is_utf8_alnumc||5.017007| is_utf8_alnum||5.006000| is_utf8_alpha||5.006000| is_utf8_ascii||5.006000| is_utf8_blank||5.017002| is_utf8_char_buf||5.015008|n is_utf8_char_slow|||n is_utf8_char||5.006000|n is_utf8_cntrl||5.006000| is_utf8_common||| is_utf8_digit||5.006000| is_utf8_graph||5.006000| is_utf8_idcont||5.008000| is_utf8_idfirst||5.006000| is_utf8_lower||5.006000| is_utf8_mark||5.006000| is_utf8_perl_space||5.011001| is_utf8_perl_word||5.011001| is_utf8_posix_digit||5.011001| is_utf8_print||5.006000| is_utf8_punct||5.006000| is_utf8_space||5.006000| is_utf8_string_loclen||5.009003|n is_utf8_string_loc||5.008001|n is_utf8_string||5.006001|n is_utf8_upper||5.006000| is_utf8_xdigit||5.006000| is_utf8_xidcont||5.013010| is_utf8_xidfirst||5.013010| isa_lookup||| items|||n ix|||n jmaybe||| join_exact||| keyword_plugin_standard||| keyword||| leave_scope||| lex_bufutf8||5.011002| lex_discard_to||5.011002| lex_grow_linestr||5.011002| lex_next_chunk||5.011002| lex_peek_unichar||5.011002| lex_read_space||5.011002| lex_read_to||5.011002| lex_read_unichar||5.011002| lex_start||5.009005| lex_stuff_pvn||5.011002| lex_stuff_pvs||5.013005| lex_stuff_pv||5.013006| lex_stuff_sv||5.011002| lex_unstuff||5.011002| listkids||| list||| load_module_nocontext|||vn load_module|5.006000||pv localize||| looks_like_bool||| looks_like_number||| lop||| mPUSHi|5.009002||p mPUSHn|5.009002||p mPUSHp|5.009002||p mPUSHs|5.010001||p mPUSHu|5.009002||p mXPUSHi|5.009002||p mXPUSHn|5.009002||p mXPUSHp|5.009002||p mXPUSHs|5.010001||p mXPUSHu|5.009002||p mad_free||| madlex||| madparse||| magic_clear_all_env||| magic_cleararylen_p||| magic_clearenv||| magic_clearhints||| magic_clearhint||| magic_clearisa||| magic_clearpack||| magic_clearsig||| magic_copycallchecker||| magic_dump||5.006000| magic_existspack||| magic_freearylen_p||| magic_freeovrld||| magic_getarylen||| magic_getdefelem||| magic_getnkeys||| magic_getpack||| magic_getpos||| magic_getsig||| magic_getsubstr||| magic_gettaint||| magic_getuvar||| magic_getvec||| magic_get||| magic_killbackrefs||| magic_methcall1||| magic_methcall|||v magic_methpack||| magic_nextpack||| magic_regdata_cnt||| magic_regdatum_get||| magic_regdatum_set||| magic_scalarpack||| magic_set_all_env||| magic_setarylen||| magic_setcollxfrm||| magic_setdbline||| magic_setdefelem||| magic_setenv||| magic_sethint||| magic_setisa||| magic_setmglob||| magic_setnkeys||| magic_setpack||| magic_setpos||| magic_setregexp||| magic_setsig||| magic_setsubstr||| magic_settaint||| magic_setutf8||| magic_setuvar||| magic_setvec||| magic_set||| magic_sizepack||| magic_wipepack||| make_matcher||| make_trie_failtable||| make_trie||| malloc_good_size|||n malloced_size|||n malloc||5.007002|n markstack_grow||| matcher_matches_sv||| mayberelocate||| measure_struct||| memEQs|5.009005||p memEQ|5.004000||p memNEs|5.009005||p memNE|5.004000||p mem_collxfrm||| mem_log_common|||n mess_alloc||| mess_nocontext|||vn mess_sv||5.013001| mess||5.006000|v method_common||| mfree||5.007002|n mg_clear||| mg_copy||| mg_dup||| mg_find_mglob||| mg_findext||5.013008| mg_find||| mg_free_type||5.013006| mg_free||| mg_get||| mg_length||5.005000| mg_localize||| mg_magical||| mg_set||| mg_size||5.005000| mini_mktime||5.007002| minus_v||| missingterm||| mode_from_discipline||| modkids||| more_bodies||| more_sv||| moreswitches||| mro_clean_isarev||| mro_gather_and_rename||| mro_get_from_name||5.010001| mro_get_linear_isa_dfs||| mro_get_linear_isa||5.009005| mro_get_private_data||5.010001| mro_isa_changed_in||| mro_meta_dup||| mro_meta_init||| mro_method_changed_in||5.009005| mro_package_moved||| mro_register||5.010001| mro_set_mro||5.010001| mro_set_private_data||5.010001| mul128||| mulexp10|||n my_atof2||5.007002| my_atof||5.006000| my_attrs||| my_bcopy|||n my_bzero|||n my_chsize||| my_clearenv||| my_cxt_index||| my_cxt_init||| my_dirfd||5.009005| my_exit_jump||| my_exit||| my_failure_exit||5.004000| my_fflush_all||5.006000| my_fork||5.007003|n my_kid||| my_lstat_flags||| my_lstat||5.019003| my_memcmp|||n my_memset||5.004000|n my_pclose||5.004000| my_popen_list||5.007001| my_popen||5.004000| my_setenv||| my_snprintf|5.009004||pvn my_socketpair||5.007003|n my_sprintf|5.009003||pvn my_stat_flags||| my_stat||5.019003| my_strftime||5.007002| my_strlcat|5.009004||pn my_strlcpy|5.009004||pn my_unexec||| my_vsnprintf||5.009004|n need_utf8|||n newANONATTRSUB||5.006000| newANONHASH||| newANONLIST||| newANONSUB||| newASSIGNOP||| newATTRSUB_flags||| newATTRSUB||5.006000| newAVREF||| newAV||| newBINOP||| newCONDOP||| newCONSTSUB_flags||5.015006| newCONSTSUB|5.004050||p newCVREF||| newDEFSVOP||| newFORM||| newFOROP||5.013007| newGIVENOP||5.009003| newGIVWHENOP||| newGP||| newGVOP||| newGVREF||| newGVgen_flags||5.015004| newGVgen||| newHVREF||| newHVhv||5.005000| newHV||| newIO||| newLISTOP||| newLOGOP||| newLOOPEX||| newLOOPOP||| newMADPROP||| newMADsv||| newMYSUB||5.017004| newNULLLIST||| newOP||| newPADOP||| newPMOP||| newPROG||| newPVOP||| newRANGE||| newRV_inc|5.004000||p newRV_noinc|5.004000||p newRV||| newSLICEOP||| newSTATEOP||| newSTUB||| newSUB||| newSVOP||| newSVREF||| newSV_type|5.009005||p newSVhek||5.009003| newSViv||| newSVnv||| newSVpadname||5.017004| newSVpv_share||5.013006| newSVpvf_nocontext|||vn newSVpvf||5.004000|v newSVpvn_flags|5.010001||p newSVpvn_share|5.007001||p newSVpvn_utf8|5.010001||p newSVpvn|5.004050||p newSVpvs_flags|5.010001||p newSVpvs_share|5.009003||p newSVpvs|5.009003||p newSVpv||| newSVrv||| newSVsv||| newSVuv|5.006000||p newSV||| newTOKEN||| newUNOP||| newWHENOP||5.009003| newWHILEOP||5.013007| newXS_flags||5.009004| newXS_len_flags||| newXSproto||5.006000| newXS||5.006000| new_collate||5.006000| new_constant||| new_ctype||5.006000| new_he||| new_logop||| new_numeric||5.006000| new_stackinfo||5.005000| new_version||5.009000| new_warnings_bitfield||| next_symbol||| nextargv||| nextchar||| ninstr|||n no_bareword_allowed||| no_fh_allowed||| no_op||| not_a_number||| not_incrementable||| nothreadhook||5.008000| nuke_stacks||| num_overflow|||n oopsAV||| oopsHV||| op_append_elem||5.013006| op_append_list||5.013006| op_clear||| op_const_sv||| op_contextualize||5.013006| op_dump||5.006000| op_free||| op_getmad_weak||| op_getmad||| op_integerize||| op_linklist||5.013006| op_lvalue_flags||| op_lvalue||5.013007| op_null||5.007002| op_prepend_elem||5.013006| op_refcnt_dec||| op_refcnt_inc||| op_refcnt_lock||5.009002| op_refcnt_unlock||5.009002| op_scope||5.013007| op_std_init||| op_unscope||| op_xmldump||| open_script||| opslab_force_free||| opslab_free_nopad||| opslab_free||| pMY_CXT_|5.007003||p pMY_CXT|5.007003||p pTHX_|5.006000||p pTHX|5.006000||p packWARN|5.007003||p pack_cat||5.007003| pack_rec||| package_version||| package||| packlist||5.008001| pad_add_anon||5.008001| pad_add_name_pvn||5.015001| pad_add_name_pvs||5.015001| pad_add_name_pv||5.015001| pad_add_name_sv||5.015001| pad_alloc_name||| pad_alloc||| pad_block_start||| pad_check_dup||| pad_compname_type||5.009003| pad_findlex||| pad_findmy_pvn||5.015001| pad_findmy_pvs||5.015001| pad_findmy_pv||5.015001| pad_findmy_sv||5.015001| pad_fixup_inner_anons||| pad_free||| pad_leavemy||| pad_new||5.008001| pad_peg|||n pad_push||| pad_reset||| pad_setsv||| pad_sv||| pad_swipe||| pad_tidy||5.008001| padlist_dup||| padlist_store||| parse_arithexpr||5.013008| parse_barestmt||5.013007| parse_block||5.013007| parse_body||| parse_fullexpr||5.013008| parse_fullstmt||5.013005| parse_ident||| parse_label||5.013007| parse_listexpr||5.013008| parse_lparen_question_flags||| parse_stmtseq||5.013006| parse_termexpr||5.013008| parse_unicode_opts||| parser_dup||| parser_free_nexttoke_ops||| parser_free||| path_is_searchable|||n peep||| pending_ident||| perl_alloc_using|||n perl_alloc|||n perl_clone_using|||n perl_clone|||n perl_construct|||n perl_destruct||5.007003|n perl_free|||n perl_parse||5.006000|n perl_run|||n pidgone||| pm_description||| pmop_dump||5.006000| pmop_xmldump||| pmruntime||| pmtrans||| pop_scope||| populate_isa|||v pregcomp||5.009005| pregexec||| pregfree2||5.011000| pregfree||| prepend_madprops||| prescan_version||5.011004| printbuf||| printf_nocontext|||vn process_special_blocks||| ptr_hash|||n ptr_table_clear||5.009005| ptr_table_fetch||5.009005| ptr_table_find|||n ptr_table_free||5.009005| ptr_table_new||5.009005| ptr_table_split||5.009005| ptr_table_store||5.009005| push_scope||| put_byte||| put_latin1_charclass_innards||| pv_display|5.006000||p pv_escape|5.009004||p pv_pretty|5.009004||p pv_uni_display||5.007003| qerror||| qsortsvu||| re_compile||5.009005| re_croak2||| re_dup_guts||| re_intuit_start||5.019001| re_intuit_string||5.006000| re_op_compile||| readpipe_override||| realloc||5.007002|n reentrant_free||5.019003| reentrant_init||5.019003| reentrant_retry||5.019003|vn reentrant_size||5.019003| ref_array_or_hash||| refcounted_he_chain_2hv||| refcounted_he_fetch_pvn||| refcounted_he_fetch_pvs||| refcounted_he_fetch_pv||| refcounted_he_fetch_sv||| refcounted_he_free||| refcounted_he_inc||| refcounted_he_new_pvn||| refcounted_he_new_pvs||| refcounted_he_new_pv||| refcounted_he_new_sv||| refcounted_he_value||| refkids||| refto||| ref||5.019003| reg_check_named_buff_matched||| reg_named_buff_all||5.009005| reg_named_buff_exists||5.009005| reg_named_buff_fetch||5.009005| reg_named_buff_firstkey||5.009005| reg_named_buff_iter||| reg_named_buff_nextkey||5.009005| reg_named_buff_scalar||5.009005| reg_named_buff||| reg_node||| reg_numbered_buff_fetch||| reg_numbered_buff_length||| reg_numbered_buff_store||| reg_qr_package||| reg_recode||| reg_scan_name||| reg_skipcomment||| reg_temp_copy||| reganode||| regatom||| regbranch||| regclass_swash||5.009004| regclass||| regcppop||| regcppush||| regcurly||| regdump_extflags||| regdump_intflags||| regdump||5.005000| regdupe_internal||| regexec_flags||5.005000| regfree_internal||5.009005| reghop3|||n reghop4|||n reghopmaybe3|||n reginclass||| reginitcolors||5.006000| reginsert||| regmatch||| regnext||5.005000| regpatws|||n regpiece||| regpposixcc||| regprop||| regrepeat||| regtail_study||| regtail||| regtry||| reguni||| regwhite|||n reg||| repeatcpy|||n report_evil_fh||| report_redefined_cv||| report_uninit||| report_wrongway_fh||| require_pv||5.006000| require_tie_mod||| restore_magic||| rninstr|||n rpeep||| rsignal_restore||| rsignal_save||| rsignal_state||5.004000| rsignal||5.004000| run_body||| run_user_filter||| runops_debug||5.005000| runops_standard||5.005000| rv2cv_op_cv||5.013006| rvpv_dup||| rxres_free||| rxres_restore||| rxres_save||| safesyscalloc||5.006000|n safesysfree||5.006000|n safesysmalloc||5.006000|n safesysrealloc||5.006000|n same_dirent||| save_I16||5.004000| save_I32||| save_I8||5.006000| save_adelete||5.011000| save_aelem_flags||5.011000| save_aelem||5.004050| save_alloc||5.006000| save_aptr||| save_ary||| save_bool||5.008001| save_clearsv||| save_delete||| save_destructor_x||5.006000| save_destructor||5.006000| save_freeop||| save_freepv||| save_freesv||| save_generic_pvref||5.006001| save_generic_svref||5.005030| save_gp||5.004000| save_hash||| save_hdelete||5.011000| save_hek_flags|||n save_helem_flags||5.011000| save_helem||5.004050| save_hints||5.010001| save_hptr||| save_int||| save_item||| save_iv||5.005000| save_lines||| save_list||| save_long||| save_magic_flags||| save_mortalizesv||5.007001| save_nogv||| save_op||5.005000| save_padsv_and_mortalize||5.010001| save_pptr||| save_pushi32ptr||5.010001| save_pushptri32ptr||| save_pushptrptr||5.010001| save_pushptr||5.010001| save_re_context||5.006000| save_scalar_at||| save_scalar||| save_set_svflags||5.009000| save_shared_pvref||5.007003| save_sptr||| save_svref||| save_vptr||5.006000| savepvn||| savepvs||5.009003| savepv||| savesharedpvn||5.009005| savesharedpvs||5.013006| savesharedpv||5.007003| savesharedsvpv||5.013006| savestack_grow_cnt||5.008001| savestack_grow||| savesvpv||5.009002| sawparens||| scalar_mod_type|||n scalarboolean||| scalarkids||| scalarseq||| scalarvoid||| scalar||| scan_bin||5.006000| scan_commit||| scan_const||| scan_formline||| scan_heredoc||| scan_hex||| scan_ident||| scan_inputsymbol||| scan_num||5.007001| scan_oct||| scan_pat||| scan_str||| scan_subst||| scan_trans||| scan_version||5.009001| scan_vstring||5.009005| scan_word||| screaminstr||5.005000| search_const||| seed||5.008001| sequence_num||| set_context||5.006000|n set_numeric_local||5.006000| set_numeric_radix||5.006000| set_numeric_standard||5.006000| setdefout||| share_hek_flags||| share_hek||5.004000| si_dup||| sighandler|||n simplify_sort||| skipspace0||| skipspace1||| skipspace2||| skipspace_flags||| softref2xv||| sortcv_stacked||| sortcv_xsub||| sortcv||| sortsv_flags||5.009003| sortsv||5.007003| space_join_names_mortal||| ss_dup||| stack_grow||| start_force||| start_glob||| start_subparse||5.004000| stdize_locale||| strEQ||| strGE||| strGT||| strLE||| strLT||| strNE||| str_to_version||5.006000| strip_return||| strnEQ||| strnNE||| study_chunk||| sub_crush_depth||| sublex_done||| sublex_push||| sublex_start||| sv_2bool_flags||5.013006| sv_2bool||| sv_2cv||| sv_2io||| sv_2iuv_common||| sv_2iuv_non_preserve||| sv_2iv_flags||5.009001| sv_2iv||| sv_2mortal||| sv_2num||| sv_2nv_flags||5.013001| sv_2pv_flags|5.007002||p sv_2pv_nolen|5.006000||p sv_2pvbyte_nolen|5.006000||p sv_2pvbyte|5.006000||p sv_2pvutf8_nolen||5.006000| sv_2pvutf8||5.006000| sv_2pv||| sv_2uv_flags||5.009001| sv_2uv|5.004000||p sv_add_arena||| sv_add_backref||| sv_backoff||| sv_bless||| sv_cat_decode||5.008001| sv_catpv_flags||5.013006| sv_catpv_mg|5.004050||p sv_catpv_nomg||5.013006| sv_catpvf_mg_nocontext|||pvn sv_catpvf_mg|5.006000|5.004000|pv sv_catpvf_nocontext|||vn sv_catpvf||5.004000|v sv_catpvn_flags||5.007002| sv_catpvn_mg|5.004050||p sv_catpvn_nomg|5.007002||p sv_catpvn||| sv_catpvs_flags||5.013006| sv_catpvs_mg||5.013006| sv_catpvs_nomg||5.013006| sv_catpvs|5.009003||p sv_catpv||| sv_catsv_flags||5.007002| sv_catsv_mg|5.004050||p sv_catsv_nomg|5.007002||p sv_catsv||| sv_catxmlpvn||| sv_catxmlpv||| sv_catxmlsv||| sv_chop||| sv_clean_all||| sv_clean_objs||| sv_clear||| sv_cmp_flags||5.013006| sv_cmp_locale_flags||5.013006| sv_cmp_locale||5.004000| sv_cmp||| sv_collxfrm_flags||5.013006| sv_collxfrm||| sv_copypv_flags||5.017002| sv_copypv_nomg||5.017002| sv_copypv||| sv_dec_nomg||5.013002| sv_dec||| sv_del_backref||| sv_derived_from_pvn||5.015004| sv_derived_from_pv||5.015004| sv_derived_from_sv||5.015004| sv_derived_from||5.004000| sv_destroyable||5.010000| sv_display||| sv_does_pvn||5.015004| sv_does_pv||5.015004| sv_does_sv||5.015004| sv_does||5.009004| sv_dump||| sv_dup_common||| sv_dup_inc_multiple||| sv_dup_inc||| sv_dup||| sv_eq_flags||5.013006| sv_eq||| sv_exp_grow||| sv_force_normal_flags||5.007001| sv_force_normal||5.006000| sv_free2||| sv_free_arenas||| sv_free||| sv_gets||5.004000| sv_grow||| sv_i_ncmp||| sv_inc_nomg||5.013002| sv_inc||| sv_insert_flags||5.010001| sv_insert||| sv_isa||| sv_isobject||| sv_iv||5.005000| sv_kill_backrefs||| sv_len_utf8_nomg||| sv_len_utf8||5.006000| sv_len||| sv_magic_portable|5.019003|5.004000|p sv_magicext_mglob||| sv_magicext||5.007003| sv_magic||| sv_mortalcopy_flags||| sv_mortalcopy||| sv_ncmp||| sv_newmortal||| sv_newref||| sv_nolocking||5.007003| sv_nosharing||5.007003| sv_nounlocking||| sv_nv||5.005000| sv_peek||5.005000| sv_pos_b2u_flags||5.019003| sv_pos_b2u_midway||| sv_pos_b2u||5.006000| sv_pos_u2b_cached||| sv_pos_u2b_flags||5.011005| sv_pos_u2b_forwards|||n sv_pos_u2b_midway|||n sv_pos_u2b||5.006000| sv_pvbyten_force||5.006000| sv_pvbyten||5.006000| sv_pvbyte||5.006000| sv_pvn_force_flags|5.007002||p sv_pvn_force||| sv_pvn_nomg|5.007003|5.005000|p sv_pvn||5.005000| sv_pvutf8n_force||5.006000| sv_pvutf8n||5.006000| sv_pvutf8||5.006000| sv_pv||5.006000| sv_recode_to_utf8||5.007003| sv_reftype||| sv_ref||| sv_release_COW||| sv_replace||| sv_report_used||| sv_resetpvn||| sv_reset||| sv_rvweaken||5.006000| sv_sethek||| sv_setiv_mg|5.004050||p sv_setiv||| sv_setnv_mg|5.006000||p sv_setnv||| sv_setpv_mg|5.004050||p sv_setpvf_mg_nocontext|||pvn sv_setpvf_mg|5.006000|5.004000|pv sv_setpvf_nocontext|||vn sv_setpvf||5.004000|v sv_setpviv_mg||5.008001| sv_setpviv||5.008001| sv_setpvn_mg|5.004050||p sv_setpvn||| sv_setpvs_mg||5.013006| sv_setpvs|5.009004||p sv_setpv||| sv_setref_iv||| sv_setref_nv||| sv_setref_pvn||| sv_setref_pvs||5.019003| sv_setref_pv||| sv_setref_uv||5.007001| sv_setsv_cow||| sv_setsv_flags||5.007002| sv_setsv_mg|5.004050||p sv_setsv_nomg|5.007002||p sv_setsv||| sv_setuv_mg|5.004050||p sv_setuv|5.004000||p sv_tainted||5.004000| sv_taint||5.004000| sv_true||5.005000| sv_unglob||| sv_uni_display||5.007003| sv_unmagicext||5.013008| sv_unmagic||| sv_unref_flags||5.007001| sv_unref||| sv_untaint||5.004000| sv_upgrade||| sv_usepvn_flags||5.009004| sv_usepvn_mg|5.004050||p sv_usepvn||| sv_utf8_decode||5.006000| sv_utf8_downgrade||5.006000| sv_utf8_encode||5.006000| sv_utf8_upgrade_flags_grow||5.011000| sv_utf8_upgrade_flags||5.007002| sv_utf8_upgrade_nomg||5.007002| sv_utf8_upgrade||5.007001| sv_uv|5.005000||p sv_vcatpvf_mg|5.006000|5.004000|p sv_vcatpvfn_flags||5.017002| sv_vcatpvfn||5.004000| sv_vcatpvf|5.006000|5.004000|p sv_vsetpvf_mg|5.006000|5.004000|p sv_vsetpvfn||5.004000| sv_vsetpvf|5.006000|5.004000|p sv_xmlpeek||| svtype||| swallow_bom||| swash_fetch||5.007002| swash_init||5.006000| swatch_get||| sys_init3||5.010000|n sys_init||5.010000|n sys_intern_clear||| sys_intern_dup||| sys_intern_init||| sys_term||5.010000|n taint_env||| taint_proper||| tied_method|||v tmps_grow||5.006000| toFOLD_uni||5.007003| toFOLD_utf8||5.019001| toFOLD||5.019001| toLOWER_L1||5.019001| toLOWER_LC||5.004000| toLOWER_uni||5.007003| toLOWER_utf8||5.015007| toLOWER||| toTITLE_uni||5.007003| toTITLE_utf8||5.015007| toTITLE||5.019001| toUPPER_uni||5.007003| toUPPER_utf8||5.015007| toUPPER||5.004000| to_byte_substr||| to_lower_latin1||| to_uni_fold||5.007003| to_uni_lower_lc||5.006000| to_uni_lower||5.007003| to_uni_title_lc||5.006000| to_uni_title||5.007003| to_uni_upper_lc||5.006000| to_uni_upper||5.007003| to_utf8_case||5.007003| to_utf8_fold||5.015007| to_utf8_lower||5.015007| to_utf8_substr||| to_utf8_title||5.015007| to_utf8_upper||5.015007| token_free||| token_getmad||| tokenize_use||| tokeq||| tokereport||| too_few_arguments_pv||| too_few_arguments_sv||| too_many_arguments_pv||| too_many_arguments_sv||| translate_substr_offsets||| try_amagic_bin||| try_amagic_un||| uiv_2buf|||n unlnk||| unpack_rec||| unpack_str||5.007003| unpackstring||5.008001| unreferenced_to_tmp_stack||| unshare_hek_or_pvn||| unshare_hek||| unsharepvn||5.004000| unwind_handler_stack||| update_debugger_info||| upg_version||5.009005| usage||| utf16_textfilter||| utf16_to_utf8_reversed||5.006001| utf16_to_utf8||5.006001| utf8_distance||5.006000| utf8_hop||5.006000| utf8_length||5.007001| utf8_mg_len_cache_update||| utf8_mg_pos_cache_update||| utf8_to_bytes||5.006001| utf8_to_uvchr_buf||5.015009| utf8_to_uvchr||5.007001| utf8_to_uvuni_buf||5.015009| utf8_to_uvuni||5.007001| utf8n_to_uvchr||| utf8n_to_uvuni||5.007001| utilize||| uvchr_to_utf8_flags||5.007003| uvchr_to_utf8||| uvuni_to_utf8_flags||5.007003| uvuni_to_utf8||5.007001| valid_utf8_to_uvchr||| valid_utf8_to_uvuni||5.015009| validate_proto||| validate_suid||| varname||| vcmp||5.009000| vcroak||5.006000| vdeb||5.007003| vform||5.006000| visit||| vivify_defelem||| vivify_ref||| vload_module|5.006000||p vmess||5.006000| vnewSVpvf|5.006000|5.004000|p vnormal||5.009002| vnumify||5.009000| vstringify||5.009000| vverify||5.009003| vwarner||5.006000| vwarn||5.006000| wait4pid||| warn_nocontext|||vn warn_sv||5.013001| warner_nocontext|||vn warner|5.006000|5.004000|pv warn|||v was_lvalue_sub||| watch||| whichsig_pvn||5.015004| whichsig_pv||5.015004| whichsig_sv||5.015004| whichsig||| win32_croak_not_implemented|||n with_queued_errors||| wrap_op_checker||5.015008| write_to_stderr||| xmldump_all_perl||| xmldump_all||| xmldump_attr||| xmldump_eval||| xmldump_form||| xmldump_indent|||v xmldump_packsubs_perl||| xmldump_packsubs||| xmldump_sub_perl||| xmldump_sub||| xmldump_vindent||| xs_apiversion_bootcheck||| xs_version_bootcheck||| yyerror_pvn||| yyerror_pv||| yyerror||| yylex||| yyparse||| yyunlex||| yywarn||| ); if (exists $opt{'list-unsupported'}) { my $f; for $f (sort { lc $a cmp lc $b } keys %API) { next unless $API{$f}{todo}; print "$f ", '.'x(40-length($f)), " ", format_version($API{$f}{todo}), "\n"; } exit 0; } # Scan for possible replacement candidates my(%replace, %need, %hints, %warnings, %depends); my $replace = 0; my($hint, $define, $function); sub find_api { my $code = shift; $code =~ s{ / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*) | "[^"\\]*(?:\\.[^"\\]*)*" | '[^'\\]*(?:\\.[^'\\]*)*' }{}egsx; grep { exists $API{$_} } $code =~ /(\w+)/mg; } while () { if ($hint) { my $h = $hint->[0] eq 'Hint' ? \%hints : \%warnings; if (m{^\s*\*\s(.*?)\s*$}) { for (@{$hint->[1]}) { $h->{$_} ||= ''; # suppress warning with older perls $h->{$_} .= "$1\n"; } } else { undef $hint } } $hint = [$1, [split /,?\s+/, $2]] if m{^\s*$rccs\s+(Hint|Warning):\s+(\w+(?:,?\s+\w+)*)\s*$}; if ($define) { if ($define->[1] =~ /\\$/) { $define->[1] .= $_; } else { if (exists $API{$define->[0]} && $define->[1] !~ /^DPPP_\(/) { my @n = find_api($define->[1]); push @{$depends{$define->[0]}}, @n if @n } undef $define; } } $define = [$1, $2] if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(.*)}; if ($function) { if (/^}/) { if (exists $API{$function->[0]}) { my @n = find_api($function->[1]); push @{$depends{$function->[0]}}, @n if @n } undef $function; } else { $function->[1] .= $_; } } $function = [$1, ''] if m{^DPPP_\(my_(\w+)\)}; $replace = $1 if m{^\s*$rccs\s+Replace:\s+(\d+)\s+$rcce\s*$}; $replace{$2} = $1 if $replace and m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+)}; $replace{$2} = $1 if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+).*$rccs\s+Replace\s+$rcce}; $replace{$1} = $2 if m{^\s*$rccs\s+Replace (\w+) with (\w+)\s+$rcce\s*$}; if (m{^\s*$rccs\s+(\w+(\s*,\s*\w+)*)\s+depends\s+on\s+(\w+(\s*,\s*\w+)*)\s+$rcce\s*$}) { my @deps = map { s/\s+//g; $_ } split /,/, $3; my $d; for $d (map { s/\s+//g; $_ } split /,/, $1) { push @{$depends{$d}}, @deps; } } $need{$1} = 1 if m{^#if\s+defined\(NEED_(\w+)(?:_GLOBAL)?\)}; } for (values %depends) { my %s; $_ = [sort grep !$s{$_}++, @$_]; } if (exists $opt{'api-info'}) { my $f; my $count = 0; my $match = $opt{'api-info'} =~ m!^/(.*)/$! ? $1 : "^\Q$opt{'api-info'}\E\$"; for $f (sort { lc $a cmp lc $b } keys %API) { next unless $f =~ /$match/; print "\n=== $f ===\n\n"; my $info = 0; if ($API{$f}{base} || $API{$f}{todo}) { my $base = format_version($API{$f}{base} || $API{$f}{todo}); print "Supported at least starting from perl-$base.\n"; $info++; } if ($API{$f}{provided}) { my $todo = $API{$f}{todo} ? format_version($API{$f}{todo}) : "5.003"; print "Support by $ppport provided back to perl-$todo.\n"; print "Support needs to be explicitly requested by NEED_$f.\n" if exists $need{$f}; print "Depends on: ", join(', ', @{$depends{$f}}), ".\n" if exists $depends{$f}; print "\n$hints{$f}" if exists $hints{$f}; print "\nWARNING:\n$warnings{$f}" if exists $warnings{$f}; $info++; } print "No portability information available.\n" unless $info; $count++; } $count or print "Found no API matching '$opt{'api-info'}'."; print "\n"; exit 0; } if (exists $opt{'list-provided'}) { my $f; for $f (sort { lc $a cmp lc $b } keys %API) { next unless $API{$f}{provided}; my @flags; push @flags, 'explicit' if exists $need{$f}; push @flags, 'depend' if exists $depends{$f}; push @flags, 'hint' if exists $hints{$f}; push @flags, 'warning' if exists $warnings{$f}; my $flags = @flags ? ' ['.join(', ', @flags).']' : ''; print "$f$flags\n"; } exit 0; } my @files; my @srcext = qw( .xs .c .h .cc .cpp -c.inc -xs.inc ); my $srcext = join '|', map { quotemeta $_ } @srcext; if (@ARGV) { my %seen; for (@ARGV) { if (-e) { if (-f) { push @files, $_ unless $seen{$_}++; } else { warn "'$_' is not a file.\n" } } else { my @new = grep { -f } glob $_ or warn "'$_' does not exist.\n"; push @files, grep { !$seen{$_}++ } @new; } } } else { eval { require File::Find; File::Find::find(sub { $File::Find::name =~ /($srcext)$/i and push @files, $File::Find::name; }, '.'); }; if ($@) { @files = map { glob "*$_" } @srcext; } } if (!@ARGV || $opt{filter}) { my(@in, @out); my %xsc = map { /(.*)\.xs$/ ? ("$1.c" => 1, "$1.cc" => 1) : () } @files; for (@files) { my $out = exists $xsc{$_} || /\b\Q$ppport\E$/i || !/($srcext)$/i; push @{ $out ? \@out : \@in }, $_; } if (@ARGV && @out) { warning("Skipping the following files (use --nofilter to avoid this):\n| ", join "\n| ", @out); } @files = @in; } die "No input files given!\n" unless @files; my(%files, %global, %revreplace); %revreplace = reverse %replace; my $filename; my $patch_opened = 0; for $filename (@files) { unless (open IN, "<$filename") { warn "Unable to read from $filename: $!\n"; next; } info("Scanning $filename ..."); my $c = do { local $/; }; close IN; my %file = (orig => $c, changes => 0); # Temporarily remove C/XS comments and strings from the code my @ccom; $c =~ s{ ( ^$HS*\#$HS*include\b[^\r\n]+\b(?:\Q$ppport\E|XSUB\.h)\b[^\r\n]* | ^$HS*\#$HS*(?:define|elif|if(?:def)?)\b[^\r\n]* ) | ( ^$HS*\#[^\r\n]* | "[^"\\]*(?:\\.[^"\\]*)*" | '[^'\\]*(?:\\.[^'\\]*)*' | / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]* ) ) }{ defined $2 and push @ccom, $2; defined $1 ? $1 : "$ccs$#ccom$cce" }mgsex; $file{ccom} = \@ccom; $file{code} = $c; $file{has_inc_ppport} = $c =~ /^$HS*#$HS*include[^\r\n]+\b\Q$ppport\E\b/m; my $func; for $func (keys %API) { my $match = $func; $match .= "|$revreplace{$func}" if exists $revreplace{$func}; if ($c =~ /\b(?:Perl_)?($match)\b/) { $file{uses_replace}{$1}++ if exists $revreplace{$func} && $1 eq $revreplace{$func}; $file{uses_Perl}{$func}++ if $c =~ /\bPerl_$func\b/; if (exists $API{$func}{provided}) { $file{uses_provided}{$func}++; if (!exists $API{$func}{base} || $API{$func}{base} > $opt{'compat-version'}) { $file{uses}{$func}++; my @deps = rec_depend($func); if (@deps) { $file{uses_deps}{$func} = \@deps; for (@deps) { $file{uses}{$_} = 0 unless exists $file{uses}{$_}; } } for ($func, @deps) { $file{needs}{$_} = 'static' if exists $need{$_}; } } } if (exists $API{$func}{todo} && $API{$func}{todo} > $opt{'compat-version'}) { if ($c =~ /\b$func\b/) { $file{uses_todo}{$func}++; } } } } while ($c =~ /^$HS*#$HS*define$HS+(NEED_(\w+?)(_GLOBAL)?)\b/mg) { if (exists $need{$2}) { $file{defined $3 ? 'needed_global' : 'needed_static'}{$2}++; } else { warning("Possibly wrong #define $1 in $filename") } } for (qw(uses needs uses_todo needed_global needed_static)) { for $func (keys %{$file{$_}}) { push @{$global{$_}{$func}}, $filename; } } $files{$filename} = \%file; } # Globally resolve NEED_'s my $need; for $need (keys %{$global{needs}}) { if (@{$global{needs}{$need}} > 1) { my @targets = @{$global{needs}{$need}}; my @t = grep $files{$_}{needed_global}{$need}, @targets; @targets = @t if @t; @t = grep /\.xs$/i, @targets; @targets = @t if @t; my $target = shift @targets; $files{$target}{needs}{$need} = 'global'; for (@{$global{needs}{$need}}) { $files{$_}{needs}{$need} = 'extern' if $_ ne $target; } } } for $filename (@files) { exists $files{$filename} or next; info("=== Analyzing $filename ==="); my %file = %{$files{$filename}}; my $func; my $c = $file{code}; my $warnings = 0; for $func (sort keys %{$file{uses_Perl}}) { if ($API{$func}{varargs}) { unless ($API{$func}{nothxarg}) { my $changes = ($c =~ s{\b(Perl_$func\s*\(\s*)(?!aTHX_?)(\)|[^\s)]*\))} { $1 . ($2 eq ')' ? 'aTHX' : 'aTHX_ ') . $2 }ge); if ($changes) { warning("Doesn't pass interpreter argument aTHX to Perl_$func"); $file{changes} += $changes; } } } else { warning("Uses Perl_$func instead of $func"); $file{changes} += ($c =~ s{\bPerl_$func(\s*)\((\s*aTHX_?)?\s*} {$func$1(}g); } } for $func (sort keys %{$file{uses_replace}}) { warning("Uses $func instead of $replace{$func}"); $file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g); } for $func (sort keys %{$file{uses_provided}}) { if ($file{uses}{$func}) { if (exists $file{uses_deps}{$func}) { diag("Uses $func, which depends on ", join(', ', @{$file{uses_deps}{$func}})); } else { diag("Uses $func"); } } $warnings += hint($func); } unless ($opt{quiet}) { for $func (sort keys %{$file{uses_todo}}) { print "*** WARNING: Uses $func, which may not be portable below perl ", format_version($API{$func}{todo}), ", even with '$ppport'\n"; $warnings++; } } for $func (sort keys %{$file{needed_static}}) { my $message = ''; if (not exists $file{uses}{$func}) { $message = "No need to define NEED_$func if $func is never used"; } elsif (exists $file{needs}{$func} && $file{needs}{$func} ne 'static') { $message = "No need to define NEED_$func when already needed globally"; } if ($message) { diag($message); $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_$func\b.*$LF//mg); } } for $func (sort keys %{$file{needed_global}}) { my $message = ''; if (not exists $global{uses}{$func}) { $message = "No need to define NEED_${func}_GLOBAL if $func is never used"; } elsif (exists $file{needs}{$func}) { if ($file{needs}{$func} eq 'extern') { $message = "No need to define NEED_${func}_GLOBAL when already needed globally"; } elsif ($file{needs}{$func} eq 'static') { $message = "No need to define NEED_${func}_GLOBAL when only used in this file"; } } if ($message) { diag($message); $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_${func}_GLOBAL\b.*$LF//mg); } } $file{needs_inc_ppport} = keys %{$file{uses}}; if ($file{needs_inc_ppport}) { my $pp = ''; for $func (sort keys %{$file{needs}}) { my $type = $file{needs}{$func}; next if $type eq 'extern'; my $suffix = $type eq 'global' ? '_GLOBAL' : ''; unless (exists $file{"needed_$type"}{$func}) { if ($type eq 'global') { diag("Files [@{$global{needs}{$func}}] need $func, adding global request"); } else { diag("File needs $func, adding static request"); } $pp .= "#define NEED_$func$suffix\n"; } } if ($pp && ($c =~ s/^(?=$HS*#$HS*define$HS+NEED_\w+)/$pp/m)) { $pp = ''; $file{changes}++; } unless ($file{has_inc_ppport}) { diag("Needs to include '$ppport'"); $pp .= qq(#include "$ppport"\n) } if ($pp) { $file{changes} += ($c =~ s/^($HS*#$HS*define$HS+NEED_\w+.*?)^/$1$pp/ms) || ($c =~ s/^(?=$HS*#$HS*include.*\Q$ppport\E)/$pp/m) || ($c =~ s/^($HS*#$HS*include.*XSUB.*\s*?)^/$1$pp/m) || ($c =~ s/^/$pp/); } } else { if ($file{has_inc_ppport}) { diag("No need to include '$ppport'"); $file{changes} += ($c =~ s/^$HS*?#$HS*include.*\Q$ppport\E.*?$LF//m); } } # put back in our C comments my $ix; my $cppc = 0; my @ccom = @{$file{ccom}}; for $ix (0 .. $#ccom) { if (!$opt{cplusplus} && $ccom[$ix] =~ s!^//!!) { $cppc++; $file{changes} += $c =~ s/$rccs$ix$rcce/$ccs$ccom[$ix] $cce/; } else { $c =~ s/$rccs$ix$rcce/$ccom[$ix]/; } } if ($cppc) { my $s = $cppc != 1 ? 's' : ''; warning("Uses $cppc C++ style comment$s, which is not portable"); } my $s = $warnings != 1 ? 's' : ''; my $warn = $warnings ? " ($warnings warning$s)" : ''; info("Analysis completed$warn"); if ($file{changes}) { if (exists $opt{copy}) { my $newfile = "$filename$opt{copy}"; if (-e $newfile) { error("'$newfile' already exists, refusing to write copy of '$filename'"); } else { local *F; if (open F, ">$newfile") { info("Writing copy of '$filename' with changes to '$newfile'"); print F $c; close F; } else { error("Cannot open '$newfile' for writing: $!"); } } } elsif (exists $opt{patch} || $opt{changes}) { if (exists $opt{patch}) { unless ($patch_opened) { if (open PATCH, ">$opt{patch}") { $patch_opened = 1; } else { error("Cannot open '$opt{patch}' for writing: $!"); delete $opt{patch}; $opt{changes} = 1; goto fallback; } } mydiff(\*PATCH, $filename, $c); } else { fallback: info("Suggested changes:"); mydiff(\*STDOUT, $filename, $c); } } else { my $s = $file{changes} == 1 ? '' : 's'; info("$file{changes} potentially required change$s detected"); } } else { info("Looks good"); } } close PATCH if $patch_opened; exit 0; sub try_use { eval "use @_;"; return $@ eq '' } sub mydiff { local *F = shift; my($file, $str) = @_; my $diff; if (exists $opt{diff}) { $diff = run_diff($opt{diff}, $file, $str); } if (!defined $diff and try_use('Text::Diff')) { $diff = Text::Diff::diff($file, \$str, { STYLE => 'Unified' }); $diff = <

$tmp") { print F $str; close F; if (open F, "$prog $file $tmp |") { while () { s/\Q$tmp\E/$file.patched/; $diff .= $_; } close F; unlink $tmp; return $diff; } unlink $tmp; } else { error("Cannot open '$tmp' for writing: $!"); } return undef; } sub rec_depend { my($func, $seen) = @_; return () unless exists $depends{$func}; $seen = {%{$seen||{}}}; return () if $seen->{$func}++; my %s; grep !$s{$_}++, map { ($_, rec_depend($_, $seen)) } @{$depends{$func}}; } sub parse_version { my $ver = shift; if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) { return ($1, $2, $3); } elsif ($ver !~ /^\d+\.[\d_]+$/) { die "cannot parse version '$ver'\n"; } $ver =~ s/_//g; $ver =~ s/$/000000/; my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; $v = int $v; $s = int $s; if ($r < 5 || ($r == 5 && $v < 6)) { if ($s % 10) { die "cannot parse version '$ver'\n"; } } return ($r, $v, $s); } sub format_version { my $ver = shift; $ver =~ s/$/000000/; my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; $v = int $v; $s = int $s; if ($r < 5 || ($r == 5 && $v < 6)) { if ($s % 10) { die "invalid version '$ver'\n"; } $s /= 10; $ver = sprintf "%d.%03d", $r, $v; $s > 0 and $ver .= sprintf "_%02d", $s; return $ver; } return sprintf "%d.%d.%d", $r, $v, $s; } sub info { $opt{quiet} and return; print @_, "\n"; } sub diag { $opt{quiet} and return; $opt{diag} and print @_, "\n"; } sub warning { $opt{quiet} and return; print "*** ", @_, "\n"; } sub error { print "*** ERROR: ", @_, "\n"; } my %given_hints; my %given_warnings; sub hint { $opt{quiet} and return; my $func = shift; my $rv = 0; if (exists $warnings{$func} && !$given_warnings{$func}++) { my $warn = $warnings{$func}; $warn =~ s!^!*** !mg; print "*** WARNING: $func\n", $warn; $rv++; } if ($opt{hints} && exists $hints{$func} && !$given_hints{$func}++) { my $hint = $hints{$func}; $hint =~ s/^/ /mg; print " --- hint for $func ---\n", $hint; } $rv; } sub usage { my($usage) = do { local(@ARGV,$/)=($0); <> } =~ /^=head\d$HS+SYNOPSIS\s*^(.*?)\s*^=/ms; my %M = ( 'I' => '*' ); $usage =~ s/^\s*perl\s+\S+/$^X $0/; $usage =~ s/([A-Z])<([^>]+)>/$M{$1}$2$M{$1}/g; print < }; my($copy) = $self =~ /^=head\d\s+COPYRIGHT\s*^(.*?)^=\w+/ms; $copy =~ s/^(?=\S+)/ /gms; $self =~ s/^$HS+Do NOT edit.*?(?=^-)/$copy/ms; $self =~ s/^SKIP.*(?=^__DATA__)/SKIP if (\@ARGV && \$ARGV[0] eq '--unstrip') { eval { require Devel::PPPort }; \$@ and die "Cannot require Devel::PPPort, please install.\\n"; if (eval \$Devel::PPPort::VERSION < $VERSION) { die "$0 was originally generated with Devel::PPPort $VERSION.\\n" . "Your Devel::PPPort is only version \$Devel::PPPort::VERSION.\\n" . "Please install a newer version, or --unstrip will not work.\\n"; } Devel::PPPort::WriteFile(\$0); exit 0; } print <$0" or die "cannot strip $0: $!\n"; print OUT "$pl$c\n"; exit 0; } __DATA__ */ #ifndef _P_P_PORTABILITY_H_ #define _P_P_PORTABILITY_H_ #ifndef DPPP_NAMESPACE # define DPPP_NAMESPACE DPPP_ #endif #define DPPP_CAT2(x,y) CAT2(x,y) #define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name) #ifndef PERL_REVISION # if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION)) # define PERL_PATCHLEVEL_H_IMPLICIT # include # endif # if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL))) # include # endif # ifndef PERL_REVISION # define PERL_REVISION (5) /* Replace: 1 */ # define PERL_VERSION PATCHLEVEL # define PERL_SUBVERSION SUBVERSION /* Replace PERL_PATCHLEVEL with PERL_VERSION */ /* Replace: 0 */ # endif #endif #define _dpppDEC2BCD(dec) ((((dec)/100)<<8)|((((dec)%100)/10)<<4)|((dec)%10)) #define PERL_BCDVERSION ((_dpppDEC2BCD(PERL_REVISION)<<24)|(_dpppDEC2BCD(PERL_VERSION)<<12)|_dpppDEC2BCD(PERL_SUBVERSION)) /* It is very unlikely that anyone will try to use this with Perl 6 (or greater), but who knows. */ #if PERL_REVISION != 5 # error ppport.h only works with Perl version 5 #endif /* PERL_REVISION != 5 */ #ifndef dTHR # define dTHR dNOOP #endif #ifndef dTHX # define dTHX dNOOP #endif #ifndef dTHXa # define dTHXa(x) dNOOP #endif #ifndef pTHX # define pTHX void #endif #ifndef pTHX_ # define pTHX_ #endif #ifndef aTHX # define aTHX #endif #ifndef aTHX_ # define aTHX_ #endif #if (PERL_BCDVERSION < 0x5006000) # ifdef USE_THREADS # define aTHXR thr # define aTHXR_ thr, # else # define aTHXR # define aTHXR_ # endif # define dTHXR dTHR #else # define aTHXR aTHX # define aTHXR_ aTHX_ # define dTHXR dTHX #endif #ifndef dTHXoa # define dTHXoa(x) dTHXa(x) #endif #ifdef I_LIMITS # include #endif #ifndef PERL_UCHAR_MIN # define PERL_UCHAR_MIN ((unsigned char)0) #endif #ifndef PERL_UCHAR_MAX # ifdef UCHAR_MAX # define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX) # else # ifdef MAXUCHAR # define PERL_UCHAR_MAX ((unsigned char)MAXUCHAR) # else # define PERL_UCHAR_MAX ((unsigned char)~(unsigned)0) # endif # endif #endif #ifndef PERL_USHORT_MIN # define PERL_USHORT_MIN ((unsigned short)0) #endif #ifndef PERL_USHORT_MAX # ifdef USHORT_MAX # define PERL_USHORT_MAX ((unsigned short)USHORT_MAX) # else # ifdef MAXUSHORT # define PERL_USHORT_MAX ((unsigned short)MAXUSHORT) # else # ifdef USHRT_MAX # define PERL_USHORT_MAX ((unsigned short)USHRT_MAX) # else # define PERL_USHORT_MAX ((unsigned short)~(unsigned)0) # endif # endif # endif #endif #ifndef PERL_SHORT_MAX # ifdef SHORT_MAX # define PERL_SHORT_MAX ((short)SHORT_MAX) # else # ifdef MAXSHORT /* Often used in */ # define PERL_SHORT_MAX ((short)MAXSHORT) # else # ifdef SHRT_MAX # define PERL_SHORT_MAX ((short)SHRT_MAX) # else # define PERL_SHORT_MAX ((short) (PERL_USHORT_MAX >> 1)) # endif # endif # endif #endif #ifndef PERL_SHORT_MIN # ifdef SHORT_MIN # define PERL_SHORT_MIN ((short)SHORT_MIN) # else # ifdef MINSHORT # define PERL_SHORT_MIN ((short)MINSHORT) # else # ifdef SHRT_MIN # define PERL_SHORT_MIN ((short)SHRT_MIN) # else # define PERL_SHORT_MIN (-PERL_SHORT_MAX - ((3 & -1) == 3)) # endif # endif # endif #endif #ifndef PERL_UINT_MAX # ifdef UINT_MAX # define PERL_UINT_MAX ((unsigned int)UINT_MAX) # else # ifdef MAXUINT # define PERL_UINT_MAX ((unsigned int)MAXUINT) # else # define PERL_UINT_MAX (~(unsigned int)0) # endif # endif #endif #ifndef PERL_UINT_MIN # define PERL_UINT_MIN ((unsigned int)0) #endif #ifndef PERL_INT_MAX # ifdef INT_MAX # define PERL_INT_MAX ((int)INT_MAX) # else # ifdef MAXINT /* Often used in */ # define PERL_INT_MAX ((int)MAXINT) # else # define PERL_INT_MAX ((int)(PERL_UINT_MAX >> 1)) # endif # endif #endif #ifndef PERL_INT_MIN # ifdef INT_MIN # define PERL_INT_MIN ((int)INT_MIN) # else # ifdef MININT # define PERL_INT_MIN ((int)MININT) # else # define PERL_INT_MIN (-PERL_INT_MAX - ((3 & -1) == 3)) # endif # endif #endif #ifndef PERL_ULONG_MAX # ifdef ULONG_MAX # define PERL_ULONG_MAX ((unsigned long)ULONG_MAX) # else # ifdef MAXULONG # define PERL_ULONG_MAX ((unsigned long)MAXULONG) # else # define PERL_ULONG_MAX (~(unsigned long)0) # endif # endif #endif #ifndef PERL_ULONG_MIN # define PERL_ULONG_MIN ((unsigned long)0L) #endif #ifndef PERL_LONG_MAX # ifdef LONG_MAX # define PERL_LONG_MAX ((long)LONG_MAX) # else # ifdef MAXLONG # define PERL_LONG_MAX ((long)MAXLONG) # else # define PERL_LONG_MAX ((long) (PERL_ULONG_MAX >> 1)) # endif # endif #endif #ifndef PERL_LONG_MIN # ifdef LONG_MIN # define PERL_LONG_MIN ((long)LONG_MIN) # else # ifdef MINLONG # define PERL_LONG_MIN ((long)MINLONG) # else # define PERL_LONG_MIN (-PERL_LONG_MAX - ((3 & -1) == 3)) # endif # endif #endif #if defined(HAS_QUAD) && (defined(convex) || defined(uts)) # ifndef PERL_UQUAD_MAX # ifdef ULONGLONG_MAX # define PERL_UQUAD_MAX ((unsigned long long)ULONGLONG_MAX) # else # ifdef MAXULONGLONG # define PERL_UQUAD_MAX ((unsigned long long)MAXULONGLONG) # else # define PERL_UQUAD_MAX (~(unsigned long long)0) # endif # endif # endif # ifndef PERL_UQUAD_MIN # define PERL_UQUAD_MIN ((unsigned long long)0L) # endif # ifndef PERL_QUAD_MAX # ifdef LONGLONG_MAX # define PERL_QUAD_MAX ((long long)LONGLONG_MAX) # else # ifdef MAXLONGLONG # define PERL_QUAD_MAX ((long long)MAXLONGLONG) # else # define PERL_QUAD_MAX ((long long) (PERL_UQUAD_MAX >> 1)) # endif # endif # endif # ifndef PERL_QUAD_MIN # ifdef LONGLONG_MIN # define PERL_QUAD_MIN ((long long)LONGLONG_MIN) # else # ifdef MINLONGLONG # define PERL_QUAD_MIN ((long long)MINLONGLONG) # else # define PERL_QUAD_MIN (-PERL_QUAD_MAX - ((3 & -1) == 3)) # endif # endif # endif #endif /* This is based on code from 5.003 perl.h */ #ifdef HAS_QUAD # ifdef cray #ifndef IVTYPE # define IVTYPE int #endif #ifndef IV_MIN # define IV_MIN PERL_INT_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_INT_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_UINT_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_UINT_MAX #endif # ifdef INTSIZE #ifndef IVSIZE # define IVSIZE INTSIZE #endif # endif # else # if defined(convex) || defined(uts) #ifndef IVTYPE # define IVTYPE long long #endif #ifndef IV_MIN # define IV_MIN PERL_QUAD_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_QUAD_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_UQUAD_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_UQUAD_MAX #endif # ifdef LONGLONGSIZE #ifndef IVSIZE # define IVSIZE LONGLONGSIZE #endif # endif # else #ifndef IVTYPE # define IVTYPE long #endif #ifndef IV_MIN # define IV_MIN PERL_LONG_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_LONG_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_ULONG_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_ULONG_MAX #endif # ifdef LONGSIZE #ifndef IVSIZE # define IVSIZE LONGSIZE #endif # endif # endif # endif #ifndef IVSIZE # define IVSIZE 8 #endif #ifndef LONGSIZE # define LONGSIZE 8 #endif #ifndef PERL_QUAD_MIN # define PERL_QUAD_MIN IV_MIN #endif #ifndef PERL_QUAD_MAX # define PERL_QUAD_MAX IV_MAX #endif #ifndef PERL_UQUAD_MIN # define PERL_UQUAD_MIN UV_MIN #endif #ifndef PERL_UQUAD_MAX # define PERL_UQUAD_MAX UV_MAX #endif #else #ifndef IVTYPE # define IVTYPE long #endif #ifndef LONGSIZE # define LONGSIZE 4 #endif #ifndef IV_MIN # define IV_MIN PERL_LONG_MIN #endif #ifndef IV_MAX # define IV_MAX PERL_LONG_MAX #endif #ifndef UV_MIN # define UV_MIN PERL_ULONG_MIN #endif #ifndef UV_MAX # define UV_MAX PERL_ULONG_MAX #endif #endif #ifndef IVSIZE # ifdef LONGSIZE # define IVSIZE LONGSIZE # else # define IVSIZE 4 /* A bold guess, but the best we can make. */ # endif #endif #ifndef UVTYPE # define UVTYPE unsigned IVTYPE #endif #ifndef UVSIZE # define UVSIZE IVSIZE #endif #ifndef sv_setuv # define sv_setuv(sv, uv) \ STMT_START { \ UV TeMpUv = uv; \ if (TeMpUv <= IV_MAX) \ sv_setiv(sv, TeMpUv); \ else \ sv_setnv(sv, (double)TeMpUv); \ } STMT_END #endif #ifndef newSVuv # define newSVuv(uv) ((uv) <= IV_MAX ? newSViv((IV)uv) : newSVnv((NV)uv)) #endif #ifndef sv_2uv # define sv_2uv(sv) ((PL_Sv = (sv)), (UV) (SvNOK(PL_Sv) ? SvNV(PL_Sv) : sv_2nv(PL_Sv))) #endif #ifndef SvUVX # define SvUVX(sv) ((UV)SvIVX(sv)) #endif #ifndef SvUVXx # define SvUVXx(sv) SvUVX(sv) #endif #ifndef SvUV # define SvUV(sv) (SvIOK(sv) ? SvUVX(sv) : sv_2uv(sv)) #endif #ifndef SvUVx # define SvUVx(sv) ((PL_Sv = (sv)), SvUV(PL_Sv)) #endif /* Hint: sv_uv * Always use the SvUVx() macro instead of sv_uv(). */ #ifndef sv_uv # define sv_uv(sv) SvUVx(sv) #endif #if !defined(SvUOK) && defined(SvIOK_UV) # define SvUOK(sv) SvIOK_UV(sv) #endif #ifndef XST_mUV # define XST_mUV(i,v) (ST(i) = sv_2mortal(newSVuv(v)) ) #endif #ifndef XSRETURN_UV # define XSRETURN_UV(v) STMT_START { XST_mUV(0,v); XSRETURN(1); } STMT_END #endif #ifndef PUSHu # define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END #endif #ifndef XPUSHu # define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END #endif #ifdef HAS_MEMCMP #ifndef memNE # define memNE(s1,s2,l) (memcmp(s1,s2,l)) #endif #ifndef memEQ # define memEQ(s1,s2,l) (!memcmp(s1,s2,l)) #endif #else #ifndef memNE # define memNE(s1,s2,l) (bcmp(s1,s2,l)) #endif #ifndef memEQ # define memEQ(s1,s2,l) (!bcmp(s1,s2,l)) #endif #endif #ifndef memEQs # define memEQs(s1, l, s2) \ (sizeof(s2)-1 == l && memEQ(s1, (s2 ""), (sizeof(s2)-1))) #endif #ifndef memNEs # define memNEs(s1, l, s2) !memEQs(s1, l, s2) #endif #ifndef MoveD # define MoveD(s,d,n,t) memmove((char*)(d),(char*)(s), (n) * sizeof(t)) #endif #ifndef CopyD # define CopyD(s,d,n,t) memcpy((char*)(d),(char*)(s), (n) * sizeof(t)) #endif #ifdef HAS_MEMSET #ifndef ZeroD # define ZeroD(d,n,t) memzero((char*)(d), (n) * sizeof(t)) #endif #else #ifndef ZeroD # define ZeroD(d,n,t) ((void)memzero((char*)(d), (n) * sizeof(t)), d) #endif #endif #ifndef PoisonWith # define PoisonWith(d,n,t,b) (void)memset((char*)(d), (U8)(b), (n) * sizeof(t)) #endif #ifndef PoisonNew # define PoisonNew(d,n,t) PoisonWith(d,n,t,0xAB) #endif #ifndef PoisonFree # define PoisonFree(d,n,t) PoisonWith(d,n,t,0xEF) #endif #ifndef Poison # define Poison(d,n,t) PoisonFree(d,n,t) #endif #ifndef Newx # define Newx(v,n,t) New(0,v,n,t) #endif #ifndef Newxc # define Newxc(v,n,t,c) Newc(0,v,n,t,c) #endif #ifndef Newxz # define Newxz(v,n,t) Newz(0,v,n,t) #endif #ifndef PERL_UNUSED_DECL # ifdef HASATTRIBUTE # if (defined(__GNUC__) && defined(__cplusplus)) || defined(__INTEL_COMPILER) # define PERL_UNUSED_DECL # else # define PERL_UNUSED_DECL __attribute__((unused)) # endif # else # define PERL_UNUSED_DECL # endif #endif #ifndef PERL_UNUSED_ARG # if defined(lint) && defined(S_SPLINT_S) /* www.splint.org */ # include # define PERL_UNUSED_ARG(x) NOTE(ARGUNUSED(x)) # else # define PERL_UNUSED_ARG(x) ((void)x) # endif #endif #ifndef PERL_UNUSED_VAR # define PERL_UNUSED_VAR(x) ((void)x) #endif #ifndef PERL_UNUSED_CONTEXT # ifdef USE_ITHREADS # define PERL_UNUSED_CONTEXT PERL_UNUSED_ARG(my_perl) # else # define PERL_UNUSED_CONTEXT # endif #endif #ifndef NOOP # define NOOP /*EMPTY*/(void)0 #endif #ifndef dNOOP # define dNOOP extern int /*@unused@*/ Perl___notused PERL_UNUSED_DECL #endif #ifndef NVTYPE # if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) # define NVTYPE long double # else # define NVTYPE double # endif typedef NVTYPE NV; #endif #ifndef INT2PTR # if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE) # define PTRV UV # define INT2PTR(any,d) (any)(d) # else # if PTRSIZE == LONGSIZE # define PTRV unsigned long # else # define PTRV unsigned # endif # define INT2PTR(any,d) (any)(PTRV)(d) # endif #endif #ifndef PTR2ul # if PTRSIZE == LONGSIZE # define PTR2ul(p) (unsigned long)(p) # else # define PTR2ul(p) INT2PTR(unsigned long,p) # endif #endif #ifndef PTR2nat # define PTR2nat(p) (PTRV)(p) #endif #ifndef NUM2PTR # define NUM2PTR(any,d) (any)PTR2nat(d) #endif #ifndef PTR2IV # define PTR2IV(p) INT2PTR(IV,p) #endif #ifndef PTR2UV # define PTR2UV(p) INT2PTR(UV,p) #endif #ifndef PTR2NV # define PTR2NV(p) NUM2PTR(NV,p) #endif #undef START_EXTERN_C #undef END_EXTERN_C #undef EXTERN_C #ifdef __cplusplus # define START_EXTERN_C extern "C" { # define END_EXTERN_C } # define EXTERN_C extern "C" #else # define START_EXTERN_C # define END_EXTERN_C # define EXTERN_C extern #endif #if defined(PERL_GCC_PEDANTIC) # ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN # define PERL_GCC_BRACE_GROUPS_FORBIDDEN # endif #endif #if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus) # ifndef PERL_USE_GCC_BRACE_GROUPS # define PERL_USE_GCC_BRACE_GROUPS # endif #endif #undef STMT_START #undef STMT_END #ifdef PERL_USE_GCC_BRACE_GROUPS # define STMT_START (void)( /* gcc supports ``({ STATEMENTS; })'' */ # define STMT_END ) #else # if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__) # define STMT_START if (1) # define STMT_END else (void)0 # else # define STMT_START do # define STMT_END while (0) # endif #endif #ifndef boolSV # define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no) #endif /* DEFSV appears first in 5.004_56 */ #ifndef DEFSV # define DEFSV GvSV(PL_defgv) #endif #ifndef SAVE_DEFSV # define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv)) #endif #ifndef DEFSV_set # define DEFSV_set(sv) (DEFSV = (sv)) #endif /* Older perls (<=5.003) lack AvFILLp */ #ifndef AvFILLp # define AvFILLp AvFILL #endif #ifndef ERRSV # define ERRSV get_sv("@",FALSE) #endif /* Hint: gv_stashpvn * This function's backport doesn't support the length parameter, but * rather ignores it. Portability can only be ensured if the length * parameter is used for speed reasons, but the length can always be * correctly computed from the string argument. */ #ifndef gv_stashpvn # define gv_stashpvn(str,len,create) gv_stashpv(str,create) #endif /* Replace: 1 */ #ifndef get_cv # define get_cv perl_get_cv #endif #ifndef get_sv # define get_sv perl_get_sv #endif #ifndef get_av # define get_av perl_get_av #endif #ifndef get_hv # define get_hv perl_get_hv #endif /* Replace: 0 */ #ifndef dUNDERBAR # define dUNDERBAR dNOOP #endif #ifndef UNDERBAR # define UNDERBAR DEFSV #endif #ifndef dAX # define dAX I32 ax = MARK - PL_stack_base + 1 #endif #ifndef dITEMS # define dITEMS I32 items = SP - MARK #endif #ifndef dXSTARG # define dXSTARG SV * targ = sv_newmortal() #endif #ifndef dAXMARK # define dAXMARK I32 ax = POPMARK; \ register SV ** const mark = PL_stack_base + ax++ #endif #ifndef XSprePUSH # define XSprePUSH (sp = PL_stack_base + ax - 1) #endif #if (PERL_BCDVERSION < 0x5005000) # undef XSRETURN # define XSRETURN(off) \ STMT_START { \ PL_stack_sp = PL_stack_base + ax + ((off) - 1); \ return; \ } STMT_END #endif #ifndef XSPROTO # define XSPROTO(name) void name(pTHX_ CV* cv) #endif #ifndef SVfARG # define SVfARG(p) ((void*)(p)) #endif #ifndef PERL_ABS # define PERL_ABS(x) ((x) < 0 ? -(x) : (x)) #endif #ifndef dVAR # define dVAR dNOOP #endif #ifndef SVf # define SVf "_" #endif #ifndef UTF8_MAXBYTES # define UTF8_MAXBYTES UTF8_MAXLEN #endif #ifndef CPERLscope # define CPERLscope(x) x #endif #ifndef PERL_HASH # define PERL_HASH(hash,str,len) \ STMT_START { \ const char *s_PeRlHaSh = str; \ I32 i_PeRlHaSh = len; \ U32 hash_PeRlHaSh = 0; \ while (i_PeRlHaSh--) \ hash_PeRlHaSh = hash_PeRlHaSh * 33 + *s_PeRlHaSh++; \ (hash) = hash_PeRlHaSh; \ } STMT_END #endif #ifndef PERLIO_FUNCS_DECL # ifdef PERLIO_FUNCS_CONST # define PERLIO_FUNCS_DECL(funcs) const PerlIO_funcs funcs # define PERLIO_FUNCS_CAST(funcs) (PerlIO_funcs*)(funcs) # else # define PERLIO_FUNCS_DECL(funcs) PerlIO_funcs funcs # define PERLIO_FUNCS_CAST(funcs) (funcs) # endif #endif /* provide these typedefs for older perls */ #if (PERL_BCDVERSION < 0x5009003) # ifdef ARGSproto typedef OP* (CPERLscope(*Perl_ppaddr_t))(ARGSproto); # else typedef OP* (CPERLscope(*Perl_ppaddr_t))(pTHX); # endif typedef OP* (CPERLscope(*Perl_check_t)) (pTHX_ OP*); #endif #ifndef isPSXSPC # define isPSXSPC(c) (isSPACE(c) || (c) == '\v') #endif #ifndef isBLANK # define isBLANK(c) ((c) == ' ' || (c) == '\t') #endif #ifdef EBCDIC #ifndef isALNUMC # define isALNUMC(c) isalnum(c) #endif #ifndef isASCII # define isASCII(c) isascii(c) #endif #ifndef isCNTRL # define isCNTRL(c) iscntrl(c) #endif #ifndef isGRAPH # define isGRAPH(c) isgraph(c) #endif #ifndef isPRINT # define isPRINT(c) isprint(c) #endif #ifndef isPUNCT # define isPUNCT(c) ispunct(c) #endif #ifndef isXDIGIT # define isXDIGIT(c) isxdigit(c) #endif #else # if (PERL_BCDVERSION < 0x5010000) /* Hint: isPRINT * The implementation in older perl versions includes all of the * isSPACE() characters, which is wrong. The version provided by * Devel::PPPort always overrides a present buggy version. */ # undef isPRINT # endif #ifdef HAS_QUAD # define WIDEST_UTYPE U64TYPE #else # define WIDEST_UTYPE U32 #endif #ifndef isALNUMC # define isALNUMC(c) (isALPHA(c) || isDIGIT(c)) #endif #ifndef isASCII # define isASCII(c) ((WIDEST_UTYPE) (c) <= 127) #endif #ifndef isCNTRL # define isCNTRL(c) ((WIDEST_UTYPE) (c) < ' ' || (c) == 127) #endif #ifndef isGRAPH # define isGRAPH(c) (isALNUM(c) || isPUNCT(c)) #endif #ifndef isPRINT # define isPRINT(c) (((c) >= 32 && (c) < 127)) #endif #ifndef isPUNCT # define isPUNCT(c) (((c) >= 33 && (c) <= 47) || ((c) >= 58 && (c) <= 64) || ((c) >= 91 && (c) <= 96) || ((c) >= 123 && (c) <= 126)) #endif #ifndef isXDIGIT # define isXDIGIT(c) (isDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) #endif #endif #ifndef PERL_SIGNALS_UNSAFE_FLAG #define PERL_SIGNALS_UNSAFE_FLAG 0x0001 #if (PERL_BCDVERSION < 0x5008000) # define D_PPP_PERL_SIGNALS_INIT PERL_SIGNALS_UNSAFE_FLAG #else # define D_PPP_PERL_SIGNALS_INIT 0 #endif #if defined(NEED_PL_signals) static U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; #elif defined(NEED_PL_signals_GLOBAL) U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; #else extern U32 DPPP_(my_PL_signals); #endif #define PL_signals DPPP_(my_PL_signals) #endif /* Hint: PL_ppaddr * Calling an op via PL_ppaddr requires passing a context argument * for threaded builds. Since the context argument is different for * 5.005 perls, you can use aTHXR (supplied by ppport.h), which will * automatically be defined as the correct argument. */ #if (PERL_BCDVERSION <= 0x5005005) /* Replace: 1 */ # define PL_ppaddr ppaddr # define PL_no_modify no_modify /* Replace: 0 */ #endif #if (PERL_BCDVERSION <= 0x5004005) /* Replace: 1 */ # define PL_DBsignal DBsignal # define PL_DBsingle DBsingle # define PL_DBsub DBsub # define PL_DBtrace DBtrace # define PL_Sv Sv # define PL_bufend bufend # define PL_bufptr bufptr # define PL_compiling compiling # define PL_copline copline # define PL_curcop curcop # define PL_curstash curstash # define PL_debstash debstash # define PL_defgv defgv # define PL_diehook diehook # define PL_dirty dirty # define PL_dowarn dowarn # define PL_errgv errgv # define PL_error_count error_count # define PL_expect expect # define PL_hexdigit hexdigit # define PL_hints hints # define PL_in_my in_my # define PL_laststatval laststatval # define PL_lex_state lex_state # define PL_lex_stuff lex_stuff # define PL_linestr linestr # define PL_na na # define PL_perl_destruct_level perl_destruct_level # define PL_perldb perldb # define PL_rsfp_filters rsfp_filters # define PL_rsfp rsfp # define PL_stack_base stack_base # define PL_stack_sp stack_sp # define PL_statcache statcache # define PL_stdingv stdingv # define PL_sv_arenaroot sv_arenaroot # define PL_sv_no sv_no # define PL_sv_undef sv_undef # define PL_sv_yes sv_yes # define PL_tainted tainted # define PL_tainting tainting # define PL_tokenbuf tokenbuf /* Replace: 0 */ #endif /* Warning: PL_parser * For perl versions earlier than 5.9.5, this is an always * non-NULL dummy. Also, it cannot be dereferenced. Don't * use it if you can avoid is and unless you absolutely know * what you're doing. * If you always check that PL_parser is non-NULL, you can * define DPPP_PL_parser_NO_DUMMY to avoid the creation of * a dummy parser structure. */ #if (PERL_BCDVERSION >= 0x5009005) # ifdef DPPP_PL_parser_NO_DUMMY # define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ (croak("panic: PL_parser == NULL in %s:%d", \ __FILE__, __LINE__), (yy_parser *) NULL))->var) # else # ifdef DPPP_PL_parser_NO_DUMMY_WARNING # define D_PPP_parser_dummy_warning(var) # else # define D_PPP_parser_dummy_warning(var) \ warn("warning: dummy PL_" #var " used in %s:%d", __FILE__, __LINE__), # endif # define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ (D_PPP_parser_dummy_warning(var) &DPPP_(dummy_PL_parser)))->var) #if defined(NEED_PL_parser) static yy_parser DPPP_(dummy_PL_parser); #elif defined(NEED_PL_parser_GLOBAL) yy_parser DPPP_(dummy_PL_parser); #else extern yy_parser DPPP_(dummy_PL_parser); #endif # endif /* PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf depends on PL_parser */ /* Warning: PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf * Do not use this variable unless you know exactly what you're * doint. It is internal to the perl parser and may change or even * be removed in the future. As of perl 5.9.5, you have to check * for (PL_parser != NULL) for this variable to have any effect. * An always non-NULL PL_parser dummy is provided for earlier * perl versions. * If PL_parser is NULL when you try to access this variable, a * dummy is being accessed instead and a warning is issued unless * you define DPPP_PL_parser_NO_DUMMY_WARNING. * If DPPP_PL_parser_NO_DUMMY is defined, the code trying to access * this variable will croak with a panic message. */ # define PL_expect D_PPP_my_PL_parser_var(expect) # define PL_copline D_PPP_my_PL_parser_var(copline) # define PL_rsfp D_PPP_my_PL_parser_var(rsfp) # define PL_rsfp_filters D_PPP_my_PL_parser_var(rsfp_filters) # define PL_linestr D_PPP_my_PL_parser_var(linestr) # define PL_bufptr D_PPP_my_PL_parser_var(bufptr) # define PL_bufend D_PPP_my_PL_parser_var(bufend) # define PL_lex_state D_PPP_my_PL_parser_var(lex_state) # define PL_lex_stuff D_PPP_my_PL_parser_var(lex_stuff) # define PL_tokenbuf D_PPP_my_PL_parser_var(tokenbuf) # define PL_in_my D_PPP_my_PL_parser_var(in_my) # define PL_in_my_stash D_PPP_my_PL_parser_var(in_my_stash) # define PL_error_count D_PPP_my_PL_parser_var(error_count) #else /* ensure that PL_parser != NULL and cannot be dereferenced */ # define PL_parser ((void *) 1) #endif #ifndef mPUSHs # define mPUSHs(s) PUSHs(sv_2mortal(s)) #endif #ifndef PUSHmortal # define PUSHmortal PUSHs(sv_newmortal()) #endif #ifndef mPUSHp # define mPUSHp(p,l) sv_setpvn(PUSHmortal, (p), (l)) #endif #ifndef mPUSHn # define mPUSHn(n) sv_setnv(PUSHmortal, (NV)(n)) #endif #ifndef mPUSHi # define mPUSHi(i) sv_setiv(PUSHmortal, (IV)(i)) #endif #ifndef mPUSHu # define mPUSHu(u) sv_setuv(PUSHmortal, (UV)(u)) #endif #ifndef mXPUSHs # define mXPUSHs(s) XPUSHs(sv_2mortal(s)) #endif #ifndef XPUSHmortal # define XPUSHmortal XPUSHs(sv_newmortal()) #endif #ifndef mXPUSHp # define mXPUSHp(p,l) STMT_START { EXTEND(sp,1); sv_setpvn(PUSHmortal, (p), (l)); } STMT_END #endif #ifndef mXPUSHn # define mXPUSHn(n) STMT_START { EXTEND(sp,1); sv_setnv(PUSHmortal, (NV)(n)); } STMT_END #endif #ifndef mXPUSHi # define mXPUSHi(i) STMT_START { EXTEND(sp,1); sv_setiv(PUSHmortal, (IV)(i)); } STMT_END #endif #ifndef mXPUSHu # define mXPUSHu(u) STMT_START { EXTEND(sp,1); sv_setuv(PUSHmortal, (UV)(u)); } STMT_END #endif /* Replace: 1 */ #ifndef call_sv # define call_sv perl_call_sv #endif #ifndef call_pv # define call_pv perl_call_pv #endif #ifndef call_argv # define call_argv perl_call_argv #endif #ifndef call_method # define call_method perl_call_method #endif #ifndef eval_sv # define eval_sv perl_eval_sv #endif /* Replace: 0 */ #ifndef PERL_LOADMOD_DENY # define PERL_LOADMOD_DENY 0x1 #endif #ifndef PERL_LOADMOD_NOIMPORT # define PERL_LOADMOD_NOIMPORT 0x2 #endif #ifndef PERL_LOADMOD_IMPORT_OPS # define PERL_LOADMOD_IMPORT_OPS 0x4 #endif #ifndef G_METHOD # define G_METHOD 64 # ifdef call_sv # undef call_sv # endif # if (PERL_BCDVERSION < 0x5006000) # define call_sv(sv, flags) ((flags) & G_METHOD ? perl_call_method((char *) SvPV_nolen_const(sv), \ (flags) & ~G_METHOD) : perl_call_sv(sv, flags)) # else # define call_sv(sv, flags) ((flags) & G_METHOD ? Perl_call_method(aTHX_ (char *) SvPV_nolen_const(sv), \ (flags) & ~G_METHOD) : Perl_call_sv(aTHX_ sv, flags)) # endif #endif /* Replace perl_eval_pv with eval_pv */ #ifndef eval_pv #if defined(NEED_eval_pv) static SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); static #else extern SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); #endif #ifdef eval_pv # undef eval_pv #endif #define eval_pv(a,b) DPPP_(my_eval_pv)(aTHX_ a,b) #define Perl_eval_pv DPPP_(my_eval_pv) #if defined(NEED_eval_pv) || defined(NEED_eval_pv_GLOBAL) SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error) { dSP; SV* sv = newSVpv(p, 0); PUSHMARK(sp); eval_sv(sv, G_SCALAR); SvREFCNT_dec(sv); SPAGAIN; sv = POPs; PUTBACK; if (croak_on_error && SvTRUE(GvSV(errgv))) croak(SvPVx(GvSV(errgv), na)); return sv; } #endif #endif #ifndef vload_module #if defined(NEED_vload_module) static void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); static #else extern void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); #endif #ifdef vload_module # undef vload_module #endif #define vload_module(a,b,c,d) DPPP_(my_vload_module)(aTHX_ a,b,c,d) #define Perl_vload_module DPPP_(my_vload_module) #if defined(NEED_vload_module) || defined(NEED_vload_module_GLOBAL) void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args) { dTHR; dVAR; OP *veop, *imop; OP * const modname = newSVOP(OP_CONST, 0, name); /* 5.005 has a somewhat hacky force_normal that doesn't croak on SvREADONLY() if PL_compling is true. Current perls take care in ck_require() to correctly turn off SvREADONLY before calling force_normal_flags(). This seems a better fix than fudging PL_compling */ SvREADONLY_off(((SVOP*)modname)->op_sv); modname->op_private |= OPpCONST_BARE; if (ver) { veop = newSVOP(OP_CONST, 0, ver); } else veop = NULL; if (flags & PERL_LOADMOD_NOIMPORT) { imop = sawparens(newNULLLIST()); } else if (flags & PERL_LOADMOD_IMPORT_OPS) { imop = va_arg(*args, OP*); } else { SV *sv; imop = NULL; sv = va_arg(*args, SV*); while (sv) { imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv)); sv = va_arg(*args, SV*); } } { const line_t ocopline = PL_copline; COP * const ocurcop = PL_curcop; const int oexpect = PL_expect; #if (PERL_BCDVERSION >= 0x5004000) utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0), veop, modname, imop); #else utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(), modname, imop); #endif PL_expect = oexpect; PL_copline = ocopline; PL_curcop = ocurcop; } } #endif #endif #ifndef load_module #if defined(NEED_load_module) static void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); static #else extern void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); #endif #ifdef load_module # undef load_module #endif #define load_module DPPP_(my_load_module) #define Perl_load_module DPPP_(my_load_module) #if defined(NEED_load_module) || defined(NEED_load_module_GLOBAL) void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...) { va_list args; va_start(args, ver); vload_module(flags, name, ver, &args); va_end(args); } #endif #endif #ifndef newRV_inc # define newRV_inc(sv) newRV(sv) /* Replace */ #endif #ifndef newRV_noinc #if defined(NEED_newRV_noinc) static SV * DPPP_(my_newRV_noinc)(SV *sv); static #else extern SV * DPPP_(my_newRV_noinc)(SV *sv); #endif #ifdef newRV_noinc # undef newRV_noinc #endif #define newRV_noinc(a) DPPP_(my_newRV_noinc)(aTHX_ a) #define Perl_newRV_noinc DPPP_(my_newRV_noinc) #if defined(NEED_newRV_noinc) || defined(NEED_newRV_noinc_GLOBAL) SV * DPPP_(my_newRV_noinc)(SV *sv) { SV *rv = (SV *)newRV(sv); SvREFCNT_dec(sv); return rv; } #endif #endif /* Hint: newCONSTSUB * Returns a CV* as of perl-5.7.1. This return value is not supported * by Devel::PPPort. */ /* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */ #if (PERL_BCDVERSION < 0x5004063) && (PERL_BCDVERSION != 0x5004005) #if defined(NEED_newCONSTSUB) static void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); static #else extern void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); #endif #ifdef newCONSTSUB # undef newCONSTSUB #endif #define newCONSTSUB(a,b,c) DPPP_(my_newCONSTSUB)(aTHX_ a,b,c) #define Perl_newCONSTSUB DPPP_(my_newCONSTSUB) #if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL) /* This is just a trick to avoid a dependency of newCONSTSUB on PL_parser */ /* (There's no PL_parser in perl < 5.005, so this is completely safe) */ #define D_PPP_PL_copline PL_copline void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv) { U32 oldhints = PL_hints; HV *old_cop_stash = PL_curcop->cop_stash; HV *old_curstash = PL_curstash; line_t oldline = PL_curcop->cop_line; PL_curcop->cop_line = D_PPP_PL_copline; PL_hints &= ~HINT_BLOCK_SCOPE; if (stash) PL_curstash = PL_curcop->cop_stash = stash; newSUB( #if (PERL_BCDVERSION < 0x5003022) start_subparse(), #elif (PERL_BCDVERSION == 0x5003022) start_subparse(0), #else /* 5.003_23 onwards */ start_subparse(FALSE, 0), #endif newSVOP(OP_CONST, 0, newSVpv((char *) name, 0)), newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */ newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv)) ); PL_hints = oldhints; PL_curcop->cop_stash = old_cop_stash; PL_curstash = old_curstash; PL_curcop->cop_line = oldline; } #endif #endif /* * Boilerplate macros for initializing and accessing interpreter-local * data from C. All statics in extensions should be reworked to use * this, if you want to make the extension thread-safe. See ext/re/re.xs * for an example of the use of these macros. * * Code that uses these macros is responsible for the following: * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts" * 2. Declare a typedef named my_cxt_t that is a structure that contains * all the data that needs to be interpreter-local. * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t. * 4. Use the MY_CXT_INIT macro such that it is called exactly once * (typically put in the BOOT: section). * 5. Use the members of the my_cxt_t structure everywhere as * MY_CXT.member. * 6. Use the dMY_CXT macro (a declaration) in all the functions that * access MY_CXT. */ #if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \ defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT) #ifndef START_MY_CXT /* This must appear in all extensions that define a my_cxt_t structure, * right after the definition (i.e. at file scope). The non-threads * case below uses it to declare the data as static. */ #define START_MY_CXT #if (PERL_BCDVERSION < 0x5004068) /* Fetches the SV that keeps the per-interpreter data. */ #define dMY_CXT_SV \ SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE) #else /* >= perl5.004_68 */ #define dMY_CXT_SV \ SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \ sizeof(MY_CXT_KEY)-1, TRUE) #endif /* < perl5.004_68 */ /* This declaration should be used within all functions that use the * interpreter-local data. */ #define dMY_CXT \ dMY_CXT_SV; \ my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv)) /* Creates and zeroes the per-interpreter data. * (We allocate my_cxtp in a Perl SV so that it will be released when * the interpreter goes away.) */ #define MY_CXT_INIT \ dMY_CXT_SV; \ /* newSV() allocates one more than needed */ \ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ Zero(my_cxtp, 1, my_cxt_t); \ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) /* This macro must be used to access members of the my_cxt_t structure. * e.g. MYCXT.some_data */ #define MY_CXT (*my_cxtp) /* Judicious use of these macros can reduce the number of times dMY_CXT * is used. Use is similar to pTHX, aTHX etc. */ #define pMY_CXT my_cxt_t *my_cxtp #define pMY_CXT_ pMY_CXT, #define _pMY_CXT ,pMY_CXT #define aMY_CXT my_cxtp #define aMY_CXT_ aMY_CXT, #define _aMY_CXT ,aMY_CXT #endif /* START_MY_CXT */ #ifndef MY_CXT_CLONE /* Clones the per-interpreter data. */ #define MY_CXT_CLONE \ dMY_CXT_SV; \ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) #endif #else /* single interpreter */ #ifndef START_MY_CXT #define START_MY_CXT static my_cxt_t my_cxt; #define dMY_CXT_SV dNOOP #define dMY_CXT dNOOP #define MY_CXT_INIT NOOP #define MY_CXT my_cxt #define pMY_CXT void #define pMY_CXT_ #define _pMY_CXT #define aMY_CXT #define aMY_CXT_ #define _aMY_CXT #endif /* START_MY_CXT */ #ifndef MY_CXT_CLONE #define MY_CXT_CLONE NOOP #endif #endif #ifndef IVdf # if IVSIZE == LONGSIZE # define IVdf "ld" # define UVuf "lu" # define UVof "lo" # define UVxf "lx" # define UVXf "lX" # elif IVSIZE == INTSIZE # define IVdf "d" # define UVuf "u" # define UVof "o" # define UVxf "x" # define UVXf "X" # else # error "cannot define IV/UV formats" # endif #endif #ifndef NVef # if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \ defined(PERL_PRIfldbl) && (PERL_BCDVERSION != 0x5006000) /* Not very likely, but let's try anyway. */ # define NVef PERL_PRIeldbl # define NVff PERL_PRIfldbl # define NVgf PERL_PRIgldbl # else # define NVef "e" # define NVff "f" # define NVgf "g" # endif #endif #ifndef SvREFCNT_inc # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc(sv) \ ({ \ SV * const _sv = (SV*)(sv); \ if (_sv) \ (SvREFCNT(_sv))++; \ _sv; \ }) # else # define SvREFCNT_inc(sv) \ ((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL) # endif #endif #ifndef SvREFCNT_inc_simple # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc_simple(sv) \ ({ \ if (sv) \ (SvREFCNT(sv))++; \ (SV *)(sv); \ }) # else # define SvREFCNT_inc_simple(sv) \ ((sv) ? (SvREFCNT(sv)++,(SV*)(sv)) : NULL) # endif #endif #ifndef SvREFCNT_inc_NN # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc_NN(sv) \ ({ \ SV * const _sv = (SV*)(sv); \ SvREFCNT(_sv)++; \ _sv; \ }) # else # define SvREFCNT_inc_NN(sv) \ (PL_Sv=(SV*)(sv),++(SvREFCNT(PL_Sv)),PL_Sv) # endif #endif #ifndef SvREFCNT_inc_void # ifdef PERL_USE_GCC_BRACE_GROUPS # define SvREFCNT_inc_void(sv) \ ({ \ SV * const _sv = (SV*)(sv); \ if (_sv) \ (void)(SvREFCNT(_sv)++); \ }) # else # define SvREFCNT_inc_void(sv) \ (void)((PL_Sv=(SV*)(sv)) ? ++(SvREFCNT(PL_Sv)) : 0) # endif #endif #ifndef SvREFCNT_inc_simple_void # define SvREFCNT_inc_simple_void(sv) STMT_START { if (sv) SvREFCNT(sv)++; } STMT_END #endif #ifndef SvREFCNT_inc_simple_NN # define SvREFCNT_inc_simple_NN(sv) (++SvREFCNT(sv), (SV*)(sv)) #endif #ifndef SvREFCNT_inc_void_NN # define SvREFCNT_inc_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) #endif #ifndef SvREFCNT_inc_simple_void_NN # define SvREFCNT_inc_simple_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) #endif #ifndef newSV_type #if defined(NEED_newSV_type) static SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); static #else extern SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); #endif #ifdef newSV_type # undef newSV_type #endif #define newSV_type(a) DPPP_(my_newSV_type)(aTHX_ a) #define Perl_newSV_type DPPP_(my_newSV_type) #if defined(NEED_newSV_type) || defined(NEED_newSV_type_GLOBAL) SV* DPPP_(my_newSV_type)(pTHX_ svtype const t) { SV* const sv = newSV(0); sv_upgrade(sv, t); return sv; } #endif #endif #if (PERL_BCDVERSION < 0x5006000) # define D_PPP_CONSTPV_ARG(x) ((char *) (x)) #else # define D_PPP_CONSTPV_ARG(x) (x) #endif #ifndef newSVpvn # define newSVpvn(data,len) ((data) \ ? ((len) ? newSVpv((data), (len)) : newSVpv("", 0)) \ : newSV(0)) #endif #ifndef newSVpvn_utf8 # define newSVpvn_utf8(s, len, u) newSVpvn_flags((s), (len), (u) ? SVf_UTF8 : 0) #endif #ifndef SVf_UTF8 # define SVf_UTF8 0 #endif #ifndef newSVpvn_flags #if defined(NEED_newSVpvn_flags) static SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); static #else extern SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); #endif #ifdef newSVpvn_flags # undef newSVpvn_flags #endif #define newSVpvn_flags(a,b,c) DPPP_(my_newSVpvn_flags)(aTHX_ a,b,c) #define Perl_newSVpvn_flags DPPP_(my_newSVpvn_flags) #if defined(NEED_newSVpvn_flags) || defined(NEED_newSVpvn_flags_GLOBAL) SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags) { SV *sv = newSVpvn(D_PPP_CONSTPV_ARG(s), len); SvFLAGS(sv) |= (flags & SVf_UTF8); return (flags & SVs_TEMP) ? sv_2mortal(sv) : sv; } #endif #endif /* Backwards compatibility stuff... :-( */ #if !defined(NEED_sv_2pv_flags) && defined(NEED_sv_2pv_nolen) # define NEED_sv_2pv_flags #endif #if !defined(NEED_sv_2pv_flags_GLOBAL) && defined(NEED_sv_2pv_nolen_GLOBAL) # define NEED_sv_2pv_flags_GLOBAL #endif /* Hint: sv_2pv_nolen * Use the SvPV_nolen() or SvPV_nolen_const() macros instead of sv_2pv_nolen(). */ #ifndef sv_2pv_nolen # define sv_2pv_nolen(sv) SvPV_nolen(sv) #endif #ifdef SvPVbyte /* Hint: SvPVbyte * Does not work in perl-5.6.1, ppport.h implements a version * borrowed from perl-5.7.3. */ #if (PERL_BCDVERSION < 0x5007000) #if defined(NEED_sv_2pvbyte) static char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); static #else extern char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); #endif #ifdef sv_2pvbyte # undef sv_2pvbyte #endif #define sv_2pvbyte(a,b) DPPP_(my_sv_2pvbyte)(aTHX_ a,b) #define Perl_sv_2pvbyte DPPP_(my_sv_2pvbyte) #if defined(NEED_sv_2pvbyte) || defined(NEED_sv_2pvbyte_GLOBAL) char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp) { sv_utf8_downgrade(sv,0); return SvPV(sv,*lp); } #endif /* Hint: sv_2pvbyte * Use the SvPVbyte() macro instead of sv_2pvbyte(). */ #undef SvPVbyte #define SvPVbyte(sv, lp) \ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp)) #endif #else # define SvPVbyte SvPV # define sv_2pvbyte sv_2pv #endif #ifndef sv_2pvbyte_nolen # define sv_2pvbyte_nolen(sv) sv_2pv_nolen(sv) #endif /* Hint: sv_pvn * Always use the SvPV() macro instead of sv_pvn(). */ /* Hint: sv_pvn_force * Always use the SvPV_force() macro instead of sv_pvn_force(). */ /* If these are undefined, they're not handled by the core anyway */ #ifndef SV_IMMEDIATE_UNREF # define SV_IMMEDIATE_UNREF 0 #endif #ifndef SV_GMAGIC # define SV_GMAGIC 0 #endif #ifndef SV_COW_DROP_PV # define SV_COW_DROP_PV 0 #endif #ifndef SV_UTF8_NO_ENCODING # define SV_UTF8_NO_ENCODING 0 #endif #ifndef SV_NOSTEAL # define SV_NOSTEAL 0 #endif #ifndef SV_CONST_RETURN # define SV_CONST_RETURN 0 #endif #ifndef SV_MUTABLE_RETURN # define SV_MUTABLE_RETURN 0 #endif #ifndef SV_SMAGIC # define SV_SMAGIC 0 #endif #ifndef SV_HAS_TRAILING_NUL # define SV_HAS_TRAILING_NUL 0 #endif #ifndef SV_COW_SHARED_HASH_KEYS # define SV_COW_SHARED_HASH_KEYS 0 #endif #if (PERL_BCDVERSION < 0x5007002) #if defined(NEED_sv_2pv_flags) static char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); static #else extern char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); #endif #ifdef sv_2pv_flags # undef sv_2pv_flags #endif #define sv_2pv_flags(a,b,c) DPPP_(my_sv_2pv_flags)(aTHX_ a,b,c) #define Perl_sv_2pv_flags DPPP_(my_sv_2pv_flags) #if defined(NEED_sv_2pv_flags) || defined(NEED_sv_2pv_flags_GLOBAL) char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) { STRLEN n_a = (STRLEN) flags; return sv_2pv(sv, lp ? lp : &n_a); } #endif #if defined(NEED_sv_pvn_force_flags) static char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); static #else extern char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); #endif #ifdef sv_pvn_force_flags # undef sv_pvn_force_flags #endif #define sv_pvn_force_flags(a,b,c) DPPP_(my_sv_pvn_force_flags)(aTHX_ a,b,c) #define Perl_sv_pvn_force_flags DPPP_(my_sv_pvn_force_flags) #if defined(NEED_sv_pvn_force_flags) || defined(NEED_sv_pvn_force_flags_GLOBAL) char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) { STRLEN n_a = (STRLEN) flags; return sv_pvn_force(sv, lp ? lp : &n_a); } #endif #endif #if (PERL_BCDVERSION < 0x5008008) || ( (PERL_BCDVERSION >= 0x5009000) && (PERL_BCDVERSION < 0x5009003) ) # define DPPP_SVPV_NOLEN_LP_ARG &PL_na #else # define DPPP_SVPV_NOLEN_LP_ARG 0 #endif #ifndef SvPV_const # define SvPV_const(sv, lp) SvPV_flags_const(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_mutable # define SvPV_mutable(sv, lp) SvPV_flags_mutable(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_flags # define SvPV_flags(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pv_flags(sv, &lp, flags)) #endif #ifndef SvPV_flags_const # define SvPV_flags_const(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX_const(sv)) : \ (const char*) sv_2pv_flags(sv, &lp, flags|SV_CONST_RETURN)) #endif #ifndef SvPV_flags_const_nolen # define SvPV_flags_const_nolen(sv, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX_const(sv) : \ (const char*) sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags|SV_CONST_RETURN)) #endif #ifndef SvPV_flags_mutable # define SvPV_flags_mutable(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) : \ sv_2pv_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) #endif #ifndef SvPV_force # define SvPV_force(sv, lp) SvPV_force_flags(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_force_nolen # define SvPV_force_nolen(sv) SvPV_force_flags_nolen(sv, SV_GMAGIC) #endif #ifndef SvPV_force_mutable # define SvPV_force_mutable(sv, lp) SvPV_force_flags_mutable(sv, lp, SV_GMAGIC) #endif #ifndef SvPV_force_nomg # define SvPV_force_nomg(sv, lp) SvPV_force_flags(sv, lp, 0) #endif #ifndef SvPV_force_nomg_nolen # define SvPV_force_nomg_nolen(sv) SvPV_force_flags_nolen(sv, 0) #endif #ifndef SvPV_force_flags # define SvPV_force_flags(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvn_force_flags(sv, &lp, flags)) #endif #ifndef SvPV_force_flags_nolen # define SvPV_force_flags_nolen(sv, flags) \ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ ? SvPVX(sv) : sv_pvn_force_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags)) #endif #ifndef SvPV_force_flags_mutable # define SvPV_force_flags_mutable(sv, lp, flags) \ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) \ : sv_pvn_force_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) #endif #ifndef SvPV_nolen # define SvPV_nolen(sv) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC)) #endif #ifndef SvPV_nolen_const # define SvPV_nolen_const(sv) \ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX_const(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC|SV_CONST_RETURN)) #endif #ifndef SvPV_nomg # define SvPV_nomg(sv, lp) SvPV_flags(sv, lp, 0) #endif #ifndef SvPV_nomg_const # define SvPV_nomg_const(sv, lp) SvPV_flags_const(sv, lp, 0) #endif #ifndef SvPV_nomg_const_nolen # define SvPV_nomg_const_nolen(sv) SvPV_flags_const_nolen(sv, 0) #endif #ifndef SvPV_nomg_nolen # define SvPV_nomg_nolen(sv) ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ ? SvPVX(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, 0)) #endif #ifndef SvPV_renew # define SvPV_renew(sv,n) STMT_START { SvLEN_set(sv, n); \ SvPV_set((sv), (char *) saferealloc( \ (Malloc_t)SvPVX(sv), (MEM_SIZE)((n)))); \ } STMT_END #endif #ifndef SvMAGIC_set # define SvMAGIC_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ (((XPVMG*) SvANY(sv))->xmg_magic = (val)); } STMT_END #endif #if (PERL_BCDVERSION < 0x5009003) #ifndef SvPVX_const # define SvPVX_const(sv) ((const char*) (0 + SvPVX(sv))) #endif #ifndef SvPVX_mutable # define SvPVX_mutable(sv) (0 + SvPVX(sv)) #endif #ifndef SvRV_set # define SvRV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ (((XRV*) SvANY(sv))->xrv_rv = (val)); } STMT_END #endif #else #ifndef SvPVX_const # define SvPVX_const(sv) ((const char*)((sv)->sv_u.svu_pv)) #endif #ifndef SvPVX_mutable # define SvPVX_mutable(sv) ((sv)->sv_u.svu_pv) #endif #ifndef SvRV_set # define SvRV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ ((sv)->sv_u.svu_rv = (val)); } STMT_END #endif #endif #ifndef SvSTASH_set # define SvSTASH_set(sv, val) \ STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ (((XPVMG*) SvANY(sv))->xmg_stash = (val)); } STMT_END #endif #if (PERL_BCDVERSION < 0x5004000) #ifndef SvUV_set # define SvUV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ (((XPVIV*) SvANY(sv))->xiv_iv = (IV) (val)); } STMT_END #endif #else #ifndef SvUV_set # define SvUV_set(sv, val) \ STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ (((XPVUV*) SvANY(sv))->xuv_uv = (val)); } STMT_END #endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(vnewSVpvf) #if defined(NEED_vnewSVpvf) static SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); static #else extern SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); #endif #ifdef vnewSVpvf # undef vnewSVpvf #endif #define vnewSVpvf(a,b) DPPP_(my_vnewSVpvf)(aTHX_ a,b) #define Perl_vnewSVpvf DPPP_(my_vnewSVpvf) #if defined(NEED_vnewSVpvf) || defined(NEED_vnewSVpvf_GLOBAL) SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args) { register SV *sv = newSV(0); sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); return sv; } #endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf) # define sv_vcatpvf(sv, pat, args) sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf) # define sv_vsetpvf(sv, pat, args) sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg) #if defined(NEED_sv_catpvf_mg) static void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); #endif #define Perl_sv_catpvf_mg DPPP_(my_sv_catpvf_mg) #if defined(NEED_sv_catpvf_mg) || defined(NEED_sv_catpvf_mg_GLOBAL) void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...) { va_list args; va_start(args, pat); sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #ifdef PERL_IMPLICIT_CONTEXT #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg_nocontext) #if defined(NEED_sv_catpvf_mg_nocontext) static void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); #endif #define sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) #define Perl_sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) #if defined(NEED_sv_catpvf_mg_nocontext) || defined(NEED_sv_catpvf_mg_nocontext_GLOBAL) void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...) { dTHX; va_list args; va_start(args, pat); sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #endif /* sv_catpvf_mg depends on sv_catpvf_mg_nocontext */ #ifndef sv_catpvf_mg # ifdef PERL_IMPLICIT_CONTEXT # define sv_catpvf_mg Perl_sv_catpvf_mg_nocontext # else # define sv_catpvf_mg Perl_sv_catpvf_mg # endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf_mg) # define sv_vcatpvf_mg(sv, pat, args) \ STMT_START { \ sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ SvSETMAGIC(sv); \ } STMT_END #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg) #if defined(NEED_sv_setpvf_mg) static void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); #endif #define Perl_sv_setpvf_mg DPPP_(my_sv_setpvf_mg) #if defined(NEED_sv_setpvf_mg) || defined(NEED_sv_setpvf_mg_GLOBAL) void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...) { va_list args; va_start(args, pat); sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #ifdef PERL_IMPLICIT_CONTEXT #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg_nocontext) #if defined(NEED_sv_setpvf_mg_nocontext) static void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); static #else extern void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); #endif #define sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) #define Perl_sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) #if defined(NEED_sv_setpvf_mg_nocontext) || defined(NEED_sv_setpvf_mg_nocontext_GLOBAL) void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...) { dTHX; va_list args; va_start(args, pat); sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); SvSETMAGIC(sv); va_end(args); } #endif #endif #endif /* sv_setpvf_mg depends on sv_setpvf_mg_nocontext */ #ifndef sv_setpvf_mg # ifdef PERL_IMPLICIT_CONTEXT # define sv_setpvf_mg Perl_sv_setpvf_mg_nocontext # else # define sv_setpvf_mg Perl_sv_setpvf_mg # endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf_mg) # define sv_vsetpvf_mg(sv, pat, args) \ STMT_START { \ sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ SvSETMAGIC(sv); \ } STMT_END #endif /* Hint: newSVpvn_share * The SVs created by this function only mimic the behaviour of * shared PVs without really being shared. Only use if you know * what you're doing. */ #ifndef newSVpvn_share #if defined(NEED_newSVpvn_share) static SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); static #else extern SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); #endif #ifdef newSVpvn_share # undef newSVpvn_share #endif #define newSVpvn_share(a,b,c) DPPP_(my_newSVpvn_share)(aTHX_ a,b,c) #define Perl_newSVpvn_share DPPP_(my_newSVpvn_share) #if defined(NEED_newSVpvn_share) || defined(NEED_newSVpvn_share_GLOBAL) SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash) { SV *sv; if (len < 0) len = -len; if (!hash) PERL_HASH(hash, (char*) src, len); sv = newSVpvn((char *) src, len); sv_upgrade(sv, SVt_PVIV); SvIVX(sv) = hash; SvREADONLY_on(sv); SvPOK_on(sv); return sv; } #endif #endif #ifndef SvSHARED_HASH # define SvSHARED_HASH(sv) (0 + SvUVX(sv)) #endif #ifndef HvNAME_get # define HvNAME_get(hv) HvNAME(hv) #endif #ifndef HvNAMELEN_get # define HvNAMELEN_get(hv) (HvNAME_get(hv) ? (I32)strlen(HvNAME_get(hv)) : 0) #endif #ifndef GvSVn # define GvSVn(gv) GvSV(gv) #endif #ifndef isGV_with_GP # define isGV_with_GP(gv) isGV(gv) #endif #ifndef gv_fetchpvn_flags # define gv_fetchpvn_flags(name, len, flags, svt) gv_fetchpv(name, flags, svt) #endif #ifndef gv_fetchsv # define gv_fetchsv(name, flags, svt) gv_fetchpv(SvPV_nolen_const(name), flags, svt) #endif #ifndef get_cvn_flags # define get_cvn_flags(name, namelen, flags) get_cv(name, flags) #endif #ifndef WARN_ALL # define WARN_ALL 0 #endif #ifndef WARN_CLOSURE # define WARN_CLOSURE 1 #endif #ifndef WARN_DEPRECATED # define WARN_DEPRECATED 2 #endif #ifndef WARN_EXITING # define WARN_EXITING 3 #endif #ifndef WARN_GLOB # define WARN_GLOB 4 #endif #ifndef WARN_IO # define WARN_IO 5 #endif #ifndef WARN_CLOSED # define WARN_CLOSED 6 #endif #ifndef WARN_EXEC # define WARN_EXEC 7 #endif #ifndef WARN_LAYER # define WARN_LAYER 8 #endif #ifndef WARN_NEWLINE # define WARN_NEWLINE 9 #endif #ifndef WARN_PIPE # define WARN_PIPE 10 #endif #ifndef WARN_UNOPENED # define WARN_UNOPENED 11 #endif #ifndef WARN_MISC # define WARN_MISC 12 #endif #ifndef WARN_NUMERIC # define WARN_NUMERIC 13 #endif #ifndef WARN_ONCE # define WARN_ONCE 14 #endif #ifndef WARN_OVERFLOW # define WARN_OVERFLOW 15 #endif #ifndef WARN_PACK # define WARN_PACK 16 #endif #ifndef WARN_PORTABLE # define WARN_PORTABLE 17 #endif #ifndef WARN_RECURSION # define WARN_RECURSION 18 #endif #ifndef WARN_REDEFINE # define WARN_REDEFINE 19 #endif #ifndef WARN_REGEXP # define WARN_REGEXP 20 #endif #ifndef WARN_SEVERE # define WARN_SEVERE 21 #endif #ifndef WARN_DEBUGGING # define WARN_DEBUGGING 22 #endif #ifndef WARN_INPLACE # define WARN_INPLACE 23 #endif #ifndef WARN_INTERNAL # define WARN_INTERNAL 24 #endif #ifndef WARN_MALLOC # define WARN_MALLOC 25 #endif #ifndef WARN_SIGNAL # define WARN_SIGNAL 26 #endif #ifndef WARN_SUBSTR # define WARN_SUBSTR 27 #endif #ifndef WARN_SYNTAX # define WARN_SYNTAX 28 #endif #ifndef WARN_AMBIGUOUS # define WARN_AMBIGUOUS 29 #endif #ifndef WARN_BAREWORD # define WARN_BAREWORD 30 #endif #ifndef WARN_DIGIT # define WARN_DIGIT 31 #endif #ifndef WARN_PARENTHESIS # define WARN_PARENTHESIS 32 #endif #ifndef WARN_PRECEDENCE # define WARN_PRECEDENCE 33 #endif #ifndef WARN_PRINTF # define WARN_PRINTF 34 #endif #ifndef WARN_PROTOTYPE # define WARN_PROTOTYPE 35 #endif #ifndef WARN_QW # define WARN_QW 36 #endif #ifndef WARN_RESERVED # define WARN_RESERVED 37 #endif #ifndef WARN_SEMICOLON # define WARN_SEMICOLON 38 #endif #ifndef WARN_TAINT # define WARN_TAINT 39 #endif #ifndef WARN_THREADS # define WARN_THREADS 40 #endif #ifndef WARN_UNINITIALIZED # define WARN_UNINITIALIZED 41 #endif #ifndef WARN_UNPACK # define WARN_UNPACK 42 #endif #ifndef WARN_UNTIE # define WARN_UNTIE 43 #endif #ifndef WARN_UTF8 # define WARN_UTF8 44 #endif #ifndef WARN_VOID # define WARN_VOID 45 #endif #ifndef WARN_ASSERTIONS # define WARN_ASSERTIONS 46 #endif #ifndef packWARN # define packWARN(a) (a) #endif #ifndef ckWARN # ifdef G_WARN_ON # define ckWARN(a) (PL_dowarn & G_WARN_ON) # else # define ckWARN(a) PL_dowarn # endif #endif #if (PERL_BCDVERSION >= 0x5004000) && !defined(warner) #if defined(NEED_warner) static void DPPP_(my_warner)(U32 err, const char *pat, ...); static #else extern void DPPP_(my_warner)(U32 err, const char *pat, ...); #endif #define Perl_warner DPPP_(my_warner) #if defined(NEED_warner) || defined(NEED_warner_GLOBAL) void DPPP_(my_warner)(U32 err, const char *pat, ...) { SV *sv; va_list args; PERL_UNUSED_ARG(err); va_start(args, pat); sv = vnewSVpvf(pat, &args); va_end(args); sv_2mortal(sv); warn("%s", SvPV_nolen(sv)); } #define warner Perl_warner #define Perl_warner_nocontext Perl_warner #endif #endif /* concatenating with "" ensures that only literal strings are accepted as argument * note that STR_WITH_LEN() can't be used as argument to macros or functions that * under some configurations might be macros */ #ifndef STR_WITH_LEN # define STR_WITH_LEN(s) (s ""), (sizeof(s)-1) #endif #ifndef newSVpvs # define newSVpvs(str) newSVpvn(str "", sizeof(str) - 1) #endif #ifndef newSVpvs_flags # define newSVpvs_flags(str, flags) newSVpvn_flags(str "", sizeof(str) - 1, flags) #endif #ifndef newSVpvs_share # define newSVpvs_share(str) newSVpvn_share(str "", sizeof(str) - 1, 0) #endif #ifndef sv_catpvs # define sv_catpvs(sv, str) sv_catpvn(sv, str "", sizeof(str) - 1) #endif #ifndef sv_setpvs # define sv_setpvs(sv, str) sv_setpvn(sv, str "", sizeof(str) - 1) #endif #ifndef hv_fetchs # define hv_fetchs(hv, key, lval) hv_fetch(hv, key "", sizeof(key) - 1, lval) #endif #ifndef hv_stores # define hv_stores(hv, key, val) hv_store(hv, key "", sizeof(key) - 1, val, 0) #endif #ifndef gv_fetchpvs # define gv_fetchpvs(name, flags, svt) gv_fetchpvn_flags(name "", sizeof(name) - 1, flags, svt) #endif #ifndef gv_stashpvs # define gv_stashpvs(name, flags) gv_stashpvn(name "", sizeof(name) - 1, flags) #endif #ifndef get_cvs # define get_cvs(name, flags) get_cvn_flags(name "", sizeof(name)-1, flags) #endif #ifndef SvGETMAGIC # define SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END #endif #ifndef PERL_MAGIC_sv # define PERL_MAGIC_sv '\0' #endif #ifndef PERL_MAGIC_overload # define PERL_MAGIC_overload 'A' #endif #ifndef PERL_MAGIC_overload_elem # define PERL_MAGIC_overload_elem 'a' #endif #ifndef PERL_MAGIC_overload_table # define PERL_MAGIC_overload_table 'c' #endif #ifndef PERL_MAGIC_bm # define PERL_MAGIC_bm 'B' #endif #ifndef PERL_MAGIC_regdata # define PERL_MAGIC_regdata 'D' #endif #ifndef PERL_MAGIC_regdatum # define PERL_MAGIC_regdatum 'd' #endif #ifndef PERL_MAGIC_env # define PERL_MAGIC_env 'E' #endif #ifndef PERL_MAGIC_envelem # define PERL_MAGIC_envelem 'e' #endif #ifndef PERL_MAGIC_fm # define PERL_MAGIC_fm 'f' #endif #ifndef PERL_MAGIC_regex_global # define PERL_MAGIC_regex_global 'g' #endif #ifndef PERL_MAGIC_isa # define PERL_MAGIC_isa 'I' #endif #ifndef PERL_MAGIC_isaelem # define PERL_MAGIC_isaelem 'i' #endif #ifndef PERL_MAGIC_nkeys # define PERL_MAGIC_nkeys 'k' #endif #ifndef PERL_MAGIC_dbfile # define PERL_MAGIC_dbfile 'L' #endif #ifndef PERL_MAGIC_dbline # define PERL_MAGIC_dbline 'l' #endif #ifndef PERL_MAGIC_mutex # define PERL_MAGIC_mutex 'm' #endif #ifndef PERL_MAGIC_shared # define PERL_MAGIC_shared 'N' #endif #ifndef PERL_MAGIC_shared_scalar # define PERL_MAGIC_shared_scalar 'n' #endif #ifndef PERL_MAGIC_collxfrm # define PERL_MAGIC_collxfrm 'o' #endif #ifndef PERL_MAGIC_tied # define PERL_MAGIC_tied 'P' #endif #ifndef PERL_MAGIC_tiedelem # define PERL_MAGIC_tiedelem 'p' #endif #ifndef PERL_MAGIC_tiedscalar # define PERL_MAGIC_tiedscalar 'q' #endif #ifndef PERL_MAGIC_qr # define PERL_MAGIC_qr 'r' #endif #ifndef PERL_MAGIC_sig # define PERL_MAGIC_sig 'S' #endif #ifndef PERL_MAGIC_sigelem # define PERL_MAGIC_sigelem 's' #endif #ifndef PERL_MAGIC_taint # define PERL_MAGIC_taint 't' #endif #ifndef PERL_MAGIC_uvar # define PERL_MAGIC_uvar 'U' #endif #ifndef PERL_MAGIC_uvar_elem # define PERL_MAGIC_uvar_elem 'u' #endif #ifndef PERL_MAGIC_vstring # define PERL_MAGIC_vstring 'V' #endif #ifndef PERL_MAGIC_vec # define PERL_MAGIC_vec 'v' #endif #ifndef PERL_MAGIC_utf8 # define PERL_MAGIC_utf8 'w' #endif #ifndef PERL_MAGIC_substr # define PERL_MAGIC_substr 'x' #endif #ifndef PERL_MAGIC_defelem # define PERL_MAGIC_defelem 'y' #endif #ifndef PERL_MAGIC_glob # define PERL_MAGIC_glob '*' #endif #ifndef PERL_MAGIC_arylen # define PERL_MAGIC_arylen '#' #endif #ifndef PERL_MAGIC_pos # define PERL_MAGIC_pos '.' #endif #ifndef PERL_MAGIC_backref # define PERL_MAGIC_backref '<' #endif #ifndef PERL_MAGIC_ext # define PERL_MAGIC_ext '~' #endif /* That's the best we can do... */ #ifndef sv_catpvn_nomg # define sv_catpvn_nomg sv_catpvn #endif #ifndef sv_catsv_nomg # define sv_catsv_nomg sv_catsv #endif #ifndef sv_setsv_nomg # define sv_setsv_nomg sv_setsv #endif #ifndef sv_pvn_nomg # define sv_pvn_nomg sv_pvn #endif #ifndef SvIV_nomg # define SvIV_nomg SvIV #endif #ifndef SvUV_nomg # define SvUV_nomg SvUV #endif #ifndef sv_catpv_mg # define sv_catpv_mg(sv, ptr) \ STMT_START { \ SV *TeMpSv = sv; \ sv_catpv(TeMpSv,ptr); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_catpvn_mg # define sv_catpvn_mg(sv, ptr, len) \ STMT_START { \ SV *TeMpSv = sv; \ sv_catpvn(TeMpSv,ptr,len); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_catsv_mg # define sv_catsv_mg(dsv, ssv) \ STMT_START { \ SV *TeMpSv = dsv; \ sv_catsv(TeMpSv,ssv); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setiv_mg # define sv_setiv_mg(sv, i) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setiv(TeMpSv,i); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setnv_mg # define sv_setnv_mg(sv, num) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setnv(TeMpSv,num); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setpv_mg # define sv_setpv_mg(sv, ptr) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setpv(TeMpSv,ptr); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setpvn_mg # define sv_setpvn_mg(sv, ptr, len) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setpvn(TeMpSv,ptr,len); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setsv_mg # define sv_setsv_mg(dsv, ssv) \ STMT_START { \ SV *TeMpSv = dsv; \ sv_setsv(TeMpSv,ssv); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_setuv_mg # define sv_setuv_mg(sv, i) \ STMT_START { \ SV *TeMpSv = sv; \ sv_setuv(TeMpSv,i); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef sv_usepvn_mg # define sv_usepvn_mg(sv, ptr, len) \ STMT_START { \ SV *TeMpSv = sv; \ sv_usepvn(TeMpSv,ptr,len); \ SvSETMAGIC(TeMpSv); \ } STMT_END #endif #ifndef SvVSTRING_mg # define SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL) #endif /* Hint: sv_magic_portable * This is a compatibility function that is only available with * Devel::PPPort. It is NOT in the perl core. * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when * it is being passed a name pointer with namlen == 0. In that * case, perl 5.8.0 and later store the pointer, not a copy of it. * The compatibility can be provided back to perl 5.004. With * earlier versions, the code will not compile. */ #if (PERL_BCDVERSION < 0x5004000) /* code that uses sv_magic_portable will not compile */ #elif (PERL_BCDVERSION < 0x5008000) # define sv_magic_portable(sv, obj, how, name, namlen) \ STMT_START { \ SV *SvMp_sv = (sv); \ char *SvMp_name = (char *) (name); \ I32 SvMp_namlen = (namlen); \ if (SvMp_name && SvMp_namlen == 0) \ { \ MAGIC *mg; \ sv_magic(SvMp_sv, obj, how, 0, 0); \ mg = SvMAGIC(SvMp_sv); \ mg->mg_len = -42; /* XXX: this is the tricky part */ \ mg->mg_ptr = SvMp_name; \ } \ else \ { \ sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \ } \ } STMT_END #else # define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e) #endif #ifdef USE_ITHREADS #ifndef CopFILE # define CopFILE(c) ((c)->cop_file) #endif #ifndef CopFILEGV # define CopFILEGV(c) (CopFILE(c) ? gv_fetchfile(CopFILE(c)) : Nullgv) #endif #ifndef CopFILE_set # define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv)) #endif #ifndef CopFILESV # define CopFILESV(c) (CopFILE(c) ? GvSV(gv_fetchfile(CopFILE(c))) : Nullsv) #endif #ifndef CopFILEAV # define CopFILEAV(c) (CopFILE(c) ? GvAV(gv_fetchfile(CopFILE(c))) : Nullav) #endif #ifndef CopSTASHPV # define CopSTASHPV(c) ((c)->cop_stashpv) #endif #ifndef CopSTASHPV_set # define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch)) #endif #ifndef CopSTASH # define CopSTASH(c) (CopSTASHPV(c) ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv) #endif #ifndef CopSTASH_set # define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch) #endif #ifndef CopSTASH_eq # define CopSTASH_eq(c,hv) ((hv) && (CopSTASHPV(c) == HvNAME(hv) \ || (CopSTASHPV(c) && HvNAME(hv) \ && strEQ(CopSTASHPV(c), HvNAME(hv))))) #endif #else #ifndef CopFILEGV # define CopFILEGV(c) ((c)->cop_filegv) #endif #ifndef CopFILEGV_set # define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv)) #endif #ifndef CopFILE_set # define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv)) #endif #ifndef CopFILESV # define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : Nullsv) #endif #ifndef CopFILEAV # define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : Nullav) #endif #ifndef CopFILE # define CopFILE(c) (CopFILESV(c) ? SvPVX(CopFILESV(c)) : Nullch) #endif #ifndef CopSTASH # define CopSTASH(c) ((c)->cop_stash) #endif #ifndef CopSTASH_set # define CopSTASH_set(c,hv) ((c)->cop_stash = (hv)) #endif #ifndef CopSTASHPV # define CopSTASHPV(c) (CopSTASH(c) ? HvNAME(CopSTASH(c)) : Nullch) #endif #ifndef CopSTASHPV_set # define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD)) #endif #ifndef CopSTASH_eq # define CopSTASH_eq(c,hv) (CopSTASH(c) == (hv)) #endif #endif /* USE_ITHREADS */ #ifndef IN_PERL_COMPILETIME # define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) #endif #ifndef IN_LOCALE_RUNTIME # define IN_LOCALE_RUNTIME (PL_curcop->op_private & HINT_LOCALE) #endif #ifndef IN_LOCALE_COMPILETIME # define IN_LOCALE_COMPILETIME (PL_hints & HINT_LOCALE) #endif #ifndef IN_LOCALE # define IN_LOCALE (IN_PERL_COMPILETIME ? IN_LOCALE_COMPILETIME : IN_LOCALE_RUNTIME) #endif #ifndef IS_NUMBER_IN_UV # define IS_NUMBER_IN_UV 0x01 #endif #ifndef IS_NUMBER_GREATER_THAN_UV_MAX # define IS_NUMBER_GREATER_THAN_UV_MAX 0x02 #endif #ifndef IS_NUMBER_NOT_INT # define IS_NUMBER_NOT_INT 0x04 #endif #ifndef IS_NUMBER_NEG # define IS_NUMBER_NEG 0x08 #endif #ifndef IS_NUMBER_INFINITY # define IS_NUMBER_INFINITY 0x10 #endif #ifndef IS_NUMBER_NAN # define IS_NUMBER_NAN 0x20 #endif #ifndef GROK_NUMERIC_RADIX # define GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send) #endif #ifndef PERL_SCAN_GREATER_THAN_UV_MAX # define PERL_SCAN_GREATER_THAN_UV_MAX 0x02 #endif #ifndef PERL_SCAN_SILENT_ILLDIGIT # define PERL_SCAN_SILENT_ILLDIGIT 0x04 #endif #ifndef PERL_SCAN_ALLOW_UNDERSCORES # define PERL_SCAN_ALLOW_UNDERSCORES 0x01 #endif #ifndef PERL_SCAN_DISALLOW_PREFIX # define PERL_SCAN_DISALLOW_PREFIX 0x02 #endif #ifndef grok_numeric_radix #if defined(NEED_grok_numeric_radix) static bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); static #else extern bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); #endif #ifdef grok_numeric_radix # undef grok_numeric_radix #endif #define grok_numeric_radix(a,b) DPPP_(my_grok_numeric_radix)(aTHX_ a,b) #define Perl_grok_numeric_radix DPPP_(my_grok_numeric_radix) #if defined(NEED_grok_numeric_radix) || defined(NEED_grok_numeric_radix_GLOBAL) bool DPPP_(my_grok_numeric_radix)(pTHX_ const char **sp, const char *send) { #ifdef USE_LOCALE_NUMERIC #ifdef PL_numeric_radix_sv if (PL_numeric_radix_sv && IN_LOCALE) { STRLEN len; char* radix = SvPV(PL_numeric_radix_sv, len); if (*sp + len <= send && memEQ(*sp, radix, len)) { *sp += len; return TRUE; } } #else /* older perls don't have PL_numeric_radix_sv so the radix * must manually be requested from locale.h */ #include dTHR; /* needed for older threaded perls */ struct lconv *lc = localeconv(); char *radix = lc->decimal_point; if (radix && IN_LOCALE) { STRLEN len = strlen(radix); if (*sp + len <= send && memEQ(*sp, radix, len)) { *sp += len; return TRUE; } } #endif #endif /* USE_LOCALE_NUMERIC */ /* always try "." if numeric radix didn't match because * we may have data from different locales mixed */ if (*sp < send && **sp == '.') { ++*sp; return TRUE; } return FALSE; } #endif #endif #ifndef grok_number #if defined(NEED_grok_number) static int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); static #else extern int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); #endif #ifdef grok_number # undef grok_number #endif #define grok_number(a,b,c) DPPP_(my_grok_number)(aTHX_ a,b,c) #define Perl_grok_number DPPP_(my_grok_number) #if defined(NEED_grok_number) || defined(NEED_grok_number_GLOBAL) int DPPP_(my_grok_number)(pTHX_ const char *pv, STRLEN len, UV *valuep) { const char *s = pv; const char *send = pv + len; const UV max_div_10 = UV_MAX / 10; const char max_mod_10 = UV_MAX % 10; int numtype = 0; int sawinf = 0; int sawnan = 0; while (s < send && isSPACE(*s)) s++; if (s == send) { return 0; } else if (*s == '-') { s++; numtype = IS_NUMBER_NEG; } else if (*s == '+') s++; if (s == send) return 0; /* next must be digit or the radix separator or beginning of infinity */ if (isDIGIT(*s)) { /* UVs are at least 32 bits, so the first 9 decimal digits cannot overflow. */ UV value = *s - '0'; /* This construction seems to be more optimiser friendly. (without it gcc does the isDIGIT test and the *s - '0' separately) With it gcc on arm is managing 6 instructions (6 cycles) per digit. In theory the optimiser could deduce how far to unroll the loop before checking for overflow. */ if (++s < send) { int digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { digit = *s - '0'; if (digit >= 0 && digit <= 9) { value = value * 10 + digit; if (++s < send) { /* Now got 9 digits, so need to check each time for overflow. */ digit = *s - '0'; while (digit >= 0 && digit <= 9 && (value < max_div_10 || (value == max_div_10 && digit <= max_mod_10))) { value = value * 10 + digit; if (++s < send) digit = *s - '0'; else break; } if (digit >= 0 && digit <= 9 && (s < send)) { /* value overflowed. skip the remaining digits, don't worry about setting *valuep. */ do { s++; } while (s < send && isDIGIT(*s)); numtype |= IS_NUMBER_GREATER_THAN_UV_MAX; goto skip_value; } } } } } } } } } } } } } } } } } } numtype |= IS_NUMBER_IN_UV; if (valuep) *valuep = value; skip_value: if (GROK_NUMERIC_RADIX(&s, send)) { numtype |= IS_NUMBER_NOT_INT; while (s < send && isDIGIT(*s)) /* optional digits after the radix */ s++; } } else if (GROK_NUMERIC_RADIX(&s, send)) { numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */ /* no digits before the radix means we need digits after it */ if (s < send && isDIGIT(*s)) { do { s++; } while (s < send && isDIGIT(*s)); if (valuep) { /* integer approximation is valid - it's 0. */ *valuep = 0; } } else return 0; } else if (*s == 'I' || *s == 'i') { s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; s++; if (s == send || (*s != 'F' && *s != 'f')) return 0; s++; if (s < send && (*s == 'I' || *s == 'i')) { s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; s++; if (s == send || (*s != 'I' && *s != 'i')) return 0; s++; if (s == send || (*s != 'T' && *s != 't')) return 0; s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0; s++; } sawinf = 1; } else if (*s == 'N' || *s == 'n') { /* XXX TODO: There are signaling NaNs and quiet NaNs. */ s++; if (s == send || (*s != 'A' && *s != 'a')) return 0; s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; s++; sawnan = 1; } else return 0; if (sawinf) { numtype &= IS_NUMBER_NEG; /* Keep track of sign */ numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT; } else if (sawnan) { numtype &= IS_NUMBER_NEG; /* Keep track of sign */ numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT; } else if (s < send) { /* we can have an optional exponent part */ if (*s == 'e' || *s == 'E') { /* The only flag we keep is sign. Blow away any "it's UV" */ numtype &= IS_NUMBER_NEG; numtype |= IS_NUMBER_NOT_INT; s++; if (s < send && (*s == '-' || *s == '+')) s++; if (s < send && isDIGIT(*s)) { do { s++; } while (s < send && isDIGIT(*s)); } else return 0; } } while (s < send && isSPACE(*s)) s++; if (s >= send) return numtype; if (len == 10 && memEQ(pv, "0 but true", 10)) { if (valuep) *valuep = 0; return IS_NUMBER_IN_UV; } return 0; } #endif #endif /* * The grok_* routines have been modified to use warn() instead of * Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit, * which is why the stack variable has been renamed to 'xdigit'. */ #ifndef grok_bin #if defined(NEED_grok_bin) static UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); static #else extern UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); #endif #ifdef grok_bin # undef grok_bin #endif #define grok_bin(a,b,c,d) DPPP_(my_grok_bin)(aTHX_ a,b,c,d) #define Perl_grok_bin DPPP_(my_grok_bin) #if defined(NEED_grok_bin) || defined(NEED_grok_bin_GLOBAL) UV DPPP_(my_grok_bin)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) { const char *s = start; STRLEN len = *len_p; UV value = 0; NV value_nv = 0; const UV max_div_2 = UV_MAX / 2; bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; bool overflowed = FALSE; if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { /* strip off leading b or 0b. for compatibility silently suffer "b" and "0b" as valid binary numbers. */ if (len >= 1) { if (s[0] == 'b') { s++; len--; } else if (len >= 2 && s[0] == '0' && s[1] == 'b') { s+=2; len-=2; } } } for (; len-- && *s; s++) { char bit = *s; if (bit == '0' || bit == '1') { /* Write it in this wonky order with a goto to attempt to get the compiler to make the common case integer-only loop pretty tight. With gcc seems to be much straighter code than old scan_bin. */ redo: if (!overflowed) { if (value <= max_div_2) { value = (value << 1) | (bit - '0'); continue; } /* Bah. We're just overflowed. */ warn("Integer overflow in binary number"); overflowed = TRUE; value_nv = (NV) value; } value_nv *= 2.0; /* If an NV has not enough bits in its mantissa to * represent a UV this summing of small low-order numbers * is a waste of time (because the NV cannot preserve * the low-order bits anyway): we could just remember when * did we overflow and in the end just multiply value_nv by the * right amount. */ value_nv += (NV)(bit - '0'); continue; } if (bit == '_' && len && allow_underscores && (bit = s[1]) && (bit == '0' || bit == '1')) { --len; ++s; goto redo; } if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) warn("Illegal binary digit '%c' ignored", *s); break; } if ( ( overflowed && value_nv > 4294967295.0) #if UVSIZE > 4 || (!overflowed && value > 0xffffffff ) #endif ) { warn("Binary number > 0b11111111111111111111111111111111 non-portable"); } *len_p = s - start; if (!overflowed) { *flags = 0; return value; } *flags = PERL_SCAN_GREATER_THAN_UV_MAX; if (result) *result = value_nv; return UV_MAX; } #endif #endif #ifndef grok_hex #if defined(NEED_grok_hex) static UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); static #else extern UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); #endif #ifdef grok_hex # undef grok_hex #endif #define grok_hex(a,b,c,d) DPPP_(my_grok_hex)(aTHX_ a,b,c,d) #define Perl_grok_hex DPPP_(my_grok_hex) #if defined(NEED_grok_hex) || defined(NEED_grok_hex_GLOBAL) UV DPPP_(my_grok_hex)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) { const char *s = start; STRLEN len = *len_p; UV value = 0; NV value_nv = 0; const UV max_div_16 = UV_MAX / 16; bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; bool overflowed = FALSE; const char *xdigit; if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { /* strip off leading x or 0x. for compatibility silently suffer "x" and "0x" as valid hex numbers. */ if (len >= 1) { if (s[0] == 'x') { s++; len--; } else if (len >= 2 && s[0] == '0' && s[1] == 'x') { s+=2; len-=2; } } } for (; len-- && *s; s++) { xdigit = strchr((char *) PL_hexdigit, *s); if (xdigit) { /* Write it in this wonky order with a goto to attempt to get the compiler to make the common case integer-only loop pretty tight. With gcc seems to be much straighter code than old scan_hex. */ redo: if (!overflowed) { if (value <= max_div_16) { value = (value << 4) | ((xdigit - PL_hexdigit) & 15); continue; } warn("Integer overflow in hexadecimal number"); overflowed = TRUE; value_nv = (NV) value; } value_nv *= 16.0; /* If an NV has not enough bits in its mantissa to * represent a UV this summing of small low-order numbers * is a waste of time (because the NV cannot preserve * the low-order bits anyway): we could just remember when * did we overflow and in the end just multiply value_nv by the * right amount of 16-tuples. */ value_nv += (NV)((xdigit - PL_hexdigit) & 15); continue; } if (*s == '_' && len && allow_underscores && s[1] && (xdigit = strchr((char *) PL_hexdigit, s[1]))) { --len; ++s; goto redo; } if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) warn("Illegal hexadecimal digit '%c' ignored", *s); break; } if ( ( overflowed && value_nv > 4294967295.0) #if UVSIZE > 4 || (!overflowed && value > 0xffffffff ) #endif ) { warn("Hexadecimal number > 0xffffffff non-portable"); } *len_p = s - start; if (!overflowed) { *flags = 0; return value; } *flags = PERL_SCAN_GREATER_THAN_UV_MAX; if (result) *result = value_nv; return UV_MAX; } #endif #endif #ifndef grok_oct #if defined(NEED_grok_oct) static UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); static #else extern UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); #endif #ifdef grok_oct # undef grok_oct #endif #define grok_oct(a,b,c,d) DPPP_(my_grok_oct)(aTHX_ a,b,c,d) #define Perl_grok_oct DPPP_(my_grok_oct) #if defined(NEED_grok_oct) || defined(NEED_grok_oct_GLOBAL) UV DPPP_(my_grok_oct)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) { const char *s = start; STRLEN len = *len_p; UV value = 0; NV value_nv = 0; const UV max_div_8 = UV_MAX / 8; bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; bool overflowed = FALSE; for (; len-- && *s; s++) { /* gcc 2.95 optimiser not smart enough to figure that this subtraction out front allows slicker code. */ int digit = *s - '0'; if (digit >= 0 && digit <= 7) { /* Write it in this wonky order with a goto to attempt to get the compiler to make the common case integer-only loop pretty tight. */ redo: if (!overflowed) { if (value <= max_div_8) { value = (value << 3) | digit; continue; } /* Bah. We're just overflowed. */ warn("Integer overflow in octal number"); overflowed = TRUE; value_nv = (NV) value; } value_nv *= 8.0; /* If an NV has not enough bits in its mantissa to * represent a UV this summing of small low-order numbers * is a waste of time (because the NV cannot preserve * the low-order bits anyway): we could just remember when * did we overflow and in the end just multiply value_nv by the * right amount of 8-tuples. */ value_nv += (NV)digit; continue; } if (digit == ('_' - '0') && len && allow_underscores && (digit = s[1] - '0') && (digit >= 0 && digit <= 7)) { --len; ++s; goto redo; } /* Allow \octal to work the DWIM way (that is, stop scanning * as soon as non-octal characters are seen, complain only iff * someone seems to want to use the digits eight and nine). */ if (digit == 8 || digit == 9) { if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) warn("Illegal octal digit '%c' ignored", *s); } break; } if ( ( overflowed && value_nv > 4294967295.0) #if UVSIZE > 4 || (!overflowed && value > 0xffffffff ) #endif ) { warn("Octal number > 037777777777 non-portable"); } *len_p = s - start; if (!overflowed) { *flags = 0; return value; } *flags = PERL_SCAN_GREATER_THAN_UV_MAX; if (result) *result = value_nv; return UV_MAX; } #endif #endif #if !defined(my_snprintf) #if defined(NEED_my_snprintf) static int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); static #else extern int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); #endif #define my_snprintf DPPP_(my_my_snprintf) #define Perl_my_snprintf DPPP_(my_my_snprintf) #if defined(NEED_my_snprintf) || defined(NEED_my_snprintf_GLOBAL) int DPPP_(my_my_snprintf)(char *buffer, const Size_t len, const char *format, ...) { dTHX; int retval; va_list ap; va_start(ap, format); #ifdef HAS_VSNPRINTF retval = vsnprintf(buffer, len, format, ap); #else retval = vsprintf(buffer, format, ap); #endif va_end(ap); if (retval < 0 || (len > 0 && (Size_t)retval >= len)) Perl_croak(aTHX_ "panic: my_snprintf buffer overflow"); return retval; } #endif #endif #if !defined(my_sprintf) #if defined(NEED_my_sprintf) static int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); static #else extern int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); #endif #define my_sprintf DPPP_(my_my_sprintf) #define Perl_my_sprintf DPPP_(my_my_sprintf) #if defined(NEED_my_sprintf) || defined(NEED_my_sprintf_GLOBAL) int DPPP_(my_my_sprintf)(char *buffer, const char* pat, ...) { va_list args; va_start(args, pat); vsprintf(buffer, pat, args); va_end(args); return strlen(buffer); } #endif #endif #ifdef NO_XSLOCKS # ifdef dJMPENV # define dXCPT dJMPENV; int rEtV = 0 # define XCPT_TRY_START JMPENV_PUSH(rEtV); if (rEtV == 0) # define XCPT_TRY_END JMPENV_POP; # define XCPT_CATCH if (rEtV != 0) # define XCPT_RETHROW JMPENV_JUMP(rEtV) # else # define dXCPT Sigjmp_buf oldTOP; int rEtV = 0 # define XCPT_TRY_START Copy(top_env, oldTOP, 1, Sigjmp_buf); rEtV = Sigsetjmp(top_env, 1); if (rEtV == 0) # define XCPT_TRY_END Copy(oldTOP, top_env, 1, Sigjmp_buf); # define XCPT_CATCH if (rEtV != 0) # define XCPT_RETHROW Siglongjmp(top_env, rEtV) # endif #endif #if !defined(my_strlcat) #if defined(NEED_my_strlcat) static Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); static #else extern Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); #endif #define my_strlcat DPPP_(my_my_strlcat) #define Perl_my_strlcat DPPP_(my_my_strlcat) #if defined(NEED_my_strlcat) || defined(NEED_my_strlcat_GLOBAL) Size_t DPPP_(my_my_strlcat)(char *dst, const char *src, Size_t size) { Size_t used, length, copy; used = strlen(dst); length = strlen(src); if (size > 0 && used < size - 1) { copy = (length >= size - used) ? size - used - 1 : length; memcpy(dst + used, src, copy); dst[used + copy] = '\0'; } return used + length; } #endif #endif #if !defined(my_strlcpy) #if defined(NEED_my_strlcpy) static Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); static #else extern Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); #endif #define my_strlcpy DPPP_(my_my_strlcpy) #define Perl_my_strlcpy DPPP_(my_my_strlcpy) #if defined(NEED_my_strlcpy) || defined(NEED_my_strlcpy_GLOBAL) Size_t DPPP_(my_my_strlcpy)(char *dst, const char *src, Size_t size) { Size_t length, copy; length = strlen(src); if (size > 0) { copy = (length >= size) ? size - 1 : length; memcpy(dst, src, copy); dst[copy] = '\0'; } return length; } #endif #endif #ifndef PERL_PV_ESCAPE_QUOTE # define PERL_PV_ESCAPE_QUOTE 0x0001 #endif #ifndef PERL_PV_PRETTY_QUOTE # define PERL_PV_PRETTY_QUOTE PERL_PV_ESCAPE_QUOTE #endif #ifndef PERL_PV_PRETTY_ELLIPSES # define PERL_PV_PRETTY_ELLIPSES 0x0002 #endif #ifndef PERL_PV_PRETTY_LTGT # define PERL_PV_PRETTY_LTGT 0x0004 #endif #ifndef PERL_PV_ESCAPE_FIRSTCHAR # define PERL_PV_ESCAPE_FIRSTCHAR 0x0008 #endif #ifndef PERL_PV_ESCAPE_UNI # define PERL_PV_ESCAPE_UNI 0x0100 #endif #ifndef PERL_PV_ESCAPE_UNI_DETECT # define PERL_PV_ESCAPE_UNI_DETECT 0x0200 #endif #ifndef PERL_PV_ESCAPE_ALL # define PERL_PV_ESCAPE_ALL 0x1000 #endif #ifndef PERL_PV_ESCAPE_NOBACKSLASH # define PERL_PV_ESCAPE_NOBACKSLASH 0x2000 #endif #ifndef PERL_PV_ESCAPE_NOCLEAR # define PERL_PV_ESCAPE_NOCLEAR 0x4000 #endif #ifndef PERL_PV_ESCAPE_RE # define PERL_PV_ESCAPE_RE 0x8000 #endif #ifndef PERL_PV_PRETTY_NOCLEAR # define PERL_PV_PRETTY_NOCLEAR PERL_PV_ESCAPE_NOCLEAR #endif #ifndef PERL_PV_PRETTY_DUMP # define PERL_PV_PRETTY_DUMP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_QUOTE #endif #ifndef PERL_PV_PRETTY_REGPROP # define PERL_PV_PRETTY_REGPROP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_LTGT|PERL_PV_ESCAPE_RE #endif /* Hint: pv_escape * Note that unicode functionality is only backported to * those perl versions that support it. For older perl * versions, the implementation will fall back to bytes. */ #ifndef pv_escape #if defined(NEED_pv_escape) static char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); static #else extern char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); #endif #ifdef pv_escape # undef pv_escape #endif #define pv_escape(a,b,c,d,e,f) DPPP_(my_pv_escape)(aTHX_ a,b,c,d,e,f) #define Perl_pv_escape DPPP_(my_pv_escape) #if defined(NEED_pv_escape) || defined(NEED_pv_escape_GLOBAL) char * DPPP_(my_pv_escape)(pTHX_ SV *dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags) { const char esc = flags & PERL_PV_ESCAPE_RE ? '%' : '\\'; const char dq = flags & PERL_PV_ESCAPE_QUOTE ? '"' : esc; char octbuf[32] = "%123456789ABCDF"; STRLEN wrote = 0; STRLEN chsize = 0; STRLEN readsize = 1; #if defined(is_utf8_string) && defined(utf8_to_uvchr) bool isuni = flags & PERL_PV_ESCAPE_UNI ? 1 : 0; #endif const char *pv = str; const char * const end = pv + count; octbuf[0] = esc; if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) sv_setpvs(dsv, ""); #if defined(is_utf8_string) && defined(utf8_to_uvchr) if ((flags & PERL_PV_ESCAPE_UNI_DETECT) && is_utf8_string((U8*)pv, count)) isuni = 1; #endif for (; pv < end && (!max || wrote < max) ; pv += readsize) { const UV u = #if defined(is_utf8_string) && defined(utf8_to_uvchr) isuni ? utf8_to_uvchr((U8*)pv, &readsize) : #endif (U8)*pv; const U8 c = (U8)u & 0xFF; if (u > 255 || (flags & PERL_PV_ESCAPE_ALL)) { if (flags & PERL_PV_ESCAPE_FIRSTCHAR) chsize = my_snprintf(octbuf, sizeof octbuf, "%"UVxf, u); else chsize = my_snprintf(octbuf, sizeof octbuf, "%cx{%"UVxf"}", esc, u); } else if (flags & PERL_PV_ESCAPE_NOBACKSLASH) { chsize = 1; } else { if (c == dq || c == esc || !isPRINT(c)) { chsize = 2; switch (c) { case '\\' : /* fallthrough */ case '%' : if (c == esc) octbuf[1] = esc; else chsize = 1; break; case '\v' : octbuf[1] = 'v'; break; case '\t' : octbuf[1] = 't'; break; case '\r' : octbuf[1] = 'r'; break; case '\n' : octbuf[1] = 'n'; break; case '\f' : octbuf[1] = 'f'; break; case '"' : if (dq == '"') octbuf[1] = '"'; else chsize = 1; break; default: chsize = my_snprintf(octbuf, sizeof octbuf, pv < end && isDIGIT((U8)*(pv+readsize)) ? "%c%03o" : "%c%o", esc, c); } } else { chsize = 1; } } if (max && wrote + chsize > max) { break; } else if (chsize > 1) { sv_catpvn(dsv, octbuf, chsize); wrote += chsize; } else { char tmp[2]; my_snprintf(tmp, sizeof tmp, "%c", c); sv_catpvn(dsv, tmp, 1); wrote++; } if (flags & PERL_PV_ESCAPE_FIRSTCHAR) break; } if (escaped != NULL) *escaped= pv - str; return SvPVX(dsv); } #endif #endif #ifndef pv_pretty #if defined(NEED_pv_pretty) static char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); static #else extern char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); #endif #ifdef pv_pretty # undef pv_pretty #endif #define pv_pretty(a,b,c,d,e,f,g) DPPP_(my_pv_pretty)(aTHX_ a,b,c,d,e,f,g) #define Perl_pv_pretty DPPP_(my_pv_pretty) #if defined(NEED_pv_pretty) || defined(NEED_pv_pretty_GLOBAL) char * DPPP_(my_pv_pretty)(pTHX_ SV *dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags) { const U8 dq = (flags & PERL_PV_PRETTY_QUOTE) ? '"' : '%'; STRLEN escaped; if (!(flags & PERL_PV_PRETTY_NOCLEAR)) sv_setpvs(dsv, ""); if (dq == '"') sv_catpvs(dsv, "\""); else if (flags & PERL_PV_PRETTY_LTGT) sv_catpvs(dsv, "<"); if (start_color != NULL) sv_catpv(dsv, D_PPP_CONSTPV_ARG(start_color)); pv_escape(dsv, str, count, max, &escaped, flags | PERL_PV_ESCAPE_NOCLEAR); if (end_color != NULL) sv_catpv(dsv, D_PPP_CONSTPV_ARG(end_color)); if (dq == '"') sv_catpvs(dsv, "\""); else if (flags & PERL_PV_PRETTY_LTGT) sv_catpvs(dsv, ">"); if ((flags & PERL_PV_PRETTY_ELLIPSES) && escaped < count) sv_catpvs(dsv, "..."); return SvPVX(dsv); } #endif #endif #ifndef pv_display #if defined(NEED_pv_display) static char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); static #else extern char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); #endif #ifdef pv_display # undef pv_display #endif #define pv_display(a,b,c,d,e) DPPP_(my_pv_display)(aTHX_ a,b,c,d,e) #define Perl_pv_display DPPP_(my_pv_display) #if defined(NEED_pv_display) || defined(NEED_pv_display_GLOBAL) char * DPPP_(my_pv_display)(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim) { pv_pretty(dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP); if (len > cur && pv[cur] == '\0') sv_catpvs(dsv, "\\0"); return SvPVX(dsv); } #endif #endif #endif /* _P_P_PORTABILITY_H_ */ /* End of File ppport.h */ libimager-perl-1.004+dfsg.orig/t/0000755000175000017500000000000012617614576016043 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/GoodTestFont.pm0000644000175000017500000000027512031434615020744 0ustar gregoagregoapackage GoodTestFont; use strict; use vars '@ISA'; # this doesn't do enough to be a font sub new { my ($class, %opts) = @_; return bless \%opts, $class; # as long as it's true } 1; libimager-perl-1.004+dfsg.orig/t/150-type/0000755000175000017500000000000012617614576017327 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/150-type/100-masked.t0000644000175000017500000006305312263740601021247 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 244; use Imager qw(:all :handy); use Imager::Test qw(is_color3 is_fcolor3); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t020masked.log"); my $base_rgb = Imager::ImgRaw::new(100, 100, 3); # put something in there my $black = NC(0, 0, 0); my $red = NC(255, 0, 0); my $green = NC(0, 255, 0); my $blue = NC(0, 0, 255); my $white = NC(255, 255, 255); my $grey = NC(128, 128, 128); use Imager::Color::Float; my $redf = Imager::Color::Float->new(1, 0, 0); my $greenf = Imager::Color::Float->new(0, 1, 0); my $bluef = Imager::Color::Float->new(0, 0, 1); my $greyf = Imager::Color::Float->new(0.5, 0.5, 0.5); my @cols = ($red, $green, $blue); for my $y (0..99) { Imager::i_plin($base_rgb, 0, $y, ($cols[$y % 3] ) x 100); } # first a simple subset image my $s_rgb = Imager::i_img_masked_new($base_rgb, undef, 25, 25, 50, 50); is(Imager::i_img_getchannels($s_rgb), 3, "1 channel image channel count match"); ok(Imager::i_img_getmask($s_rgb) & 1, "1 channel image mask"); ok(Imager::i_img_virtual($s_rgb), "1 channel image thinks it isn't virtual"); is(Imager::i_img_bits($s_rgb), 8, "1 channel image has bits == 8"); is(Imager::i_img_type($s_rgb), 0, # direct "1 channel image is direct"); my @ginfo = i_img_info($s_rgb); is($ginfo[0], 50, "check width"); is($ginfo[1], 50, "check height"); # sample some pixels through the subset my $c = Imager::i_get_pixel($s_rgb, 0, 0); is_color3($c, 0, 255, 0, "check (0,0)"); $c = Imager::i_get_pixel($s_rgb, 49, 49); # (25+49)%3 = 2 is_color3($c, 0, 0, 255, "check (49,49)"); # try writing to it for my $y (0..49) { Imager::i_plin($s_rgb, 0, $y, ($cols[$y % 3]) x 50); } pass("managed to write to it"); # and checking the target image $c = Imager::i_get_pixel($base_rgb, 25, 25); is_color3($c, 255, 0, 0, "check (25,25)"); $c = Imager::i_get_pixel($base_rgb, 29, 29); is_color3($c, 0, 255, 0, "check (29,29)"); undef $s_rgb; # a basic background for my $y (0..99) { Imager::i_plin($base_rgb, 0, $y, ($red ) x 100); } my $mask = Imager::ImgRaw::new(50, 50, 1); # some venetian blinds for my $y (4..20) { Imager::i_plin($mask, 5, $y*2, ($white) x 40); } # with a strip down the middle for my $y (0..49) { Imager::i_plin($mask, 20, $y, ($white) x 8); } my $m_rgb = Imager::i_img_masked_new($base_rgb, $mask, 25, 25, 50, 50); ok($m_rgb, "make masked with mask"); for my $y (0..49) { Imager::i_plin($m_rgb, 0, $y, ($green) x 50); } my @color_tests = ( [ 25+0, 25+0, $red ], [ 25+19, 25+0, $red ], [ 25+20, 25+0, $green ], [ 25+27, 25+0, $green ], [ 25+28, 25+0, $red ], [ 25+49, 25+0, $red ], [ 25+19, 25+7, $red ], [ 25+19, 25+8, $green ], [ 25+19, 25+9, $red ], [ 25+0, 25+8, $red ], [ 25+4, 25+8, $red ], [ 25+5, 25+8, $green ], [ 25+44, 25+8, $green ], [ 25+45, 25+8, $red ], [ 25+49, 25+49, $red ], ); my $test_num = 15; for my $test (@color_tests) { my ($x, $y, $testc) = @$test; my ($r, $g, $b) = $testc->rgba; my $c = Imager::i_get_pixel($base_rgb, $x, $y); is_color3($c, $r, $g, $b, "at ($x, $y)"); } { # tests for the OO versions, fairly simple, since the basic functionality # is covered by the low-level interface tests my $base = Imager->new(xsize=>100, ysize=>100); ok($base, "make base OO image"); $base->box(color=>$blue, filled=>1); # fill it all my $mask = Imager->new(xsize=>80, ysize=>80, channels=>1); $mask->box(color=>$white, filled=>1, xmin=>5, xmax=>75, ymin=>5, ymax=>75); my $m_img = $base->masked(mask=>$mask, left=>5, top=>5); ok($m_img, "make masked OO image"); is($m_img->getwidth, 80, "check width"); $m_img->box(color=>$green, filled=>1); my $c = $m_img->getpixel(x=>0, y=>0); is_color3($c, 0, 0, 255, "check (0,0)"); $c = $m_img->getpixel(x => 5, y => 5); is_color3($c, 0, 255, 0, "check (5,5)"); # older versions destroyed the Imager::ImgRaw object manually in # Imager::DESTROY rather than letting Imager::ImgRaw::DESTROY # destroy the object # so we test here by destroying the base and mask objects and trying # to draw to the masked wrapper # you may need to test with ElectricFence to trigger the problem undef $mask; undef $base; $m_img->box(color=>$blue, filled=>1); pass("didn't crash unreffing base or mask for masked image"); } # 35.7% cover on maskimg.c up to here { # error handling: my $base = Imager->new(xsize => 100, ysize => 100); ok($base, "make base"); { # make masked image subset outside of the base image my $masked = $base->masked(left => 100); ok (!$masked, "fail to make empty masked"); is($base->errstr, "subset outside of target image", "check message"); } } { # size limiting my $base = Imager->new(xsize => 10, ysize => 10); ok($base, "make base for size limit tests"); { my $masked = $base->masked(left => 5, right => 15); ok($masked, "make masked"); is($masked->getwidth, 5, "check width truncated"); } { my $masked = $base->masked(top => 5, bottom => 15); ok($masked, "make masked"); is($masked->getheight, 5, "check height truncated"); } } # 36.7% up to here $mask = Imager->new(xsize => 80, ysize => 80, channels => 1); $mask->box(filled => 1, color => $white, xmax => 39, ymax => 39); $mask->box(fill => { hatch => "check1x1" }, ymin => 40, xmax => 39); { my $base = Imager->new(xsize => 100, ysize => 100, bits => "double"); ok($base, "base for single pixel tests"); is($base->type, "direct", "check type"); my $masked = $base->masked(mask => $mask, left => 1, top => 2); my $limited = $base->masked(left => 1, top => 2); is($masked->type, "direct", "check masked is same type as base"); is($limited->type, "direct", "check limited is same type as base"); { # single pixel writes, masked { ok($masked->setpixel(x => 1, y => 3, color => $green), "set (1,3) in masked (2, 5) in based"); my $c = $base->getpixel(x => 2, y => 5); is_color3($c, 0, 255, 0, "check it wrote through"); ok($masked->setpixel(x => 45, y => 2, color => $red), "set (45,2) in masked (46,4) in base (no mask)"); $c = $base->getpixel(x => 46, y => 4); is_color3($c, 0, 0, 0, "shouldn't have written through"); } { ok($masked->setpixel(x => 2, y => 3, color => $redf), "write float red to (2,3) base(3,5)"); my $c = $base->getpixel(x => 3, y => 5); is_color3($c, 255, 0, 0, "check it wrote through"); ok($masked->setpixel(x => 45, y => 3, color => $greenf), "set float (45,3) in masked (46,5) in base (no mask)"); $c = $base->getpixel(x => 46, y => 5); is_color3($c, 0, 0, 0, "check it didn't write"); } { # write out of range should fail is($masked->setpixel(x => 80, y => 0, color => $green), "0 but true", "write 8-bit color out of range"); is($masked->setpixel(x => 0, y => 80, color => $greenf), "0 but true", "write float color out of range"); } } # 46.9 { print "# plin coverage\n"; { $base->box(filled => 1, color => $black); # plin masked # simple path is($masked->setscanline(x => 76, y => 1, pixels => [ ($red, $green) x 3 ]), 4, "try to write 6 pixels, but only write 4"); is_deeply([ $base->getsamples(x => 77, y => 3, width => 4) ], [ ( 0 ) x 12 ], "check not written through"); # !simple path is($masked->setscanline(x => 4, y => 2, pixels => [ ($red, $green, $blue, $grey) x (72/4) ]), 72, "write many pixels (masked)"); is_deeply([ $base->getsamples(x => 5, y => 4, width => 72) ], [ ( (255, 0, 0), (0, 255, 0), (0, 0, 255), (128, 128, 128)) x 9, ( 0, 0, 0 ) x 36 ], "check written through to base"); # simple path, due to number of transitions is($masked->setscanline(x => 0, y => 40, pixels => [ ($red, $green, $blue, $grey) x 5 ]), 20, "try to write 20 pixels, with alternating write through"); is_deeply([ $base->getsamples(x => 1, y => 42, width => 20) ], [ ( (0, 0, 0), (0,255,0), (0,0,0), (128,128,128) ) x 5 ], "check correct pixels written through"); } { $base->box(filled => 1, color => $black); # plin, non-masked path is($limited->setscanline(x => 4, y => 2, pixels => [ ($red, $green, $blue, $grey) x (72/4) ]), 72, "write many pixels (limited)"); is_deeply([ $base->getsamples(x => 5, y => 4, width => 72) ], [ ( (255, 0, 0), (0, 255, 0), (0, 0, 255), (128, 128, 128)) x 18 ], "check written through to based"); } { # draw outside fails is($masked->setscanline(x => 80, y => 2, pixels => [ $red, $green ]), 0, "check writing no pixels"); } } { print "# plinf coverage\n"; { $base->box(filled => 1, color => $black); # plinf masked # simple path is($masked->setscanline(x => 76, y => 1, pixels => [ ($redf, $greenf) x 3 ]), 4, "try to write 6 pixels, but only write 4"); is_deeply([ $base->getsamples(x => 77, y => 3, width => 4, type => "float") ], [ ( 0 ) x 12 ], "check not written through"); # !simple path is($masked->setscanline(x => 4, y => 2, pixels => [ ($redf, $greenf, $bluef, $greyf) x (72/4) ]), 72, "write many pixels (masked)"); is_deeply([ $base->getsamples(x => 5, y => 4, width => 72, type => "float") ], [ ( (1, 0, 0), (0, 1, 0), (0, 0, 1), (0.5, 0.5, 0.5)) x 9, ( 0, 0, 0 ) x 36 ], "check written through to base"); # simple path, due to number of transitions is($masked->setscanline(x => 0, y => 40, pixels => [ ($redf, $greenf, $bluef, $greyf) x 5 ]), 20, "try to write 20 pixels, with alternating write through"); is_deeply([ $base->getsamples(x => 1, y => 42, width => 20, type => "float") ], [ ( (0, 0, 0), (0,1,0), (0,0,0), (0.5,0.5,0.5) ) x 5 ], "check correct pixels written through"); } { $base->box(filled => 1, color => $black); # plinf, non-masked path is($limited->setscanline(x => 4, y => 2, pixels => [ ($redf, $greenf, $bluef, $greyf) x (72/4) ]), 72, "write many pixels (limited)"); is_deeply([ $base->getsamples(x => 5, y => 4, width => 72, type => "float") ], [ ( (1, 0, 0), (0, 1, 0), (0, 0, 1), (0.5, 0.5, 0.5)) x 18 ], "check written through to based"); } { # draw outside fails is($masked->setscanline(x => 80, y => 2, pixels => [ $redf, $greenf ]), 0, "check writing no pixels"); } } # 71.4% { { print "# gpix\n"; # gpix $base->box(filled => 1, color => $black); ok($base->setpixel(x => 4, y => 10, color => $red), "set base(4,10) to red"); is_fcolor3($masked->getpixel(x => 3, y => 8), 255, 0, 0, "check pixel written"); # out of range is($masked->getpixel(x => -1, y => 1), undef, "check failure to left"); is($masked->getpixel(x => 0, y => -1), undef, "check failure to top"); is($masked->getpixel(x => 80, y => 1), undef, "check failure to right"); is($masked->getpixel(x => 0, y => 80), undef, "check failure to bottom"); } { print "# gpixf\n"; # gpixf $base->box(filled => 1, color => $black); ok($base->setpixel(x => 4, y => 10, color => $redf), "set base(4,10) to red"); is_fcolor3($masked->getpixel(x => 3, y => 8, type => "float"), 1.0, 0, 0, 0, "check pixel written"); # out of range is($masked->getpixel(x => -1, y => 1, type => "float"), undef, "check failure to left"); is($masked->getpixel(x => 0, y => -1, type => "float"), undef, "check failure to top"); is($masked->getpixel(x => 80, y => 1, type => "float"), undef, "check failure to right"); is($masked->getpixel(x => 0, y => 80, type => "float"), undef, "check failure to bottom"); } } # 74.5 { { print "# glin\n"; $base->box(filled => 1, color => $black); is($base->setscanline(x => 31, y => 3, pixels => [ ( $red, $green) x 10 ]), 20, "write 20 pixels to base image"); my @colors = $masked-> getscanline(x => 30, y => 1, width => 20); is(@colors, 20, "check we got right number of colors"); is_color3($colors[0], 255, 0, 0, "check first pixel"); is_color3($colors[19], 0, 255, 0, "check last pixel"); @colors = $masked->getscanline(x => 76, y => 2, width => 10); is(@colors, 4, "read line from right edge"); is_color3($colors[0], 0, 0, 0, "check pixel"); is_deeply([ $masked->getscanline(x => -1, y => 0, width => 1) ], [], "fail read left of image"); is_deeply([ $masked->getscanline(x => 0, y => -1, width => 1) ], [], "fail read top of image"); is_deeply([$masked->getscanline(x => 80, y => 0, width => 1)], [], "fail read right of image"); is_deeply([$masked->getscanline(x => 0, y => 80, width => 1)], [], "fail read bottom of image"); } { print "# glinf\n"; $base->box(filled => 1, color => $black); is($base->setscanline(x => 31, y => 3, pixels => [ ( $redf, $greenf) x 10 ]), 20, "write 20 pixels to base image"); my @colors = $masked-> getscanline(x => 30, y => 1, width => 20, type => "float"); is(@colors, 20, "check we got right number of colors"); is_fcolor3($colors[0], 1.0, 0, 0, 0, "check first pixel"); is_fcolor3($colors[19], 0, 1.0, 0, 0, "check last pixel"); @colors = $masked-> getscanline(x => 76, y => 2, width => 10, type => "float"); is(@colors, 4, "read line from right edge"); is_fcolor3($colors[0], 0, 0, 0, 0, "check pixel"); is_deeply([ $masked->getscanline(x => -1, y => 0, width => 1, type => "float") ], [], "fail read left of image"); is_deeply([ $masked->getscanline(x => 0, y => -1, width => 1, type => "float") ], [], "fail read top of image"); is_deeply([$masked->getscanline(x => 80, y => 0, width => 1, type => "float")], [], "fail read right of image"); is_deeply([$masked->getscanline(x => 0, y => 80, width => 1, type => "float")], [], "fail read bottom of image"); } } # 81.6% { { print "# gsamp\n"; $base->box(filled => 1, color => $black); is($base->setscanline(x => 31, y => 3, pixels => [ ( $red, $green) x 10 ]), 20, "write 20 pixels to base image"); my @samps = $masked-> getsamples(x => 30, y => 1, width => 20); is(@samps, 60, "check we got right number of samples"); is_deeply(\@samps, [ (255, 0, 0, 0, 255, 0) x 10 ], "check it"); @samps = $masked-> getsamples(x => 76, y => 2, width => 10); is(@samps, 12, "read line from right edge"); is_deeply(\@samps, [ (0, 0, 0) x 4], "check result"); is_deeply([ $masked->getsamples(x => -1, y => 0, width => 1) ], [], "fail read left of image"); is_deeply([ $masked->getsamples(x => 0, y => -1, width => 1) ], [], "fail read top of image"); is_deeply([$masked->getsamples(x => 80, y => 0, width => 1)], [], "fail read right of image"); is_deeply([$masked->getsamples(x => 0, y => 80, width => 1)], [], "fail read bottom of image"); } { print "# gsampf\n"; $base->box(filled => 1, color => $black); is($base->setscanline(x => 31, y => 3, pixels => [ ( $redf, $greenf) x 10 ]), 20, "write 20 pixels to base image"); my @samps = $masked-> getsamples(x => 30, y => 1, width => 20, type => "float"); is(@samps, 60, "check we got right number of samples"); is_deeply(\@samps, [ (1.0, 0, 0, 0, 1.0, 0) x 10 ], "check it"); @samps = $masked-> getsamples(x => 76, y => 2, width => 10, type => "float"); is(@samps, 12, "read line from right edge"); is_deeply(\@samps, [ (0, 0, 0) x 4], "check result"); is_deeply([ $masked->getsamples(x => -1, y => 0, width => 1, type => "float") ], [], "fail read left of image"); is_deeply([ $masked->getsamples(x => 0, y => -1, width => 1, type => "float") ], [], "fail read top of image"); is_deeply([$masked->getsamples(x => 80, y => 0, width => 1, type => "float")], [], "fail read right of image"); is_deeply([$masked->getsamples(x => 0, y => 80, width => 1, type => "float")], [], "fail read bottom of image"); } } # 86.2% } { my $base = Imager->new(xsize => 100, ysize => 100, type => "paletted"); ok($base, "make paletted base"); is($base->type, "paletted", "check we got paletted"); is($base->addcolors(colors => [ $black, $red, $green, $blue ]), "0 but true", "add some colors to base"); my $masked = $base->masked(mask => $mask, left => 1, top => 2); my $limited = $base->masked(left => 1, top => 2); is($masked->type, "paletted", "check masked is same type as base"); is($limited->type, "paletted", "check limited is same type as base"); { # make sure addcolors forwarded is($masked->addcolors(colors => [ $grey ]), 4, "test addcolors forwarded"); my @colors = $masked->getcolors(); is(@colors, 5, "check getcolors forwarded"); is_color3($colors[1], 255, 0, 0, "check color from palette"); } my ($blacki, $redi, $greeni, $bluei, $greyi) = 0 .. 4; { # gpal print "# gpal\n"; $base->box(filled => 1, color => $black); is($base->setscanline(x => 0, y => 5, type => "index", pixels => [ ( $redi, $greeni, $bluei, $greyi) x 25 ]), 100, "write some pixels to base"); my @indexes = $masked->getscanline(y => 3, type => "index", width => "81"); is(@indexes, 80, "got 80 indexes"); is_deeply(\@indexes, [ ( $greeni, $bluei, $greyi, $redi) x 20 ], "check values"); is_deeply([ $masked->getscanline(x => -1, y => 3, type => "index") ], [], "fail read left of image"); } # 89.8% { # ppal, unmasked print "# ppal\n"; $base->box(filled => 1, color => $black); is($limited->setscanline(x => 1, y => 1, type => "index", pixels => [ ( $redi, $greeni, $bluei) x 3 ]), 9, "ppal limited"); is_deeply([ $base->getscanline(x => 2, y => 3, type => "index", width => 9) ], [ ( $redi, $greeni, $bluei) x 3 ], "check set in base"); } { # ppal, masked $base->box(filled => 1, color => $black); is($masked->setscanline(x => 1, y => 2, type => "index", pixels => [ ( $redi, $greeni, $bluei, $greyi) x 12 ]), 48, "ppal masked"); is_deeply([ $base->getscanline(x => 0, y => 4, type => "index") ], [ 0, 0, ( $redi, $greeni, $bluei, $greyi ) x 9, $redi, $greeni, $bluei, ( 0 ) x 59 ], "check written"); } { # ppal, errors is($masked->setscanline(x => -1, y => 0, type => "index", pixels => [ $redi, $bluei ]), 0, "fail to write ppal"); is($masked->setscanline(x => 78, y => 0, type => "index", pixels => [ $redi, $bluei, $greeni, $greyi ]), 2, "write over right side"); } } my $full_mask = Imager->new(xsize => 10, ysize => 10, channels => 1); $full_mask->box(filled => 1, color => NC(255, 0, 0)); # no mask and mask with full coverage should behave the same my $psamp_outside_error = "Image position outside of image"; for my $masked (0, 1){ # psamp print "# psamp masked: $masked\n"; my $imback = Imager::ImgRaw::new(20, 20, 3); my $mask; if ($masked) { $mask = $full_mask->{IMG}; } my $imraw = Imager::i_img_masked_new($imback, $mask, 3, 4, 10, 10); { is(Imager::i_psamp($imraw, 0, 2, undef, [ 255, 128, 64 ]), 3, "i_psamp def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psamp($imraw, 1, 3, undef, [ 64, 128, 192 ]), 3, "i_psamp def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 192, "check color written"); is(Imager::i_psamp($imraw, 1, 7, [ 0, 1, 2 ], [ 64, 128, 192 ]), 3, "i_psamp channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 192, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psamp($imraw, 2, 4, [ 0, 1 ], [ 255, 128, 64, 32 ]), 4, "i_psamp channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psamp($imraw, 0, 5, [ 0, 1, 2 ], [ (128, 63, 32) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 63, 32) x 10 ], "check full row"); is(Imager::i_psamp($imraw, 8, 8, [ 0, 1, 2 ], [ 255, 128, 32, 64, 32, 16, 32, 16, 8 ]), 6, "i_psamp channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, 3 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, -1 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psamp($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } print "# end psamp tests\n"; } for my $masked (0, 1) { # psampf print "# psampf\n"; my $imback = Imager::ImgRaw::new(20, 20, 3); my $mask; if ($masked) { $mask = $full_mask->{IMG}; } my $imraw = Imager::i_img_masked_new($imback, $mask, 3, 4, 10, 10); { is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3, "i_psampf def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3, "i_psampf def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191, "check color written"); is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3, "i_psampf channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4, "i_psampf channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 64, 32) x 10 ], "check full row"); is(Imager::i_psampf($imraw, 8, 8, [ 0, 1, 2 ], [ 1.0, 0.5, 0.125, 0.25, 0.125, 0.0625, 0.125, 0, 1 ]), 6, "i_psampf channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, 3 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, -1 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psampf($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } print "# end psampf tests\n"; } { my $sub_mask = $full_mask->copy; $sub_mask->box(filled => 1, color => NC(0,0,0), xmin => 4, xmax => 6); my $base = Imager::ImgRaw::new(20, 20, 3); my $masked = Imager::i_img_masked_new($base, $sub_mask->{IMG}, 3, 4, 10, 10); is(Imager::i_psamp($masked, 0, 2, undef, [ ( 0, 127, 255) x 10 ]), 30, "psamp() to masked image"); is_deeply([ Imager::i_gsamp($base, 0, 20, 6, undef) ], [ ( 0, 0, 0 ) x 3, # left of mask ( 0, 127, 255 ) x 4, # masked area ( 0, 0, 0 ) x 3, # unmasked area ( 0, 127, 255 ) x 3, # masked area ( 0, 0, 0 ) x 7 ], # right of mask "check values written"); is(Imager::i_psampf($masked, 0, 2, undef, [ ( 0, 0.5, 1.0) x 10 ]), 30, "psampf() to masked image"); is_deeply([ Imager::i_gsamp($base, 0, 20, 6, undef) ], [ ( 0, 0, 0 ) x 3, # left of mask ( 0, 128, 255 ) x 4, # masked area ( 0, 0, 0 ) x 3, # unmasked area ( 0, 128, 255 ) x 3, # masked area ( 0, 0, 0 ) x 7 ], # right of mask "check values written"); } { my $empty = Imager->new; ok(!$empty->masked, "fail to make a masked image from an empty"); is($empty->errstr, "masked: empty input image", "check error message"); } Imager->close_log(); unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t020masked.log"; } sub _get_error { my @errors = Imager::i_errors(); return join(": ", map $_->[0], @errors); } libimager-perl-1.004+dfsg.orig/t/150-type/030-double.t0000644000175000017500000002657212263740601021264 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 136; BEGIN { use_ok(Imager => qw(:all :handy)) } use Imager::Test qw(test_image is_image is_color3); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t022double.log"); use Imager::Test qw(image_bounds_checks test_colorf_gpix test_colorf_glin mask_tests); use Imager::Color::Float; my $im_g = Imager::i_img_double_new(100, 101, 1); ok(Imager::i_img_getchannels($im_g) == 1, "1 channel image channel count mismatch"); ok(Imager::i_img_getmask($im_g) & 1, "1 channel image bad mask"); ok(Imager::i_img_virtual($im_g) == 0, "1 channel image thinks it is virtual"); my $double_bits = length(pack("d", 1)) * 8; print "# $double_bits double bits\n"; ok(Imager::i_img_bits($im_g) == $double_bits, "1 channel image has bits != $double_bits"); ok(Imager::i_img_type($im_g) == 0, "1 channel image isn't direct"); my @ginfo = i_img_info($im_g); ok($ginfo[0] == 100, "1 channel image width incorrect"); ok($ginfo[1] == 101, "1 channel image height incorrect"); undef $im_g; my $im_rgb = Imager::i_img_double_new(100, 101, 3); ok(Imager::i_img_getchannels($im_rgb) == 3, "3 channel image channel count mismatch"); ok((Imager::i_img_getmask($im_rgb) & 7) == 7, "3 channel image bad mask"); ok(Imager::i_img_bits($im_rgb) == $double_bits, "3 channel image has bits != $double_bits"); ok(Imager::i_img_type($im_rgb) == 0, "3 channel image isn't direct"); my $redf = NCF(1, 0, 0); my $greenf = NCF(0, 1, 0); my $bluef = NCF(0, 0, 1); # fill with red for my $y (0..101) { Imager::i_plinf($im_rgb, 0, $y, ($redf) x 100); } # basic sanity test_colorf_gpix($im_rgb, 0, 0, $redf); test_colorf_gpix($im_rgb, 99, 0, $redf); test_colorf_gpix($im_rgb, 0, 100, $redf); test_colorf_gpix($im_rgb, 99, 100, $redf); test_colorf_glin($im_rgb, 0, 0, [ ($redf) x 100 ], 'sanity glin @0'); test_colorf_glin($im_rgb, 0, 100, [ ($redf) x 100 ], 'sanity glin @100'); Imager::i_plinf($im_rgb, 20, 1, ($greenf) x 60); test_colorf_glin($im_rgb, 0, 1, [ ($redf) x 20, ($greenf) x 60, ($redf) x 20 ], 'check after write'); # basic OO tests my $ooimg = Imager->new(xsize=>200, ysize=>201, bits=>'double'); ok($ooimg, "couldn't make double image"); is($ooimg->bits, 'double', "oo didn't give double image"); ok(!$ooimg->is_bilevel, 'not monochrome'); # check that the image is copied correctly my $oocopy = $ooimg->copy; is($oocopy->bits, 'double', "oo copy didn't give double image"); ok(!Imager->new(xsize=>0, ysize=>1, bits=>'double'), "fail making 0 width image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct message"); ok(!Imager->new(xsize=>1, ysize=>0, bits=>'double'), "fail making 0 height image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct message"); ok(!Imager->new(xsize=>-1, ysize=>1, bits=>'double'), "fail making -ve width image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct message"); ok(!Imager->new(xsize=>1, ysize=>-1, bits=>'double'), "fail making -ve height image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct message"); ok(!Imager->new(xsize=>1, ysize=>1, bits=>'double', channels=>0), "fail making 0 channel image"); cmp_ok(Imager->errstr, '=~', qr/channels must be between 1 and 4/, "and correct message"); ok(!Imager->new(xsize=>1, ysize=>1, bits=>'double', channels=>5), "fail making 5 channel image"); cmp_ok(Imager->errstr, '=~', qr/channels must be between 1 and 4/, "and correct message"); { # https://rt.cpan.org/Ticket/Display.html?id=8213 # check for handling of memory allocation of very large images # only test this on 32-bit machines - on a 64-bit machine it may # result in trying to allocate 4Gb of memory, which is unfriendly at # least and may result in running out of memory, causing a different # type of exit use Config; SKIP: { $Config{ptrsize} == 4 or skip "don't want to allocate 4Gb", 8; my $uint_range = 256 ** $Config{intsize}; my $dbl_size = $Config{doublesize} || 8; my $dim1 = int(sqrt($uint_range/$dbl_size))+1; my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1, bits=>'double'); is($im_b, undef, "integer overflow check - 1 channel"); $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1, bits=>'double'); ok($im_b, "but same width ok"); $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1, bits=>'double'); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); # do a similar test with a 3 channel image, so we're sure we catch # the same case where the third dimension causes the overflow my $dim3 = int(sqrt($uint_range / 3 / $dbl_size))+1; $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3, bits=>'double'); is($im_b, undef, "integer overflow check - 3 channel"); $im_b = Imager->new(xsize=>$dim3, ysize=>1, channels=>3, bits=>'double'); ok($im_b, "but same width ok"); $im_b = Imager->new(xsize=>1, ysize=>$dim3, channels=>3, bits=>'double'); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); } } { # check the channel mask function my $im = Imager->new(xsize => 10, ysize=>10, bits=>'double'); mask_tests($im); } { # bounds checking my $im = Imager->new(xsize => 10, ysize=>10, bits=>'double'); image_bounds_checks($im); } { # convert to rgb double my $im = test_image(); my $imdb = $im->to_rgb_double; print "# check conversion to double\n"; is($imdb->bits, "double", "check bits"); is_image($im, $imdb, "check image data matches"); } { # empty image handling my $im = Imager->new; ok($im, "make empty image"); ok(!$im->to_rgb_double, "convert empty image to double"); is($im->errstr, "to_rgb_double: empty input image", "check message"); } my $psamp_outside_error = "Image position outside of image"; { # psamp print "# psamp\n"; my $imraw = Imager::i_img_double_new(10, 10, 3); { is(Imager::i_psamp($imraw, 0, 2, undef, [ 255, 128, 64 ]), 3, "i_psamp def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psamp($imraw, 1, 3, undef, [ 64, 128, 192 ]), 3, "i_psamp def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 192, "check color written"); is(Imager::i_psamp($imraw, 1, 7, [ 0, 1, 2 ], [ 64, 128, 192 ]), 3, "i_psamp channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 192, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psamp($imraw, 2, 4, [ 0, 1 ], [ 255, 128, 64, 32 ]), 4, "i_psamp channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psamp($imraw, 0, 5, [ 0, 1, 2 ], [ (128, 63, 32) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 63, 32) x 10 ], "check full row"); is(Imager::i_psamp($imraw, 8, 8, [ 0, 1, 2 ], [ 255, 128, 32, 64, 32, 16, 32, 16, 8 ]), 6, "i_psamp channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, 3 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, -1 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psamp($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } print "# end psamp tests\n"; } { # psampf print "# psampf\n"; my $imraw = Imager::i_img_double_new(10, 10, 3); { is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3, "i_psampf def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3, "i_psampf def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191, "check color written"); is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3, "i_psampf channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4, "i_psampf channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 64, 32) x 10 ], "check full row"); is(Imager::i_psampf($imraw, 8, 8, [ 0, 1, 2 ], [ 1.0, 0.5, 0.125, 0.25, 0.125, 0.0625, 0.125, 0, 1 ]), 6, "i_psampf channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, 3 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, -1 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psampf($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } print "# end psampf tests\n"; } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t022double.log"; } sub _get_error { my @errors = Imager::i_errors(); return join(": ", map $_->[0], @errors); } libimager-perl-1.004+dfsg.orig/t/150-type/040-palette.t0000644000175000017500000006321012263740601021437 0ustar gregoagregoa#!perl -w # some of this is tested in t01introvert.t too use strict; use Test::More tests => 226; BEGIN { use_ok("Imager", ':handy'); } use Imager::Test qw(image_bounds_checks test_image is_color3 isnt_image is_color4 is_fcolor3); Imager->open_log(log => "testout/t023palette.log"); sub isbin($$$); my $img = Imager->new(xsize=>50, ysize=>50, type=>'paletted'); ok($img, "paletted image created"); is($img->type, 'paletted', "got a paletted image"); my $black = Imager::Color->new(0,0,0); my $red = Imager::Color->new(255,0,0); my $green = Imager::Color->new(0,255,0); my $blue = Imager::Color->new(0,0,255); my $white = Imager::Color->new(255,255,255); # add some color my $blacki = $img->addcolors(colors=>[ $black, $red, $green, $blue ]); print "# blacki $blacki\n"; ok(defined $blacki && $blacki == 0, "we got the first color"); is($img->colorcount(), 4, "should have 4 colors"); is($img->maxcolors, 256, "maxcolors always 256"); my ($redi, $greeni, $bluei) = 1..3; my @all = $img->getcolors; ok(@all == 4, "all colors is 4"); coloreq($all[0], $black, "first black"); coloreq($all[1], $red, "then red"); coloreq($all[2], $green, "then green"); coloreq($all[3], $blue, "and finally blue"); # keep this as an assignment, checking for scalar context # we don't want the last color, otherwise if the behaviour changes to # get all up to the last (count defaulting to size-index) we'd get a # false positive my $one_color = $img->getcolors(start=>$redi); ok($one_color->isa('Imager::Color'), "check scalar context"); coloreq($one_color, $red, "and that it's what we want"); # make sure we can find colors ok(!defined($img->findcolor(color=>$white)), "shouldn't be able to find white"); ok($img->findcolor(color=>$black) == $blacki, "find black"); ok($img->findcolor(color=>$red) == $redi, "find red"); ok($img->findcolor(color=>$green) == $greeni, "find green"); ok($img->findcolor(color=>$blue) == $bluei, "find blue"); # various failure tests for setcolors ok(!defined($img->setcolors(start=>-1, colors=>[$white])), "expect failure: low index"); ok(!defined($img->setcolors(start=>1, colors=>[])), "expect failure: no colors"); ok(!defined($img->setcolors(start=>5, colors=>[$white])), "expect failure: high index"); # set the green index to white ok($img->setcolors(start => $greeni, colors => [$white]), "set a color"); # and check it coloreq(scalar($img->getcolors(start=>$greeni)), $white, "make sure it was set"); ok($img->findcolor(color=>$white) == $greeni, "and that we can find it"); ok(!defined($img->findcolor(color=>$green)), "and can't find the old color"); # write a few colors ok(scalar($img->setcolors(start=>$redi, colors=>[ $green, $red])), "save multiple"); coloreq(scalar($img->getcolors(start=>$redi)), $green, "first of multiple"); coloreq(scalar($img->getcolors(start=>$greeni)), $red, "second of multiple"); # put it back $img->setcolors(start=>$red, colors=>[$red, $green]); # draw on the image, make sure it stays paletted when it should ok($img->box(color=>$red, filled=>1), "fill with red"); is($img->type, 'paletted', "paletted after fill"); ok($img->box(color=>$green, filled=>1, xmin=>10, ymin=>10, xmax=>40, ymax=>40), "green box"); is($img->type, 'paletted', 'still paletted after box'); # an AA line will almost certainly convert the image to RGB, don't use # an AA line here ok($img->line(color=>$blue, x1=>10, y1=>10, x2=>40, y2=>40), "draw a line"); is($img->type, 'paletted', 'still paletted after line'); # draw with white - should convert to direct ok($img->box(color=>$white, filled=>1, xmin=>20, ymin=>20, xmax=>30, ymax=>30), "white box"); is($img->type, 'direct', "now it should be direct"); # various attempted to make a paletted image from our now direct image my $palimg = $img->to_paletted; ok($palimg, "we got an image"); # they should be the same pixel for pixel ok(Imager::i_img_diff($img->{IMG}, $palimg->{IMG}) == 0, "same pixels"); # strange case: no color picking, and no colors # this was causing a segmentation fault $palimg = $img->to_paletted(colors=>[ ], make_colors=>'none'); ok(!defined $palimg, "to paletted with an empty palette is an error"); print "# ",$img->errstr,"\n"; ok(scalar($img->errstr =~ /no colors available for translation/), "and got the correct msg"); ok(!Imager->new(xsize=>1, ysize=>-1, type=>'paletted'), "fail on -ve height"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>-1, ysize=>1, type=>'paletted'), "fail on -ve width"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>-1, ysize=>-1, type=>'paletted'), "fail on -ve width/height"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>1, ysize=>1, type=>'paletted', channels=>0), "fail on 0 channels"); cmp_ok(Imager->errstr, '=~', qr/Channels must be positive and <= 4/, "and correct error message"); ok(!Imager->new(xsize=>1, ysize=>1, type=>'paletted', channels=>5), "fail on 5 channels"); cmp_ok(Imager->errstr, '=~', qr/Channels must be positive and <= 4/, "and correct error message"); { # https://rt.cpan.org/Ticket/Display.html?id=8213 # check for handling of memory allocation of very large images # only test this on 32-bit machines - on a 64-bit machine it may # result in trying to allocate 4Gb of memory, which is unfriendly at # least and may result in running out of memory, causing a different # type of exit use Config; SKIP: { skip("don't want to allocate 4Gb", 10) unless $Config{ptrsize} == 4; my $uint_range = 256 ** $Config{intsize}; my $dim1 = int(sqrt($uint_range))+1; my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1, type=>'paletted'); is($im_b, undef, "integer overflow check - 1 channel"); $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1, type=>'paletted'); ok($im_b, "but same width ok"); $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1, type=>'paletted'); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); # do a similar test with a 3 channel image, so we're sure we catch # the same case where the third dimension causes the overflow # for paletted images the third dimension can't cause an overflow # but make sure we didn't anything too dumb in the checks my $dim3 = $dim1; $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3, type=>'paletted'); is($im_b, undef, "integer overflow check - 3 channel"); $im_b = Imager->new(xsize=>$dim3, ysize=>1, channels=>3, type=>'paletted'); ok($im_b, "but same width ok"); $im_b = Imager->new(xsize=>1, ysize=>$dim3, channels=>3, type=>'paletted'); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); # test the scanline allocation check # divide by 2 to get int range, by 3 so that the image (one byte/pixel) # doesn't integer overflow, but the scanline of i_color (4/pixel) does my $dim4 = $uint_range / 3; my $im_o = Imager->new(xsize=>$dim4, ysize=>1, channels=>3, type=>'paletted'); is($im_o, undef, "integer overflow check - scanline size"); cmp_ok(Imager->errstr, '=~', qr/integer overflow calculating scanline allocation/, "check error message"); } } { # http://rt.cpan.org/NoAuth/Bug.html?id=9672 my $warning; local $SIG{__WARN__} = sub { $warning = "@_"; my $printed = $warning; $printed =~ s/\n$//; $printed =~ s/\n/\n\#/g; print "# ",$printed, "\n"; }; my $img = Imager->new(xsize=>10, ysize=>10); $img->to_paletted(); cmp_ok($warning, '=~', 'void', "correct warning"); cmp_ok($warning, '=~', 'palette\\.t', "correct file"); } { # http://rt.cpan.org/NoAuth/Bug.html?id=12676 # setcolors() has a fencepost error my $img = Imager->new(xsize=>10, ysize=>10, type=>'paletted'); is($img->addcolors(colors=>[ $black, $red ]), "0 but true", "add test colors"); ok($img->setcolors(start=>1, colors=>[ $green ]), "set the last color"); ok(!$img->setcolors(start=>2, colors=>[ $black ]), "set after the last color"); } { # https://rt.cpan.org/Ticket/Display.html?id=20056 # added named color support to addcolor/setcolor my $img = Imager->new(xsize => 10, ysize => 10, type => 'paletted'); is($img->addcolors(colors => [ qw/000000 FF0000/ ]), "0 but true", "add colors as strings instead of objects"); my @colors = $img->getcolors; iscolor($colors[0], $black, "check first color"); iscolor($colors[1], $red, "check second color"); ok($img->setcolors(colors => [ qw/00FF00 0000FF/ ]), "setcolors as strings instead of objects"); @colors = $img->getcolors; iscolor($colors[0], $green, "check first color"); iscolor($colors[1], $blue, "check second color"); # make sure we handle bad colors correctly is($img->colorcount, 2, "start from a known state"); is($img->addcolors(colors => [ 'XXFGXFXGXFX' ]), undef, "fail to add unknown color"); is($img->errstr, 'No color named XXFGXFXGXFX found', 'check error message'); is($img->setcolors(colors => [ 'XXFGXFXGXFXZ' ]), undef, "fail to set to unknown color"); is($img->errstr, 'No color named XXFGXFXGXFXZ found', 'check error message'); } { # https://rt.cpan.org/Ticket/Display.html?id=20338 # OO interface to i_glin/i_plin my $im = Imager->new(xsize => 10, ysize => 10, type => 'paletted'); is($im->addcolors(colors => [ "#000", "#F00", "#0F0", "#00F" ]), "0 but true", "add some test colors") or print "# ", $im->errstr, "\n"; # set a pixel to check $im->setpixel(x => 1, 'y' => 0, color => "#0F0"); is_deeply([ $im->getscanline('y' => 0, type=>'index') ], [ 0, 2, (0) x 8 ], "getscanline index in list context"); isbin($im->getscanline('y' => 0, type=>'index'), "\x00\x02" . "\x00" x 8, "getscanline index in scalar context"); is($im->setscanline('y' => 0, pixels => [ 1, 2, 0, 3 ], type => 'index'), 4, "setscanline with list"); is($im->setscanline('y' => 0, x => 4, pixels => pack("C*", 3, 2, 1, 0, 3), type => 'index'), 5, "setscanline with pv"); is_deeply([ $im->getscanline(type => 'index', 'y' => 0) ], [ 1, 2, 0, 3, 3, 2, 1, 0, 3, 0 ], "check values set"); eval { # should croak on OOR index $im->setscanline('y' => 1, pixels => [ 255 ], type=>'index'); }; ok($@, "croak on setscanline() to invalid index"); eval { # same again with pv $im->setscanline('y' => 1, pixels => "\xFF", type => 'index'); }; ok($@, "croak on setscanline() with pv to invalid index"); } { print "# make_colors => mono\n"; # test mono make_colors my $imrgb = Imager->new(xsize => 10, ysize => 10); $imrgb->setpixel(x => 0, 'y' => 0, color => '#FFF'); $imrgb->setpixel(x => 1, 'y' => 0, color => '#FF0'); $imrgb->setpixel(x => 2, 'y' => 0, color => '#000'); my $mono = $imrgb->to_paletted(make_colors => 'mono', translate => 'closest'); is($mono->type, 'paletted', "check we get right image type"); is($mono->colorcount, 2, "only 2 colors"); my ($is_mono, $ziw) = $mono->is_bilevel; ok($is_mono, "check monochrome check true"); is($ziw, 0, "check ziw false"); my @colors = $mono->getcolors; iscolor($colors[0], $black, "check first entry"); iscolor($colors[1], $white, "check second entry"); my @pixels = $mono->getscanline(x => 0, 'y' => 0, width => 3, type=>'index'); is($pixels[0], 1, "check white pixel"); is($pixels[1], 1, "check yellow pixel"); is($pixels[2], 0, "check black pixel"); } { # check for the various mono images we accept my $mono_8_bw_3 = Imager->new(xsize => 2, ysize => 2, channels => 3, type => 'paletted'); ok($mono_8_bw_3->addcolors(colors => [ qw/000000 FFFFFF/ ]), "mono8bw3 - add colors"); ok($mono_8_bw_3->is_bilevel, "it's mono"); is(($mono_8_bw_3->is_bilevel)[1], 0, 'zero not white'); my $mono_8_wb_3 = Imager->new(xsize => 2, ysize => 2, channels => 3, type => 'paletted'); ok($mono_8_wb_3->addcolors(colors => [ qw/FFFFFF 000000/ ]), "mono8wb3 - add colors"); ok($mono_8_wb_3->is_bilevel, "it's mono"); is(($mono_8_wb_3->is_bilevel)[1], 1, 'zero is white'); my $mono_8_bw_1 = Imager->new(xsize => 2, ysize => 2, channels => 1, type => 'paletted'); ok($mono_8_bw_1->addcolors(colors => [ qw/000000 FFFFFF/ ]), "mono8bw - add colors"); ok($mono_8_bw_1->is_bilevel, "it's mono"); is(($mono_8_bw_1->is_bilevel)[1], 0, 'zero not white'); my $mono_8_wb_1 = Imager->new(xsize => 2, ysize => 2, channels => 1, type => 'paletted'); ok($mono_8_wb_1->addcolors(colors => [ qw/FFFFFF 000000/ ]), "mono8wb - add colors"); ok($mono_8_wb_1->is_bilevel, "it's mono"); is(($mono_8_wb_1->is_bilevel)[1], 1, 'zero is white'); } { # check bounds checking my $im = Imager->new(xsize => 10, ysize => 10, type=>'paletted'); ok($im->addcolors(colors => [ $black ]), "add color of pixel bounds check writes"); image_bounds_checks($im); } { # test colors array returns colors my $data; my $im = test_image(); my @colors; my $imp = $im->to_paletted(colors => \@colors, make_colors => 'webmap', translate => 'closest'); ok($imp, "made paletted"); is(@colors, 216, "should be 216 colors in the webmap"); is_color3($colors[0], 0, 0, 0, "first should be 000000"); is_color3($colors[1], 0, 0, 0x33, "second should be 000033"); is_color3($colors[8], 0, 0x33, 0x66, "9th should be 003366"); } { # RT 68508 my $im = Imager->new(xsize => 10, ysize => 10); $im->box(filled => 1, color => Imager::Color->new(255, 0, 0)); my $palim = $im->to_paletted(make_colors => "mono", translate => "errdiff"); ok($palim, "convert to mono with error diffusion"); my $blank = Imager->new(xsize => 10, ysize => 10); isnt_image($palim, $blank, "make sure paletted isn't all black"); } { # check validation of palette entries my $im = Imager->new(xsize => 10, ysize => 10, type => 'paletted'); $im->addcolors(colors => [ $black, $red ]); { my $no_croak = eval { $im->setscanline(y => 0, type => 'index', pixels => [ 0, 1 ]); 1; }; ok($no_croak, "valid values don't croak"); } { my $no_croak = eval { $im->setscanline(y => 0, type => 'index', pixels => pack("C*", 0, 1)); 1; }; ok($no_croak, "valid values don't croak (packed)"); } { my $no_croak = eval { $im->setscanline(y => 0, type => 'index', pixels => [ 2, 255 ]); 1; }; ok(!$no_croak, "invalid values do croak"); } { my $no_croak = eval { $im->setscanline(y => 0, type => 'index', pixels => pack("C*", 2, 255)); 1; }; ok(!$no_croak, "invalid values do croak (packed)"); } } { my $im = Imager->new(xsize => 1, ysize => 1); my $im_bad = Imager->new; { my @map = Imager->make_palette({}); ok(!@map, "make_palette should fail with no images"); is(Imager->errstr, "make_palette: supply at least one image", "check error message"); } { my @map = Imager->make_palette({}, $im, $im_bad, $im); ok(!@map, "make_palette should fail with an empty image"); is(Imager->errstr, "make_palette: image 2 is empty", "check error message"); } { my @map = Imager->make_palette({ make_colors => "mono" }, $im); is(@map, 2, "mono should make 2 color palette") or skip("unexpected color count", 2); is_color4($map[0], 0, 0, 0, 255, "check map[0]"); is_color4($map[1], 255, 255, 255, 255, "check map[1]"); } { my @map = Imager->make_palette({ make_colors => "gray4" }, $im); is(@map, 4, "gray4 should make 4 color palette") or skip("unexpected color count", 4); is_color4($map[0], 0, 0, 0, 255, "check map[0]"); is_color4($map[1], 85, 85, 85, 255, "check map[1]"); is_color4($map[2], 170, 170, 170, 255, "check map[2]"); is_color4($map[3], 255, 255, 255, 255, "check map[3]"); } { my @map = Imager->make_palette({ make_colors => "gray16" }, $im); is(@map, 16, "gray16 should make 16 color palette") or skip("unexpected color count", 4); is_color4($map[0], 0, 0, 0, 255, "check map[0]"); is_color4($map[1], 17, 17, 17, 255, "check map[1]"); is_color4($map[2], 34, 34, 34, 255, "check map[2]"); is_color4($map[15], 255, 255, 255, 255, "check map[15]"); } { my @map = Imager->make_palette({ make_colors => "gray" }, $im); is(@map, 256, "gray16 should make 256 color palette") or skip("unexpected color count", 4); is_color4($map[0], 0, 0, 0, 255, "check map[0]"); is_color4($map[1], 1, 1, 1, 255, "check map[1]"); is_color4($map[33], 33, 33, 33, 255, "check map[2]"); is_color4($map[255], 255, 255, 255, 255, "check map[15]"); } } my $psamp_outside_error = "Image position outside of image"; { # psamp print "# psamp\n"; my $imraw = Imager::i_img_pal_new(10, 10, 3, 255); my @colors = ( NC(0, 0, 0), NC(255, 128, 64), NC(64, 128, 192), NC(64, 0, 192), NC(255, 128, 0), NC(64, 32, 0), NC(128, 63, 32), NC(255, 128, 32), NC(64, 32, 16), ); is(Imager::i_addcolors($imraw, @colors), "0 but true", "add colors needed for testing"); { is(Imager::i_psamp($imraw, 0, 2, undef, [ 255, 128, 64 ]), 3, "i_psamp def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psamp($imraw, 1, 3, undef, [ 64, 128, 192 ]), 3, "i_psamp def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 192, "check color written"); is(Imager::i_psamp($imraw, 1, 7, [ 0, 1, 2 ], [ 64, 128, 192 ]), 3, "i_psamp channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 192, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psamp($imraw, 2, 4, [ 0, 1 ], [ 255, 128, 64, 32 ]), 4, "i_psamp channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psamp($imraw, 0, 5, [ 0, 1, 2 ], [ (128, 63, 32) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 63, 32) x 10 ], "check full row"); is(Imager::i_psamp($imraw, 8, 8, [ 0, 1, 2 ], [ 255, 128, 32, 64, 32, 16, 32, 16, 8 ]), 6, "i_psamp channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, 3 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, -1 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psamp($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check message"); is(Imager::i_psamp($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check message"); is(Imager::i_psamp($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check message"); is(Imager::i_psamp($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check message"); } ok(Imager::i_img_type($imraw), "still paletted"); print "# end psamp tests\n"; } { # psampf print "# psampf\n"; my $imraw = Imager::i_img_pal_new(10, 10, 3, 255); my @colors = ( NC(0, 0, 0), NC(255, 128, 64), NC(64, 128, 192), NC(64, 0, 191), NC(255, 128, 0), NC(64, 32, 0), NC(128, 64, 32), NC(255, 128, 32), NC(64, 32, 16), ); is(Imager::i_addcolors($imraw, @colors), "0 but true", "add colors needed for testing"); { is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3, "i_psampf def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3, "i_psampf def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191, "check color written"); is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3, "i_psampf channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4, "i_psampf channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 64, 32) x 10 ], "check full row"); is(Imager::i_psampf($imraw, 8, 8, [ 0, 1, 2 ], [ 1.0, 0.5, 0.125, 0.25, 0.125, 0.0625, 0.125, 0, 1 ]), 6, "i_psampf channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, 3 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, -1 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psampf($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check message"); is(Imager::i_psampf($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check message"); is(Imager::i_psampf($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check message"); is(Imager::i_psampf($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check message"); } ok(Imager::i_img_type($imraw), "still paletted"); print "# end psampf tests\n"; } { # 75258 - gpixf() broken for paletted images my $im = Imager->new(xsize => 10, ysize => 10, type => "paletted"); ok($im, "make a test image"); my @colors = ( $black, $red, $green, $blue ); is($im->addcolors(colors => \@colors), "0 but true", "add some colors"); $im->setpixel(x => 0, y => 0, color => $red); $im->setpixel(x => 1, y => 0, color => $green); $im->setpixel(x => 2, y => 0, color => $blue); is_fcolor3($im->getpixel(x => 0, y => 0, type => "float"), 1.0, 0, 0, "get a pixel in float form, make sure it's red"); is_fcolor3($im->getpixel(x => 1, y => 0, type => "float"), 0, 1.0, 0, "get a pixel in float form, make sure it's green"); is_fcolor3($im->getpixel(x => 2, y => 0, type => "float"), 0, 0, 1.0, "get a pixel in float form, make sure it's blue"); } { my $empty = Imager->new; ok(!$empty->to_paletted, "can't convert an empty image"); is($empty->errstr, "to_paletted: empty input image", "check error message"); is($empty->addcolors(colors => [ $black ]), -1, "can't addcolors() to an empty image"); is($empty->errstr, "addcolors: empty input image", "check error message"); ok(!$empty->setcolors(colors => [ $black ]), "can't setcolors() to an empty image"); is($empty->errstr, "setcolors: empty input image", "check error message"); ok(!$empty->getcolors(), "can't getcolors() from an empty image"); is($empty->errstr, "getcolors: empty input image", "check error message"); is($empty->colorcount, -1, "can't colorcount() an empty image"); is($empty->errstr, "colorcount: empty input image", "check error message"); is($empty->maxcolors, -1, "can't maxcolors() an empty image"); is($empty->errstr, "maxcolors: empty input image", "check error message"); is($empty->findcolor(color => $blue), undef, "can't findcolor an empty image"); is($empty->errstr, "findcolor: empty input image", "check error message"); } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t023palette.log" } sub iscolor { my ($c1, $c2, $msg) = @_; my $builder = Test::Builder->new; my @c1 = $c1->rgba; my @c2 = $c2->rgba; if (!$builder->ok($c1[0] == $c2[0] && $c1[1] == $c2[1] && $c1[2] == $c2[2], $msg)) { $builder->diag(<new; if (!$builder->ok($got eq $expected, $msg)) { (my $got_dec = $got) =~ s/([^ -~])/sprintf("\\x%02x", ord $1)/ge; (my $exp_dec = $expected) =~ s/([^ -~])/sprintf("\\x%02x", ord $1)/ge; $builder->diag(<rgba; my ($rr, $gr, $br, $ar) = $right->rgba; print "# comparing color($rl,$gl,$bl,$al) with ($rr,$gr,$br,$ar)\n"; ok($rl == $rr && $gl == $gr && $bl == $br && $al == $ar, $comment); } sub _get_error { my @errors = Imager::i_errors(); return join(": ", map $_->[0], @errors); } libimager-perl-1.004+dfsg.orig/t/150-type/020-sixteen.t0000644000175000017500000003375412541477542021502 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 155; BEGIN { use_ok(Imager=>qw(:all :handy)) } -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t021sixteen.log"); use Imager::Color::Float; use Imager::Test qw(test_image is_image image_bounds_checks test_colorf_gpix test_colorf_glin mask_tests is_color3); my $im_g = Imager::i_img_16_new(100, 101, 1); is(Imager::i_img_getchannels($im_g), 1, "1 channel image channel count"); ok(Imager::i_img_getmask($im_g) & 1, "1 channel image mask"); ok(!Imager::i_img_virtual($im_g), "shouldn't be marked virtual"); is(Imager::i_img_bits($im_g), 16, "1 channel image has bits == 16"); is(Imager::i_img_type($im_g), 0, "1 channel image isn't direct"); my @ginfo = i_img_info($im_g); is($ginfo[0], 100, "1 channel image width"); is($ginfo[1], 101, "1 channel image height"); undef $im_g; my $im_rgb = Imager::i_img_16_new(100, 101, 3); is(Imager::i_img_getchannels($im_rgb), 3, "3 channel image channel count"); ok((Imager::i_img_getmask($im_rgb) & 7) == 7, "3 channel image mask"); is(Imager::i_img_bits($im_rgb), 16, "3 channel image bits"); is(Imager::i_img_type($im_rgb), 0, "3 channel image type"); my $redf = NCF(1, 0, 0); my $greenf = NCF(0, 1, 0); my $bluef = NCF(0, 0, 1); # fill with red for my $y (0..101) { Imager::i_plinf($im_rgb, 0, $y, ($redf) x 100); } pass("fill with red"); # basic sanity test_colorf_gpix($im_rgb, 0, 0, $redf, 0, "top-left"); test_colorf_gpix($im_rgb, 99, 0, $redf, 0, "top-right"); test_colorf_gpix($im_rgb, 0, 100, $redf, 0, "bottom left"); test_colorf_gpix($im_rgb, 99, 100, $redf, 0, "bottom right"); test_colorf_glin($im_rgb, 0, 0, [ ($redf) x 100 ], "first line"); test_colorf_glin($im_rgb, 0, 100, [ ($redf) x 100 ], "last line"); Imager::i_plinf($im_rgb, 20, 1, ($greenf) x 60); test_colorf_glin($im_rgb, 0, 1, [ ($redf) x 20, ($greenf) x 60, ($redf) x 20 ], "added some green in the middle"); { my @samples; is(Imager::i_gsamp_bits($im_rgb, 18, 22, 1, 16, \@samples, 0, [ 0 .. 2 ]), 12, "i_gsamp_bits all channels - count") or print "# ", Imager->_error_as_msg(), "\n"; is_deeply(\@samples, [ 65535, 0, 0, 65535, 0, 0, 0, 65535, 0, 0, 65535, 0 ], "check samples retrieved"); @samples = (); is(Imager::i_gsamp_bits($im_rgb, 18, 22, 1, 16, \@samples, 0, [ 0, 2 ]), 8, "i_gsamp_bits some channels - count") or print "# ", Imager->_error_as_msg(), "\n"; is_deeply(\@samples, [ 65535, 0, 65535, 0, 0, 0, 0, 0 ], "check samples retrieved"); # fail gsamp is(Imager::i_gsamp_bits($im_rgb, 18, 22, 1, 16, \@samples, 0, [ 0, 3 ]), undef, "i_gsamp_bits fail bad channel"); is(Imager->_error_as_msg(), 'No channel 3 in this image', 'check message'); is(Imager::i_gsamp_bits($im_rgb, 18, 22, 1, 17, \@samples, 0, [ 0, 2 ]), 8, "i_gsamp_bits succeed high bits"); is($samples[0], 131071, "check correct with high bits"); # write some samples back my @wr_samples = ( 0, 0, 65535, 65535, 0, 0, 0, 65535, 0, 65535, 65535, 0 ); is(Imager::i_psamp_bits($im_rgb, 18, 2, 16, [ 0 .. 2 ], \@wr_samples), 12, "write 16-bit samples") or print "# ", Imager->_error_as_msg(), "\n"; @samples = (); is(Imager::i_gsamp_bits($im_rgb, 18, 22, 2, 16, \@samples, 0, [ 0 .. 2 ]), 12, "read them back") or print "# ", Imager->_error_as_msg(), "\n"; is_deeply(\@samples, \@wr_samples, "check they match"); my $c = Imager::i_get_pixel($im_rgb, 18, 2); is_color3($c, 0, 0, 255, "check it write to the right places"); } # basic OO tests my $oo16img = Imager->new(xsize=>200, ysize=>201, bits=>16); ok($oo16img, "make a 16-bit oo image"); is($oo16img->bits, 16, "test bits"); isnt($oo16img->is_bilevel, "should not be considered mono"); # make sure of error handling ok(!Imager->new(xsize=>0, ysize=>1, bits=>16), "fail to create a 0 pixel wide image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>1, ysize=>0, bits=>16), "fail to create a 0 pixel high image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>-1, ysize=>1, bits=>16), "fail to create a negative width image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>1, ysize=>-1, bits=>16), "fail to create a negative height image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>-1, ysize=>-1, bits=>16), "fail to create a negative width/height image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "and correct error message"); ok(!Imager->new(xsize=>1, ysize=>1, bits=>16, channels=>0), "fail to create a zero channel image"); cmp_ok(Imager->errstr, '=~', qr/channels must be between 1 and 4/, "and correct error message"); ok(!Imager->new(xsize=>1, ysize=>1, bits=>16, channels=>5), "fail to create a five channel image"); cmp_ok(Imager->errstr, '=~', qr/channels must be between 1 and 4/, "and correct error message"); { # https://rt.cpan.org/Ticket/Display.html?id=8213 # check for handling of memory allocation of very large images # only test this on 32-bit machines - on a 64-bit machine it may # result in trying to allocate 4Gb of memory, which is unfriendly at # least and may result in running out of memory, causing a different # type of exit SKIP: { use Config; $Config{ptrsize} == 4 or skip("don't want to allocate 4Gb", 10); my $uint_range = 256 ** $Config{intsize}; print "# range $uint_range\n"; my $dim1 = int(sqrt($uint_range/2))+1; my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1, bits=>16); is($im_b, undef, "integer overflow check - 1 channel"); $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1, bits=>16); ok($im_b, "but same width ok"); $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1, bits=>16); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); # do a similar test with a 3 channel image, so we're sure we catch # the same case where the third dimension causes the overflow my $dim3 = int(sqrt($uint_range / 3 / 2))+1; $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3, bits=>16); is($im_b, undef, "integer overflow check - 3 channel"); $im_b = Imager->new(xisze=>$dim3, ysize=>1, channels=>3, bits=>16); ok($im_b, "but same width ok"); $im_b = Imager->new(xisze=>1, ysize=>$dim3, channels=>3, bits=>16); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); # check we can allocate a scanline, unlike double images the scanline # in the image itself is smaller than a line of i_fcolor # divide by 2 to get to int range, by 2 for 2 bytes/pixel, by 3 to # fit the image allocation in, but for the floats to overflow my $dim4 = $uint_range / 2 / 2 / 3; my $im_o = Imager->new(xsize=>$dim4, ysize=>1, channels=>1, bits=>16); is($im_o, undef, "integer overflow check - scanline"); cmp_ok(Imager->errstr, '=~', qr/integer overflow calculating scanline allocation/, "check error message"); } } { # check the channel mask function my $im = Imager->new(xsize => 10, ysize=>10, bits=>16); mask_tests($im, 1.0/65535); } { # convert to rgb16 my $im = test_image(); my $im16 = $im->to_rgb16; print "# check conversion to 16 bit\n"; is($im16->bits, 16, "check bits"); is_image($im, $im16, "check image data matches"); } { # empty image handling my $im = Imager->new; ok($im, "make empty image"); ok(!$im->to_rgb16, "convert empty image to 16-bit"); is($im->errstr, "to_rgb16: empty input image", "check message"); } { # bounds checks my $im = Imager->new(xsize => 10, ysize => 10, bits => 16); image_bounds_checks($im); } { my $im = Imager->new(xsize => 10, ysize => 10, bits => 16, channels => 3); my @wr_samples = map int(rand 65536), 1..30; is($im->setsamples('y' => 1, data => \@wr_samples, type => '16bit'), 30, "write 16-bit to OO image") or print "# ", $im->errstr, "\n"; my @samples; is($im->getsamples(y => 1, target => \@samples, type => '16bit'), 30, "read 16-bit from OO image") or print "# ", $im->errstr, "\n"; is_deeply(\@wr_samples, \@samples, "check it matches"); } my $psamp_outside_error = "Image position outside of image"; { # psamp print "# psamp\n"; my $imraw = Imager::i_img_16_new(10, 10, 3); { is(Imager::i_psamp($imraw, 0, 2, undef, [ 255, 128, 64 ]), 3, "i_psamp def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psamp($imraw, 1, 3, undef, [ 64, 128, 192 ]), 3, "i_psamp def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 192, "check color written"); is(Imager::i_psamp($imraw, 1, 7, [ 0, 1, 2 ], [ 64, 128, 192 ]), 3, "i_psamp channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 192, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psamp($imraw, 2, 4, [ 0, 1 ], [ 255, 128, 64, 32 ]), 4, "i_psamp channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psamp($imraw, 0, 5, [ 0, 1, 2 ], [ (128, 63, 32) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 63, 32) x 10 ], "check full row"); is(Imager::i_psamp($imraw, 8, 8, [ 0, 1, 2 ], [ 255, 128, 32, 64, 32, 16, 32, 16, 8 ]), 6, "i_psamp channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, 3 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, -1 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psamp($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } print "# end psamp tests\n"; } { # psampf print "# psampf\n"; my $imraw = Imager::i_img_16_new(10, 10, 3); { is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3, "i_psampf def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 127, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3, "i_psampf def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191, "check color written"); is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3, "i_psampf channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4, "i_psampf channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 127, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (127, 64, 32) x 10 ], "check full row"); is(Imager::i_psampf($imraw, 8, 8, [ 0, 1, 2 ], [ 1.0, 0.5, 0.125, 0.25, 0.125, 0.0625, 0.125, 0, 1 ]), 6, "i_psampf channels [0, 1, 2], 9 samples, but room for 6"); } { # errors we catch is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, 3 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, -1 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psampf($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } print "# end psampf tests\n"; } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t021sixteen.log"; } sub _get_error { my @errors = Imager::i_errors(); return join(": ", map $_->[0], @errors); } libimager-perl-1.004+dfsg.orig/t/100-base/0000755000175000017500000000000012617614576017253 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/100-base/010-introvert.t0000644000175000017500000013620612614520110021753 0ustar gregoagregoa#!perl -w # t/t01introvert.t - tests internals of image formats # to make sure we get expected values use strict; use Test::More tests => 492; BEGIN { use_ok(Imager => qw(:handy :all)) } use Imager::Test qw(image_bounds_checks is_color3 is_color4 is_fcolor4 color_cmp mask_tests is_fcolor3); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t01introvert.log"); my $im_g = Imager::ImgRaw::new(100, 101, 1); my $red = NC(255, 0, 0); my $green = NC(0, 255, 0); my $blue = NC(0, 0, 255); use Imager::Color::Float; my $f_black = Imager::Color::Float->new(0, 0, 0); my $f_red = Imager::Color::Float->new(1.0, 0, 0); my $f_green = Imager::Color::Float->new(0, 1.0, 0); my $f_blue = Imager::Color::Float->new(0, 0, 1.0); is(Imager::i_img_getchannels($im_g), 1, "1 channel image channel count"); ok(Imager::i_img_getmask($im_g) & 1, "1 channel image mask"); ok(!Imager::i_img_virtual($im_g), "1 channel image not virtual"); is(Imager::i_img_bits($im_g), 8, "1 channel image has 8 bits/sample"); is(Imager::i_img_type($im_g), 0, "1 channel image is direct"); is(Imager::i_img_get_width($im_g), 100, "100 pixels wide"); is(Imager::i_img_get_height($im_g), 101, "101 pixels high"); my @ginfo = Imager::i_img_info($im_g); is($ginfo[0], 100, "1 channel image width"); is($ginfo[1], 101, "1 channel image height"); undef $im_g; # can we check for release after this somehow? my $im_rgb = Imager::ImgRaw::new(100, 101, 3); is(Imager::i_img_getchannels($im_rgb), 3, "3 channel image channel count"); is((Imager::i_img_getmask($im_rgb) & 7), 7, "3 channel image mask"); is(Imager::i_img_bits($im_rgb), 8, "3 channel image has 8 bits/sample"); is(Imager::i_img_type($im_rgb), 0, "3 channel image is direct"); undef $im_rgb; my $im_pal = Imager::i_img_pal_new(100, 101, 3, 256); ok($im_pal, "make paletted image"); is(Imager::i_img_getchannels($im_pal), 3, "pal img channel count"); is(Imager::i_img_bits($im_pal), 8, "pal img bits"); is(Imager::i_img_type($im_pal), 1, "pal img is paletted"); my $red_idx = check_add($im_pal, $red, 0); my $green_idx = check_add($im_pal, $green, 1); my $blue_idx = check_add($im_pal, $blue, 2); # basic writing of palette indicies # fill with red is(Imager::i_ppal($im_pal, 0, 0, ($red_idx) x 100), 100, "write red 100 times"); # and blue is(Imager::i_ppal($im_pal, 50, 0, ($blue_idx) x 50), 50, "write blue 50 times"); # make sure we get it back my @pals = Imager::i_gpal($im_pal, 0, 100, 0); ok(!grep($_ != $red_idx, @pals[0..49]), "check for red"); ok(!grep($_ != $blue_idx, @pals[50..99]), "check for blue"); is(Imager::i_gpal($im_pal, 0, 100, 0), "\0" x 50 . "\2" x 50, "gpal in scalar context"); my @samp = Imager::i_gsamp($im_pal, 0, 100, 0, [ 0, 1, 2 ]); is(@samp, 300, "gsamp count in list context"); my @samp_exp = ((255, 0, 0) x 50, (0, 0, 255) x 50); is_deeply(\@samp, \@samp_exp, "gsamp list deep compare"); my $samp = Imager::i_gsamp($im_pal, 0, 100, 0, [ 0, 1, 2 ]); is(length($samp), 300, "gsamp scalar length"); is($samp, "\xFF\0\0" x 50 . "\0\0\xFF" x 50, "gsamp scalar bytes"); # reading indicies as colors my $c_red = Imager::i_get_pixel($im_pal, 0, 0); ok($c_red, "got the red pixel"); is_color3($c_red, 255, 0, 0, "and it's red"); my $c_blue = Imager::i_get_pixel($im_pal, 50, 0); ok($c_blue, "got the blue pixel"); is_color3($c_blue, 0, 0, 255, "and it's blue"); # drawing with colors ok(Imager::i_ppix($im_pal, 0, 0, $green) == 0, "draw with color in palette"); # that was in the palette, should still be paletted is(Imager::i_img_type($im_pal), 1, "image still paletted"); my $c_green = Imager::i_get_pixel($im_pal, 0, 0); ok($c_green, "got green pixel"); is_color3($c_green, 0, 255, 0, "and it's green"); is(Imager::i_colorcount($im_pal), 3, "still 3 colors in palette"); is(Imager::i_findcolor($im_pal, $green), 1, "and green is the second"); my $black = NC(0, 0, 0); # this should convert the image to RGB ok(Imager::i_ppix($im_pal, 1, 0, $black) == 0, "draw with black (not in palette)"); is(Imager::i_img_type($im_pal), 0, "pal img shouldn't be paletted now"); { my %quant = ( colors => [$red, $green, $blue, $black], make_colors => 'none', ); my $im_pal2 = Imager::i_img_to_pal($im_pal, \%quant); ok($im_pal2, "got an image from quantizing"); is(@{$quant{colors}}, 4, "quant has the right number of colours"); is(Imager::i_colorcount($im_pal2), 4, "and so does the image"); my @colors = Imager::i_getcolors($im_pal2, 0, 4); my ($first) = Imager::i_getcolors($im_pal2, 0); my @first = $colors[0]->rgba; is_color3($first, $first[0], $first[1], $first[2], "check first color is first for multiple or single fetch"); is_color3($colors[0], 255, 0, 0, "still red"); is_color3($colors[1], 0, 255, 0, "still green"); is_color3($colors[2], 0, 0, 255, "still blue"); is_color3($colors[3], 0, 0, 0, "still black"); my @samples = Imager::i_gsamp($im_pal2, 0, 100, 0, [ 0, 1, 2 ]); my @expect = unpack("C*", "\0\xFF\0\0\0\0"."\xFF\0\0" x 48 . "\0\0\xFF" x 50); my $match_list = is_deeply(\@samples, \@expect, "colors are still correct"); my $samples = Imager::i_gsamp($im_pal2, 0, 100, 0, [ 0, 1, 2 ]); my $match_scalar = is_deeply([ unpack("C*", $samples) ], \@expect, "colors are still correct (scalar)"); unless ($match_list && $match_scalar) { # this has been failing on a particular smoker, provide more # diagnostic information print STDERR "Pallete:\n"; print STDERR " $_: ", join(",", $colors[$_]->rgba), "\n" for 0..$#colors; print STDERR "Samples (list): ", join(",", @samples), "\n"; print STDERR "Samples (scalar): ", join(",", unpack("C*", $samples)), "\n"; print STDERR "Indexes: ", join(",", Imager::i_gpal($im_pal2, 0, 100, 0)), "\n"; } } # test the OO interfaces my $impal2 = Imager->new(type=>'pseudo', xsize=>200, ysize=>201); ok($impal2, "make paletted via OO") or diag(Imager->errstr); is($impal2->getchannels, 3, "check channels"); is($impal2->bits, 8, "check bits"); is($impal2->type, 'paletted', "check type"); is($impal2->getwidth, 200, "check width"); is($impal2->getheight, 201, "check height"); is($impal2->colormodel, "rgb", "check color model (string)"); is($impal2->colormodel(numeric => 1), 3, "check color model (numeric)"); is($impal2->alphachannel, undef, "check alpha channel (has none)"); is($impal2->colorchannels, 3, "check colorchannels"); { my $red_idx = $impal2->addcolors(colors=>[$red]); ok($red_idx, "add red to OO"); is(0+$red_idx, 0, "and it's expected index for red"); my $blue_idx = $impal2->addcolors(colors=>[$blue, $green]); ok($blue_idx, "add blue/green via OO"); is($blue_idx, 1, "and it's expected index for blue"); my $green_idx = $blue_idx + 1; my $c = $impal2->getcolors(start=>$green_idx); is_color3($c, 0, 255, 0, "found green where expected"); my @cols = $impal2->getcolors; is(@cols, 3, "got 3 colors"); my @exp = ( $red, $blue, $green ); my $good = 1; for my $i (0..2) { if (color_cmp($cols[$i], $exp[$i])) { $good = 0; last; } } ok($good, "all colors in palette as expected"); is($impal2->colorcount, 3, "and colorcount returns 3"); is($impal2->maxcolors, 256, "maxcolors as expected"); is($impal2->findcolor(color=>$blue), 1, "findcolors found blue"); ok($impal2->setcolors(start=>0, colors=>[ $blue, $red ]), "we can setcolors"); # make an rgb version my $imrgb2 = $impal2->to_rgb8() or diag($impal2->errstr); is($imrgb2->type, 'direct', "converted is direct"); # and back again, specifying the palette my @colors = ( $red, $blue, $green ); my $impal3 = $imrgb2->to_paletted(colors=>\@colors, make_colors=>'none', translate=>'closest'); ok($impal3, "got a paletted image from conversion"); dump_colors(@colors); print "# in image\n"; dump_colors($impal3->getcolors); is($impal3->colorcount, 3, "new image has expected color table size"); is($impal3->type, 'paletted', "and is paletted"); } { my $im = Imager->new; ok($im, "make empty image"); ok(!$im->to_rgb8, "convert to rgb8"); is($im->errstr, "to_rgb8: empty input image", "check message"); is($im->bits, undef, "can't call bits on an empty image"); is($im->errstr, "bits: empty input image", "check message"); is($im->type, undef, "can't call type on an empty image"); is($im->errstr, "type: empty input image", "check message"); is($im->virtual, undef, "can't call virtual on an empty image"); is($im->errstr, "virtual: empty input image", "check message"); is($im->is_bilevel, undef, "can't call virtual on an empty image"); is($im->errstr, "is_bilevel: empty input image", "check message"); ok(!$im->getscanline(y => 0), "can't call getscanline on an empty image"); is($im->errstr, "getscanline: empty input image", "check message"); ok(!$im->setscanline(y => 0, pixels => [ $red, $blue ]), "can't call setscanline on an empty image"); is($im->errstr, "setscanline: empty input image", "check message"); ok(!$im->getsamples(y => 0), "can't call getsamples on an empty image"); is($im->errstr, "getsamples: empty input image", "check message"); is($im->getwidth, undef, "can't get width of empty image"); is($im->errstr, "getwidth: empty input image", "check message"); is($im->getheight, undef, "can't get height of empty image"); is($im->errstr, "getheight: empty input image", "check message"); is($im->getchannels, undef, "can't get channels of empty image"); is($im->errstr, "getchannels: empty input image", "check message"); is($im->getmask, undef, "can't get mask of empty image"); is($im->errstr, "getmask: empty input image", "check message"); is($im->setmask, undef, "can't set mask of empty image"); is($im->errstr, "setmask: empty input image", "check message"); is($im->colorchannels, undef, "can't get colorchannels of empty image"); is($im->errstr, "colorchannels: empty input image", "check message"); is($im->alphachannel, undef, "can't get alphachannel of empty image"); is($im->errstr, "alphachannel: empty input image", "check message"); is($im->colormodel, undef, "can't get colormodel of empty image"); is($im->errstr, "colormodel: empty input image", "check message"); } { # basic checks, 8-bit direct images my $im = Imager->new(xsize => 2, ysize => 3); ok($im, 'create 8-bit direct image'); is($im->bits, 8, '8 bits'); ok(!$im->virtual, 'not virtual'); is($im->type, 'direct', 'direct image'); ok(!$im->is_bilevel, 'not mono'); } ok(!Imager->new(xsize=>0, ysize=>1), "fail to create 0 height image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "0 height error message check"); ok(!Imager->new(xsize=>1, ysize=>0), "fail to create 0 width image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "0 width error message check"); ok(!Imager->new(xsize=>-1, ysize=>1), "fail to create -ve height image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "-ve width error message check"); ok(!Imager->new(xsize=>1, ysize=>-1), "fail to create -ve width image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "-ve height error message check"); ok(!Imager->new(xsize=>-1, ysize=>-1), "fail to create -ve width/height image"); cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/, "-ve width/height error message check"); ok(!Imager->new(xsize=>1, ysize=>1, channels=>0), "fail to create a zero channel image"); cmp_ok(Imager->errstr, '=~', qr/channels must be between 1 and 4/, "out of range channel message check"); ok(!Imager->new(xsize=>1, ysize=>1, channels=>5), "fail to create a five channel image"); cmp_ok(Imager->errstr, '=~', qr/channels must be between 1 and 4/, "out of range channel message check"); { # https://rt.cpan.org/Ticket/Display.html?id=8213 # check for handling of memory allocation of very large images # only test this on 32-bit machines - on a 64-bit machine it may # result in trying to allocate 4Gb of memory, which is unfriendly at # least and may result in running out of memory, causing a different # type of exit SKIP: { use Config; skip("don't want to allocate 4Gb", 8) unless $Config{ptrsize} == 4; my $uint_range = 256 ** $Config{intsize}; print "# range $uint_range\n"; my $dim1 = int(sqrt($uint_range))+1; my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1); is($im_b, undef, "integer overflow check - 1 channel"); $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1); ok($im_b, "but same width ok"); $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); # do a similar test with a 3 channel image, so we're sure we catch # the same case where the third dimension causes the overflow my $dim3 = int(sqrt($uint_range / 3))+1; $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3); is($im_b, undef, "integer overflow check - 3 channel"); $im_b = Imager->new(xisze=>$dim3, ysize=>1, channels=>3); ok($im_b, "but same width ok"); $im_b = Imager->new(xisze=>1, ysize=>$dim3, channels=>3); ok($im_b, "but same height ok"); cmp_ok(Imager->errstr, '=~', qr/integer overflow/, "check the error message"); } } { # http://rt.cpan.org/NoAuth/Bug.html?id=9672 my $warning; local $SIG{__WARN__} = sub { $warning = "@_"; my $printed = $warning; $printed =~ s/\n$//; $printed =~ s/\n/\n\#/g; print "# ",$printed, "\n"; }; my $img = Imager->new(xsize=>10, ysize=>10); $img->to_rgb8(); # doesn't really matter what the source is cmp_ok($warning, '=~', 'void', "correct warning"); cmp_ok($warning, '=~', 'introvert\\.t', "correct file"); } { # http://rt.cpan.org/NoAuth/Bug.html?id=11860 my $im = Imager->new(xsize=>2, ysize=>2); $im->setpixel(x=>0, 'y'=>0, color=>$red); $im->setpixel(x=>1, 'y'=>0, color=>$blue); my @row = Imager::i_glin($im->{IMG}, 0, 2, 0); is(@row, 2, "got 2 pixels from i_glin"); is_color3($row[0], 255, 0, 0, "red first"); is_color3($row[1], 0, 0, 255, "then blue"); } { # general tag tests # we don't care much about the image itself my $im = Imager::ImgRaw::new(10, 10, 1); ok(Imager::i_tags_addn($im, 'alpha', 0, 101), "i_tags_addn(...alpha, 0, 101)"); ok(Imager::i_tags_addn($im, undef, 99, 102), "i_tags_addn(...undef, 99, 102)"); is(Imager::i_tags_count($im), 2, "should have 2 tags"); ok(Imager::i_tags_addn($im, undef, 99, 103), "i_tags_addn(...undef, 99, 103)"); is(Imager::i_tags_count($im), 3, "should have 3 tags, despite the dupe"); is(Imager::i_tags_find($im, 'alpha', 0), '0 but true', "find alpha"); is(Imager::i_tags_findn($im, 99, 0), 1, "find 99"); is(Imager::i_tags_findn($im, 99, 2), 2, "find 99 again"); is(Imager::i_tags_get($im, 0), 101, "check first"); is(Imager::i_tags_get($im, 1), 102, "check second"); is(Imager::i_tags_get($im, 2), 103, "check third"); ok(Imager::i_tags_add($im, 'beta', 0, "hello", 0), "add string with string key"); ok(Imager::i_tags_add($im, 'gamma', 0, "goodbye", 0), "add another one"); ok(Imager::i_tags_add($im, undef, 199, "aloha", 0), "add one keyed by number"); is(Imager::i_tags_find($im, 'beta', 0), 3, "find beta"); is(Imager::i_tags_find($im, 'gamma', 0), 4, "find gamma"); is(Imager::i_tags_findn($im, 199, 0), 5, "find 199"); ok(Imager::i_tags_delete($im, 2), "delete"); is(Imager::i_tags_find($im, 'beta', 0), 2, 'find beta after deletion'); ok(Imager::i_tags_delbyname($im, 'beta'), 'delete beta by name'); is(Imager::i_tags_find($im, 'beta', 0), undef, 'beta not there now'); is(Imager::i_tags_get_string($im, "gamma"), "goodbye", 'i_tags_get_string() on a string'); is(Imager::i_tags_get_string($im, 99), 102, 'i_tags_get_string() on a number entry'); ok(Imager::i_tags_delbycode($im, 99), 'delete by code'); is(Imager::i_tags_findn($im, 99, 0), undef, '99 not there now'); is(Imager::i_tags_count($im), 3, 'final count of 3'); } { print "# low-level scan line function tests\n"; my $im = Imager::ImgRaw::new(10, 10, 4); Imager::i_ppix($im, 5, 0, $red); # i_glin/i_glinf my @colors = Imager::i_glin($im, 0, 10, 0); is_deeply([ (0) x 20, (255, 0, 0, 255), (0) x 16 ], [ map $_->rgba, @colors ], "i_glin - list context"); my $colors = Imager::i_glin($im, 0, 10, 0); is("00" x 20 . "FF0000FF" . "00" x 16, uc unpack("H*", $colors), "i_glin - scalar context"); my @fcolors = Imager::i_glinf($im, 0, 10, 0); is_deeply([ (0.0) x 20, (1.0, 0, 0, 1.0) , (0) x 16 ], [ map $_->rgba, @fcolors ], "i_glinf - list context"); my $fcolors = Imager::i_glinf($im, 0, 10, 0); is_deeply([ (0.0) x 20, (1.0, 0, 0, 1.0) , (0) x 16 ], [ unpack "d*", $fcolors ], "i_glinf - scalar context"); # i_plin/i_plinf my @plin_colors = (($black) x 4, $red, $blue, ($black) x 4); is(Imager::i_plin($im, 0, 1, @plin_colors), 10, "i_plin - pass in a list"); # make sure we get it back is_deeply([ map [ $_->rgba ], @plin_colors ], [ map [ $_->rgba ], Imager::i_glin($im, 0, 10, 1) ], "check i_plin wrote to the image"); my @scalar_plin = ( (0,0,0,0) x 4, (0, 255, 0, 255), (0, 0, 255, 255), (0, 0, 0, 0) x 4, ); is(Imager::i_plin($im, 0, 2, pack("C*", @scalar_plin)), 10, "i_plin - pass in a scalar"); is_deeply(\@scalar_plin, [ map $_->rgba , Imager::i_glin($im, 0, 10, 2) ], "check i_plin scalar wrote to the image"); my @plinf_colors = # Note: only 9 pixels ( ($f_blue) x 4, $f_red, ($f_black) x 3, $f_black ); is(Imager::i_plinf($im, 0, 3, @plinf_colors), 9, "i_plinf - list"); is_deeply([ map $_->rgba, Imager::i_glinf($im, 0, 9, 3) ], [ map $_->rgba, @plinf_colors ], "check colors were written"); my @scalar_plinf = ( ( 1.0, 1.0, 0, 1.0 ) x 3, ( 0, 1.0, 1.0, 1.0 ) x 2, ( 0, 0, 0, 0 ), ( 1.0, 0, 1.0, 1.0 ), ); is(Imager::i_plinf($im, 2, 4, pack("d*", @scalar_plinf)), 7, "i_plinf - scalar"); is_deeply(\@scalar_plinf, [ map $_->rgba, Imager::i_glinf($im, 2, 9, 4) ], "check colors were written"); is_deeply([ Imager::i_gsamp($im, 0, 10, 0, [ 0, 3 ]) ], [ (0, 0) x 5, (255, 255), (0, 0) x 4 ], "i_gsamp list context"); is("0000" x 5 . "FFFF" . "0000" x 4, uc unpack("H*", Imager::i_gsamp($im, 0, 10, 0, [ 0, 3 ])), "i_gsamp scalar context"); is_deeply([ Imager::i_gsampf($im, 2, 9, 4, [ 0, 2, 3 ]) ], [ (1.0, 0, 1.0) x 3, (0, 1.0, 1.0) x 2, (0, 0, 0), (1.0, 1.0, 1.0) ], "i_gsampf - list context"); is_deeply([ unpack("d*", Imager::i_gsampf($im, 2, 9, 4, [ 0, 2, 3 ])) ], [ (1.0, 0, 1.0) x 3, (0, 1.0, 1.0) x 2, (0, 0, 0), (1.0, 1.0, 1.0) ], "i_gsampf - scalar context"); print "# end low-level scan-line function tests\n"; } my $psamp_outside_error = "Image position outside of image"; { # psamp print "# psamp\n"; my $imraw = Imager::ImgRaw::new(10, 20, 3); { is(Imager::i_psamp($imraw, 0, 2, undef, [ 255, 128, 64 ]), 3, "i_psamp def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psamp($imraw, 1, 3, undef, [ 64, 128, 192 ]), 3, "i_psamp def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 192, "check color written"); is(Imager::i_psamp($imraw, 1, 7, [ 0, 1, 2 ], [ 64, 128, 192 ]), 3, "i_psamp channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 192, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psamp($imraw, 2, 4, [ 0, 1 ], [ 255, 128, 64, 32 ]), 4, "i_psamp channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psamp($imraw, 0, 5, [ 0, 1, 2 ], [ (128, 63, 32) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 63, 32) x 10 ], "check full row"); is(Imager::i_psamp($imraw, 8, 8, [ 0, 1, 2 ], [ 255, 128, 32, 64, 32, 16, 32, 16, 8 ]), 6, "i_psamp channels [0, 1, 2], 9 samples, but room for 6"); is(Imager::i_psamp($imraw, 4, 6, undef, [ 0 .. 18 ], 1), 18, "psamp with offset"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 6, undef) ], [ (0) x 12, 1 .. 18 ], "check result"); is(Imager::i_psamp($imraw, 4, 11, undef, [ 0 .. 18 ], 1, 3), 9, "psamp with offset and width"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 11, undef) ], [ (0) x 12, 1 .. 9, (0) x 9 ], "check result"); } { # errors we catch is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, 3 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, -1 ], [ 255, 128, 32 ]), undef, "i_psamp channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psamp($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 0, 20, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psamp($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } { # test the im_sample_list typemap ok(!eval { Imager::i_psamp($imraw, 9, 9, [ 0 ], undef); 1 }, "pass undef as the sample list"); like($@, qr/data must be a scalar or an arrayref/, "check message"); ok(!eval { Imager::i_psamp($imraw, 9, 9, [ 0 ], { a => 1 }); 1 }, "hashref as the sample list"); like($@, qr/data must be a scalar or an arrayref/, "check message"); ok(!eval { Imager::i_psamp($imraw, 9, 9, [ 0 ], []); 1 }, "empty sample list"); like($@, qr/i_psamp: no samples provided in data/, "check message"); ok(!eval { Imager::i_psamp($imraw, 9, 9, [ 0 ], ""); 1 }, "empty scalar sample list"); like($@, qr/i_psamp: no samples provided in data/, "check message"); # not the typemap is(Imager::i_psamp($imraw, 0, 8, undef, [ (0) x 3 ], -1), undef, "negative offset"); is(_get_error(), "offset must be non-negative", "check message"); is(Imager::i_psamp($imraw, 0, 8, undef, [ (0) x 3 ], 4), undef, "too high offset"); is(_get_error(), "offset greater than number of samples supplied", "check message"); } print "# end psamp tests\n"; } { # psampf print "# psampf\n"; my $imraw = Imager::ImgRaw::new(10, 20, 3); { is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3, "i_psampf def channels, 3 samples"); is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64, "check color written"); Imager::i_img_setmask($imraw, 5); is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3, "i_psampf def channels, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191, "check color written"); is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3, "i_psampf channels listed, 3 samples, masked"); is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191, "check color written"); Imager::i_img_setmask($imraw, ~0); is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4, "i_psampf channels [0, 1], 4 samples"); is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0, "check first color written"); is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0, "check second color written"); is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30, "write a full row"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ], [ (128, 64, 32) x 10 ], "check full row"); is(Imager::i_psampf($imraw, 8, 8, [ 0, 1, 2 ], [ 1.0, 0.5, 0.125, 0.25, 0.125, 0.0625, 0.125, 0, 1 ]), 6, "i_psampf channels [0, 1, 2], 9 samples, but room for 6"); is(Imager::i_psampf($imraw, 4, 6, undef, [ map $_/254.9, 0 .. 18 ], 1), 18, "psampf with offset"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 6, undef) ], [ (0) x 12, 1 .. 18 ], "check result"); is(Imager::i_psampf($imraw, 4, 11, undef, [ map $_/254.9, 0 .. 18 ], 1, 3), 9, "psampf with offset and width"); is_deeply([ Imager::i_gsamp($imraw, 0, 10, 11, undef) ], [ (0) x 12, 1 .. 9, (0) x 9 ], "check result"); } { # errors we catch is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, 3 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, 3], 3 samples (invalid channel number)"); is(_get_error(), "No channel 3 in this image", "check error message"); is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, -1 ], [ 1, 0.5, 0.125 ]), undef, "i_psampf channels [0, 1, -1], 3 samples (invalid channel number)"); is(_get_error(), "No channel -1 in this image", "check error message"); is(Imager::i_psampf($imraw, 0, -1, undef, [ 0, 0, 0 ]), undef, "negative y"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 0, 20, undef, [ 0, 0, 0 ]), undef, "y overflow"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, -1, 0, undef, [ 0, 0, 0 ]), undef, "negative x"); is(_get_error(), $psamp_outside_error, "check error message"); is(Imager::i_psampf($imraw, 10, 0, undef, [ 0, 0, 0 ]), undef, "x overflow"); is(_get_error(), $psamp_outside_error, "check error message"); } { # test the im_fsample_list typemap ok(!eval { Imager::i_psampf($imraw, 9, 9, [ 0 ], undef); 1 }, "pass undef as the sample list"); like($@, qr/data must be a scalar or an arrayref/, "check message"); ok(!eval { Imager::i_psampf($imraw, 9, 9, [ 0 ], { a => 1 }); 1 }, "hashref as the sample list"); like($@, qr/data must be a scalar or an arrayref/, "check message"); ok(!eval { Imager::i_psampf($imraw, 9, 9, [ 0 ], []); 1 }, "empty sample list"); like($@, qr/i_psampf: no samples provided in data/, "check message"); ok(!eval { Imager::i_psampf($imraw, 9, 9, [ 0 ], ""); 1 }, "empty scalar sample list"); like($@, qr/i_psampf: no samples provided in data/, "check message"); # not the typemap is(Imager::i_psampf($imraw, 0, 8, undef, [ (0) x 3 ], -1), undef, "negative offset"); is(_get_error(), "offset must be non-negative", "check message"); is(Imager::i_psampf($imraw, 0, 8, undef, [ (0) x 3 ], 4), undef, "too high offset"); is(_get_error(), "offset greater than number of samples supplied", "check message"); } print "# end psampf tests\n"; } { print "# OO level scanline function tests\n"; my $im = Imager->new(xsize=>10, ysize=>10, channels=>4); $im->setpixel(color=>$red, 'x'=>5, 'y'=>0); ok(!$im->getscanline(), "getscanline() - supply nothing, get nothing"); is($im->errstr, "missing y parameter", "check message"); is_deeply([ map [ $_->rgba ], $im->getscanline('y'=>0) ], [ ([ 0,0,0,0]) x 5, [ 255, 0, 0, 255 ], ([ 0,0,0,0]) x 4 ], "getscanline, list context, default x, width"); is_deeply([ map [ $_->rgba ], $im->getscanline('y'=>0, 'x'=>3) ], [ ([0,0,0,0]) x 2, [ 255, 0, 0, 255 ], ([0,0,0,0]) x 4 ], "getscanline, list context, default width"); is_deeply([ map [ $_->rgba ], $im->getscanline('y'=>0, 'x'=>4, width=>4) ], [ [0,0,0,0], [ 255, 0, 0, 255 ], ([0,0,0,0]) x 2 ], "getscanline, list context, no defaults"); is(uc unpack("H*", $im->getscanline('y'=>0)), "00000000" x 5 . "FF0000FF" . "00000000" x 4, "getscanline, scalar context, default x, width"); is_deeply([ map [ $_->rgba ], $im->getscanline('y'=>0, 'x'=>4, width=>4, type=>'float') ], [ [0,0,0,0], [ 1.0, 0, 0, 1.0 ], ([0,0,0,0]) x 2 ], "getscanline float, list context, no defaults"); is_deeply([ unpack "d*", $im->getscanline('y'=>0, 'x'=>4, width=>4, type=>'float') ], [ (0,0,0,0), ( 1.0, 0, 0, 1.0 ), (0,0,0,0) x 2 ], "getscanline float, scalar context, no defaults"); ok(!$im->getscanline('y'=>0, type=>'invalid'), "check invalid type checking"); like($im->errstr, qr/invalid type parameter/, "check message for invalid type"); my @plin_colors = (($black) x 4, $red, $blue, ($green) x 4); is($im->setscanline('y'=>1, pixels=>\@plin_colors), 10, "setscanline - arrayref, default x"); is_deeply([ map [ $_->rgba ], @plin_colors ], [ map [ $_->rgba ], $im->getscanline('y'=>1) ], "check colors were written"); my @plin_colors2 = ( $green, $red, $blue, $red ); is($im->setscanline('y'=>2, 'x'=>3, pixels=>\@plin_colors2), 4, "setscanline - arrayref"); # using map instead of x here due to a bug in some versions of Test::More # fixed in the latest Test::More is_deeply([ ( map [ 0,0,0,0 ], 1..3), (map [ $_->rgba ], @plin_colors2), ( map [ 0,0,0,0 ], 1..3) ], [ map [ $_->rgba ], $im->getscanline('y'=>2) ], "check write to middle of line"); my $raw_colors = pack "H*", "FF00FFFF"."FF0000FF"."FFFFFFFF"; is($im->setscanline('y'=>3, 'x'=>2, pixels=>$raw_colors), 3, "setscanline - scalar, default raw type") or print "# ",$im->errstr,"\n"; is(uc unpack("H*", $im->getscanline('y'=>3, 'x'=>1, 'width'=>5)), "00000000".uc(unpack "H*", $raw_colors)."00000000", "check write"); # float colors my @fcolors = ( $f_red, $f_blue, $f_black, $f_green ); is($im->setscanline('y'=>4, 'x'=>3, pixels=>\@fcolors), 4, "setscanline - float arrayref"); is_deeply([ map [ $_->rgba ], @fcolors ], [ map [ $_->rgba ], $im->getscanline('y'=>4, 'x'=>3, width=>4, type=>'float') ], "check write"); # packed my $packed_fcolors = pack "d*", map $_->rgba, @fcolors; is($im->setscanline('y'=>5, 'x'=>4, pixels=>$packed_fcolors, type=>'float'), 4, "setscanline - float scalar"); is_deeply([ map [ $_->rgba ], @fcolors ], [ map [ $_->rgba ], $im->getscanline('y'=>5, 'x'=>4, width=>4, type=>'float') ], "check write"); # get samples is_deeply([ $im->getsamples('y'=>1, channels=>[ 0 ]) ], [ map +($_->rgba)[0], @plin_colors ], "get channel 0, list context, default x, width"); is_deeply([ unpack "C*", $im->getsamples('y'=>1, channels=>[0, 2]) ], [ map { ($_->rgba)[0, 2] } @plin_colors ], "get channel 0, 1, scalar context"); is_deeply([ $im->getsamples('y'=>4, 'x'=>3, width=>4, type=>'float', channels=>[1,3]) ], [ map { ($_->rgba)[1,3] } @fcolors ], "get channels 1,3, list context, float samples"); is_deeply([ unpack "d*", $im->getsamples('y'=>4, 'x'=>3, width=>4, type=>'float', channels=>[3,2,1,0]) ], [ map { ($_->rgba)[3,2,1,0] } @fcolors ], "get channels 3..0 as scalar, float samples"); print "# end OO level scanline function tests\n"; } { # RT 74882 # for the non-gsamp_bits case with a target parameter it was # treating the target parameter as a hashref { my $im = Imager->new(xsize => 10, ysize => 10); my $c1 = NC(0, 63, 255); my $c2 = NC(255, 128, 255); is($im->setscanline(y => 1, pixels => [ ( $c1, $c2 ) x 5 ]), 10, "set some test data") or diag "setscanline: ", $im->errstr; my @target; is($im->getsamples(y => 1, x => 1, target => \@target, width => 3), 9, "getsamples to target"); is_deeply(\@target, [ 255, 128, 255, 0, 63, 255, 255, 128, 255 ], "check result"); } { my $im = Imager->new(xsize => 10, ysize => 10, bits => "double"); my $c1 = NCF(0, 0.25, 1.0); my $c2 = NCF(1.0, 0.5, 1.0); is($im->setscanline(y => 1, pixels => [ ( $c1, $c2 ) x 5 ]), 10, "set some test data") or diag "setscanline: ", $im->errstr; my @target; is($im->getsamples(y => 1, x => 1, target => \@target, width => 3, type => "float"), 9, "getsamples to target"); is_deeply(\@target, [ 1.0, 0.5, 1.0, 0, 0.25, 1.0, 1.0, 0.5, 1.0 ], "check result"); } } { # to avoid confusion, i_glin/i_glinf modified to return 0 in unused # channels at the perl level my $im = Imager->new(xsize => 4, ysize => 4, channels => 2); my $fill = Imager::Color->new(128, 255, 0, 0); ok($im->box(filled => 1, color => $fill), 'fill it up'); my $data = $im->getscanline('y' => 0); is(unpack("H*", $data), "80ff000080ff000080ff000080ff0000", "check we get zeros"); my @colors = $im->getscanline('y' => 0); is_color4($colors[0], 128, 255, 0, 0, "check object interface[0]"); is_color4($colors[1], 128, 255, 0, 0, "check object interface[1]"); is_color4($colors[2], 128, 255, 0, 0, "check object interface[2]"); is_color4($colors[3], 128, 255, 0, 0, "check object interface[3]"); my $dataf = $im->getscanline('y' => 0, type => 'float'); # the extra pack/unpack is to force double precision rather than long # double, otherwise the test fails is_deeply([ unpack("d*", $dataf) ], [ unpack("d*", pack("d*", ( 128.0 / 255.0, 1.0, 0, 0, ) x 4)) ], "check we get zeroes (double)"); my @fcolors = $im->getscanline('y' => 0, type => 'float'); is_fcolor4($fcolors[0], 128.0/255.0, 1.0, 0, 0, "check object interface[0]"); is_fcolor4($fcolors[1], 128.0/255.0, 1.0, 0, 0, "check object interface[1]"); is_fcolor4($fcolors[2], 128.0/255.0, 1.0, 0, 0, "check object interface[2]"); is_fcolor4($fcolors[3], 128.0/255.0, 1.0, 0, 0, "check object interface[3]"); } { # check the channel mask function my $im = Imager->new(xsize => 10, ysize=>10, bits=>8); mask_tests($im, 0.005); } { # check bounds checking my $im = Imager->new(xsize => 10, ysize => 10); image_bounds_checks($im); } { # setsamples() interface to psamp() my $im = Imager->new(xsize => 10, ysize => 10); is($im->setsamples(y => 1, x => 2, data => [ 1 .. 6 ]), 6, "simple put (array), default channels"); is_deeply([ $im->getsamples(y => 1, x => 0) ], [ (0) x 6, 1 .. 6, (0) x 18 ], "check they were stored"); is($im->setsamples(y => 3, x => 3, data => pack("C*", 2 .. 10 )), 9, "simple put (scalar), default channels") or diag $im->errstr; is_deeply([ $im->getsamples(y => 3, x => 0) ], [ (0) x 9, 2 .. 10, (0) x 12 ], "check they were stored"); is($im->setsamples(y => 4, x => 4, data => [ map $_ / 254.5, 1 .. 6 ], type => 'float'), 6, "simple put (float array), default channels"); is_deeply([ $im->getsamples(y => 4, x => 0) ], [ (0) x 12, 1 .. 6, (0) x 12 ], "check they were stored"); is($im->setsamples(y => 5, x => 3, data => pack("d*", map $_ / 254.5, 1 .. 6), type => 'float'), 6, "simple put (float scalar), default channels"); is_deeply([ $im->getsamples(y => 5, x => 0) ], [ (0) x 9, 1 .. 6, (0) x 15 ], "check they were stored"); is($im->setsamples(y => 7, x => 3, data => [ 0 .. 18 ], offset => 1), 18, "setsamples offset"); is_deeply([ $im->getsamples(y => 7) ], [ (0) x 9, 1 .. 18, (0) x 3 ], "check result"); is($im->setsamples(y => 8, x => 3, data => [ map $_ / 254.9, 0 .. 18 ], offset => 1, type => 'float'), 18, "setsamples offset (float)"); is_deeply([ $im->getsamples(y => 8) ], [ (0) x 9, 1 .. 18, (0) x 3 ], "check result"); is_deeply([ $im->setsamples(y => 6, x => 10, data => [ (0) x 3 ]) ], [], "check out of range result (8bit)"); is($im->errstr, $psamp_outside_error, "check error message"); is_deeply([ $im->setsamples(y => 6, x => 10, data => [ (0) x 3 ], type => "float") ], [], "check out of range result (float)"); is($im->errstr, $psamp_outside_error, "check error message"); is_deeply([ $im->setsamples(y => 6, x => 2, channels => [0, 1, 3 ], data => [ (0) x 3 ]) ], [], "check bad channels (8bit)"); is($im->errstr, "No channel 3 in this image", "check error message"); is_deeply([ $im->setsamples(y => 6, x => 2, channels => [0, 1, 3 ], data => [ (0) x 3 ], type => "float") ], [], "check bad channels (float)"); is($im->errstr, "No channel 3 in this image", "check error message"); is($im->setsamples(y => 5, data => [ (0) x 3 ], type => "bad"), undef, "setsamples with bad type"); is($im->errstr, "setsamples: type parameter invalid", "check error message"); is($im->setsamples(y => 5), undef, "setsamples with no data"); is($im->errstr, "setsamples: data parameter missing", "check error message"); is($im->setsamples(y => 5, data => undef), undef, "setsamples with undef data"); is($im->errstr, "setsamples: data parameter not defined", "check error message"); my $imempty = Imager->new; is($imempty->setsamples(y => 0, data => [ (0) x 3 ]), undef, "setsamples to empty image"); is($imempty->errstr, "setsamples: empty input image", "check error message"); } { # getpixel parameters my $im = Imager->new(xsize => 10, ysize => 10); $im->box(filled => 1, xmax => 4, color => NC(255, 0, 0)); $im->box(filled => 1, xmin => 5, ymax => 4, color => NC(0, 255, 255)); $im->box(filled => 1, xmin => 5, ymin => 5, color => NC(255, 0, 255)); { # error handling my $empty = Imager->new; ok(!$empty->getpixel(x => 0, y => 0), "getpixel empty image"); is($empty->errstr, "getpixel: empty input image", "check message"); ok(!$im->getpixel(y => 0), "missing x"); is($im->errstr, "getpixel: missing x or y parameter", "check message"); $im->_set_error("something different"); ok(!$im->getpixel(x => 0), "missing y"); is($im->errstr, "getpixel: missing x or y parameter", "check message"); ok(!$im->getpixel(x => [], y => 0), "empty x array ref"); is($im->errstr, "getpixel: x is a reference to an empty array", "check message"); ok(!$im->getpixel(x => 0, y => []), "empty y array ref"); is($im->errstr, "getpixel: y is a reference to an empty array", "check message"); ok(!$im->getpixel(x => 0, y => 0, type => "bad"), "bad type (scalar path)"); is($im->errstr, "getpixel: type must be '8bit' or 'float'", "check message"); $im->_set_error("something different"); ok(!$im->getpixel(x => [ 0 ], y => [ 0 ], type => "bad"), "bad type (array path)"); is($im->errstr, "getpixel: type must be '8bit' or 'float'", "check message"); } # simple calls is_color4($im->getpixel(x => 1, y => 0), 255, 0, 0, 0, "getpixel(1, 0)"); is_color4($im->getpixel(x => 8, y => 1), 0, 255, 255, 0, "getpixel(8, 1)"); is_color4($im->getpixel(x => 8, y => 7), 255, 0, 255, 0, "getpixel(8, 7)"); { # simple arrayrefs my @colors = $im->getpixel(x => [ 0, 8, 7 ], y => [ 0, 7, 3 ]); is(@colors, 3, "getpixel 2 3 element array refs"); is_color3($colors[0], 255, 0, 0, "check first color"); is_color3($colors[1], 255, 0, 255, "check second color"); is_color3($colors[2], 0, 255, 255, "check third color"); } # array and scalar { my @colors = $im->getpixel(x => 5, y => [ 4, 5, 9 ]); is(@colors, 3, "getpixel x scalar, y arrayref of 3"); is_color3($colors[0], 0, 255, 255, "check first color"); is_color3($colors[1], 255, 0, 255, "check second color"); is_color3($colors[2], 255, 0, 255, "check third color"); } { my @colors = $im->getpixel(x => [ 0, 4, 5 ], y => 2); is(@colors, 3, "getpixel y scalar, x arrayref of 3"); is_color3($colors[0], 255, 0, 0, "check first color"); is_color3($colors[1], 255, 0, 0, "check second color"); is_color3($colors[2], 0, 255, 255, "check third color"); } { # float is_fcolor3($im->getpixel(x => 1, y => 0, type => 'float'), 1.0, 0, 0, "getpixel(1,0) float"); is_fcolor4($im->getpixel(x => 8, y => 1, type => 'float'), 0, 1.0, 1.0, 0, "getpixel(8,1) float"); is_fcolor4($im->getpixel(x => 8, y => 7, type => 'float'), 1.0, 0, 1.0, 0, "getpixel(8,7) float"); my @colors = $im->getpixel(x => [ 0, 8, 7 ], y => [ 0, 7, 3 ], type => 'float'); is(@colors, 3, "getpixel 2 3 element array refs (float)"); is_fcolor3($colors[0], 1, 0, 0, "check first color"); is_fcolor3($colors[1], 1, 0, 1, "check second color"); is_fcolor3($colors[2], 0, 1, 1, "check third color"); } { # out of bounds my @colors = $im->getpixel(x => [ 0, -1, 5, 10 ], y => 0); is(@colors, 4, "should be 4 entries") or diag $im->errstr; is_color3($colors[0], 255, 0, 0, "first red"); is($colors[1], undef, "second undef"); is_color3($colors[2], 0, 255, 255, "third cyan"); is($colors[3], undef, "fourth undef"); } { # out of bounds my @colors = $im->getpixel(x => [ 0, -1, 5, 10 ], y => 0, type => "float"); is(@colors, 4, "should be 4 entries") or diag $im->errstr; is_fcolor3($colors[0], 1.0, 0, 0, "first red"); is($colors[1], undef, "second undef"); is_fcolor3($colors[2], 0, 1.0, 1.0, "third cyan"); is($colors[3], undef, "fourth undef"); } } { # setpixel my $im = Imager->new(xsize => 10, ysize => 10); { # errors my $empty = Imager->new; is_deeply([ $empty->setpixel(x => 0, y => 0, color => $red) ], [], "setpixel on empty image"); is($empty->errstr, "setpixel: empty input image", "check message"); is_deeply([ $im->setpixel(y => 0, color => $red) ], [], "missing x"); is($im->errstr, "setpixel: missing x or y parameter", "check message"); $im->_set_error("something different"); is_deeply([$im->setpixel(x => 0, color => $red)], [], "missing y"); is($im->errstr, "setpixel: missing x or y parameter", "check message"); is_deeply([ $im->setpixel(x => [], y => 0, color => $red) ], [], "empty x array ref"); is($im->errstr, "setpixel: x is a reference to an empty array", "check message"); is_deeply([$im->setpixel(x => 0, y => [], color => $red)], [], "empty y array ref"); is($im->errstr, "setpixel: y is a reference to an empty array", "check message"); is_deeply([ $im->setpixel(x => 0, y => 0, color => "not really a color") ], [], "color not a color"); is($im->errstr, "setpixel: No color named not really a color found", "check message"); } # simple set is($im->setpixel(x => 0, y => 0, color => $red), 1, "simple setpixel") or diag "simple set float: ", $im->errstr; is_color3($im->getpixel(x => 0, y => 0), 255, 0, 0, "check stored pixel"); is($im->setpixel(x => 1, y => 2, color => $f_red), 1, "simple setpixel (float)") or diag "simple set float: ", $im->errstr; is_color3($im->getpixel(x => 1, y => 2), 255, 0, 0, "check stored pixel"); is($im->setpixel(x => -1, y => 0, color => $red), "0 but true", "simple setpixel outside of image"); is($im->setpixel(x => 0, y => -1, color => $f_red), "0 but true", "simple setpixel (float) outside of image"); # simple arrayrefs is($im->setpixel( x => [ 0, 8, 7 ], y => [ 0, 7, 3 ], color => $blue), 3, "setpixel with 3 element array refs"); my @colors = $im->getpixel(x => [ 8, 7, 0 ], y => [ 7, 3, 0 ]); is_color3($colors[0], 0, 0, 255, "check first color"); is_color3($colors[1], 0, 0, 255, "check second color"); is_color3($colors[2], 0, 0, 255, "check third color"); # array and scalar { is($im->setpixel(x => 5, y => [ 4, 5, 9 ], color => $green), 3, "setpixel with x scalar, y arrayref of 3"); my @colors = $im->getpixel(x => [ 5, 5, 5 ], y => [ 4, 5, 9 ]); is_color3($colors[0], 0, 255, 0, "check first color"); is_color3($colors[1], 0, 255, 0, "check second color"); is_color3($colors[2], 0, 255, 0, "check third color"); } { is($im->setpixel(x => [ 0, 4, 5 ], y => 2, color => $blue), 3, "setpixel with y scalar, x arrayref of 3"); my @colors = $im->getpixel(x => [ 0, 4, 5 ], y => [ 2, 2, 2 ]); is_color3($colors[0], 0, 0, 255, "check first color"); is_color3($colors[1], 0, 0, 255, "check second color"); is_color3($colors[2], 0, 0, 255, "check third color"); } { is($im->setpixel(x => [ 0, -1, 10, 5, 0 ], y => [ 0, 1, 2, 3, 1 ], color => $blue), 3, "set array with two bad locations") or diag "set array bad locations: ", $im->errstr; my @colors = $im->getpixel(x => [ 0, 5, 0 ], y => [ 0, 3, 1 ]); is_color3($colors[0], 0, 0, 255, "check first color"); is_color3($colors[1], 0, 0, 255, "check second color"); is_color3($colors[2], 0, 0, 255, "check third color"); } { is($im->setpixel(x => [ 0, -1, 10, 5, 0 ], y => [ 0, 1, 2, 3, 1 ], color => $f_green), 3, "set array with two bad locations (float)") or diag "set array bad locations (float): ", $im->errstr; my @colors = $im->getpixel(x => [ 0, 5, 0 ], y => [ 0, 3, 1 ]); is_color3($colors[0], 0, 255, 0, "check first color"); is_color3($colors[1], 0, 255, 0, "check second color"); is_color3($colors[2], 0, 255, 0, "check third color"); } { # default color is($im->setpixel(x => 0, y => 9), 1, "setpixel() default color") or diag "setpixel default color: ", $im->errstr; is_color3($im->getpixel(x => 0, y => 9), 255, 255, 255, "check color set"); } } { my $empty = Imager->new; ok(!$empty->addtag(name => "foo", value => 1), "can't addtag on an empty image"); is($empty->errstr, "addtag: empty input image", "check error message"); ok(!$empty->settag(name => "foo", value => 1), "can't settag on an empty image"); is($empty->errstr, "settag: empty input image", "check error message"); ok(!$empty->deltag(name => "foo"), "can't deltag on an empty image"); is($empty->errstr, "deltag: empty input image", "check error message"); ok(!$empty->tags(name => "foo"), "can't tags on an empty image"); is($empty->errstr, "tags: empty input image", "check error message"); } { my @tests = ( [ "gray", 1, undef ], [ "graya", 1, 1 ], [ "rgb", 3, undef ], [ "rgba", 3, 3 ], ); for my $test (@tests) { my ($model, $color_channels, $alpha) = @$test; my $im = Imager->new(model => $model, xsize => 10, ysize => 10) or die "Cannot create $model image:", Imager->errstr; ok($im, "make a $model image via model"); is($im->colormodel, $model, "check colormodel is $model"); is($im->alphachannel, $alpha, "check alphachannel"); is($im->colorchannels, $color_channels, "check colorchannels"); } } Imager->close_log(); unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t01introvert.log"; } sub check_add { my ($im, $color, $expected) = @_; my $index = Imager::i_addcolors($im, $color); ok($index, "got index"); print "# $index\n"; is(0+$index, $expected, "index matched expected"); my ($new) = Imager::i_getcolors($im, $index); ok($new, "got the color"); ok(color_cmp($new, $color) == 0, "color matched what was added"); $index; } # sub array_ncmp { # my ($a1, $a2) = @_; # my $len = @$a1 < @$a2 ? @$a1 : @$a2; # for my $i (0..$len-1) { # my $diff = $a1->[$i] <=> $a2->[$i] # and return $diff; # } # return @$a1 <=> @$a2; # } sub dump_colors { for my $col (@_) { print "# ", map(sprintf("%02X", $_), ($col->rgba)[0..2]),"\n"; } } sub _get_error { my @errors = Imager::i_errors(); return join(": ", map $_->[0], @errors); } libimager-perl-1.004+dfsg.orig/t/100-base/800-tr18561.t0000644000175000017500000000045012263740601020760 0ustar gregoagregoa#!perl -w # regression test for RT issue 18561 # use strict; use Test::More tests => 1; eval { use Imager; my $i = Imager->new( xsize => 50, ysize => 50, ); $i->setpixel( x => 10, y => 10, color => [0, 0, 0], ); }; ok(!$@, "shouldn't crash") or print "# $@\n"; libimager-perl-1.004+dfsg.orig/t/100-base/020-color.t0000644000175000017500000001760412263740601021047 0ustar gregoagregoa#!perl -w # Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) use Test::More tests => 70; use Imager; use Imager::Test qw(is_fcolor4); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t15color.log"); my $c1 = Imager::Color->new(100, 150, 200, 250); ok(test_col($c1, 100, 150, 200, 250), 'simple 4-arg'); my $c2 = Imager::Color->new(100, 150, 200); ok(test_col($c2, 100, 150, 200, 255), 'simple 3-arg'); my $c3 = Imager::Color->new("#6496C8"); ok(test_col($c3, 100, 150, 200, 255), 'web color'); # crashes in Imager-0.38pre8 and earlier my @foo; for (1..1000) { push(@foo, Imager::Color->new("#FFFFFF")); } my $fail; for (@foo) { Imager::Color::set_internal($_, 128, 128, 128, 128) == $_ or ++$fail; Imager::Color::set_internal($_, 128, 128, 128, 128) == $_ or ++$fail; test_col($_, 128, 128, 128, 128) or ++$fail; } ok(!$fail, 'consitency check'); # test the new OO methods color_ok('r g b',, 100, 150, 200, 255, Imager::Color->new(r=>100, g=>150, b=>200)); color_ok('red green blue', 101, 151, 201, 255, Imager::Color->new(red=>101, green=>151, blue=>201)); color_ok('grey', 102, 255, 255, 255, Imager::Color->new(grey=>102)); color_ok('gray', 103, 255, 255, 255, Imager::Color->new(gray=>103)); SKIP: { skip "no X rgb.txt found", 1 unless grep -r, Imager::Color::_test_x_palettes(); color_ok('xname', 0, 0, 255, 255, Imager::Color->new(xname=>'blue')); } color_ok('gimp', 255, 250, 250, 255, Imager::Color->new(gimp=>'snow', palette=>'testimg/test_gimp_pal')); color_ok('h s v', 255, 255, 255, 255, Imager::Color->new(h=>0, 's'=>0, 'v'=>1.0)); color_ok('h s v again', 255, 0, 0, 255, Imager::Color->new(h=>0, 's'=>1, v=>1)); color_ok('web 6 digit', 128, 129, 130, 255, Imager::Color->new(web=>'#808182')); color_ok('web 3 digit', 0x11, 0x22, 0x33, 255, Imager::Color->new(web=>'#123')); color_ok('rgb arrayref', 255, 150, 121, 255, Imager::Color->new(rgb=>[ 255, 150, 121 ])); color_ok('rgba arrayref', 255, 150, 121, 128, Imager::Color->new(rgba=>[ 255, 150, 121, 128 ])); color_ok('hsv arrayref', 255, 0, 0, 255, Imager::Color->new(hsv=>[ 0, 1, 1 ])); color_ok('channel0-3', 129, 130, 131, 134, Imager::Color->new(channel0=>129, channel1=>130, channel2=>131, channel3=>134)); color_ok('c0-3', 129, 130, 131, 134, Imager::Color->new(c0=>129, c1=>130, c2=>131, c3=>134)); color_ok('channels arrayref', 200, 201, 203, 204, Imager::Color->new(channels=>[ 200, 201, 203, 204 ])); color_ok('name', 255, 250, 250, 255, Imager::Color->new(name=>'snow', palette=>'testimg/test_gimp_pal')); # test the internal HSV <=> RGB conversions # these values were generated using the GIMP # all but hue is 0..360, saturation and value from 0 to 1 # rgb from 0 to 255 my @hsv_vs_rgb = ( { hsv => [ 0, 0.2, 0.1 ], rgb=> [ 25, 20, 20 ] }, { hsv => [ 0, 0.5, 1.0 ], rgb => [ 255, 127, 127 ] }, { hsv => [ 100, 0.5, 1.0 ], rgb => [ 170, 255, 127 ] }, { hsv => [ 100, 1.0, 1.0 ], rgb=> [ 85, 255, 0 ] }, { hsv => [ 335, 0.5, 0.5 ], rgb=> [127, 63, 90 ] }, ); use Imager::Color::Float; my $test_num = 23; my $index = 0; for my $entry (@hsv_vs_rgb) { print "# color index $index\n"; my $hsv = $entry->{hsv}; my $rgb = $entry->{rgb}; my $fhsvo = Imager::Color::Float->new($hsv->[0]/360.0, $hsv->[1], $hsv->[2]); my $fc = Imager::Color::Float::i_hsv_to_rgb($fhsvo); fcolor_close_enough("i_hsv_to_rgbf $index", $rgb->[0]/255, $rgb->[1]/255, $rgb->[2]/255, $fc); my $fc2 = Imager::Color::Float::i_rgb_to_hsv($fc); fcolor_close_enough("i_rgbf_to_hsv $index", $hsv->[0]/360.0, $hsv->[1], $hsv->[2], $fc2); my $hsvo = Imager::Color->new($hsv->[0]*255/360.0, $hsv->[1] * 255, $hsv->[2] * 255); my $c = Imager::Color::i_hsv_to_rgb($hsvo); color_close_enough("i_hsv_to_rgb $index", @$rgb, $c); my $c2 = Imager::Color::i_rgb_to_hsv($c); color_close_enough_hsv("i_rgb_to_hsv $index", $hsv->[0]*255/360.0, $hsv->[1] * 255, $hsv->[2] * 255, $c2); ++$index; } # check the built-ins table color_ok('builtin black', 0, 0, 0, 255, Imager::Color->new(builtin=>'black')); { my $c1 = Imager::Color->new(255, 255, 255, 0); my $c2 = Imager::Color->new(255, 255, 255, 255); ok(!$c1->equals(other=>$c2), "not equal no ignore alpha"); ok(scalar($c1->equals(other=>$c2, ignore_alpha=>1)), "equal with ignore alpha"); ok($c1->equals(other=>$c1), "equal to itself"); } { # http://rt.cpan.org/NoAuth/Bug.html?id=13143 # Imager::Color->new(color_name) warning if HOME environment variable not set local $ENV{HOME}; my @warnings; local $SIG{__WARN__} = sub { push @warnings, "@_" }; # presumably no-one will name a color like this. my $c1 = Imager::Color->new(gimp=>"ABCDEFGHIJKLMNOP"); is(@warnings, 0, "Should be no warnings") or do { print "# $_" for @warnings }; } { # float color from hex triple my $f3white = Imager::Color::Float->new("#FFFFFF"); is_fcolor4($f3white, 1.0, 1.0, 1.0, 1.0, "check color #FFFFFF"); my $f3black = Imager::Color::Float->new("#000000"); is_fcolor4($f3black, 0, 0, 0, 1.0, "check color #000000"); my $f3grey = Imager::Color::Float->new("#808080"); is_fcolor4($f3grey, 0x80/0xff, 0x80/0xff, 0x80/0xff, 1.0, "check color #808080"); my $f4white = Imager::Color::Float->new("#FFFFFF80"); is_fcolor4($f4white, 1.0, 1.0, 1.0, 0x80/0xff, "check color #FFFFFF80"); } { # fail to make a color ok(!Imager::Color::Float->new("-unknown-"), "try to make float color -unknown-"); } { # set after creation my $c = Imager::Color::Float->new(0, 0, 0); is_fcolor4($c, 0, 0, 0, 1.0, "check simple init of float color"); ok($c->set(1.0, 0.5, 0.25, 1.0), "set() the color"); is_fcolor4($c, 1.0, 0.5, 0.25, 1.0, "check after set"); ok(!$c->set("-unknown-"), "set to unknown"); } { # test ->hsv my $c = Imager::Color->new(255, 0, 0); my($h,$s,$v) = $c->hsv; is($h,0,'red hue'); is($s,1,'red saturation'); is($v,1,'red value'); $c = Imager::Color->new(0, 255, 0); ($h,$s,$v) = $c->hsv; is($h,120,'green hue'); is($s,1,'green saturation'); is($v,1,'green value'); $c = Imager::Color->new(0, 0, 255); ($h,$s,$v) = $c->hsv; is($h,240,'blue hue'); is($s,1,'blue saturation'); is($v,1,'blue value'); $c = Imager::Color->new(255, 255, 255); ($h,$s,$v) = $c->hsv; is($h,0,'white hue'); is($s,0,'white saturation'); is($v,1,'white value'); $c = Imager::Color->new(0, 0, 0); ($h,$s,$v) = $c->hsv; is($h,0,'black hue'); is($s,0,'black saturation'); is($v,0,'black value'); } sub test_col { my ($c, $r, $g, $b, $a) = @_; unless ($c) { print "# $Imager::ERRSTR\n"; return 0; } my ($cr, $cg, $cb, $ca) = $c->rgba; return $r == $cr && $g == $cg && $b == $cb && $a == $ca; } sub color_close_enough { my ($name, $r, $g, $b, $c) = @_; my ($cr, $cg, $cb) = $c->rgba; ok(abs($cr-$r) <= 5 && abs($cg-$g) <= 5 && abs($cb-$b) <= 5, "$name - ($cr, $cg, $cb) <=> ($r, $g, $b)"); } sub color_close_enough_hsv { my ($name, $h, $s, $v, $c) = @_; my ($ch, $cs, $cv) = $c->rgba; if ($ch < 5 && $h > 250) { $ch += 255; } elsif ($ch > 250 && $h < 5) { $h += 255; } ok(abs($ch-$h) <= 5 && abs($cs-$s) <= 5 && abs($cv-$v) <= 5, "$name - ($ch, $cs, $cv) <=> ($h, $s, $v)"); } sub fcolor_close_enough { my ($name, $r, $g, $b, $c) = @_; my ($cr, $cg, $cb) = $c->rgba; ok(abs($cr-$r) <= 0.01 && abs($cg-$g) <= 0.01 && abs($cb-$b) <= 0.01, "$name - ($cr, $cg, $cb) <=> ($r, $g, $b)"); } sub color_ok { my ($name, $r, $g, $b, $a, $c) = @_; unless (ok(test_col($c, $r, $g, $b, $a), $name)) { print "# ($r,$g,$b,$a) != (".join(",", $c ? $c->rgba: ()).")\n"; } } libimager-perl-1.004+dfsg.orig/t/100-base/030-countc.t0000644000175000017500000000557412533552635021240 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 22; use Imager; -d "testout" or mkdir "testout"; Imager::init('log'=>'testout/t90cc.log'); { my $img=Imager->new(); ok($img->open(file=>'testimg/scale.ppm'), 'load test image') or print "failed: ",$img->{ERRSTR},"\n"; ok(defined($img->getcolorcount(maxcolors=>10000)), 'check color count is small enough'); print "# color count: ".$img->getcolorcount()."\n"; is($img->getcolorcount(), 86, 'expected number of colors'); is($img->getcolorcount(maxcolors => 50), undef, 'check overflow handling'); } { my $black = Imager::Color->new(0, 0, 0); my $blue = Imager::Color->new(0, 0, 255); my $red = Imager::Color->new(255, 0, 0); my $im = Imager->new(xsize=>50, ysize=>50); my $count = $im->getcolorcount(); is ($count, 1, "getcolorcount is 1"); my @colour_usage = $im->getcolorusage(); is_deeply (\@colour_usage, [2500], "2500 are in black"); $im->box(filled=>1, color=>$blue, xmin=>25); $count = $im->getcolorcount(); is ($count, 2, "getcolorcount is 2"); @colour_usage = $im->getcolorusage(); is_deeply(\@colour_usage, [1250, 1250] , "1250, 1250: Black and blue"); $im->box(filled=>1, color=>$red, ymin=>25); $count = $im->getcolorcount(); is ($count, 3, "getcolorcount is 3"); @colour_usage = $im->getcolorusage(); is_deeply(\@colour_usage, [625, 625, 1250] , "625, 625, 1250: Black blue and red"); @colour_usage = $im->getcolorusage(maxcolors => 2); is(@colour_usage, 0, 'test overflow check'); my $colour_usage = $im->getcolorusagehash(); my $red_pack = pack("CCC", 255, 0, 0); my $blue_pack = pack("CCC", 0, 0, 255); my $black_pack = pack("CCC", 0, 0, 0); is_deeply( $colour_usage, { $black_pack => 625, $blue_pack => 625, $red_pack => 1250 }, "625, 625, 1250: Black blue and red (hash)"); is($im->getcolorusagehash(maxcolors => 2), undef, 'test overflow check'); # test with a greyscale image my $im_g = $im->convert(preset => 'grey'); # since the grey preset scales each source channel differently # each of the original colors will be converted to different colors is($im_g->getcolorcount, 3, '3 colors (grey)'); is_deeply([ $im_g->getcolorusage ], [ 625, 625, 1250 ], 'color counts (grey)'); is_deeply({ "\x00" => 625, "\x12" => 625, "\x38" => 1250 }, $im_g->getcolorusagehash, 'color usage hash (grey)'); } { my $empty = Imager->new; is($empty->getcolorcount, undef, "can't getcolorcount an empty image"); is($empty->errstr, "getcolorcount: empty input image", "check error message"); is($empty->getcolorusagehash, undef, "can't getcolorusagehash an empty image"); is($empty->errstr, "getcolorusagehash: empty input image", "check error message"); is($empty->getcolorusage, undef, "can't getcolorusage an empty image"); is($empty->errstr, "getcolorusage: empty input image", "check error message"); } libimager-perl-1.004+dfsg.orig/t/100-base/801-tr18561b.t0000644000175000017500000000072712263740601021132 0ustar gregoagregoa#!perl -w # variant on the code that produces 18561 # the old _color() code could return floating colors in some cases # but in most cases the caller couldn't handle it use strict; use Test::More tests => 1; eval { use Imager; use Imager::Color::Float; # prevent the actual 18561 crash my $i = Imager->new( xsize => 50, ysize => 50, ); $i->line(x1 => 0, y1 => 0, x2 => 99, y2=>99, color => [ 0, 0, 0 ]); }; ok(!$@, "shouldn't crash") or print "# $@\n"; libimager-perl-1.004+dfsg.orig/t/450-api/0000755000175000017500000000000012617614576017122 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/450-api/100-inline.t0000644000175000017500000005155012507371373021062 0ustar gregoagregoa#!perl -w # # this tests both the Inline interface and the API use strict; use Test::More; use Imager::Test qw(is_color3 is_color4); eval "require Inline::C;"; plan skip_all => "Inline required for testing API" if $@; eval "require Parse::RecDescent;"; plan skip_all => "Could not load Parse::RecDescent" if $@; use Cwd 'getcwd'; plan skip_all => "Inline won't work in directories with spaces" if getcwd() =~ / /; plan skip_all => "perl 5.005_04, 5.005_05 too buggy" if $] =~ /^5\.005_0[45]$/; -d "testout" or mkdir "testout"; print STDERR "Inline version $Inline::VERSION\n"; plan tests => 120; require Inline; Inline->import(with => 'Imager'); Inline->import("FORCE"); # force rebuild #Inline->import(C => Config => OPTIMIZE => "-g"); Inline->bind(C => <<'EOS'); #include int pixel_count(Imager::ImgRaw im) { return im->xsize * im->ysize; } int count_color(Imager::ImgRaw im, Imager::Color c) { int count = 0, x, y, chan; i_color read_c; for (x = 0; x < im->xsize; ++x) { for (y = 0; y < im->ysize; ++y) { int match = 1; i_gpix(im, x, y, &read_c); for (chan = 0; chan < im->channels; ++chan) { if (read_c.channel[chan] != c->channel[chan]) { match = 0; break; } } if (match) ++count; } } return count; } Imager make_10x10() { i_img *im = i_img_8_new(10, 10, 3); i_color c; c.channel[0] = c.channel[1] = c.channel[2] = 255; i_box_filled(im, 0, 0, im->xsize-1, im->ysize-1, &c); return im; } /* tests that all of the APIs are visible - most of them anyway */ Imager do_lots(Imager src) { i_img *im = i_img_8_new(100, 100, 3); i_img *fill_im = i_img_8_new(5, 5, 3); i_img *testim; i_color red, blue, green, black, temp_color; i_fcolor redf, bluef; i_fill_t *hatch, *fhatch_fill; i_fill_t *im_fill; i_fill_t *solid_fill, *fsolid_fill; i_fill_t *fount_fill; void *block; double matrix[9] = /* 30 degree rotation */ { 0.866025, -0.5, 0, 0.5, 0.866025, 0, 0, 0, 1, }; i_fountain_seg fseg; i_img_tags tags; int entry; double temp_double; red.channel[0] = 255; red.channel[1] = 0; red.channel[2] = 0; red.channel[3] = 255; blue.channel[0] = 0; blue.channel[1] = 0; blue.channel[2] = 255; blue.channel[3] = 255; green.channel[0] = 0; green.channel[1] = 255; green.channel[2] = 0; green.channel[3] = 255; black.channel[0] = black.channel[1] = black.channel[2] = 0; black.channel[3] = 255; hatch = i_new_fill_hatch(&red, &blue, 0, 1, NULL, 0, 0); i_box(im, 0, 0, 9, 9, &red); i_box_filled(im, 10, 0, 19, 9, &blue); i_box_cfill(im, 20, 0, 29, 9, hatch); /* make an image fill, and try it */ i_box_cfill(fill_im, 0, 0, 4, 4, hatch); im_fill = i_new_fill_image(fill_im, matrix, 2, 2, 0); i_box_cfill(im, 30, 0, 39, 9, im_fill); /* make a solid fill and try it */ solid_fill = i_new_fill_solid(&red, 0); i_box_cfill(im, 40, 0, 49, 9, solid_fill); /* floating fills */ redf.channel[0] = 1.0; redf.channel[1] = 0; redf.channel[2] = 0; redf.channel[3] = 1.0; bluef.channel[0] = 0; bluef.channel[1] = 0; bluef.channel[2] = 1.0; bluef.channel[3] = 1.0; fsolid_fill = i_new_fill_solidf(&redf, 0); i_box_cfill(im, 50, 0, 59, 9, fsolid_fill); fhatch_fill = i_new_fill_hatchf(&redf, &bluef, 0, 2, NULL, 0, 0); i_box_cfill(im, 60, 0, 69, 9, fhatch_fill); /* fountain fill */ fseg.start = 0; fseg.middle = 0.5; fseg.end = 1.0; fseg.c[0] = redf; fseg.c[1] = bluef; fseg.type = i_fst_linear; fseg.color = i_fc_hue_down; fount_fill = i_new_fill_fount(70, 0, 80, 0, i_ft_linear, i_fr_triangle, 0, i_fts_none, 1, 1, &fseg); i_box_cfill(im, 70, 0, 79, 9, fount_fill); i_line(im, 0, 10, 10, 15, &blue, 1); i_line_aa(im, 0, 19, 10, 15, &red, 1); i_arc(im, 15, 15, 4, 45, 160, &blue); i_arc_aa(im, 25, 15, 4, 75, 280, &red); i_arc_cfill(im, 35, 15, 4, 0, 215, hatch); i_arc_aa_cfill(im, 45, 15, 4, 30, 210, hatch); i_circle_aa(im, 55, 15, 4, &red); i_box(im, 61, 11, 68, 18, &red); i_flood_fill(im, 65, 15, &blue); i_box(im, 71, 11, 78, 18, &red); i_flood_cfill(im, 75, 15, hatch); i_box_filled(im, 1, 21, 9, 24, &red); i_box_filled(im, 1, 25, 9, 29, &blue); i_flood_fill_border(im, 5, 25, &green, &black); i_box_filled(im, 11, 21, 19, 24, &red); i_box_filled(im, 11, 25, 19, 29, &blue); i_flood_cfill_border(im, 15, 25, hatch, &black); { double x[3]; double y[3]; i_polygon_t poly; x[0] = 55; y[0] = 25; x[1] = 55; y[1] = 50; x[2] = 70; y[2] = 50; i_poly_aa_m(im, 3, x, y, i_pfm_evenodd, &red); x[2] = 40; i_poly_aa_cfill_m(im, 3, x, y, i_pfm_evenodd, hatch); y[0] = 65; poly.x = x; poly.y = y; poly.count = 3; i_poly_poly_aa(im, 1, &poly, i_pfm_nonzero, &green); x[2] = 70; i_poly_poly_aa_cfill(im, 1, &poly, i_pfm_nonzero, hatch); } i_fill_destroy(fount_fill); i_fill_destroy(fhatch_fill); i_fill_destroy(solid_fill); i_fill_destroy(fsolid_fill); i_fill_destroy(hatch); i_fill_destroy(im_fill); i_img_destroy(fill_im); /* make sure we can make each image type */ testim = i_img_16_new(100, 100, 3); i_img_destroy(testim); testim = i_img_double_new(100, 100, 3); i_img_destroy(testim); testim = i_img_pal_new(100, 100, 3, 256); i_img_destroy(testim); testim = i_sametype(im, 50, 50); i_img_destroy(testim); testim = i_sametype_chans(im, 50, 50, 4); i_img_destroy(testim); i_clear_error(); i_push_error(0, "Hello"); i_push_errorf(0, "%s", "World"); /* make sure tags create/destroy work */ i_tags_new(&tags); i_tags_destroy(&tags); block = mymalloc(20); block = myrealloc(block, 50); myfree(block); i_tags_set(&im->tags, "lots_string", "foo", -1); i_tags_setn(&im->tags, "lots_number", 101); if (!i_tags_find(&im->tags, "lots_number", 0, &entry)) { i_push_error(0, "lots_number tag not found"); i_img_destroy(im); return NULL; } i_tags_delete(&im->tags, entry); /* these won't delete anything, but it makes sure the macros and function pointers are correct */ i_tags_delbyname(&im->tags, "unknown"); i_tags_delbycode(&im->tags, 501); i_tags_set_float(&im->tags, "lots_float", 0, 3.14); if (!i_tags_get_float(&im->tags, "lots_float", 0, &temp_double)) { i_push_error(0, "lots_float not found"); i_img_destroy(im); return NULL; } if (fabs(temp_double - 3.14) > 0.001) { i_push_errorf(0, "lots_float incorrect %g", temp_double); i_img_destroy(im); return NULL; } i_tags_set_float2(&im->tags, "lots_float2", 0, 100 * sqrt(2.0), 5); if (!i_tags_get_int(&im->tags, "lots_float2", 0, &entry)) { i_push_error(0, "lots_float2 not found as int"); i_img_destroy(im); return NULL; } if (entry != 141) { i_push_errorf(0, "lots_float2 unexpected value %d", entry); i_img_destroy(im); return NULL; } i_tags_set_color(&im->tags, "lots_color", 0, &red); if (!i_tags_get_color(&im->tags, "lots_color", 0, &temp_color)) { i_push_error(0, "lots_color not found as color"); i_img_destroy(im); return NULL; } return im; } void io_fd(int fd) { Imager::IO io = io_new_fd(fd); i_io_write(io, "test", 4); i_io_close(io); io_glue_destroy(io); } int io_bufchain_test() { Imager::IO io = io_new_bufchain(); unsigned char *result; size_t size; if (i_io_write(io, "test2", 5) != 5) { fprintf(stderr, "write failed\n"); return 0; } if (!i_io_flush(io)) { fprintf(stderr, "flush failed\n"); return 0; } if (i_io_close(io) != 0) { fprintf(stderr, "close failed\n"); return 0; } size = io_slurp(io, &result); if (size != 5) { fprintf(stderr, "wrong size\n"); return 0; } if (memcmp(result, "test2", 5)) { fprintf(stderr, "data mismatch\n"); return 0; } if (i_io_seek(io, 0, 0) != 0) { fprintf(stderr, "seek failure\n"); return 0; } myfree(result); io_glue_destroy(io); return 1; } const char * io_buffer_test(SV *in) { STRLEN len; const char *in_str = SvPV(in, len); static char buf[100]; Imager::IO io = io_new_buffer(in_str, len, NULL, NULL); ssize_t read_size; read_size = i_io_read(io, buf, sizeof(buf)-1); io_glue_destroy(io); if (read_size < 0 || read_size >= sizeof(buf)) { return ""; } buf[read_size] = '\0'; return buf; } const char * io_peekn_test(SV *in) { STRLEN len; const char *in_str = SvPV(in, len); static char buf[100]; Imager::IO io = io_new_buffer(in_str, len, NULL, NULL); ssize_t read_size; read_size = i_io_peekn(io, buf, sizeof(buf)-1); io_glue_destroy(io); if (read_size < 0 || read_size >= sizeof(buf)) { return ""; } buf[read_size] = '\0'; return buf; } const char * io_gets_test(SV *in) { STRLEN len; const char *in_str = SvPV(in, len); static char buf[100]; Imager::IO io = io_new_buffer(in_str, len, NULL, NULL); ssize_t read_size; read_size = i_io_gets(io, buf, sizeof(buf), 's'); io_glue_destroy(io); if (read_size < 0 || read_size >= sizeof(buf)) { return ""; } return buf; } int io_getc_test(SV *in) { STRLEN len; const char *in_str = SvPV(in, len); static char buf[100]; Imager::IO io = io_new_buffer(in_str, len, NULL, NULL); int result; result = i_io_getc(io); io_glue_destroy(io); return result; } int io_peekc_test(SV *in) { STRLEN len; const char *in_str = SvPV(in, len); static char buf[100]; Imager::IO io = io_new_buffer(in_str, len, NULL, NULL); int result; i_io_set_buffered(io, 0); result = i_io_peekc(io); io_glue_destroy(io); return result; } int test_render_color(Imager work_8) { i_render *r8; i_color c; unsigned char render_coverage[3]; render_coverage[0] = 0; render_coverage[1] = 128; render_coverage[2] = 255; r8 = i_render_new(work_8, 10); c.channel[0] = 128; c.channel[1] = 255; c.channel[2] = 0; c.channel[3] = 255; i_render_color(r8, 0, 0, sizeof(render_coverage), render_coverage, &c); c.channel[3] = 128; i_render_color(r8, 0, 1, sizeof(render_coverage), render_coverage, &c); c.channel[3] = 0; i_render_color(r8, 0, 2, sizeof(render_coverage), render_coverage, &c); i_render_delete(r8); return 1; } int raw_psamp(Imager im, int chan_count) { static i_sample_t samps[] = { 0, 127, 255 }; i_clear_error(); return i_psamp(im, 0, 1, 0, samps, NULL, chan_count); } int raw_psampf(Imager im, int chan_count) { static i_fsample_t samps[] = { 0, 0.5, 1.0 }; i_clear_error(); return i_psampf(im, 0, 1, 0, samps, NULL, chan_count); } int test_mutex() { i_mutex_t m; m = i_mutex_new(); i_mutex_lock(m); i_mutex_unlock(m); i_mutex_destroy(m); return 1; } int test_slots() { im_slot_t slot = im_context_slot_new(NULL); if (im_context_slot_get(aIMCTX, slot)) { fprintf(stderr, "slots should default to NULL\n"); return 0; } if (!im_context_slot_set(aIMCTX, slot, &slot)) { fprintf(stderr, "set slot failed\n"); return 0; } if (im_context_slot_get(aIMCTX, slot) != &slot) { fprintf(stderr, "get slot didn't match\n"); return 0; } return 1; } int color_channels(Imager im) { return i_img_color_channels(im); } int color_model(Imager im) { return (int)i_img_color_model(im); } int alpha_channel(Imager im) { int channel; if (!i_img_alpha_channel(im, &channel)) channel = -1; return channel; } EOS my $im = Imager->new(xsize=>50, ysize=>50); is(pixel_count($im), 2500, "pixel_count"); my $black = Imager::Color->new(0,0,0); is(count_color($im, $black), 2500, "count_color black on black image"); my $im2 = make_10x10(); my $white = Imager::Color->new(255, 255, 255); is(count_color($im2, $white), 100, "check new image white count"); ok($im2->box(filled=>1, xmin=>1, ymin=>1, xmax => 8, ymax=>8, color=>$black), "try new image"); is(count_color($im2, $black), 64, "check modified black count"); is(count_color($im2, $white), 36, "check modified white count"); my $im3 = do_lots($im2); ok($im3, "do_lots()") or print "# ", Imager->_error_as_msg, "\n"; ok($im3->write(file=>'testout/t82lots.ppm'), "write t82lots.ppm"); { # RT #24992 # the T_IMAGER_FULL_IMAGE typemap entry was returning a blessed # hash with an extra ref, causing memory leaks my $im = make_10x10(); my $im2 = Imager->new(xsize => 10, ysize => 10); require B; my $imb = B::svref_2object($im); my $im2b = B::svref_2object($im2); is ($imb->REFCNT, $im2b->REFCNT, "check refcnt of imager object hash between normal and typemap generated"); } SKIP: { use IO::File; my $fd_filename = "testout/t82fd.txt"; { my $fh = IO::File->new($fd_filename, "w") or skip("Can't create file: $!", 1); io_fd(fileno($fh)); $fh->close; } { my $fh = IO::File->new($fd_filename, "r") or skip("Can't open file: $!", 1); my $data = <$fh>; is($data, "test", "make sure data written to fd"); } unlink $fd_filename; } ok(io_bufchain_test(), "check bufchain functions"); is(io_buffer_test("test3"), "test3", "check io_new_buffer() and i_io_read"); is(io_peekn_test("test5"), "test5", "check i_io_peekn"); is(io_gets_test("test"), "tes", "check i_io_gets()"); is(io_getc_test("ABC"), ord "A", "check i_io_getc(_imp)?"); is(io_getc_test("XYZ"), ord "X", "check i_io_peekc(_imp)?"); for my $bits (8, 16) { print "# bits: $bits\n"; # the floating point processing is a little more accurate my $bump = $bits == 16 ? 1 : 0; { my $im = Imager->new(xsize => 10, ysize => 10, channels => 3, bits => $bits); ok($im->box(filled => 1, color => '#808080'), "fill work image with gray"); ok(test_render_color($im), "call render_color on 3 channel image"); is_color3($im->getpixel(x => 0, y => 0), 128, 128, 128, "check zero coverage, alpha 255 color, bits $bits"); is_color3($im->getpixel(x => 1, y => 0), 128, 191+$bump, 63+$bump, "check 128 coverage, alpha 255 color, bits $bits"); is_color3($im->getpixel(x => 2, y => 0), 128, 255, 0, "check 255 coverage, alpha 255 color, bits $bits"); is_color3($im->getpixel(x => 0, y => 1), 128, 128, 128, "check zero coverage, alpha 128 color, bits $bits"); is_color3($im->getpixel(x => 1, y => 1), 128, 159+$bump, 95+$bump, "check 128 coverage, alpha 128 color, bits $bits"); is_color3($im->getpixel(x => 2, y => 1), 128, 191+$bump, 63+$bump, "check 255 coverage, alpha 128 color, bits $bits"); is_color3($im->getpixel(x => 0, y => 2), 128, 128, 128, "check zero coverage, alpha 0 color, bits $bits"); is_color3($im->getpixel(x => 1, y => 2), 128, 128, 128, "check 128 coverage, alpha 0 color, bits $bits"); is_color3($im->getpixel(x => 2, y => 2), 128, 128, 128, "check 255 coverage, alpha 0 color, bits $bits"); } { my $im = Imager->new(xsize => 10, ysize => 10, channels => 4, bits => $bits); ok($im->box(filled => 1, color => '#808080'), "fill work image with opaque gray"); ok(test_render_color($im), "call render_color on 4 channel image"); is_color4($im->getpixel(x => 0, y => 0), 128, 128, 128, 255, "check zero coverage, alpha 255 color, bits $bits"); is_color4($im->getpixel(x => 1, y => 0), 128, 191+$bump, 63+$bump, 255, "check 128 coverage, alpha 255 color, bits $bits"); is_color4($im->getpixel(x => 2, y => 0), 128, 255, 0, 255, "check 255 coverage, alpha 255 color, bits $bits"); is_color4($im->getpixel(x => 0, y => 1), 128, 128, 128, 255, "check zero coverage, alpha 128 color, bits $bits"); is_color4($im->getpixel(x => 1, y => 1), 128, 159+$bump, 95+$bump, 255, "check 128 coverage, alpha 128 color, bits $bits"); is_color4($im->getpixel(x => 2, y => 1), 128, 191+$bump, 63+$bump, 255, "check 255 coverage, alpha 128 color, bits $bits"); is_color4($im->getpixel(x => 0, y => 2), 128, 128, 128, 255, "check zero coverage, alpha 0 color, bits $bits"); is_color4($im->getpixel(x => 1, y => 2), 128, 128, 128, 255, "check 128 coverage, alpha 0 color, bits $bits"); is_color4($im->getpixel(x => 2, y => 2), 128, 128, 128, 255, "check 255 coverage, alpha 0 color, bits $bits"); } { my $im = Imager->new(xsize => 10, ysize => 10, channels => 4, bits => $bits); ok($im->box(filled => 1, color => Imager::Color->new(128, 128, 128, 64)), "fill work image with translucent gray"); ok(test_render_color($im), "call render_color on 4 channel image"); is_color4($im->getpixel(x => 0, y => 0), 128, 128, 128, 64, "check zero coverage, alpha 255 color, bits $bits"); is_color4($im->getpixel(x => 1, y => 0), 128, 230, 25+$bump, 159+$bump, "check 128 coverage, alpha 255 color, bits $bits"); is_color4($im->getpixel(x => 2, y => 0), 128, 255, 0, 255, "check 255 coverage, alpha 255 color, bits $bits"); is_color4($im->getpixel(x => 0, y => 1), 128, 128, 128, 64, "check zero coverage, alpha 128 color, bits $bits"); is_color4($im->getpixel(x => 1, y => 1), 129-$bump, 202-$bump, 55, 111+$bump, "check 128 coverage, alpha 128 color, bits $bits"); is_color4($im->getpixel(x => 2, y => 1), 128, 230, 25+$bump, 159+$bump, "check 255 coverage, alpha 128 color, bits $bits"); is_color4($im->getpixel(x => 0, y => 2), 128, 128, 128, 64, "check zero coverage, alpha 0 color, bits $bits"); is_color4($im->getpixel(x => 1, y => 2), 128, 128, 128, 64, "check 128 coverage, alpha 0 color, bits $bits"); is_color4($im->getpixel(x => 2, y => 2), 128, 128, 128, 64, "check 255 coverage, alpha 0 color, bits $bits"); } } { my $im = Imager->new(xsize => 10, ysize => 10); is(raw_psamp($im, 4), -1, "bad channel list (4) for psamp should fail"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psamp($im, 0), -1, "bad channel list (0) for psamp should fail"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 4), -1, "bad channel list (4) for psampf should fail"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 0), -1, "bad channel list (0) for psampf should fail"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); } { my $im = Imager->new(xsize => 10, ysize => 10, bits => 16); is(raw_psamp($im, 4), -1, "bad channel list (4) for psamp should fail (16-bit)"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psamp($im, 0), -1, "bad channel list (0) for psamp should fail (16-bit)"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 4), -1, "bad channel list (4) for psampf should fail (16-bit)"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 0), -1, "bad channel list (0) for psampf should fail (16-bit)"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); } { my $im = Imager->new(xsize => 10, ysize => 10, bits => 'double'); is(raw_psamp($im, 4), -1, "bad channel list (4) for psamp should fail (double)"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psamp($im, 0), -1,, "bad channel list (0) for psamp should fail (double)"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 4), -1, "bad channel list (4) for psampf should fail (double)"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 0), -1, "bad channel list (0) for psampf should fail (double)"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); } { my $im = Imager->new(xsize => 10, ysize => 10, type => "paletted"); is(raw_psamp($im, 4), -1, "bad channel list (4) for psamp should fail (paletted)"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psamp($im, 0), -1, "bad channel list (0) for psamp should fail (paletted)"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 4), -1, "bad channel list (4) for psampf should fail (paletted)"); is(_get_error(), "chan_count 4 out of range, must be >0, <= channels", "check message"); is(raw_psampf($im, 0), -1, "bad channel list (0) for psampf should fail (paletted)"); is(_get_error(), "chan_count 0 out of range, must be >0, <= channels", "check message"); is($im->type, "paletted", "make sure we kept the image type"); } { my $rgb = Imager->new(xsize => 10, ysize => 10); is(color_model($rgb), 3, "check i_img_color_model() api"); is(color_channels($rgb), 3, "check i_img_color_channels() api"); is(alpha_channel($rgb), -1, "check i_img_alpha_channel() api"); } ok(test_mutex(), "call mutex APIs"); ok(test_slots(), "call slot APIs"); sub _get_error { my @errors = Imager::i_errors(); return join(": ", map $_->[0], @errors); } libimager-perl-1.004+dfsg.orig/t/450-api/110-inlinectx.t0000644000175000017500000000406412263740601021571 0ustar gregoagregoa#!perl -w # # this tests both the Inline interface and the API with IMAGER_NO_CONTEXT use strict; use Test::More; use Imager::Test qw(is_color3 is_color4); eval "require Inline::C;"; plan skip_all => "Inline required for testing API" if $@; eval "require Parse::RecDescent;"; plan skip_all => "Could not load Parse::RecDescent" if $@; use Cwd 'getcwd'; plan skip_all => "Inline won't work in directories with spaces" if getcwd() =~ / /; plan skip_all => "perl 5.005_04, 5.005_05 too buggy" if $] =~ /^5\.005_0[45]$/; -d "testout" or mkdir "testout"; plan tests => 5; require Inline; Inline->import(C => Config => AUTO_INCLUDE => "#define IMAGER_NO_CONTEXT\n"); Inline->import(with => 'Imager'); Inline->import("FORCE"); # force rebuild #Inline->import(C => Config => OPTIMIZE => "-g"); Inline->bind(C => <<'EOS'); #include Imager make_10x10() { dIMCTX; i_img *im = i_img_8_new(10, 10, 3); i_color c; c.channel[0] = c.channel[1] = c.channel[2] = 255; i_box_filled(im, 0, 0, im->xsize-1, im->ysize-1, &c); return im; } void error_dIMCTX() { dIMCTX; im_clear_error(aIMCTX); im_push_error(aIMCTX, 0, "test1"); im_push_errorf(aIMCTX, 0, "test%d", 2); im_log((aIMCTX, 0, "test logging\n")); } void error_dIMCTXim(Imager im) { dIMCTXim(im); im_clear_error(aIMCTX); im_push_error(aIMCTX, 0, "test1"); } int context_refs() { dIMCTX; im_context_refinc(aIMCTX, "context_refs"); im_context_refdec(aIMCTX, "context_refs"); return 1; } EOS Imager->open_log(log => "testout/t84inlinectx.log"); my $im2 = make_10x10(); ok($im2, "make an image"); is_color3($im2->getpixel(x => 0, y => 0), 255, 255, 255, "check the colors"); error_dIMCTX(); is(_get_error(), "test2: test1", "check dIMCTX"); my $im = Imager->new(xsize => 1, ysize => 1); error_dIMCTXim($im); is(_get_error(), "test1", "check dIMCTXim"); ok(context_refs(), "check refcount functions"); Imager->close_log(); unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t84inlinectx.log"; } sub _get_error { my @errors = Imager::i_errors(); return join(": ", map $_->[0], @errors); } libimager-perl-1.004+dfsg.orig/t/Pod/0000755000175000017500000000000012617614576016565 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/Pod/Coverage/0000755000175000017500000000000012617614576020320 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/Pod/Coverage/Imager.pm0000644000175000017500000000167012263740601022050 0ustar gregoagregoapackage Pod::Coverage::Imager; use strict; use base 'Pod::Coverage'; sub _get_pods { my $self = shift; my $package = $self->{package}; #print "getting pod location for '$package'\n" if TRACE_ALL; $self->{pod_from} ||= pod_where( { -inc => 1 }, $package ); my $pod_from = $self->{pod_from}; $pod_from = [ $pod_from ] unless ref $pod_from; unless ($pod_from) { $self->{why_unrated} = "couldn't find pod"; return; } #print "parsing '$pod_from'\n" if TRACE_ALL; my $pod = Pod::Coverage::Extractor->new; for my $pod_file (@$pod_from) { $pod->parse_from_file( $pod_file, '/dev/null' ); } return $pod->{identifiers} || []; } sub _get_syms { my ($self, $package) = @_; if ($self->{module}) { eval "require $self->{module}"; return if $@; # fake out require (my $file = $package) =~ s(::)(/)g; $file .= ".pm"; $INC{$file} = 1; } return $self->SUPER::_get_syms($package); } 1; libimager-perl-1.004+dfsg.orig/t/950-kwalitee/0000755000175000017500000000000012617614576020163 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/950-kwalitee/010-pod.t0000644000175000017500000000073012263740601021412 0ustar gregoagregoa#!perl -w use strict; use Test::More; use ExtUtils::Manifest qw(maniread); $ENV{AUTOMATED_TESTING} || $ENV{IMAGER_AUTHOR_TESTING} or plan skip_all => "POD only tested under automated or author testing"; eval "use Test::Pod 1.00;"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; my $manifest = maniread(); my @pod = grep /\.(pm|pl|pod|PL)$/, keys %$manifest; plan tests => scalar(@pod); for my $file (@pod) { pod_file_ok($file, "pod ok in $file"); } libimager-perl-1.004+dfsg.orig/t/950-kwalitee/030-podcover.t0000644000175000017500000000605112263740601022455 0ustar gregoagregoa#!perl -w use strict; use lib 't'; use Test::More; use ExtUtils::Manifest qw(maniread); #sub Pod::Coverage::TRACE_ALL() { 1 } eval "use Test::Pod::Coverage 1.08;"; # 1.08 required for coverage_class support plan skip_all => "Test::Pod::Coverage 1.08 required for POD coverage" if $@; # scan for a list of files to get Imager method documentation from my $manifest = maniread(); my @pods = ( 'Imager.pm', grep /\.pod$/, keys %$manifest ); my @private = ( '^io?_', '^DSO_', '^Inline$', '^yatf$', '^malloc_state$', '^init_log$', '^polybezier$', # not ready for public consumption '^border$', # I don't know what it is, expect it to go away ); my @trustme = ( '^open$', ); plan tests => 20; { pod_coverage_ok('Imager', { also_private => \@private, pod_from => \@pods, trustme => \@trustme, coverage_class => 'Pod::Coverage::Imager' }); pod_coverage_ok('Imager::Font'); my @color_private = ( '^i_', '_internal$' ); pod_coverage_ok('Imager::Color', { also_private => \@color_private }); pod_coverage_ok('Imager::Color::Float', { also_private => \@color_private }); pod_coverage_ok('Imager::Color::Table'); pod_coverage_ok('Imager::ExtUtils'); pod_coverage_ok('Imager::Expr'); my $trust_parents = { coverage_class => 'Pod::Coverage::CountParents' }; pod_coverage_ok('Imager::Expr::Assem', $trust_parents); pod_coverage_ok('Imager::Fill'); pod_coverage_ok('Imager::Font::BBox'); pod_coverage_ok('Imager::Font::Wrap'); pod_coverage_ok('Imager::Fountain'); pod_coverage_ok('Imager::Matrix2d'); pod_coverage_ok('Imager::Regops'); pod_coverage_ok('Imager::Transform'); pod_coverage_ok('Imager::Test'); pod_coverage_ok('Imager::IO', { pod_from => "lib/Imager/IO.pod", coverage_class => "Pod::Coverage::Imager", module => "Imager", }); } { # check all documented methods/functions are in the method index my $coverage = Pod::Coverage::Imager->new(package => 'Imager', pod_from => \@pods, trustme => \@trustme, also_private => \@private); my %methods = map { $_ => 1 } $coverage->covered; open IMAGER, "< Imager.pm" or die "Cannot open Imager.pm: $!"; while () { last if /^=head1 METHOD INDEX/; } my @indexed; my @unknown_indexed; while () { last if /^=\w/ && !/^=for\b/; if (/^(\w+)\(/) { push @indexed, $1; unless (delete $methods{$1}) { push @unknown_indexed, $1; } } } unless (is(keys %methods, 0, "all methods in method index")) { diag "the following methods are documented but not in the index:"; diag $_ for sort keys %methods; } unless (is(@unknown_indexed, 0, "only methods in method index")) { diag "the following names are in the method index but not documented"; diag $_ for sort @unknown_indexed; } sub dict_cmp_func; is_deeply(\@indexed, [ sort dict_cmp_func @indexed ], "check method index is alphabetically sorted"); } sub dict_cmp_func { (my $tmp_a = lc $a) =~ tr/_//d; (my $tmp_b = lc $b) =~ tr/_//d; $tmp_a cmp $tmp_b; } libimager-perl-1.004+dfsg.orig/t/950-kwalitee/020-samples.t0000644000175000017500000000154312263740601022300 0ustar gregoagregoa#!perl -w # packaging test - make sure we included the samples in the MANIFEST use Test::More; use ExtUtils::Manifest qw(maniread); # first build a list of samples from samples/README open SAMPLES, "< samples/README" or die "Cannot open samples/README: $!"; my @sample_files; while () { chomp; /^\w[\w.-]+\.\w+$/ and push @sample_files, $_; } close SAMPLES; my $manifest = maniread(); my @mani_samples = sort grep m(^samples/\w+\.pl$), keys %$manifest; plan tests => scalar(@sample_files) + scalar(@mani_samples); for my $filename (@sample_files) { ok(exists($manifest->{"samples/$filename"}), "sample file $filename in manifest"); } my %files = map { $_ => 1 } @sample_files; for my $filename (@mani_samples) { $filename =~ s(^samples/)(); ok(exists $files{$filename}, "sample $filename in manifest found in README"); } libimager-perl-1.004+dfsg.orig/t/950-kwalitee/050-meta.t0000644000175000017500000000075512263740601021571 0ustar gregoagregoa#!perl -w use strict; use Test::More; plan skip_all => "Only run as part of the dist" unless -f "META.yml"; eval "use CPAN::Meta 2.110580;"; plan skip_all => "CPAN::Meta required for testing META.yml" if $@; plan skip_all => "Only if automated or author testing" unless $ENV{AUTOMATED_TESTING} || -d "../.git"; plan tests => 1; my $meta; unless (ok(eval { $meta = CPAN::Meta->load_file("META.yml", { lazy_validation => 0 }) }, "loaded META.yml successfully")) { diag($@); } libimager-perl-1.004+dfsg.orig/t/950-kwalitee/040-strict.t0000644000175000017500000000103212263740601022137 0ustar gregoagregoa#!perl -w # this is intended for various kwalitee tests use strict; use Test::More; use ExtUtils::Manifest qw(maniread); my $manifest = maniread; # work up counts first my @pl_files = grep /\.(p[lm]|PL|perl)$/, keys %$manifest; plan tests => scalar(@pl_files); for my $filename (@pl_files) { open PL, "< $filename" or die "Cannot open $filename: $!"; my $found_strict; while () { if (/^use strict;/) { ++$found_strict; last; } } close PL; ok($found_strict, "file $filename has use strict"); } libimager-perl-1.004+dfsg.orig/t/950-kwalitee/060-podstruct.t0000644000175000017500000000476512263740601022700 0ustar gregoagregoa#!perl -w use strict; use Test::More; $ENV{AUTOMATED_TESTING} || $ENV{IMAGER_AUTHOR_TESTING} or plan skip_all => "POD only tested under automated or author testing"; BEGIN { eval 'use Pod::Parser 1.50;'; plan skip_all => "Pod::Parser 1.50 required for podlinkcheck" if $@; } use File::Spec::Functions qw(rel2abs abs2rel splitdir); use ExtUtils::Manifest qw(maniread); # this test is intended to catch errors like in # https://rt.cpan.org/Ticket/Display.html?id=85413 my @pod; # files with pod my $base = rel2abs("."); my $manifest = maniread(); my @files = sort grep /\.(pod|pm)$/ && !/^inc/, keys %$manifest; my %item_in; for my $file (@files) { my $parser = PodPreparse->new; $parser->parse_from_file($file); if ($parser->{is_pod}) { push @pod, $file; } } plan tests => 3 * scalar(@pod); my @req_head1s = qw(NAME DESCRIPTION AUTHOR); for my $file (@pod) { my $parser = PodStructCheck->new; my $relfile = abs2rel($file, $base); $parser->{bad_quotes} = []; $parser->{dup_words} = []; $parser->parse_from_file($file); my @missing; for my $head (@req_head1s) { push @missing, $head unless $parser->{head1s}{$head}; } unless (ok(!@missing, "$relfile: check missing headers")) { diag "$relfile: missing head1s @missing\n"; } unless (ok(!@{$parser->{bad_quotes}}, "$relfile: check for bad quotes")) { diag "$relfile:$_->[1]: bad quote in: $_->[0]" for @{$parser->{bad_quotes}}; } unless (ok(!@{$parser->{dup_words}}, "$relfile: check for duplicate words")) { diag "$relfile:$_->[1]: dup word '$_->[0]' in: $_->[2]" for @{$parser->{dup_words}}; } } package PodPreparse; BEGIN { our @ISA = qw(Pod::Parser); } sub command { my ($self, $cmd, $para) = @_; $self->{is_pod} = 1; } sub verbatim {} sub textblock {} package PodStructCheck; BEGIN { our @ISA = qw(Pod::Parser); } sub command { my ($self, $command, $paragraph, $line_num) = @_; if ($command eq "head1") { $paragraph =~ s/\s+\z//; $self->{head1s}{$paragraph} = 1; if ($paragraph =~ /\A[^']*'\z/ || $paragraph =~ /\A[^"]*"\z/ || $paragraph =~ /\A'[^']*\z/ || $paragraph =~ /\A"[^"]*\z/) { push @{$self->{bad_quotes}}, [ $paragraph, $line_num ]; } } } sub verbatim {} sub textblock { my ($self, $text, $line_num) = @_; if (my ($sample, $word) = $text =~ /(.{0,10}\b(\w+)\s+\2\b.{0,10})/s) { # avoid catching "C C" if ($word ne "C") { push @{$self->{dup_words}}, [ $word, $line_num, $sample ]; } } } sub sequence { } libimager-perl-1.004+dfsg.orig/t/250-draw/0000755000175000017500000000000012617614576017304 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/250-draw/030-paste.t0000644000175000017500000003014712263740601021074 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 60; use Imager; use Imager::Test qw(is_image); #$Imager::DEBUG=1; -d "testout" or mkdir "testout"; Imager::init('log'=>'testout/t66paste.log'); # the original smoke tests my $img=Imager->new() || die "unable to create image object\n"; ok($img->open(file=>'testimg/scale.ppm',type=>'pnm'), "load test img"); my $nimg=Imager->new() or die "Unable to create image object\n"; ok($nimg->open(file=>'testimg/scale.ppm',type=>'pnm'), "load test img again"); ok($img->paste(img=>$nimg, top=>30, left=>30), "paste it") or print "# ", $img->errstr, "\n";; ok($img->write(type=>'pnm',file=>'testout/t66.ppm'), "save it") or print "# ", $img->errstr, "\n"; { my $empty = Imager->new; ok(!$empty->paste(src => $nimg), "paste into empty image"); is($empty->errstr, "paste: empty input image", "check error message"); ok(!$img->paste(src => $empty), "paste from empty image"); is($img->errstr, "paste: empty input image (for src)", "check error message"); ok(!$img->paste(), "no source image"); is($img->errstr, "no source image"); } # more stringent tests { my $src = Imager->new(xsize => 100, ysize => 110); $src->box(filled=>1, color=>'FF0000'); $src->box(filled=>1, color=>'0000FF', xmin => 20, ymin=>20, xmax=>79, ymax=>79); my $targ = Imager->new(xsize => 100, ysize => 110); $targ->box(filled=>1, color =>'00FFFF'); $targ->box(filled=>1, color=>'00FF00', xmin=>20, ymin=>20, xmax=>79, ymax=>79); my $work = $targ->copy; ok($work->paste(src=>$src, left => 15, top => 10), "paste whole image"); # build comparison image my $cmp = $targ->copy; $cmp->box(filled=>1, xmin=>15, ymin => 10, color=>'FF0000'); $cmp->box(filled=>1, xmin=>35, ymin => 30, xmax=>94, ymax=>89, color=>'0000FF'); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "compare pasted and expected"); $work = $targ->copy; ok($work->paste(src=>$src, left=>2, top=>7, src_minx => 10, src_miny => 15), "paste from inside src"); $cmp = $targ->copy; $cmp->box(filled=>1, xmin=>2, ymin=>7, xmax=>91, ymax=>101, color=>'FF0000'); $cmp->box(filled=>1, xmin=>12, ymin=>12, xmax=>71, ymax=>71, color=>'0000FF'); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "compare pasted and expected"); # paste part source $work = $targ->copy; ok($work->paste(src=>$src, left=>15, top=>20, src_minx=>10, src_miny=>15, src_maxx=>80, src_maxy =>70), "paste src cropped all sides"); $cmp = $targ->copy; $cmp->box(filled=>1, xmin=>15, ymin=>20, xmax=>84, ymax=>74, color=>'FF0000'); $cmp->box(filled=>1, xmin=>25, ymin=>25, xmax=>84, ymax=>74, color=>'0000FF'); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "compare pasted and expected"); # go by width instead $work = $targ->copy; ok($work->paste(src=>$src, left=>15, top=>20, src_minx=>10, src_miny => 15, width => 70, height => 55), "same but specify width/height instead"); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "compare pasted and expected"); # use src_coords $work = $targ->copy; ok($work->paste(src=>$src, left => 15, top => 20, src_coords => [ 10, 15, 80, 70 ]), "using src_coords"); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "compare pasted and expected"); { # Issue #18712 # supplying just src_maxx would set the internal maxy to undef # supplying just src_maxy would be ignored # src_maxy (or it's derived value) was being bounds checked against # the image width instead of the image height $work = $targ->copy; my @warns; local $SIG{__WARN__} = sub { push @warns, "@_"; print "# @_"; }; ok($work->paste(src=>$src, left => 15, top => 20, src_maxx => 50), "paste with just src_maxx"); ok(!@warns, "shouldn't warn"); my $cmp = $targ->copy; $cmp->box(filled=>1, color => 'FF0000', xmin => 15, ymin => 20, xmax => 64, ymax => 109); $cmp->box(filled=>1, color => '0000FF', xmin => 35, ymin => 40, xmax => 64, ymax => 99); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "check correctly pasted"); $work = $targ->copy; @warns = (); ok($work->paste(src=>$src, left=>15, top=>20, src_maxy => 60), "paste with just src_maxy"); ok(!@warns, "shouldn't warn"); $cmp = $targ->copy; $cmp->box(filled => 1, color => 'FF0000', xmin => 15, ymin => 20, xmax => 99, ymax => 79); $cmp->box(filled => 1, color => '0000FF', xmin => 35, ymin => 40, xmax => 94, ymax => 79); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "check pasted correctly"); $work = $targ->copy; @warns = (); ok($work->paste(src=>$src, left=>15, top=>20, src_miny => 20, src_maxy => 105), "paste with src_maxy > source width"); $cmp = $targ->copy; $cmp->box(filled => 1, color => 'FF0000', xmin => 15, ymin => 20, ymax => 104); $cmp->box(filled => 1, color => '0000FF', xmin => 35, ymin => 20, xmax => 94, ymax => 79); is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, "check pasted correctly"); } } { # https://rt.cpan.org/Ticket/Display.html?id=30908 # we now adapt the source channels to the target # check each combination works as expected # various source images my $src1 = Imager->new(xsize => 50, ysize => 50, channels => 1); my $g_grey_full = Imager::Color->new(128, 255, 0, 0); my $g_white_50 = Imager::Color->new(255, 128, 0, 0); $src1->box(filled => 1, xmax => 24, color => $g_grey_full); my $src2 = Imager->new(xsize => 50, ysize => 50, channels => 2); $src2->box(filled => 1, xmax => 24, color => $g_grey_full); $src2->box(filled => 1, xmin => 25, color => $g_white_50); my $c_red_full = Imager::Color->new(255, 0, 0); my $c_blue_full = Imager::Color->new(0, 0, 255); my $src3 = Imager->new(xsize => 50, ysize => 50, channels => 3); $src3->box(filled => 1, xmax => 24, color => $c_red_full); $src3->box(filled => 1, xmin => 25, color => $c_blue_full); my $c_green_50 = Imager::Color->new(0, 255, 0, 127); my $src4 = Imager->new(xsize => 50, ysize => 50, channels => 4); $src4->box(filled => 1, xmax => 24, color => $c_blue_full); $src4->box(filled => 1, xmin => 25, color => $c_green_50); my @left_box = ( box => [ 25, 25, 49, 74 ] ); my @right_box = ( box => [ 50, 25, 74, 74 ] ); { # 1 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 1); $base->box(filled => 1, color => Imager::Color->new(64, 255, 0, 0)); my $work = $base->copy; ok($work->paste(left => 25, top => 25, src => $src1), "paste 1 to 1"); my $comp = $base->copy; $comp->box(filled => 1, color => $g_grey_full, @left_box); $comp->box(filled => 1, color => [ 0, 0, 0, 0 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(left => 25, top => 25, src => $src2), "paste 2 to 1"); $comp = $base->copy; $comp->box(filled => 1, @left_box, color => $g_grey_full); $comp->box(filled => 1, @right_box, color => [ 128, 0, 0, 0 ]); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(left => 25, top => 25, src => $src3), "paste 3 to 1"); $comp = $base->copy; $comp->box(filled => 1, @left_box, color => [ 57, 255, 0, 0 ]); $comp->box(filled => 1, @right_box, color => [ 18, 255, 0, 0 ]); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(left => 25, top => 25, src => $src4), "paste 4 to 1"); $comp = $base->copy; $comp->box(filled => 1, color => [ 18, 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 90, 255, 0, 0 ], @right_box); is_image($work, $comp, "compare paste target to expected"); } { # 2 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 2); $base->box(filled => 1, color => [ 128, 128, 0, 0 ]); my $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src1), "paste 1 to 2"); my $comp = $base->copy; $comp->box(filled => 1, color => $g_grey_full, @left_box); $comp->box(filled => 1, color => [ 0, 255, 0, 0 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src2), "paste 2 to 2"); $comp = $base->copy; $comp->box(filled => 1, color => $g_grey_full, @left_box); $comp->box(filled => 1, color => $g_white_50, @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src3), "paste 3 to 2"); $comp = $base->copy; $comp->box(filled => 1, color => [ 57, 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 18, 255, 0, 0 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src4), "paste 4 to 2"); $comp = $base->copy; $comp->box(filled => 1, color => [ 18, 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 180, 127, 0, 0 ], @right_box); is_image($work, $comp, "compare paste target to expected"); } { # 3 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 3); $base->box(filled => 1, color => [ 128, 255, 0, 0 ]); my $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src1), "paste 1 to 3"); my $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 0, 0 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src2), "paste 2 to 3"); $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src3), "paste 3 to 3"); $comp = $base->copy; $comp->box(filled => 1, color => [ 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 255 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src4), "paste 4 to 3"); $comp = $base->copy; $comp->box(filled => 1, color => [ 0, 0, 255 ], @left_box); $comp->box(filled => 1, color => [ 0, 127, 0 ], @right_box); is_image($work, $comp, "compare paste target to expected"); } { # 4 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 4); $base->box(filled => 1, color => [ 128, 255, 64, 128 ]); my $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src1), "paste 1 to 4"); my $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 0, 255 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src2), "paste 2 to 4"); $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 255, 255, 255, 128 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src3), "paste 3 to 4"); $comp = $base->copy; $comp->box(filled => 1, color => [ 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 255 ], @right_box); is_image($work, $comp, "compare paste target to expected"); $work = $base->copy; ok($work->paste(top => 25, left => 25, src => $src4), "paste 4 to 4"); $comp = $base->copy; $comp->box(filled => 1, color => $c_blue_full, @left_box); $comp->box(filled => 1, color => $c_green_50, @right_box); is_image($work, $comp, "compare paste target to expected"); } } libimager-perl-1.004+dfsg.orig/t/250-draw/050-polyaa.t0000644000175000017500000002251412461136230021243 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 24; use Imager qw/NC/; use Imager::Test qw(is_image is_color3); sub PI () { 3.14159265358979323846 } -d "testout" or mkdir "testout"; my @out_files; END { unless ($ENV{IMAGER_KEEP_FILES}) { unlink @out_files; rmdir "testout"; } } Imager->open_log(log => "testout/250-polyaa.log"); push @out_files, "testout/250-polyaa.log"; my $red = Imager::Color->new(255,0,0); my $green = Imager::Color->new(0,255,0); my $blue = Imager::Color->new(0,0,255); my $white = Imager::Color->new(255,255,255); my $black = Imager::Color->new(0, 0, 0); { # artifacts with multiple vertical lobes # https://rt.cpan.org/Ticket/Display.html?id=43518 # previously this would have a full coverage pixel at (0,0) caused # by the (20,0.5) point in the right lobe my @pts = ( [ 0.5, -9 ], [ 10, -9 ], [ 10, 11 ], [ 15, 11 ], [ 15, -9 ], [ 17, -9 ], [ 20, 0.5 ], [ 17, 11 ], [ 0.5, 11 ], ); my $im = Imager->new(xsize => 10, ysize => 2); ok($im->polygon(points => \@pts, color => $white), "draw with inside point"); ok($im->write(file => "testout/250-poly-inside.ppm"), "save to file"); push @out_files, "testout/250-poly-inside.ppm"; # both scanlines should be the same my $line0 = $im->crop(top => 0, height => 1); my $line1 = $im->crop(top => 1, height => 1); is_image($line0, $line1, "both scanlines should be the same"); } { # check vertical edges are consistent my $im = Imager->new(xsize => 10, ysize => 10); ok($im->polygon(points => [ [ 0.5, 0 ], [ 9.25, 0 ], [ 9.25, 10 ], [ 0.5, 10 ] ], color => $white, aa => 1), "draw polygon with mid pixel vertical edges") or diag $im->errstr; my @line0 = $im->getscanline(y => 0); my $im2 = Imager->new(xsize => 10, ysize => 10); for my $y (0..9) { $im2->setscanline(y => $y, pixels => \@line0); } is_image($im, $im2, "all scan lines should be the same"); is_color3($line0[0], 128, 128, 128, "(0,0) should be 50% coverage"); is_color3($line0[9], 64, 64, 64, "(9,0) should be 25% coverage"); } { # check horizontal edges are consistent my $im = Imager->new(xsize => 10, ysize => 10); ok($im->polygon(points => [ [ 0, 0.5 ], [ 0, 9.25 ], [ 10, 9.25 ], [ 10, 0.5 ] ], color => $white, aa => 1), "draw polygon with mid-pixel horizontal edges"); is_deeply([ $im->getsamples(y => 0, channels => [ 0 ]) ], [ (128) x 10 ], "all of line 0 should be 50% coverage"); is_deeply([ $im->getsamples(y => 9, channels => [ 0 ]) ], [ (64) x 10 ], "all of line 9 should be 25% coverage"); } { my $img = Imager->new(xsize=>20, ysize=>10); my @data = translate(5.5,5, rotate(0, scale(5, 5, get_polygon(n_gon => 5) ) ) ); my ($x, $y) = array_to_refpair(@data); ok(Imager::i_poly_aa_m($img->{IMG}, $x, $y, 0, $white), "primitive poly"); ok($img->write(file=>"testout/250-poly.ppm"), "write to file") or diag $img->errstr; push @out_files, "testout/250-poly.ppm"; my $zoom = make_zoom($img, 8, \@data, $red); ok($zoom, "make zoom of primitive"); $zoom->write(file=>"testout/250-poly-zoom.ppm") or die $zoom->errstr; push @out_files, "testout/250-poly-zoom.ppm"; } { my $img = Imager->new(xsize=>300, ysize=>100); my $good = 1; for my $n (0..55) { my @data = translate(20+20*($n%14),18+20*int($n/14), rotate(15*$n/PI, scale(15, 15, get_polygon('box') ) ) ); my ($x, $y) = array_to_refpair(@data); Imager::i_poly_aa_m($img->{IMG}, $x, $y, 0, NC(rand(255), rand(255), rand(255))) or $good = 0; } $img->write(file=>"testout/250-poly-big.ppm") or die $img->errstr; ok($good, "primitive squares"); push @out_files, "testout/250-poly-big.ppm"; } { my $img = Imager->new(xsize => 300, ysize => 300); ok($img -> polygon(color=>$white, points => [ translate(150,150, rotate(45*PI/180, scale(70,70, get_polygon('wavycircle', 32*8, sub { 1.2+1*cos(4*$_) })))) ], ), "method call") or diag $img->errstr(); $img->write(file=>"testout/250-poly-wave.ppm") or die $img->errstr; push @out_files, "testout/250-poly-wave.ppm"; } { my $img = Imager->new(xsize=>10,ysize=>6); my @data = translate(165,5, scale(80,80, get_polygon('wavycircle', 32*8, sub { 1+1*cos(4*$_) }))); ok($img -> polygon(color=>$white, points => [ translate(165,5, scale(80,80, get_polygon('wavycircle', 32*8, sub { 1+1*cos(4*$_) }))) ], ), "bug check") or diag $img->errstr(); make_zoom($img,20,\@data, $blue)->write(file=>"testout/250-poly-wavebug.ppm") or die $img->errstr; push @out_files, "testout/250-poly-wavebug.ppm"; } { my $img = Imager->new(xsize=>300, ysize=>300); ok($img->polygon(fill=>{ hatch=>'cross1', fg=>'00FF00', bg=>'0000FF', dx=>3 }, points => [ translate(150,150, scale(70,70, get_polygon('wavycircle', 32*8, sub { 1+1*cos(4*$_) }))) ], ), "poly filled with hatch") or diag $img->errstr(); $img->write(file=>"testout/250-poly-wave_fill.ppm") or die $img->errstr; push @out_files, "testout/250-poly-wave_fill.ppm"; } { my $img = Imager->new(xsize=>300, ysize=>300, bits=>16); ok($img->polygon(fill=>{ hatch=>'cross1', fg=>'00FF00', bg=>'0000FF' }, points => [ translate(150,150, scale(70,70, get_polygon('wavycircle', 32*8, sub { 1+1*cos(5*$_) }))) ], ), "hatched to 16-bit image") or diag $img->errstr(); $img->write(file=>"testout/250-poly-wave_fill16.ppm") or die $img->errstr; push @out_files, "testout/250-poly-wave_fill16.ppm"; } { my $img = Imager->new(xsize => 100, ysize => 100); my $poly = [ [ [ 10, 90, 90, 10 ], [ 10, 10, 90, 90 ], ], [ [ 20, 45, 45, 20 ], [ 20, 20, 80, 80 ], ], [ [ 55, 55, 80, 80 ], [ 20, 80, 80, 20 ], ], ]; ok($img->polypolygon ( points => $poly, filled => 1, color => $white, ), "default polypolygon"); push @out_files, "testout/250-poly-ppeo.ppm"; ok($img->write(file => "testout/250-poly-ppeo.ppm"), "save to file"); my $cmp_eo = Imager->new(xsize => 100, ysize => 100); $cmp_eo->box(filled => 1, color => $white, box => [ 10, 10, 89, 89 ]); $cmp_eo->box(filled => 1, color => $black, box => [ 20, 20, 44, 79 ]); $cmp_eo->box(filled => 1, color => $black, box => [ 55, 20, 79, 79 ]); is_image($img, $cmp_eo, "check even/odd matches"); $img = Imager->new(xsize => 100, ysize => 100); ok($img->polypolygon ( points => $poly, filled => 1, color => $white, mode => "nonzero", ), "default polypolygon"); my $cmp_nz = Imager->new(xsize => 100, ysize => 100); $cmp_nz->box(filled => 1, color => $white, box => [ 10, 10, 89, 89 ]); $cmp_nz->box(filled => 1, color => $black, box => [ 55, 20, 79, 79 ]); is_image($img, $cmp_nz, "check non-zero matches"); push @out_files, "testout/250-poly-ppnz.ppm"; ok($img->write(file => "testout/250-poly-ppnz.ppm"), "save to file"); } Imager->close_log; Imager::malloc_state(); #initialized in a BEGIN, later my %primitives; my %polygens; sub get_polygon { my $name = shift; if (exists $primitives{$name}) { return @{$primitives{$name}}; } if (exists $polygens{$name}) { return $polygens{$name}->(@_); } die "polygon spec: $name unknown\n"; } sub make_zoom { my ($img, $sc, $polydata, $linecolor) = @_; # scale with nearest neighboor sampling my $timg = $img->scale(scalefactor=>$sc, qtype=>'preview'); # draw the grid for(my $lx=0; $lx<$timg->getwidth(); $lx+=$sc) { $timg->line(color=>$green, x1=>$lx, x2=>$lx, y1=>0, y2=>$timg->getheight(), antialias=>0); } for(my $ly=0; $ly<$timg->getheight(); $ly+=$sc) { $timg->line(color=>$green, y1=>$ly, y2=>$ly, x1=>0, x2=>$timg->getwidth(), antialias=>0); } my @data = scale($sc, $sc, @$polydata); push(@data, $data[0]); my ($x, $y) = array_to_refpair(@data); $timg->polyline(color=>$linecolor, 'x'=>$x, 'y'=>$y, antialias=>0); return $timg; } # utility functions to manipulate point data sub scale { my ($x, $y, @data) = @_; return map { [ $_->[0]*$x , $_->[1]*$y ] } @data; } sub translate { my ($x, $y, @data) = @_; map { [ $_->[0]+$x , $_->[1]+$y ] } @data; } sub rotate { my ($rad, @data) = @_; map { [ $_->[0]*cos($rad)+$_->[1]*sin($rad) , $_->[1]*cos($rad)-$_->[0]*sin($rad) ] } @data; } sub array_to_refpair { my (@x, @y); for (@_) { push(@x, $_->[0]); push(@y, $_->[1]); } return \@x, \@y; } BEGIN { %primitives = ( box => [ [-0.5,-0.5], [0.5,-0.5], [0.5,0.5], [-0.5,0.5] ], triangle => [ [0,0], [1,0], [1,1] ], ); %polygens = ( wavycircle => sub { my $numv = shift; my $radfunc = shift; my @radians = map { $_*2*PI/$numv } 0..$numv-1; my @radius = map { $radfunc->($_) } @radians; map { [ $radius[$_] * cos($radians[$_]), $radius[$_] * sin($radians[$_]) ] } 0..$#radians; }, n_gon => sub { my $N = shift; map { [ cos($_*2*PI/$N), sin($_*2*PI/$N) ] } 0..$N-1; }, ); } libimager-perl-1.004+dfsg.orig/t/250-draw/060-polypoly.t0000644000175000017500000000551712461136230021652 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 12; use Imager qw/NC/; use Imager::Test qw(is_image is_color3); sub PI () { 3.14159265358979323846 } -d "testout" or mkdir "testout"; my @cleanup; push @cleanup, "testout/060-polypoly.log"; Imager->open_log(log => "testout/060-polypoly.log"); my $red = NC(255,0,0); my $green = NC(0,255,0); my $blue = NC(0,0,255); my $white = NC(255,255,255); my $black = NC(0, 0, 0); END { unlink @cleanup unless $ENV{IMAGER_KEEP_FILES}; rmdir "testout"; } { my $out = "testout/060-ppsimple.ppm"; my $im = Imager->new(xsize => 100, ysize => 100); ok($im->polypolygon ( filled => 1, color => $red, points => [ [ [ 20, 20, 40, 40 ], [ 20, 80, 80, 20 ], ], [ [ 60, 60, 80, 80 ], [ 20, 80, 80, 20 ], ], ] ), "simple filled polypolygon"); ok($im->write(file => $out), "save to $out"); my $cmp = Imager->new(xsize => 100, ysize => 100); $cmp->box(filled => 1, color => $red, box => [ 20, 20, 39, 79 ]); $cmp->box(filled => 1, color => $red, box => [ 60, 20, 79, 79 ]); is_image($im, $cmp, "check expected output"); push @cleanup, $out; } { my $im = Imager->new(xsize => 100, ysize => 100); my $cross_cw = [ [ [ 10, 90, 90, 10 ], [ 40, 40, 60, 60 ], ], [ [ 40, 60, 60, 40 ], [ 10, 10, 90, 90 ], ], ]; ok($im->polypolygon ( filled => 1, color => $red, points =>$cross_cw, mode => "nonzero", ), "cross polypolygon nz"); save($im, "060-ppcrossnz.ppm"); my $cmp = Imager->new(xsize => 100, ysize => 100); $cmp->box(filled => 1, color => $red, box => [ 10, 40, 89, 59 ]); $cmp->box(filled => 1, color => $red, box => [ 40, 10, 59, 89 ]); is_image($im, $cmp, "check expected output"); my $im2 = Imager->new(xsize => 100, ysize => 100); ok($im2->polypolygon ( filled => 1, color => $red, points =>$cross_cw, #mode => "nonzero", # default to evenodd ), "cross polypolygon eo"); save($im2, "060-ppcrosseo.ppm"); $cmp->box(filled => 1, color => $black, box => [ 40, 40, 59, 59 ]); is_image($im2, $cmp, "check expected output"); # same as cross_cw except that the second box is in reversed order my $cross_diff = [ [ [ 10, 90, 90, 10 ], [ 40, 40, 60, 60 ], ], [ [ 40, 60, 60, 40 ], [ 90, 90, 10, 10 ], ], ]; my $im3 = Imager->new(xsize => 100, ysize => 100); ok($im3->polypolygon ( filled => 1, color => $red, points => $cross_diff, mode => "nonzero", ), "cross polypolygon diff"); is_image($im3, $cmp, "check expected output"); save($im3, "060-ppcrossdiff.ppm"); } Imager->close_log; sub save { my ($im, $file) = @_; $file = "testout/" . $file; push @cleanup, $file; ok($im->write(file => $file), "save to $file"); } libimager-perl-1.004+dfsg.orig/t/250-draw/100-fill.t0000644000175000017500000006021312263740601020701 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 165; use Imager ':handy'; use Imager::Fill; use Imager::Color::Float; use Imager::Test qw(is_image is_color4 is_fcolor4 is_color3); use Config; -d "testout" or mkdir "testout"; Imager::init_log("testout/t20fill.log", 1); my $blue = NC(0,0,255); my $red = NC(255, 0, 0); my $redf = Imager::Color::Float->new(1, 0, 0); my $bluef = Imager::Color::Float->new(0, 0, 1); my $rsolid = Imager::i_new_fill_solid($blue, 0); ok($rsolid, "building solid fill"); my $raw1 = Imager::ImgRaw::new(100, 100, 3); # use the normal filled box Imager::i_box_filled($raw1, 0, 0, 99, 99, $blue); my $raw2 = Imager::ImgRaw::new(100, 100, 3); Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rsolid); ok(1, "drawing with solid fill"); my $diff = Imager::i_img_diff($raw1, $raw2); ok($diff == 0, "solid fill doesn't match"); Imager::i_box_filled($raw1, 0, 0, 99, 99, $red); my $rsolid2 = Imager::i_new_fill_solidf($redf, 0); ok($rsolid2, "creating float solid fill"); Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rsolid2); $diff = Imager::i_img_diff($raw1, $raw2); ok($diff == 0, "float solid fill doesn't match"); # ok solid still works, let's try a hatch # hash1 is a 2x2 checkerboard my $rhatcha = Imager::i_new_fill_hatch($red, $blue, 0, 1, undef, 0, 0); my $rhatchb = Imager::i_new_fill_hatch($blue, $red, 0, 1, undef, 2, 0); ok($rhatcha && $rhatchb, "can't build hatched fill"); # the offset should make these match Imager::i_box_cfill($raw1, 0, 0, 99, 99, $rhatcha); Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb); ok(1, "filling with hatch"); $diff = Imager::i_img_diff($raw1, $raw2); ok($diff == 0, "hatch images different"); $rhatchb = Imager::i_new_fill_hatch($blue, $red, 0, 1, undef, 4, 6); Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb); $diff = Imager::i_img_diff($raw1, $raw2); ok($diff == 0, "hatch images different"); # I guess I was tired when I originally did this - make sure it keeps # acting the way it's meant to # I had originally expected these to match with the red and blue swapped $rhatchb = Imager::i_new_fill_hatch($red, $blue, 0, 1, undef, 2, 2); Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb); $diff = Imager::i_img_diff($raw1, $raw2); ok($diff == 0, "hatch images different"); # this shouldn't match $rhatchb = Imager::i_new_fill_hatch($red, $blue, 0, 1, undef, 1, 1); Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb); $diff = Imager::i_img_diff($raw1, $raw2); ok($diff, "hatch images the same!"); # custom hatch # the inverse of the 2x2 checkerboard my $hatch = pack("C8", 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC); my $rcustom = Imager::i_new_fill_hatch($blue, $red, 0, 0, $hatch, 0, 0); Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rcustom); $diff = Imager::i_img_diff($raw1, $raw2); ok(!$diff, "custom hatch mismatch"); { # basic test of floating color hatch fills # this will exercise the code that the gcc shipped with OS X 10.4 # forgets to generate # the float version is called iff we're working with a non-8-bit image # i_new_fill_hatchf() makes the same object as i_new_fill_hatch() but # we test the other construction code path here my $fraw1 = Imager::i_img_double_new(100, 100, 3); my $fhatch1 = Imager::i_new_fill_hatchf($redf, $bluef, 0, 1, undef, 0, 0); ok($fraw1, "making double image 1"); ok($fhatch1, "making float hatch 1"); Imager::i_box_cfill($fraw1, 0, 0, 99, 99, $fhatch1); my $fraw2 = Imager::i_img_double_new(100, 100, 3); my $fhatch2 = Imager::i_new_fill_hatchf($bluef, $redf, 0, 1, undef, 0, 2); ok($fraw2, "making double image 2"); ok($fhatch2, "making float hatch 2"); Imager::i_box_cfill($fraw2, 0, 0, 99, 99, $fhatch2); $diff = Imager::i_img_diff($fraw1, $fraw2); ok(!$diff, "float custom hatch mismatch"); save($fraw1, "testout/t20hatchf1.ppm"); save($fraw2, "testout/t20hatchf2.ppm"); } # test the oo interface my $im1 = Imager->new(xsize=>100, ysize=>100); my $im2 = Imager->new(xsize=>100, ysize=>100); my $solid = Imager::Fill->new(solid=>'#FF0000'); ok($solid, "creating oo solid fill"); ok($solid->{fill}, "bad oo solid fill"); $im1->box(fill=>$solid); $im2->box(filled=>1, color=>$red); $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG}); ok(!$diff, "oo solid fill"); my $hatcha = Imager::Fill->new(hatch=>'check2x2'); my $hatchb = Imager::Fill->new(hatch=>'check2x2', dx=>2); $im1->box(fill=>$hatcha); $im2->box(fill=>$hatchb); # should be different $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG}); ok($diff, "offset checks the same!"); $hatchb = Imager::Fill->new(hatch=>'check2x2', dx=>2, dy=>2); $im2->box(fill=>$hatchb); $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG}); ok(!$diff, "offset into similar check should be the same"); # test dymanic build of fill $im2->box(fill=>{hatch=>'check2x2', dx=>2, fg=>NC(255,255,255), bg=>NC(0,0,0)}); $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG}); ok(!$diff, "offset and flipped should be the same"); # a simple demo my $im = Imager->new(xsize=>200, ysize=>200); $im->box(xmin=>10, ymin=>10, xmax=>190, ymax=>190, fill=>{ hatch=>'check4x4', fg=>NC(128, 0, 0), bg=>NC(128, 64, 0) }) or print "# ",$im->errstr,"\n"; $im->arc(r=>80, d1=>45, d2=>75, fill=>{ hatch=>'stipple2', combine=>1, fg=>[ 0, 0, 0, 255 ], bg=>{ rgba=>[255,255,255,160] } }) or print "# ",$im->errstr,"\n"; $im->arc(r=>80, d1=>75, d2=>135, fill=>{ fountain=>'radial', xa=>100, ya=>100, xb=>20, yb=>100 }) or print "# ",$im->errstr,"\n"; $im->write(file=>'testout/t20_sample.ppm'); # flood fill tests my $rffimg = Imager::ImgRaw::new(100, 100, 3); # build a H Imager::i_box_filled($rffimg, 10, 10, 20, 90, $blue); Imager::i_box_filled($rffimg, 80, 10, 90, 90, $blue); Imager::i_box_filled($rffimg, 20, 45, 80, 55, $blue); my $black = Imager::Color->new(0, 0, 0); Imager::i_flood_fill($rffimg, 15, 15, $red); my $rffcmp = Imager::ImgRaw::new(100, 100, 3); # build a H Imager::i_box_filled($rffcmp, 10, 10, 20, 90, $red); Imager::i_box_filled($rffcmp, 80, 10, 90, 90, $red); Imager::i_box_filled($rffcmp, 20, 45, 80, 55, $red); $diff = Imager::i_img_diff($rffimg, $rffcmp); ok(!$diff, "flood fill difference"); my $ffim = Imager->new(xsize=>100, ysize=>100); my $yellow = Imager::Color->new(255, 255, 0); $ffim->box(xmin=>10, ymin=>10, xmax=>20, ymax=>90, color=>$blue, filled=>1); $ffim->box(xmin=>20, ymin=>45, xmax=>80, ymax=>55, color=>$blue, filled=>1); $ffim->box(xmin=>80, ymin=>10, xmax=>90, ymax=>90, color=>$blue, filled=>1); ok($ffim->flood_fill('x'=>50, 'y'=>50, color=>$red), "flood fill"); $diff = Imager::i_img_diff($rffcmp, $ffim->{IMG}); ok(!$diff, "oo flood fill difference"); $ffim->flood_fill('x'=>50, 'y'=>50, fill=> { hatch => 'check2x2', fg => '0000FF', }); # fill=>{ # fountain=>'radial', # xa=>50, ya=>50, # xb=>10, yb=>10, # }); $ffim->write(file=>'testout/t20_ooflood.ppm'); my $copy = $ffim->copy; ok($ffim->flood_fill('x' => 50, 'y' => 50, color => $red, border => '000000'), "border solid flood fill"); is(Imager::i_img_diff($ffim->{IMG}, $rffcmp), 0, "compare"); ok($ffim->flood_fill('x' => 50, 'y' => 50, fill => { hatch => 'check2x2', fg => '0000FF', }, border => '000000'), "border cfill fill"); is(Imager::i_img_diff($ffim->{IMG}, $copy->{IMG}), 0, "compare"); # test combining modes my $fill = NC(192, 128, 128, 128); my $target = NC(64, 32, 64); my $trans_target = NC(64, 32, 64, 128); my %comb_tests = ( none=> { opaque => $fill, trans => $fill, }, normal=> { opaque => NC(128, 80, 96), trans => NC(150, 96, 107, 191), }, multiply => { opaque => NC(56, 24, 48), trans => NC(101, 58, 74, 192), }, dissolve => { opaque => [ $target, NC(192, 128, 128, 255) ], trans => [ $trans_target, NC(192, 128, 128, 255) ], }, add => { opaque => NC(159, 96, 128), trans => NC(128, 80, 96, 255), }, subtract => { opaque => NC(0, 0, 0), trans => NC(0, 0, 0, 255), }, diff => { opaque => NC(96, 64, 64), trans => NC(127, 85, 85, 192), }, lighten => { opaque => NC(128, 80, 96), trans => NC(149, 95, 106, 192), }, darken => { opaque => $target, trans => NC(106, 63, 85, 192), }, # the following results are based on the results of the tests and # are suspect for that reason (and were broken at one point ) # but trying to work them out manually just makes my head hurt - TC hue => { opaque => NC(64, 32, 47), trans => NC(64, 32, 42, 128), }, saturation => { opaque => NC(63, 37, 64), trans => NC(64, 39, 64, 128), }, value => { opaque => NC(127, 64, 128), trans => NC(149, 75, 150, 128), }, color => { opaque => NC(64, 37, 52), trans => NC(64, 39, 50, 128), }, ); for my $comb (Imager::Fill->combines) { my $test = $comb_tests{$comb}; my $fillobj = Imager::Fill->new(solid=>$fill, combine=>$comb); for my $bits (qw(8 double)) { { my $targim = Imager->new(xsize=>4, ysize=>4, bits => $bits); $targim->box(filled=>1, color=>$target); $targim->box(fill=>$fillobj); my $c = Imager::i_get_pixel($targim->{IMG}, 1, 1); my $allowed = $test->{opaque}; $allowed =~ /ARRAY/ or $allowed = [ $allowed ]; ok(scalar grep(color_close($_, $c), @$allowed), "opaque '$comb' $bits bits") or print "# got:",join(",", $c->rgba)," allowed: ", join("|", map { join(",", $_->rgba) } @$allowed),"\n"; } { # make sure the alpha path in the combine function produces the same # or at least as sane a result as the non-alpha path my $targim = Imager->new(xsize=>4, ysize=>4, channels => 4, bits => $bits); $targim->box(filled=>1, color=>$target); $targim->box(fill=>$fillobj); my $c = Imager::i_get_pixel($targim->{IMG}, 1, 1); my $allowed = $test->{opaque}; $allowed =~ /ARRAY/ or $allowed = [ $allowed ]; ok(scalar grep(color_close4($_, $c), @$allowed), "opaque '$comb' 4-channel $bits bits") or print "# got:",join(",", $c->rgba)," allowed: ", join("|", map { join(",", $_->rgba) } @$allowed),"\n"; } { my $transim = Imager->new(xsize => 4, ysize => 4, channels => 4, bits => $bits); $transim->box(filled=>1, color=>$trans_target); $transim->box(fill => $fillobj); my $c = $transim->getpixel(x => 1, 'y' => 1); my $allowed = $test->{trans}; $allowed =~ /ARRAY/ or $allowed = [ $allowed ]; ok(scalar grep(color_close4($_, $c), @$allowed), "translucent '$comb' $bits bits") or print "# got:",join(",", $c->rgba)," allowed: ", join("|", map { join(",", $_->rgba) } @$allowed),"\n"; } } } ok($ffim->arc(r=>45, color=>$blue, aa=>1), "aa circle"); $ffim->write(file=>"testout/t20_aacircle.ppm"); # image based fills my $green = NC(0, 255, 0); my $fillim = Imager->new(xsize=>40, ysize=>40, channels=>4); $fillim->box(filled=>1, xmin=>5, ymin=>5, xmax=>35, ymax=>35, color=>NC(0, 0, 255, 128)); $fillim->arc(filled=>1, r=>10, color=>$green, aa=>1); my $ooim = Imager->new(xsize=>150, ysize=>150); $ooim->box(filled=>1, color=>$green, xmin=>70, ymin=>25, xmax=>130, ymax=>125); $ooim->box(filled=>1, color=>$blue, xmin=>20, ymin=>25, xmax=>80, ymax=>125); $ooim->arc(r=>30, color=>$red, aa=>1); my $oocopy = $ooim->copy(); ok($oocopy->arc(fill=>{image=>$fillim, combine=>'normal', xoff=>5}, r=>40), "image based fill"); $oocopy->write(file=>'testout/t20_image.ppm'); # a more complex version use Imager::Matrix2d ':handy'; $oocopy = $ooim->copy; ok($oocopy->arc(fill=>{ image=>$fillim, combine=>'normal', matrix=>m2d_rotate(degrees=>30), xoff=>5 }, r=>40), "transformed image based fill"); $oocopy->write(file=>'testout/t20_image_xform.ppm'); ok(!$oocopy->arc(fill=>{ hatch=>"not really a hatch" }, r=>20), "error handling of automatic fill conversion"); ok($oocopy->errstr =~ /Unknown hatch type/, "error message for automatic fill conversion"); # previous box fills to float images, or using the fountain fill # got into a loop here SKIP: { skip("can't test without alarm()", 1) unless $Config{d_alarm}; skip("Your signals are misconfigured", 1) unless exists $SIG{ALRM}; local $SIG{ALRM} = sub { die; }; eval { alarm(2); ok($ooim->box(xmin=>20, ymin=>20, xmax=>80, ymax=>40, fill=>{ fountain=>'linear', xa=>20, ya=>20, xb=>80, yb=>20 }), "linear box fill"); alarm 0; }; $@ and ok(0, "linear box fill $@"); } # test that passing in a non-array ref returns an error { my $fill = Imager::Fill->new(fountain=>'linear', xa => 20, ya=>20, xb=>20, yb=>40, segments=>"invalid"); ok(!$fill, "passing invalid segments produces an error"); cmp_ok(Imager->errstr, '=~', 'array reference', "check the error message"); } # test that colors in segments are converted { my @segs = ( [ 0.0, 0.5, 1.0, '000000', '#FFF', 0, 0 ], ); my $fill = Imager::Fill->new(fountain=>'linear', xa => 0, ya=>20, xb=>49, yb=>20, segments=>\@segs); ok($fill, "check that color names are converted") or print "# ",Imager->errstr,"\n"; my $im = Imager->new(xsize=>50, ysize=>50); $im->box(fill=>$fill); my $left = $im->getpixel('x'=>0, 'y'=>20); ok(color_close($left, Imager::Color->new(0,0,0)), "check black converted correctly"); my $right = $im->getpixel('x'=>49, 'y'=>20); ok(color_close($right, Imager::Color->new(255,255,255)), "check white converted correctly"); # check that invalid colors handled correctly my @segs2 = ( [ 0.0, 0.5, 1.0, '000000', 'FxFxFx', 0, 0 ], ); my $fill2 = Imager::Fill->new(fountain=>'linear', xa => 0, ya=>20, xb=>49, yb=>20, segments=>\@segs2); ok(!$fill2, "check handling of invalid color names"); cmp_ok(Imager->errstr, '=~', 'No color named', "check error message"); } { # RT #35278 # hatch fills on a grey scale image don't adapt colors for my $bits (8, 'double') { my $im_g = Imager->new(xsize => 10, ysize => 10, channels => 1, bits => $bits); $im_g->box(filled => 1, color => 'FFFFFF'); my $fill = Imager::Fill->new ( combine => 'normal', hatch => 'weave', fg => '000000', bg => 'FFFFFF' ); $im_g->box(fill => $fill); my $im_c = Imager->new(xsize => 10, ysize => 10, channels => 3, bits => $bits); $im_c->box(filled => 1, color => 'FFFFFF'); $im_c->box(fill => $fill); my $im_cg = $im_g->convert(preset => 'rgb'); is_image($im_c, $im_cg, "check hatch is the same between color and greyscale (bits $bits)"); # check the same for image fills my $grey_fill = Imager::Fill->new ( image => $im_g, combine => 'normal' ); my $im_cfg = Imager->new(xsize => 20, ysize => 20, bits => $bits); $im_cfg->box(filled => 1, color => '808080'); $im_cfg->box(fill => $grey_fill); my $rgb_fill = Imager::Fill->new ( image => $im_cg, combine => 'normal' ); my $im_cfc = Imager->new(xsize => 20, ysize => 20, bits => $bits); $im_cfc->box(filled => 1, color => '808080'); $im_cfc->box(fill => $rgb_fill); is_image($im_cfg, $im_cfc, "check filling from grey image matches filling from rgb (bits = $bits)"); my $im_gfg = Imager->new(xsize => 20, ysize => 20, channels => 1, bits => $bits); $im_gfg->box(filled => 1, color => '808080'); $im_gfg->box(fill => $grey_fill); my $im_gfg_c = $im_gfg->convert(preset => 'rgb'); is_image($im_gfg_c, $im_cfg, "check grey filled with grey against base (bits = $bits)"); my $im_gfc = Imager->new(xsize => 20, ysize => 20, channels => 1, bits => $bits); $im_gfc->box(filled => 1, color => '808080'); $im_gfc->box(fill => $rgb_fill); my $im_gfc_c = $im_gfc->convert(preset => 'rgb'); is_image($im_gfc_c, $im_cfg, "check grey filled with color against base (bits = $bits)"); } } { # alpha modifying fills { # 8-bit/sample my $base_img = Imager->new(xsize => 4, ysize => 2, channels => 4); $base_img->setscanline ( x => 0, y => 0, pixels => [ map Imager::Color->new($_), qw/FF000020 00FF0080 00008040 FFFF00FF/, ], ); $base_img->setscanline ( x => 0, y => 1, pixels => [ map Imager::Color->new($_), qw/FFFF00FF FF000000 00FF0080 00008040/ ] ); my $base_fill = Imager::Fill->new ( image => $base_img, combine => "normal", ); ok($base_fill, "make the base image fill"); my $fill50 = Imager::Fill->new(type => "opacity", opacity => 0.5, other => $base_fill) or print "# ", Imager->errstr, "\n"; ok($fill50, "make 50% alpha translation fill"); { # 4 channel image my $out = Imager->new(xsize => 10, ysize => 10, channels => 4); $out->box(fill => $fill50); is_color4($out->getpixel(x => 0, y => 0), 255, 0, 0, 16, "check alpha output"); is_color4($out->getpixel(x => 2, y => 1), 0, 255, 0, 64, "check alpha output"); $out->box(filled => 1, color => "000000"); is_color4($out->getpixel(x => 0, y => 0), 0, 0, 0, 255, "check after clear"); $out->box(fill => $fill50); is_color4($out->getpixel(x => 4, y => 2), 16, 0, 0, 255, "check drawn against background"); is_color4($out->getpixel(x => 6, y => 3), 0, 64, 0, 255, "check drawn against background"); } { # 3 channel image my $out = Imager->new(xsize => 10, ysize => 10, channels => 3); $out->box(fill => $fill50); is_color3($out->getpixel(x => 0, y => 0), 16, 0, 0, "check alpha output"); is_color3($out->getpixel(x => 2, y => 1), 0, 64, 0, "check alpha output"); is_color3($out->getpixel(x => 0, y => 1), 128, 128, 0, "check alpha output"); } } { # double/sample use Imager::Color::Float; my $base_img = Imager->new(xsize => 4, ysize => 2, channels => 4, bits => "double"); $base_img->setscanline ( x => 0, y => 0, pixels => [ map Imager::Color::Float->new(@$_), [ 1, 0, 0, 0.125 ], [ 0, 1, 0, 0.5 ], [ 0, 0, 0.5, 0.25 ], [ 1, 1, 0, 1 ], ], ); $base_img->setscanline ( x => 0, y => 1, pixels => [ map Imager::Color::Float->new(@$_), [ 1, 1, 0, 1 ], [ 1, 0, 0, 0 ], [ 0, 1, 0, 0.5 ], [ 0, 0, 0.5, 0.25 ], ] ); my $base_fill = Imager::Fill->new ( image => $base_img, combine => "normal", ); ok($base_fill, "make the base image fill"); my $fill50 = Imager::Fill->new(type => "opacity", opacity => 0.5, other => $base_fill) or print "# ", Imager->errstr, "\n"; ok($fill50, "make 50% alpha translation fill"); my $out = Imager->new(xsize => 10, ysize => 10, channels => 4, bits => "double"); $out->box(fill => $fill50); is_fcolor4($out->getpixel(x => 0, y => 0, type => "float"), 1, 0, 0, 0.0625, "check alpha output at 0,0"); is_fcolor4($out->getpixel(x => 2, y => 1, type => "float"), 0, 1, 0, 0.25, "check alpha output at 2,1"); $out->box(filled => 1, color => "000000"); is_fcolor4($out->getpixel(x => 0, y => 0, type => "float"), 0, 0, 0, 1, "check after clear"); $out->box(fill => $fill50); is_fcolor4($out->getpixel(x => 4, y => 2, type => "float"), 0.0625, 0, 0, 1, "check drawn against background at 4,2"); is_fcolor4($out->getpixel(x => 6, y => 3, type => "float"), 0, 0.25, 0, 1, "check drawn against background at 6,3"); } ok(!Imager::Fill->new(type => "opacity"), "should fail to make an opacity fill with no other fill object"); is(Imager->errstr, "'other' parameter required to create opacity fill", "check error message"); ok(!Imager::Fill->new(type => "opacity", other => "xx"), "should fail to make an opacity fill with a bad other parameter"); is(Imager->errstr, "'other' parameter must be an Imager::Fill object to create an opacity fill", "check error message"); # check auto conversion of hashes ok(Imager::Fill->new(type => "opacity", other => { solid => "FF0000" }), "check we auto-create fills") or print "# ", Imager->errstr, "\n"; { # fill with combine none was modifying the wrong channel for a # no-alpha target image my $fill = Imager::Fill->new(solid => "#FFF", combine => "none"); my $fill2 = Imager::Fill->new ( type => "opacity", opacity => 0.5, other => $fill ); my $im = Imager->new(xsize => 1, ysize => 1); ok($im->box(fill => $fill2), "fill with replacement opacity fill"); is_color3($im->getpixel(x => 0, y => 0), 255, 255, 255, "check for correct colour"); } { require Imager::Fountain; my $fount = Imager::Fountain->new; $fount->add(c1 => "FFFFFF"); # simple white to black # base fill is a fountain my $base_fill = Imager::Fill->new ( fountain => "linear", segments => $fount, xa => 0, ya => 0, xb => 100, yb => 100, ); ok($base_fill, "made fountain fill base"); my $op_fill = Imager::Fill->new ( type => "opacity", other => $base_fill, opacity => 0.5, ); ok($op_fill, "made opacity fountain fill"); my $im = Imager->new(xsize => 100, ysize => 100); ok($im->box(fill => $op_fill), "draw with it"); } } { # RT 71309 my $fount = Imager::Fountain->simple(colors => [ '#804041', '#804041' ], positions => [ 0, 1 ]); my $im = Imager->new(xsize => 40, ysize => 40); $im->box(filled => 1, color => '#804040'); my $fill = Imager::Fill->new ( combine => 0, fountain => "linear", segments => $fount, xa => 0, ya => 0, xb => 40, yb => 40, ); $im->polygon(fill => $fill, points => [ [ 0, 0 ], [ 40, 20 ], [ 20, 40 ], ] ); # the bug magnified the differences between the source and destination # color, blending between the background and fill colors here only allows # for those 2 colors in the result. # with the bug extra colors appeared along the edge of the polygon. is($im->getcolorcount, 2, "only original and fill color"); } SKIP: { # the wrong image dimension was used for adjusting vs yoff, # producing uncovered parts of the output image my $tx = Imager->new(xsize => 30, ysize => 20); ok($tx, "create texture image") or diag "create texture image", Imager->errstr; $tx or skip "no texture image", 7; ok($tx->box(filled => 1, color => "ff0000"), "fill texture image") or diag "fill texture image", $tx->errstr; my $cmp = Imager->new(xsize => 100, ysize => 100); ok($cmp, "create comparison image") or diag "create comparison image: ", Imager->errstr; $cmp or skip "no comparison image", 5; ok($cmp->box(filled => 1, color => "FF0000"), "fill compare image") or diag "fill compare image: ", $cmp->errstr; my $im = Imager->new(xsize => 100, ysize => 100); ok($im, "make test image") or diag "make test image: ", Imager->errstr; $im or skip "no test image", 3; my $fill = Imager::Fill->new(image => $tx, yoff => 10); ok($fill, "make xoff=10 image fill") or diag "make fill: ", Imager->errstr; $fill or skip "no fill", 2; ok($im->box(fill => $fill), "fill test image") or diag "fill test image: ", $im->errstr; is_image($im, $cmp, "check test image"); } sub color_close { my ($c1, $c2) = @_; my @c1 = $c1->rgba; my @c2 = $c2->rgba; for my $i (0..2) { if (abs($c1[$i]-$c2[$i]) > 2) { return 0; } } return 1; } sub color_close4 { my ($c1, $c2) = @_; my @c1 = $c1->rgba; my @c2 = $c2->rgba; for my $i (0..3) { if (abs($c1[$i]-$c2[$i]) > 2) { return 0; } } return 1; } # for use during testing sub save { my ($im, $name) = @_; open FH, "> $name" or die "Cannot create $name: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); Imager::i_writeppm_wiol($im, $io) or die "Cannot save to $name"; undef $io; close FH; } libimager-perl-1.004+dfsg.orig/t/250-draw/200-compose.t0000644000175000017500000002225312263740601021423 0ustar gregoagregoa#!perl -w use strict; use Imager qw(:handy); use Test::More tests => 120; use Imager::Test qw(is_image is_imaged); -d "testout" or mkdir "testout"; Imager::init_log("testout/t62compose.log", 1); my @files; my %types = ( double => { blue => NCF(0, 0, 1), red => NCF(1, 0, 0), green2 => NCF(0, 1, 0, 0.5), green2_on_blue => NCF(0, 0.5, 0.5), red3_on_blue => NCF(1/3, 0, 2/3), green6_on_blue => NCF(0, 1/6, 5/6), red2_on_blue => NCF(0.5, 0, 0.5), green4_on_blue => NCF(0, 0.25, 0.75), gray100 => NCF(1.0, 0, 0), gray50 => NCF(0.5, 0, 0), is_image => \&is_imaged, }, 8 => { blue => NC(0, 0, 255), red => NC(255, 0, 0), green2 => NC(0, 255, 0, 128), green2_on_blue => NC(0, 128, 127), red3_on_blue => NC(85, 0, 170), green6_on_blue => NC(0, 42, 213), red2_on_blue => NC(128, 0, 127), green4_on_blue => NC(0, 64, 191), gray100 => NC(255, 0, 0), gray50 => NC(128, 0, 0), is_image => \&is_image, }, ); for my $type_id (sort keys %types) { my $type = $types{$type_id}; my $blue = $type->{blue}; my $red = $type->{red}; my $green2 = $type->{green2}; my $green2_on_blue = $type->{green2_on_blue}; my $red3_on_blue = $type->{red3_on_blue}; my $green6_on_blue = $type->{green6_on_blue}; my $red2_on_blue = $type->{red2_on_blue}; my $green4_on_blue = $type->{green4_on_blue}; my $gray100 = $type->{gray100}; my $gray50 = $type->{gray50}; my $is_image = $type->{is_image}; print "# type $type_id\n"; my $targ = Imager->new(xsize => 100, ysize => 100, bits => $type_id); $targ->box(color => $blue, filled => 1); is($targ->type, "direct", "check target image type"); is($targ->bits, $type_id, "check target bits"); my $src = Imager->new(xsize => 40, ysize => 40, channels => 4, bits => $type_id); $src->box(filled => 1, color => $red, xmax => 19, ymax => 19); $src->box(filled => 1, xmin => 20, color => $green2); save_to($src, "${type_id}_src"); my $mask_ones = Imager->new(channels => 1, xsize => 40, ysize => 40, bits => $type_id); $mask_ones->box(filled => 1, color => NC(255, 255, 255)); # mask or full mask, should be the same for my $mask_info ([ "nomask" ], [ "fullmask", mask => $mask_ones ]) { my ($mask_type, @mask_extras) = @$mask_info; print "# $mask_type\n"; { my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin=> 5, ymin => 10, xmax => 24, ymax => 29); $cmp->box(filled => 1, color => $green2_on_blue, xmin => 25, ymin => 10, xmax => 44, ymax => 49); { my $work = $targ->copy; ok($work->compose(src => $src, tx => 5, ty => 10, @mask_extras), "$mask_type - simple compose"); $is_image->($work, $cmp, "check match"); save_to($work, "${type_id}_${mask_type}_simple"); } { # >1 opacity my $work = $targ->copy; ok($work->compose(src => $src, tx => 5, ty => 10, opacity => 2.0, @mask_extras), "$mask_type - compose with opacity > 1.0 acts like opacity=1.0"); $is_image->($work, $cmp, "check match"); } { # 0 opacity is a failure my $work = $targ->copy; ok(!$work->compose(src => $src, tx => 5, ty => 10, opacity => 0.0, @mask_extras), "$mask_type - compose with opacity = 0 is an error"); is($work->errstr, "opacity must be positive", "check message"); } } { # compose at 1/3 my $work = $targ->copy; ok($work->compose(src => $src, tx => 7, ty => 33, opacity => 1/3, @mask_extras), "$mask_type - simple compose at 1/3"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red3_on_blue, xmin => 7, ymin => 33, xmax => 26, ymax => 52); $cmp->box(filled => 1, color => $green6_on_blue, xmin => 27, ymin => 33, xmax => 46, ymax => 72); $is_image->($work, $cmp, "check match"); } { # targ off top left my $work = $targ->copy; ok($work->compose(src => $src, tx => -5, ty => -3, @mask_extras), "$mask_type - compose off top left"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin=> 0, ymin => 0, xmax => 14, ymax => 16); $cmp->box(filled => 1, color => $green2_on_blue, xmin => 15, ymin => 0, xmax => 34, ymax => 36); $is_image->($work, $cmp, "check match"); } { # targ off bottom right my $work = $targ->copy; ok($work->compose(src => $src, tx => 65, ty => 67, @mask_extras), "$mask_type - targ off bottom right"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin=> 65, ymin => 67, xmax => 84, ymax => 86); $cmp->box(filled => 1, color => $green2_on_blue, xmin => 85, ymin => 67, xmax => 99, ymax => 99); $is_image->($work, $cmp, "check match"); } { # src off top left my $work = $targ->copy; my @more_mask_extras; if (@mask_extras) { push @more_mask_extras, ( mask_left => -5, mask_top => -15, ); } ok($work->compose(src => $src, tx => 10, ty => 20, src_left => -5, src_top => -15, @mask_extras, @more_mask_extras), "$mask_type - source off top left"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin=> 15, ymin => 35, xmax => 34, ymax => 54); $cmp->box(filled => 1, color => $green2_on_blue, xmin => 35, ymin => 35, xmax => 54, ymax => 74); $is_image->($work, $cmp, "check match"); } { # src off bottom right my $work = $targ->copy; ok($work->compose(src => $src, tx => 10, ty => 20, src_left => 10, src_top => 15, width => 40, height => 40, @mask_extras), "$mask_type - source off bottom right"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin=> 10, ymin => 20, xmax => 19, ymax => 24); $cmp->box(filled => 1, color => $green2_on_blue, xmin => 20, ymin => 20, xmax => 39, ymax => 44); $is_image->($work, $cmp, "check match"); } { # simply out of bounds my $work = $targ->copy; ok(!$work->compose(src => $src, tx => 100, @mask_extras), "$mask_type - off the right of the target"); $is_image->($work, $targ, "no changes"); ok(!$work->compose(src => $src, ty => 100, @mask_extras), "$mask_type - off the bottom of the target"); $is_image->($work, $targ, "no changes"); ok(!$work->compose(src => $src, tx => -40, @mask_extras), "$mask_type - off the left of the target"); $is_image->($work, $targ, "no changes"); ok(!$work->compose(src => $src, ty => -40, @mask_extras), "$mask_type - off the top of the target"); $is_image->($work, $targ, "no changes"); } } # masked tests my $mask = Imager->new(xsize => 40, ysize => 40, channels => 1, bits => $type_id); $mask->box(filled => 1, xmax => 19, color => $gray100); $mask->box(filled => 1, xmin => 20, ymax => 14, xmax => 34, color => $gray50); is($mask->bits, $type_id, "check mask bits"); { my $work = $targ->copy; ok($work->compose(src => $src, tx => 5, ty => 7, mask => $mask), "simple draw masked"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin => 5, ymin => 7, xmax => 24, ymax => 26); $cmp->box(filled => 1, color => $green4_on_blue, xmin => 25, ymin => 7, xmax => 39, ymax => 21); $is_image->($work, $cmp, "check match"); save_to($work, "${type_id}_simp_masked"); save_to($work, "${type_id}_simp_masked_cmp"); } { my $work = $targ->copy; ok($work->compose(src => $src, tx => 5, ty => 7, mask_left => 5, mask_top => 2, mask => $mask), "draw with mask offset"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin => 5, ymin => 7, xmax => 19, ymax => 26); $cmp->box(filled => 1, color => $red2_on_blue, xmin => 20, ymin => 7, xmax => 24, ymax => 19); $cmp->box(filled => 1, color => $green4_on_blue, xmin => 25, ymin => 7, xmax => 34, ymax => 19); $is_image->($work, $cmp, "check match"); } { my $work = $targ->copy; ok($work->compose(src => $src, tx => 5, ty => 7, mask_left => -3, mask_top => -2, mask => $mask), "draw with negative mask offsets"); my $cmp = $targ->copy; $cmp->box(filled => 1, color => $red, xmin => 8, ymin => 9, xmax => 24, ymax => 26); $cmp->box(filled => 1, color => $green2_on_blue, xmin => 25, ymin => 9, xmax => 27, ymax => 46); $cmp->box(filled => 1, color => $green4_on_blue, xmin => 28, ymin => 9, xmax => 42, ymax => 23); $is_image->($work, $cmp, "check match"); } } { my $empty = Imager->new; my $good = Imager->new(xsize => 1, ysize => 1); ok(!$empty->compose(src => $good), "can't compose to empty image"); is($empty->errstr, "compose: empty input image", "check error message"); ok(!$good->compose(src => $empty), "can't compose from empty image"); is($good->errstr, "compose: empty input image (for src)", "check error message"); ok(!$good->compose(src => $good, mask => $empty), "can't compose with empty mask"); is($good->errstr, "compose: empty input image (for mask)", "check error message"); } unless ($ENV{IMAGER_KEEP_FILES}) { unlink @files; } sub save_to { my ($im, $name) = @_; my $type = $ENV{IMAGER_SAVE_TYPE} || "ppm"; $name = "testout/t62_$name.$type"; $im->write(file => $name, pnm_write_wide_data => 1); push @files, $name; } libimager-perl-1.004+dfsg.orig/t/250-draw/020-flood.t0000644000175000017500000001242412524332021021051 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 177; use Imager; use Imager::Test qw(is_image); -d "testout" or mkdir "testout"; { # flood_fill wouldn't fill to the right if the area was just a # single scan-line my $im = Imager->new(xsize => 5, ysize => 3); ok($im, "make flood_fill test image"); ok($im->line(x1 => 0, y1 => 1, x2 => 4, y2 => 1, color => "white"), "create fill area"); ok($im->flood_fill(x => 3, y => 1, color => "blue"), "fill it"); my $cmp = Imager->new(xsize => 5, ysize => 3); ok($cmp, "make test image"); ok($cmp->line(x1 => 0, y1 => 1, x2 => 4, y2 => 1, color => "blue"), "synthezied filled area"); is_image($im, $cmp, "flood_fill filled horizontal line"); } SKIP: { # flood_fill won't fill entire line below if line above is shorter my $im = Imager->new(file => "testimg/filltest.ppm"); ok($im, "Load test image") or skip("Couldn't load test image: " . Imager->errstr, 3); # fill from first bad place my $fill1 = $im->copy; ok($fill1->flood_fill(x => 8, y => 2, color => "#000000"), "fill from a top most spot"); my $cmp = Imager->new(xsize => $im->getwidth, ysize => $im->getheight); is_image($fill1, $cmp, "check it filled the lot"); ok($fill1->write(file => "testout/t22fill1.ppm"), "save"); # second bad place my $fill2 = $im->copy; ok($fill2->flood_fill(x => 17, y => 3, color => "#000000"), "fill from not quite top most spot"); is_image($fill2, $cmp, "check it filled the lot"); ok($fill2->write(file => "testout/t22fill2.ppm"), "save"); } { # verticals my $im = vimage("FFFFFF"); my $cmp = vimage("FF0000"); ok($im->flood_fill(x => 4, y=> 8, color => "FF0000"), "fill at bottom of vertical well"); is_image($im, $cmp, "check the result"); } { # 103786 - when filling up would cross a 4-connected border to the left # incorrectly my $im = Imager->new(xsize => 20, ysize => 20); $im->box(filled => 1, box => [ 0, 10, 9, 19 ], color => "FFFFFF"); $im->box(filled => 1, box => [ 10, 0, 19, 9 ], color => "FFFFFF"); my $cmp = $im->copy; $cmp->box(filled => 1, box => [ 10, 10, 19, 19 ], color => "0000FF"); ok($im->flood_fill(x => 19, y => 19, color => "0000FF"), "flood_fill() to big checks"); is_image($im, $cmp, "check result correct"); } { # keys for tests are: # name - base name of the test, the fill position is added # boxes - arrayref of boxes to draw # floods - arrayref of boxes representing the area to be flood filled, # defaults to the whole image # fillats - positions to start filling from # Note that floods are drawn before the boxes, so the boxes obscure the # filled area my @tests = ( { name => "1-pixel border", boxes => [ [ 1, 1, 18, 18 ] ], fillats => [ [ 0, 0 ], [ 19, 0 ], [ 0, 19 ], [ 19, 19 ], [ 10, 0 ], [ 10, 19 ], [ 0, 10 ], [ 19, 10 ], ] }, { name => "vertical connect check", boxes => [ [ 0, 0, 8, 11 ], [ 10, 8, 19, 19 ], ], fillats => [ [ 19, 0 ], [ 0, 19 ], ], }, { name => "horizontal connect check", boxes => [ [ 0, 0, 11, 8 ], [ 10, 10, 19, 19 ], ], fillats => [ [ 19, 0 ], [ 0, 19 ], ], }, { name => "fill from inner line to 1-pixel border", boxes => [ [ 1, 1, 18, 9 ], [ 1, 10, 9, 10 ], [ 1, 11, 18, 19 ], ], fillats => [ [ 10, 10 ], [ 0, 0 ] ], }, { name => "4-connected", boxes => [ [ 11, 0, 19, 6 ], [ 0, 7, 10, 15 ], [ 11, 16, 19, 19 ], ], floods => [ [ 11, 7, 19, 15 ], ], fillats => [ [ 19, 10 ], [ 19, 7 ], [ 19, 15 ], [ 11, 10 ], [ 11, 7 ], [ 11, 15 ], ] }, ); my $box_color = Imager::Color->new("FF0000"); my $fill_color = Imager::Color->new("00FF00"); for my $test (@tests) { my $base_name = $test->{name}; my $boxes = $test->{boxes}; my $floods = $test->{floods} || [ [ 0, 0, 19, 19 ] ]; my $fillats = $test->{fillats}; for my $pos (@$fillats) { for my $flip ("none", "h", "v", "vh") { my ($fillx, $filly) = @$pos; my $im = Imager->new(xsize => 20, ysize => 20); my $cmp = Imager->new(xsize => 20, ysize => 20); for my $flood (@$floods) { $cmp->box(box => $flood, filled => 1, color => $fill_color); } for my $image ($im, $cmp) { for my $box (@$boxes) { $image->box(filled => 1, color => $box_color, box => $box ); } } if ($flip ne "none") { $_->flip(dir => $flip) for $im, $cmp; $flip =~ /h/ and $fillx = 19 - $fillx; $flip =~ /v/ and $filly = 19 - $filly; } ok($im->flood_fill(x => $fillx, y => $filly, color => $fill_color), "$base_name - \@($fillx,$filly) - flip $flip - fill"); is_image($im, $cmp, "$base_name - \@($fillx,$filly) - flip $flip - compare"); } } } } unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t22fill1.ppm"; unlink "testout/t22fill2.ppm"; } # make a vertical test image sub vimage { my $c = shift; my $im = Imager->new(xsize => 10, ysize => 10); $im->line(x1 => 1, y1 => 1, x2 => 8, y2 => 1, color => $c); $im->line(x1 => 4, y1 => 2, x2 => 4, y2 => 8, color => $c); return $im; } libimager-perl-1.004+dfsg.orig/t/250-draw/010-draw.t0000644000175000017500000003117412263740601020714 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 256; use Imager ':all'; use Imager::Test qw(is_color3 is_image); use constant PI => 3.14159265358979; -d "testout" or mkdir "testout"; init_log("testout/t21draw.log",1); my $redobj = NC(255, 0, 0); my $red = 'FF0000'; my $greenobj = NC(0, 255, 0); my $green = [ 0, 255, 0 ]; my $blueobj = NC(0, 0, 255); my $blue = { hue=>240, saturation=>1, value=>1 }; my $white = '#FFFFFF'; { my $img = Imager->new(xsize=>100, ysize=>500); ok($img->box(color=>$blueobj, xmin=>10, ymin=>10, xmax=>48, ymax=>18), "box with color obj"); ok($img->box(color=>$blue, xmin=>10, ymin=>20, xmax=>48, ymax=>28), "box with color"); ok($img->box(color=>$redobj, xmin=>10, ymin=>30, xmax=>28, ymax=>48, filled=>1), "filled box with color obj"); ok($img->box(color=>$red, xmin=>30, ymin=>30, xmax=>48, ymax=>48, filled=>1), "filled box with color"); ok($img->arc('x'=>75, 'y'=>25, r=>24, color=>$redobj), "filled arc with colorobj"); ok($img->arc('x'=>75, 'y'=>25, r=>20, color=>$green), "filled arc with colorobj"); ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$white, d1=>325, d2=>225), "filled arc with color"); ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$blue, d1=>225, d2=>325), "filled arc with color"); ok($img->arc('x'=>75, 'y'=>25, r=>15, color=>$green, aa=>1), "filled arc with color"); ok($img->line(color=>$blueobj, x1=>5, y1=>55, x2=>35, y2=>95), "line with colorobj"); # FIXME - neither the start nor end-point is set for a non-aa line my $c = Imager::i_get_pixel($img->{IMG}, 5, 55); ok(color_cmp($c, $blueobj) == 0, "# TODO start point not set"); ok($img->line(color=>$red, x1=>10, y1=>55, x2=>40, y2=>95, aa=>1), "aa line with color"); ok($img->line(color=>$green, x1=>15, y1=>55, x2=>45, y2=>95, antialias=>1), "antialias line with color"); ok($img->polyline(points=>[ [ 55, 55 ], [ 90, 60 ], [ 95, 95] ], color=>$redobj), "polyline points with color obj"); ok($img->polyline('x'=>[ 55, 85, 90 ], 'y'=>[60, 65, 95], color=>$green, aa=>1), "polyline xy with color aa"); ok($img->polyline('x'=>[ 55, 80, 85 ], 'y'=>[65, 70, 95], color=>$green, antialias=>1), "polyline xy with color antialias"); ok($img->setpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], color=>$red), "set array of pixels"); ok($img->setpixel('x'=>39, 'y'=>55, color=>$green), "set single pixel"); use Imager::Color::Float; my $flred = Imager::Color::Float->new(1, 0, 0, 0); my $flgreen = Imager::Color::Float->new(0, 1, 0, 0); ok($img->setpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59], color=>$flred), "set array of float pixels"); ok($img->setpixel('x'=>45, 'y'=>55, color=>$flgreen), "set single float pixel"); my @gp = $img->getpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59]); ok(grep($_->isa('Imager::Color'), @gp) == 3, "check getpixel result type"); ok(grep(color_cmp($_, NC(255, 0, 0)) == 0, @gp) == 3, "check getpixel result colors"); my $gp = $img->getpixel('x'=>45, 'y'=>55); ok($gp->isa('Imager::Color'), "check scalar getpixel type"); ok(color_cmp($gp, NC(0, 255, 0)) == 0, "check scalar getpixel color"); @gp = $img->getpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], type=>'float'); ok(grep($_->isa('Imager::Color::Float'), @gp) == 3, "check getpixel float result type"); ok(grep(color_cmp($_, $flred) == 0, @gp) == 3, "check getpixel float result type"); $gp = $img->getpixel('x'=>39, 'y'=>55, type=>'float'); ok($gp->isa('Imager::Color::Float'), "check scalar float getpixel type"); ok(color_cmp($gp, $flgreen) == 0, "check scalar float getpixel color"); # more complete arc tests ok($img->arc(x=>25, 'y'=>125, r=>20, d1=>315, d2=>45, color=>$greenobj), "color arc through angle 0"); # use diff combine here to make sure double writing is noticable ok($img->arc(x=>75, 'y'=>125, r=>20, d1=>315, d2=>45, fill => { solid=>$blueobj, combine => 'diff' }), "fill arc through angle 0"); ok($img->arc(x=>25, 'y'=>175, r=>20, d1=>315, d2=>225, color=>$redobj), "concave color arc"); angle_marker($img, 25, 175, 23, 315, 225); ok($img->arc(x=>75, 'y'=>175, r=>20, d1=>315, d2=>225, fill => { solid=>$greenobj, combine=>'diff' }), "concave fill arc"); angle_marker($img, 75, 175, 23, 315, 225); ok($img->arc(x=>25, y=>225, r=>20, d1=>135, d2=>45, color=>$redobj), "another concave color arc"); angle_marker($img, 25, 225, 23, 45, 135); ok($img->arc(x=>75, y=>225, r=>20, d1=>135, d2=>45, fill => { solid=>$blueobj, combine=>'diff' }), "another concave fillarc"); angle_marker($img, 75, 225, 23, 45, 135); ok($img->arc(x=>25, y=>275, r=>20, d1=>135, d2=>45, color=>$redobj, aa=>1), "concave color arc aa"); ok($img->arc(x=>75, y=>275, r=>20, d1=>135, d2=>45, fill => { solid=>$blueobj, combine=>'diff' }, aa=>1), "concave fill arc aa"); ok($img->circle(x=>25, y=>325, r=>20, color=>$redobj), "color circle no aa"); ok($img->circle(x=>75, y=>325, r=>20, color=>$redobj, aa=>1), "color circle aa"); ok($img->circle(x=>25, 'y'=>375, r=>20, fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }), "fill circle no aa"); ok($img->circle(x=>75, 'y'=>375, r=>20, aa=>1, fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }), "fill circle aa"); ok($img->arc(x=>50, y=>450, r=>45, d1=>135, d2=>45, fill => { solid=>$blueobj, combine=>'diff' }), "another concave fillarc"); angle_marker($img, 50, 450, 47, 45, 135); ok($img->write(file=>'testout/t21draw.ppm'), "saving output"); } { my $im = Imager->new(xsize => 400, ysize => 400); ok($im->arc(x => 200, y => 202, r => 10, filled => 0), "draw circle outline"); is_color3($im->getpixel(x => 200, y => 202), 0, 0, 0, "check center not filled"); ok($im->arc(x => 198, y => 200, r => 13, filled => 0, color => "#f88"), "draw circle outline"); is_color3($im->getpixel(x => 198, y => 200), 0, 0, 0, "check center not filled"); ok($im->arc(x => 200, y => 200, r => 24, filled => 0, color => "#0ff"), "draw circle outline"); my $r = 40; while ($r < 180) { ok($im->arc(x => 200, y => 200, r => $r, filled => 0, color => "#ff0"), "draw circle outline r $r"); $r += 15; } ok($im->write(file => "testout/t21circout.ppm"), "save arc outline"); } { my $im = Imager->new(xsize => 400, ysize => 400); { my $lc = Imager::Color->new(32, 32, 32); my $an = 0; while ($an < 360) { my $an_r = $an * PI / 180; my $ca = cos($an_r); my $sa = sin($an_r); $im->line(aa => 1, color => $lc, x1 => 198 + 5 * $ca, y1 => 202 + 5 * $sa, x2 => 198 + 190 * $ca, y2 => 202 + 190 * $sa); $an += 5; } } my $d1 = 0; my $r = 20; while ($d1 < 350) { ok($im->arc(x => 198, y => 202, r => $r, d1 => $d1, d2 => $d1+300, filled => 0), "draw arc outline r$r d1$d1 len 300"); ok($im->arc(x => 198, y => 202, r => $r+3, d1 => $d1, d2 => $d1+40, filled => 0, color => '#FFFF00'), "draw arc outline r$r d1$d1 len 40"); $d1 += 15; $r += 6; } is_color3($im->getpixel(x => 198, y => 202), 0, 0, 0, "check center not filled"); ok($im->write(file => "testout/t21arcout.ppm"), "save arc outline"); } { my $im = Imager->new(xsize => 400, ysize => 400); ok($im->arc(x => 197, y => 201, r => 10, filled => 0, aa => 1, color => 'white'), "draw circle outline"); is_color3($im->getpixel(x => 197, y => 201), 0, 0, 0, "check center not filled"); ok($im->arc(x => 197, y => 205, r => 13, filled => 0, color => "#f88", aa => 1), "draw circle outline"); is_color3($im->getpixel(x => 197, y => 205), 0, 0, 0, "check center not filled"); ok($im->arc(x => 190, y => 215, r => 24, filled => 0, color => [0,0, 255, 128], aa => 1), "draw circle outline"); my $r = 40; while ($r < 190) { ok($im->arc(x => 197, y => 201, r => $r, filled => 0, aa => 1, color => '#ff0'), "draw aa circle rad $r"); $r += 7; } ok($im->write(file => "testout/t21aacircout.ppm"), "save arc outline"); } { my $im = Imager->new(xsize => 400, ysize => 400); { my $lc = Imager::Color->new(32, 32, 32); my $an = 0; while ($an < 360) { my $an_r = $an * PI / 180; my $ca = cos($an_r); my $sa = sin($an_r); $im->line(aa => 1, color => $lc, x1 => 198 + 5 * $ca, y1 => 202 + 5 * $sa, x2 => 198 + 190 * $ca, y2 => 202 + 190 * $sa); $an += 5; } } my $d1 = 0; my $r = 20; while ($d1 < 350) { ok($im->arc(x => 198, y => 202, r => $r, d1 => $d1, d2 => $d1+300, filled => 0, aa => 1), "draw aa arc outline r$r d1$d1 len 300"); ok($im->arc(x => 198, y => 202, r => $r+3, d1 => $d1, d2 => $d1+40, filled => 0, color => '#FFFF00', aa => 1), "draw aa arc outline r$r d1$d1 len 40"); $d1 += 15; $r += 6; } is_color3($im->getpixel(x => 198, y => 202), 0, 0, 0, "check center not filled"); ok($im->write(file => "testout/t21aaarcout.ppm"), "save arc outline"); } { my $im = Imager->new(xsize => 400, ysize => 400); my $an = 0; my $step = 15; while ($an <= 360-$step) { my $cx = int(200 + 20 * cos(($an+$step/2) * PI / 180)); my $cy = int(200 + 20 * sin(($an+$step/2) * PI / 180)); ok($im->arc(x => $cx, y => $cy, aa => 1, color => "#fff", d1 => $an, d2 => $an+$step, filled => 0, r => 170), "angle starting from $an"); ok($im->arc(x => $cx+0.5, y => $cy+0.5, aa => 1, color => "#ff0", d1 => $an, d2 => $an+$step, r => 168), "filled angle starting from $an"); $an += $step; } ok($im->write(file => "testout/t21aaarcs.ppm"), "save arc outline"); } { # we document that drawing from d1 to d2 where d2 > d1 will draw an # arc going through 360 degrees, test that my $im = Imager->new(xsize => 200, ysize => 200); ok($im->arc(x => 100, y => 100, aa => 0, filled => 0, color => '#fff', d1 => 270, d2 => 90, r => 90), "draw non-aa arc through 0"); ok($im->arc(x => 100, y => 100, aa => 1, filled => 0, color => '#fff', d1 => 270, d2 => 90, r => 80), "draw aa arc through 0"); ok($im->write(file => "testout/t21arc0.ppm"), "save arc through 0"); } { # test drawing color defaults { my $im = Imager->new(xsize => 10, ysize => 10); ok($im->box(), "default outline the image"); # should outline the image is_color3($im->getpixel(x => 0, y => 0), 255, 255, 255, "check outline default color TL"); is_color3($im->getpixel(x => 9, y => 5), 255, 255, 255, "check outline default color MR"); } { my $im = Imager->new(xsize => 10, ysize => 10); ok($im->box(filled => 1), "default fill the image"); # should fill the image is_color3($im->getpixel(x => 0, y => 0), 255, 255, 255, "check fill default color TL"); is_color3($im->getpixel(x => 5, y => 5), 255, 255, 255, "check fill default color MM"); } } { my $empty = Imager->new; ok(!$empty->box(), "can't draw box to empty image"); is($empty->errstr, "box: empty input image", "check error message"); ok(!$empty->arc(), "can't draw arc to empty image"); is($empty->errstr, "arc: empty input image", "check error message"); ok(!$empty->line(x1 => 0, y1 => 0, x2 => 10, y2 => 0), "can't draw line to empty image"); is($empty->errstr, "line: empty input image", "check error message"); ok(!$empty->polyline(points => [ [ 0, 0 ], [ 10, 0 ] ]), "can't draw polyline to empty image"); is($empty->errstr, "polyline: empty input image", "check error message"); ok(!$empty->polygon(points => [ [ 0, 0 ], [ 10, 0 ], [ 0, 10 ] ]), "can't draw polygon to empty image"); is($empty->errstr, "polygon: empty input image", "check error message"); ok(!$empty->flood_fill(x => 0, y => 0), "can't flood fill to empty image"); is($empty->errstr, "flood_fill: empty input image", "check error message"); } malloc_state(); unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t21draw.ppm"; unlink "testout/t21circout.ppm"; unlink "testout/t21aacircout.ppm"; unlink "testout/t21arcout.ppm"; unlink "testout/t21aaarcout.ppm"; unlink "testout/t21aaarcs.ppm"; unlink "testout/t21arc0.ppm"; } sub color_cmp { my ($l, $r) = @_; my @l = $l->rgba; my @r = $r->rgba; # print "# (",join(",", @l[0..2]),") <=> (",join(",", @r[0..2]),")\n"; return $l[0] <=> $r[0] || $l[1] <=> $r[1] || $l[2] <=> $r[2]; } sub angle_marker { my ($img, $x, $y, $radius, @angles) = @_; for my $angle (@angles) { my $x1 = int($x + $radius * cos($angle * PI / 180) + 0.5); my $y1 = int($y + $radius * sin($angle * PI / 180) + 0.5); my $x2 = int($x + (5+$radius) * cos($angle * PI / 180) + 0.5); my $y2 = int($y + (5+$radius) * sin($angle * PI / 180) + 0.5); $img->line(x1=>$x1, y1=>$y1, x2=>$x2, y2=>$y2, color=>'#FFF'); } } libimager-perl-1.004+dfsg.orig/t/250-draw/040-rubthru.t0000644000175000017500000003167512263740601021463 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 76; use Imager qw(:all :handy); use Imager::Test qw(is_image); -d "testout" or mkdir "testout"; init_log("testout/t69rubthru.log", 1); my $src_height = 80; my $src_width = 80; # raw interface my $targ = Imager::ImgRaw::new(100, 100, 3); my $src = Imager::ImgRaw::new($src_height, $src_width, 4); my $halfred = NC(255, 0, 0, 128); i_box_filled($src, 20, 20, 60, 60, $halfred); ok(i_rubthru($targ, $src, 10, 10, 0, 0, $src_width, $src_height), "low level rubthrough"); my $c = Imager::i_get_pixel($targ, 10, 10); ok($c, "get pixel at (10, 10)"); ok(color_cmp($c, NC(0, 0, 0)) == 0, "check for correct color"); $c = Imager::i_get_pixel($targ, 30, 30); ok($c, "get pixel at (30, 30)"); ok(color_cmp($c, NC(128, 0, 0)) == 0, "check color"); my $black = NC(0, 0, 0); # reset the target and try a grey+alpha source i_box_filled($targ, 0, 0, 100, 100, $black); my $gsrc = Imager::ImgRaw::new($src_width, $src_height, 2); my $halfwhite = NC(255, 128, 0); i_box_filled($gsrc, 20, 20, 60, 60, $halfwhite); ok(i_rubthru($targ, $gsrc, 10, 10, 0, 0, $src_width, $src_height), "low level with grey/alpha source"); $c = Imager::i_get_pixel($targ, 15, 15); ok($c, "get at (15, 15)"); ok(color_cmp($c, NC(0, 0, 0)) == 0, "check color"); $c = Imager::i_get_pixel($targ, 30, 30); ok($c, "get pixel at (30, 30)"); ok(color_cmp($c, NC(128, 128, 128)) == 0, "check color"); # try grey target and grey alpha source my $gtarg = Imager::ImgRaw::new(100, 100, 1); ok(i_rubthru($gtarg, $gsrc, 10, 10, 0, 0, $src_width, $src_height), "low level with grey target and gray/alpha source"); $c = Imager::i_get_pixel($gtarg, 10, 10); ok($c, "get pixel at 10, 10"); is(($c->rgba)[0], 0, "check grey level"); is((Imager::i_get_pixel($gtarg, 30, 30)->rgba)[0], 128, "check grey level at 30, 30"); # simple test for 16-bit/sample images my $targ16 = Imager::i_img_16_new(100, 100, 3); ok(i_rubthru($targ16, $src, 10, 10, 0, 0, $src_width, $src_height), "smoke test vs 16-bit/sample image"); $c = Imager::i_get_pixel($targ16, 30, 30); ok($c, "get pixel at 30, 30"); ok(color_cmp($c, NC(128, 0, 0)) == 0, "check color"); # check the OO interface my $ootarg = Imager->new(xsize=>100, ysize=>100); my $oosrc = Imager->new(xsize=>80, ysize=>80, channels=>4); $oosrc->box(color=>$halfred, xmin=>20, ymin=>20, xmax=>60, ymax=>60, filled=>1); ok($ootarg->rubthrough(src=>$oosrc, tx=>10, ty=>10), "oo rubthrough"); ok(color_cmp(Imager::i_get_pixel($ootarg->{IMG}, 10, 10), NC(0, 0, 0)) == 0, "check pixel at 10, 10"); ok(color_cmp(Imager::i_get_pixel($ootarg->{IMG}, 30, 30), NC(128, 0, 0)) == 0, "check pixel at 30, 30"); my $oogtarg = Imager->new(xsize=>100, ysize=>100, channels=>1); { # check empty image errors my $empty = Imager->new; ok(!$empty->rubthrough(src => $oosrc), "check empty target"); is($empty->errstr, 'rubthrough: empty input image', "check error message"); ok(!$oogtarg->rubthrough(src=>$empty), "check empty source"); is($oogtarg->errstr, 'rubthrough: empty input image (for src)', "check error message"); } { # alpha source and target for my $method (qw/rubthrough compose/) { my $src = Imager->new(xsize => 10, ysize => 1, channels => 4); my $targ = Imager->new(xsize => 10, ysize => 2, channels => 4); # simple initialization $targ->setscanline('y' => 1, x => 1, pixels => [ NC(255, 128, 0, 255), NC(255, 128, 0, 128), NC(255, 128, 0, 0), NC(255, 128, 0, 255), NC(255, 128, 0, 128), NC(255, 128, 0, 0), NC(255, 128, 0, 255), NC(255, 128, 0, 128), NC(255, 128, 0, 0), ]); $src->setscanline('y' => 0, pixels => [ NC(0, 128, 255, 0), NC(0, 128, 255, 0), NC(0, 128, 255, 0), NC(0, 128, 255, 128), NC(0, 128, 255, 128), NC(0, 128, 255, 128), NC(0, 128, 255, 255), NC(0, 128, 255, 255), NC(0, 128, 255, 255), ]); ok($targ->$method(src => $src, combine => 'normal', tx => 1, ty => 1), "do 4 on 4 $method"); iscolora($targ->getpixel(x => 1, 'y' => 1), NC(255, 128, 0, 255), "check at zero source coverage on full targ coverage"); iscolora($targ->getpixel(x => 2, 'y' => 1), NC(255, 128, 0, 128), "check at zero source coverage on half targ coverage"); iscolora($targ->getpixel(x => 3, 'y' => 1), NC(255, 128, 0, 0), "check at zero source coverage on zero targ coverage"); iscolora($targ->getpixel(x => 4, 'y' => 1), NC(127, 128, 128, 255), "check at half source_coverage on full targ coverage"); iscolora($targ->getpixel(x => 5, 'y' => 1), NC(85, 128, 170, 191), "check at half source coverage on half targ coverage"); iscolora($targ->getpixel(x => 6, 'y' => 1), NC(0, 128, 255, 128), "check at half source coverage on zero targ coverage"); iscolora($targ->getpixel(x => 7, 'y' => 1), NC(0, 128, 255, 255), "check at full source_coverage on full targ coverage"); iscolora($targ->getpixel(x => 8, 'y' => 1), NC(0, 128, 255, 255), "check at full source coverage on half targ coverage"); iscolora($targ->getpixel(x => 9, 'y' => 1), NC(0, 128, 255, 255), "check at full source coverage on zero targ coverage"); } } { # https://rt.cpan.org/Ticket/Display.html?id=30908 # we now adapt the source channels to the target # check each combination works as expected # various source images my $src1 = Imager->new(xsize => 50, ysize => 50, channels => 1); my $g_grey_full = Imager::Color->new(128, 255, 0, 0); my $g_white_50 = Imager::Color->new(255, 128, 0, 0); $src1->box(filled => 1, xmax => 24, color => $g_grey_full); my $src2 = Imager->new(xsize => 50, ysize => 50, channels => 2); $src2->box(filled => 1, xmax => 24, color => $g_grey_full); $src2->box(filled => 1, xmin => 25, color => $g_white_50); my $c_red_full = Imager::Color->new(255, 0, 0); my $c_blue_full = Imager::Color->new(0, 0, 255); my $src3 = Imager->new(xsize => 50, ysize => 50, channels => 3); $src3->box(filled => 1, xmax => 24, color => $c_red_full); $src3->box(filled => 1, xmin => 25, color => $c_blue_full); my $c_green_50 = Imager::Color->new(0, 255, 0, 127); my $src4 = Imager->new(xsize => 50, ysize => 50, channels => 4); $src4->box(filled => 1, xmax => 24, color => $c_blue_full); $src4->box(filled => 1, xmin => 25, color => $c_green_50); my @left_box = ( box => [ 25, 25, 49, 74 ] ); my @right_box = ( box => [ 50, 25, 74, 74 ] ); { # 1 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 1); $base->box(filled => 1, color => Imager::Color->new(64, 255, 0, 0)); my $work = $base->copy; ok($work->rubthrough(left => 25, top => 25, src => $src1), "rubthrough 1 to 1"); my $comp = $base->copy; $comp->box(filled => 1, color => $g_grey_full, @left_box); $comp->box(filled => 1, color => [ 0, 0, 0, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(left => 25, top => 25, src => $src2), "rubthrough 2 to 1"); $comp = $base->copy; $comp->box(filled => 1, @left_box, color => $g_grey_full); $comp->box(filled => 1, @right_box, color => [ 159, 0, 0, 0 ]); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(left => 25, top => 25, src => $src3), "rubthrough 3 to 1"); $comp = $base->copy; $comp->box(filled => 1, @left_box, color => [ 57, 255, 0, 0 ]); $comp->box(filled => 1, @right_box, color => [ 18, 255, 0, 0 ]); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(left => 25, top => 25, src => $src4), "rubthrough 4 to 1"); $comp = $base->copy; $comp->box(filled => 1, color => [ 18, 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 121, 255, 0, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); } { # 2 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 2); $base->box(filled => 1, color => [ 128, 128, 0, 0 ]); my $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src1), "rubthrough 1 to 2"); my $comp = $base->copy; $comp->box(filled => 1, color => $g_grey_full, @left_box); $comp->box(filled => 1, color => [ 0, 255, 0, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src2), "rubthrough 2 to 2"); $comp = $base->copy; $comp->box(filled => 1, color => $g_grey_full, @left_box); $comp->box(filled => 1, color => [ 213, 191, 0, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src3), "rubthrough 3 to 2"); $comp = $base->copy; $comp->box(filled => 1, color => [ 57, 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 18, 255, 0, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src4), "rubthrough 4 to 2"); $comp = $base->copy; $comp->box(filled => 1, color => [ 18, 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 162, 191, 0, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); } { # 3 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 3); $base->box(filled => 1, color => [ 128, 255, 0, 0 ]); my $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src1), "rubthrough 1 to 3"); my $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 0, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src2), "rubthrough 2 to 3"); $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 191, 255, 128, 255 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src3), "rubthrough 3 to 3"); $comp = $base->copy; $comp->box(filled => 1, color => [ 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 255 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src4), "rubthrough 4 to 3"); $comp = $base->copy; $comp->box(filled => 1, color => [ 0, 0, 255 ], @left_box); $comp->box(filled => 1, color => [ 64, 255, 0 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); } { # 4 channel output my $base = Imager->new(xsize => 100, ysize => 100, channels => 4); $base->box(filled => 1, color => [ 128, 255, 64, 128 ]); my $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src1), "rubthrough 1 to 4"); my $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 0, 255 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src2), "rubthrough 2 to 4"); $comp = $base->copy; $comp->box(filled => 1, color => [ 128, 128, 128, 255 ], @left_box); $comp->box(filled => 1, color => [ 213, 255, 192, 191 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src3), "rubthrough 3 to 4"); $comp = $base->copy; $comp->box(filled => 1, color => [ 255, 0, 0 ], @left_box); $comp->box(filled => 1, color => [ 0, 0, 255 ], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); $work = $base->copy; ok($work->rubthrough(top => 25, left => 25, src => $src4), "rubthrough 4 to 4"); $comp = $base->copy; $comp->box(filled => 1, color => $c_blue_full, @left_box); $comp->box(filled => 1, color => [ 43, 255, 21, 191], @right_box); is_image($work, $comp, "compare rubthrough target to expected"); } } sub color_cmp { my ($l, $r) = @_; my @l = $l->rgba; my @r = $r->rgba; print "# (",join(",", @l[0..2]),") <=> (",join(",", @r[0..2]),")\n"; return $l[0] <=> $r[0] || $l[1] <=> $r[1] || $l[2] <=> $r[2]; } sub iscolora { my ($c1, $c2, $msg) = @_; my $builder = Test::Builder->new; my @c1 = $c1->rgba; my @c2 = $c2->rgba; if (!$builder->ok($c1[0] == $c2[0] && $c1[1] == $c2[1] && $c1[2] == $c2[2] && $c1[3] == $c2[3], $msg)) { $builder->diag(< 124; -d "testout" or mkdir "testout"; Imager::init_log("testout/t61filters.log", 1); use Imager::Test qw(is_image_similar test_image is_image is_color4 is_fcolor4); # meant for testing the filters themselves my $imbase = test_image(); my $im_other = Imager->new(xsize=>150, ysize=>150); $im_other->box(xmin=>30, ymin=>60, xmax=>120, ymax=>90, filled=>1); test($imbase, {type=>'autolevels'}, 'testout/t61_autolev.ppm'); test($imbase, {type=>'autolevels_skew'}, 'testout/t61_autoskew.ppm'); test($imbase, {type=>'contrast', intensity=>0.5}, 'testout/t61_contrast.ppm'); # this one's kind of cool test($imbase, {type=>'conv', coef=>[ 0.3, 1, 0.3, ], }, 'testout/t61_conv_blur.ppm'); { my $work = $imbase->copy; ok(!Imager::i_conv($work->{IMG}, []), "conv should fail with empty array"); ok(!$work->filter(type => 'conv', coef => []), "check the conv OO intergave too"); is($work->errstr, "there must be at least one coefficient", "check conv error message"); } { my $work8 = $imbase->copy; ok(!$work8->filter(type => "conv", coef => "ABC"), "coef not an array"); } { my $work8 = $imbase->copy; ok(!$work8->filter(type => "conv", coef => [ -1, 2, -1 ]), "should fail if sum of coef is 0"); is($work8->errstr, "sum of coefficients is zero", "check message"); } { my $work8 = $imbase->copy; my $work16 = $imbase->to_rgb16; my $coef = [ -0.2, 1, -0.2 ]; ok($work8->filter(type => "conv", coef => $coef), "filter 8 bit image"); ok($work16->filter(type => "conv", , coef => $coef), "filter 16 bit image"); is_image_similar($work8, $work16, 80000, "8 and 16 bit conv match"); } { my $gauss = test($imbase, {type=>'gaussian', stddev=>5 }, 'testout/t61_gaussian.ppm'); my $imbase16 = $imbase->to_rgb16; my $gauss16 = test($imbase16, {type=>'gaussian', stddev=>5 }, 'testout/t61_gaussian16.ppm'); is_image_similar($gauss, $gauss16, 250000, "8 and 16 gaussian match"); } test($imbase, { type=>'gradgen', dist=>1, xo=>[ 10, 10, 120 ], yo=>[ 10, 140, 60 ], colors=> [ NC('#FF0000'), NC('#FFFF00'), NC('#00FFFF') ]}, 'testout/t61_gradgen.ppm'); test($imbase, {type=>'mosaic', size=>8}, 'testout/t61_mosaic.ppm'); test($imbase, {type=>'hardinvert'}, 'testout/t61_hardinvert.ppm'); { # invert - 8 bit my $im = Imager->new(xsize => 1, ysize => 1, channels => 4); ok($im, "make test image for invert test"); ok($im->setpixel(x => 0, y => 0, color => "000010C0"), "set a test pixel"); my $copy = $im->copy; ok($im->filter(type => "hardinvert"), "hardinvert it"); is_color4($im->getpixel(x => 0, y => 0), 255, 255, 0xEF, 0xC0, "check only colour inverted"); ok($copy->filter(type => "hardinvertall"), "hardinvertall copy"); is_color4($copy->getpixel(x => 0, y => 0), 255, 255, 0xEF, 0x3f, "check all inverted"); } { # invert - double image my $im = Imager->new(xsize => 1, ysize => 1, channels => 4, bits => "double"); ok($im, "make double test image for invert test"); ok($im->setpixel(x => 0, y => 0, color => Imager::Color::Float->new(0, 0, 0.125, 0.75)), "set a test pixel"); my $copy = $im->copy; ok($im->filter(type => "hardinvert"), "hardinvert it"); is_fcolor4($im->getpixel(x => 0, y => 0, type => "double"), 1.0, 1.0, 0.875, 0.75, 1e-5, "check only colour inverted"); ok($copy->filter(type => "hardinvertall"), "hardinvertall copy"); is_fcolor4($copy->getpixel(x => 0, y => 0, type =>"double"), 1.0, 1.0, 0.875, 0.25, 1e-5, "check all inverted"); } test($imbase, {type=>'noise'}, 'testout/t61_noise.ppm'); test($imbase, {type=>'radnoise'}, 'testout/t61_radnoise.ppm'); test($imbase, {type=>'turbnoise'}, 'testout/t61_turbnoise.ppm'); test($imbase, {type=>'bumpmap', bump=>$im_other, lightx=>30, lighty=>30}, 'testout/t61_bumpmap.ppm'); test($imbase, {type=>'bumpmap_complex', bump=>$im_other}, 'testout/t61_bumpmap_complex.ppm'); test($imbase, {type=>'postlevels', levels=>3}, 'testout/t61_postlevels.ppm'); test($imbase, {type=>'watermark', wmark=>$im_other }, 'testout/t61_watermark.ppm'); test($imbase, {type=>'fountain', xa=>75, ya=>75, xb=>85, yb=>30, repeat=>'triangle', #ftype=>'radial', super_sample=>'circle', ssample_param => 16, }, 'testout/t61_fountain.ppm'); use Imager::Fountain; my $f1 = Imager::Fountain->new; $f1->add(end=>0.2, c0=>NC(255, 0,0), c1=>NC(255, 255,0)); $f1->add(start=>0.2, c0=>NC(255,255,0), c1=>NC(0,0,255,0)); test($imbase, { type=>'fountain', xa=>20, ya=>130, xb=>130, yb=>20, #repeat=>'triangle', segments=>$f1 }, 'testout/t61_fountain2.ppm'); my $f2 = Imager::Fountain->new ->add(end=>0.5, c0=>NC(255,0,0), c1=>NC(255,0,0), color=>'hueup') ->add(start=>0.5, c0=>NC(255,0,0), c1=>NC(255,0,0), color=>'huedown'); #use Data::Dumper; #print Dumper($f2); test($imbase, { type=>'fountain', xa=>20, ya=>130, xb=>130, yb=>20, segments=>$f2 }, 'testout/t61_fount_hsv.ppm'); my $f3 = Imager::Fountain->read(gimp=>'testimg/gimpgrad'); ok($f3, "read gimpgrad"); test($imbase, { type=>'fountain', xa=>75, ya=>75, xb=>90, yb=>15, segments=>$f3, super_sample=>'grid', ftype=>'radial_square', combine=>'color' }, 'testout/t61_fount_gimp.ppm'); { # test new fountain with no parameters my $warn = ''; local $SIG{__WARN__} = sub { $warn .= "@_" }; my $f4 = Imager::Fountain->read(); ok(!$f4, "read with no parameters does nothing"); like($warn, qr/Nothing to do!/, "check the warning"); } { # test with missing file my $warn = ''; local $SIG{__WARN__} = sub { $warn .= "@_" }; my $f = Imager::Fountain->read(gimp => "no-such-file"); ok(!$f, "try to read a fountain defintion that doesn't exist"); is($warn, "", "should be no warning"); like(Imager->errstr, qr/^Cannot open no-such-file: /, "check message"); } SKIP: { my $fh = IO::File->new("testimg/gimpgrad", "r"); ok($fh, "opened gradient") or skip "Couldn't open gradient: $!", 1; my $f = Imager::Fountain->read(gimp => $fh); ok($f, "read gradient from file handle"); } { # not a gradient my $f = Imager::Fountain->read(gimp => "t/400-filter/010-filters.t"); ok(!$f, "fail to read non-gradient"); is(Imager->errstr, "t/400-filter/010-filters.t is not a GIMP gradient file", "check error message"); } { # an invalid gradient file my $f = Imager::Fountain->read(gimp => "testimg/gradbad.ggr"); ok(!$f, "fail to read bad gradient (bad seg count)"); is(Imager->errstr, "testimg/gradbad.ggr is missing the segment count", "check error message"); } { # an invalid gradient file my $f = Imager::Fountain->read(gimp => "testimg/gradbad2.ggr"); ok(!$f, "fail to read bad gradient (bad segment)"); is(Imager->errstr, "Bad segment definition", "check error message"); } test($imbase, { type=>'unsharpmask', stddev=>2.0 }, 'testout/t61_unsharp.ppm'); test($imbase, {type=>'conv', coef=>[ -1, 3, -1, ], }, 'testout/t61_conv_sharp.ppm'); test($imbase, { type=>'nearest_color', dist=>1, xo=>[ 10, 10, 120 ], yo=>[ 10, 140, 60 ], colors=> [ NC('#FF0000'), NC('#FFFF00'), NC('#00FFFF') ]}, 'testout/t61_nearest.ppm'); # Regression test: the checking of the segment type was incorrect # (the comparison was checking the wrong variable against the wrong value) my $f4 = [ [ 0, 0.5, 1, NC(0,0,0), NC(255,255,255), 5, 0 ] ]; test($imbase, {type=>'fountain', xa=>75, ya=>75, xb=>90, yb=>15, segments=>$f4, super_sample=>'grid', ftype=>'linear', combine=>'color' }, 'testout/t61_regress_fount.ppm'); my $im2 = $imbase->copy; $im2->box(xmin=>20, ymin=>20, xmax=>40, ymax=>40, color=>'FF0000', filled=>1); $im2->write(file=>'testout/t61_diff_base.ppm'); my $im3 = Imager->new(xsize=>150, ysize=>150, channels=>3); $im3->box(xmin=>20, ymin=>20, xmax=>40, ymax=>40, color=>'FF0000', filled=>1); my $diff = $imbase->difference(other=>$im2); ok($diff, "got difference image"); SKIP: { skip(1, "missing comp or diff image") unless $im3 && $diff; is(Imager::i_img_diff($im3->{IMG}, $diff->{IMG}), 0, "compare test image and diff image"); } # newer versions of gimp add a line to the gradient file my $name; my $f5 = Imager::Fountain->read(gimp=>'testimg/newgimpgrad.ggr', name => \$name); ok($f5, "read newer gimp gradient") or print "# ",Imager->errstr,"\n"; is($name, "imager test gradient", "check name read correctly"); $f5 = Imager::Fountain->read(gimp=>'testimg/newgimpgrad.ggr'); ok($f5, "check we handle case of no name reference correctly") or print "# ",Imager->errstr,"\n"; # test writing of gradients ok($f2->write(gimp=>'testout/t61grad1.ggr'), "save a gradient") or print "# ",Imager->errstr,"\n"; undef $name; my $f6 = Imager::Fountain->read(gimp=>'testout/t61grad1.ggr', name=>\$name); ok($f6, "read what we wrote") or print "# ",Imager->errstr,"\n"; ok(!defined $name, "we didn't set the name, so shouldn't get one"); # try with a name ok($f2->write(gimp=>'testout/t61grad2.ggr', name=>'test gradient'), "write gradient with a name") or print "# ",Imager->errstr,"\n"; undef $name; my $f7 = Imager::Fountain->read(gimp=>'testout/t61grad2.ggr', name=>\$name); ok($f7, "read what we wrote") or print "# ",Imager->errstr,"\n"; is($name, "test gradient", "check the name matches"); # we attempt to convert color names in segments to segments now { my @segs = ( [ 0.0, 0.5, 1.0, '000000', '#FFF', 0, 0 ], ); my $im = Imager->new(xsize=>50, ysize=>50); ok($im->filter(type=>'fountain', segments => \@segs, xa=>0, ya=>30, xb=>49, yb=>30), "fountain with color names instead of objects in segments"); my $left = $im->getpixel('x'=>0, 'y'=>20); ok(color_close($left, Imager::Color->new(0,0,0)), "check black converted correctly"); my $right = $im->getpixel('x'=>49, 'y'=>20); ok(color_close($right, Imager::Color->new(255,255,255)), "check white converted correctly"); # check that invalid color names are handled correctly my @segs2 = ( [ 0.0, 0.5, 1.0, '000000', 'FxFxFx', 0, 0 ], ); ok(!$im->filter(type=>'fountain', segments => \@segs2, xa=>0, ya=>30, xb=>49, yb=>30), "fountain with invalid color name"); cmp_ok($im->errstr, '=~', 'No color named', "check error message"); } { # test simple gradient creation my @colors = map Imager::Color->new($_), qw/white blue red/; my $s = Imager::Fountain->simple(positions => [ 0, 0.3, 1.0 ], colors => \@colors); ok($s, "made simple gradient"); my $start = $s->[0]; is($start->[0], 0, "check start of first correct"); is_color4($start->[3], 255, 255, 255, 255, "check color at start"); } { # simple gradient error modes { my $warn = ''; local $SIG{__WARN__} = sub { $warn .= "@_" }; my $s = Imager::Fountain->simple(); ok(!$s, "no parameters to simple()"); like($warn, qr/Nothing to do/); } { my $s = Imager::Fountain->simple(positions => [ 0, 1 ], colors => [ NC(0, 0, 0) ]); ok(!$s, "mismatch of positions and colors fails"); is(Imager->errstr, "positions and colors must be the same size", "check message"); } { my $s = Imager::Fountain->simple(positions => [ 0 ], colors => [ NC(0, 0, 0) ]); ok(!$s, "not enough positions"); is(Imager->errstr, "not enough segments"); } } { my $im = Imager->new(xsize=>100, ysize=>100); # build the gradient the hard way - linear from black to white, # then back again my @simple = ( [ 0, 0.25, 0.5, 'black', 'white', 0, 0 ], [ 0.5. 0.75, 1.0, 'white', 'black', 0, 0 ], ); # across my $linear = $im->filter(type => "fountain", ftype => 'linear', repeat => 'sawtooth', xa => 0, ya => $im->getheight / 2, xb => $im->getwidth - 1, yb => $im->getheight / 2); ok($linear, "linear fountain sample"); # around my $revolution = $im->filter(type => "fountain", ftype => 'revolution', xa => $im->getwidth / 2, ya => $im->getheight / 2, xb => $im->getwidth / 2, yb => 0); ok($revolution, "revolution fountain sample"); # out from the middle my $radial = $im->filter(type => "fountain", ftype => 'radial', xa => $im->getwidth / 2, ya => $im->getheight / 2, xb => $im->getwidth / 2, yb => 0); ok($radial, "radial fountain sample"); } { # try a simple custom filter that uses the Perl image interface sub perl_filt { my %args = @_; my $im = $args{imager}; my $channels = $args{channels}; unless (@$channels) { $channels = [ reverse(0 .. $im->getchannels-1) ]; } my @chans = @$channels; push @chans, 0 while @chans < 4; for my $y (0 .. $im->getheight-1) { my $row = $im->getsamples(y => $y, channels => \@chans); $im->setscanline(y => $y, pixels => $row); } } Imager->register_filter(type => 'perl_test', callsub => \&perl_filt, defaults => { channels => [] }, callseq => [ qw/imager channels/ ]); test($imbase, { type => 'perl_test' }, 'testout/t61perl.ppm'); } { # check the difference method out my $im1 = Imager->new(xsize => 3, ysize => 2); $im1->box(filled => 1, color => '#FF0000'); my $im2 = $im1->copy; $im1->setpixel(x => 1, 'y' => 0, color => '#FF00FF'); $im2->setpixel(x => 1, 'y' => 0, color => '#FF01FF'); $im1->setpixel(x => 2, 'y' => 0, color => '#FF00FF'); $im2->setpixel(x => 2, 'y' => 0, color => '#FF02FF'); my $diff1 = $im1->difference(other => $im2); my $cmp1 = Imager->new(xsize => 3, ysize => 2, channels => 4); $cmp1->setpixel(x => 1, 'y' => 0, color => '#FF01FF'); $cmp1->setpixel(x => 2, 'y' => 0, color => '#FF02FF'); is_image($diff1, $cmp1, "difference() - check image with mindist 0"); my $diff2 = $im1->difference(other => $im2, mindist => 1); my $cmp2 = Imager->new(xsize => 3, ysize => 2, channels => 4); $cmp2->setpixel(x => 2, 'y' => 0, color => '#FF02FF'); is_image($diff2, $cmp2, "difference() - check image with mindist 1"); } { # and again with large samples my $im1 = Imager->new(xsize => 3, ysize => 2, bits => 'double'); $im1->box(filled => 1, color => '#FF0000'); my $im2 = $im1->copy; $im1->setpixel(x => 1, 'y' => 0, color => '#FF00FF'); $im2->setpixel(x => 1, 'y' => 0, color => '#FF01FF'); $im1->setpixel(x => 2, 'y' => 0, color => '#FF00FF'); $im2->setpixel(x => 2, 'y' => 0, color => '#FF02FF'); my $diff1 = $im1->difference(other => $im2); my $cmp1 = Imager->new(xsize => 3, ysize => 2, channels => 4); $cmp1->setpixel(x => 1, 'y' => 0, color => '#FF01FF'); $cmp1->setpixel(x => 2, 'y' => 0, color => '#FF02FF'); is_image($diff1, $cmp1, "difference() - check image with mindist 0 - large samples"); my $diff2 = $im1->difference(other => $im2, mindist => 1.1); my $cmp2 = Imager->new(xsize => 3, ysize => 2, channels => 4); $cmp2->setpixel(x => 2, 'y' => 0, color => '#FF02FF'); is_image($diff2, $cmp2, "difference() - check image with mindist 1.1 - large samples"); } { my $empty = Imager->new; ok(!$empty->filter(type => "hardinvert"), "can't filter an empty image"); is($empty->errstr, "filter: empty input image", "check error message"); ok(!$empty->difference(other => $imbase), "can't difference empty image"); is($empty->errstr, "difference: empty input image", "check error message"); ok(!$imbase->difference(other => $empty), "can't difference against empty image"); is($imbase->errstr, "difference: empty input image (other image)", "check error message"); } sub test { my ($in, $params, $out) = @_; my $copy = $in->copy; if (ok($copy->filter(%$params), $params->{type})) { ok($copy->write(file=>$out), "write $params->{type}") or print "# ",$copy->errstr,"\n"; } else { diag($copy->errstr); SKIP: { skip("couldn't filter", 1); } } $copy; } sub color_close { my ($c1, $c2) = @_; my @c1 = $c1->rgba; my @c2 = $c2->rgba; for my $i (0..2) { if (abs($c1[$i]-$c2[$i]) > 2) { return 0; } } return 1; } libimager-perl-1.004+dfsg.orig/t/850-thread/0000755000175000017500000000000012617614576017624 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/850-thread/110-log.t0000644000175000017500000000452012263740601021054 0ustar gregoagregoa#!perl -w use strict; # avoiding this prologue would be nice, but it seems to be unavoidable, # see "It is also important to note ..." in perldoc threads use Config; my $loaded_threads; BEGIN { if ($Config{useithreads} && $] > 5.008007) { $loaded_threads = eval { require threads; threads->import; 1; }; } } use Test::More; $Config{useithreads} or plan skip_all => "can't test Imager's threads support with no threads"; $] > 5.008007 or plan skip_all => "require a perl with CLONE_SKIP to test Imager's threads support"; $loaded_threads or plan skip_all => "couldn't load threads"; $INC{"Devel/Cover.pm"} and plan skip_all => "threads and Devel::Cover don't get along"; use Imager; -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t080log1.log") or plan skip_all => "Cannot open log file: " . Imager->errstr; plan tests => 3; Imager->log("main thread a\n"); my $t1 = threads->create ( sub { Imager->log("child thread a\n"); Imager->open_log(log => "testout/t080log2.log") or die "Cannot open second log file: ", Imager->errstr; Imager->log("child thread b\n"); sleep(1); Imager->log("child thread c\n"); sleep(1); 1; } ); Imager->log("main thread b\n"); sleep(1); Imager->log("main thread c\n"); ok($t1->join, "join child thread"); Imager->log("main thread d\n"); Imager->close_log(); my %log1 = parse_log("testout/t080log1.log"); my %log2 = parse_log("testout/t080log2.log"); my @log1 = ( "main thread a", "main thread b", "child thread a", "main thread c", "main thread d", ); my @log2 = ( "child thread b", "child thread c", ); is_deeply(\%log1, { map {; $_ => 1 } @log1 }, "check messages in main thread log"); is_deeply(\%log2, { map {; $_ => 1 } @log2 }, "check messages in child thread log"); # grab the messages from the given log sub parse_log { my ($filename) = @_; open my $fh, "<", $filename or die "Cannot open log file $filename: $!"; my %lines; while (<$fh>) { chomp; my ($date, $time, $file_line, $level, $message) = split ' ', $_, 5; $lines{$message} = 1; } delete $lines{"Imager - log started (level = 1)"}; delete $lines{"Imager $Imager::VERSION starting"}; return %lines; } END { unlink "testout/t080log1.log", "testout/t080log2.log" unless $ENV{IMAGER_KEEP_FILES}; } libimager-perl-1.004+dfsg.orig/t/850-thread/100-error.t0000644000175000017500000000325612263740601021430 0ustar gregoagregoa#!perl -w use strict; # avoiding this prologue would be nice, but it seems to be unavoidable, # see "It is also important to note ..." in perldoc threads use Config; my $loaded_threads; BEGIN { if ($Config{useithreads} && $] > 5.008007) { $loaded_threads = eval { require threads; threads->import; 1; }; } } use Test::More; $Config{useithreads} or plan skip_all => "can't test Imager's threads support with no threads"; $] > 5.008007 or plan skip_all => "require a perl with CLONE_SKIP to test Imager's threads support"; $loaded_threads or plan skip_all => "couldn't load threads"; $INC{"Devel/Cover.pm"} and plan skip_all => "threads and Devel::Cover don't get along"; use Imager; # test that the error contexts are separate under threads plan tests => 11; Imager->open_log(log => "testout/t081error.log"); Imager::i_clear_error(); Imager::i_push_error(0, "main thread a"); my @threads; for my $tid (1..5) { my $t1 = threads->create ( sub { my $id = shift; Imager::i_push_error(0, "$id: child thread a"); sleep(1+rand(4)); Imager::i_push_error(1, "$id: child thread b"); is_deeply([ Imager::i_errors() ], [ [ "$id: child thread b", 1 ], [ "$id: child thread a", 0 ], ], "$id: check errors in child"); 1; }, $tid ); push @threads, [ $tid, $t1 ]; } Imager::i_push_error(1, "main thread b"); for my $thread (@threads) { my ($id, $t1) = @$thread; ok($t1->join, "join child $id"); } Imager::i_push_error(2, "main thread c"); is_deeply([ Imager::i_errors() ], [ [ "main thread c", 2 ], [ "main thread b", 1 ], [ "main thread a", 0 ], ], "check errors in parent"); libimager-perl-1.004+dfsg.orig/t/850-thread/010-base.t0000644000175000017500000000503512263740601021206 0ustar gregoagregoa#!perl use strict; use Imager; use Imager::Color::Float; use Imager::Fill; use Config; my $loaded_threads; BEGIN { if ($Config{useithreads} && $] > 5.008007) { $loaded_threads = eval { require threads; threads->import; 1; }; } } use Test::More; $Config{useithreads} or plan skip_all => "can't test Imager's threads support with no threads"; $] > 5.008007 or plan skip_all => "require a perl with CLONE_SKIP to test Imager's threads support"; $loaded_threads or plan skip_all => "couldn't load threads"; $INC{"Devel/Cover.pm"} and plan skip_all => "threads and Devel::Cover don't get along"; # https://rt.cpan.org/Ticket/Display.html?id=65812 # https://github.com/schwern/test-more/issues/labels/Test-Builder2#issue/100 $Test::More::VERSION =~ /^2\.00_/ and plan skip_all => "threads are hosed in 2.00_06 and presumably all 2.00_*"; plan tests => 13; my $thread = threads->create(sub { 1; }); ok($thread->join, "join first thread"); # these are all, or contain, XS allocated objects, if we don't handle # CLONE requests, or provide a CLONE_SKIP, we'll probably see a # double-free, one from the thread, and the other from the main line # of control. # # So make one of each my $im = Imager->new(xsize => 10, ysize => 10); my $c = Imager::Color->new(0, 0, 0); # make some sort of color ok($c, "made the color"); my $cf = Imager::Color::Float->new(0, 0, 0); ok($cf, "made the float color"); my $hl; SKIP: { Imager::Internal::Hlines::testing() or skip "no hlines visible to test", 1; $hl = Imager::Internal::Hlines::new(0, 100, 0, 100); ok($hl, "made the hlines"); } my $io = Imager::io_new_bufchain(); ok($io, "made the io"); my $tt; SKIP: { $Imager::formats{tt} or skip("No TT font support", 1); $tt = Imager::Font->new(type => "tt", file => "fontfiles/dodge.ttf"); ok($tt, "made the font"); } my $ft2; SKIP: { $Imager::formats{ft2} or skip "No FT2 support", 1; $ft2 = Imager::Font->new(type => "ft2", file => "fontfiles/dodge.ttf"); ok($ft2, "made ft2 font"); } my $fill = Imager::Fill->new(solid => $c); ok($fill, "made the fill"); my $t2 = threads->create ( sub { ok(!UNIVERSAL::isa($im->{IMG}, "Imager::ImgRaw"), "the low level image object should become unblessed"); ok(!$im->_valid_image, "image no longer considered valid"); is($im->errstr, "images do not cross threads", "check error message"); 1; } ); ok($t2->join, "join second thread"); #print STDERR $im->{IMG}, "\n"; ok(UNIVERSAL::isa($im->{IMG}, "Imager::ImgRaw"), "but the object should be fine in the main thread"); libimager-perl-1.004+dfsg.orig/t/900-util/0000755000175000017500000000000012617614576017326 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/900-util/060-extutil.t0000644000175000017500000000153412263740601021501 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 6; use File::Spec; { # RT 37353 local @INC = @INC; unshift @INC, File::Spec->catdir('blib', 'lib'); unshift @INC, File::Spec->catdir('blib', 'arch'); require Imager::ExtUtils; my $path = Imager::ExtUtils->base_dir; ok(File::Spec->file_name_is_absolute($path), "check dirs absolute") or print "# $path\n"; } { # includes my $includes = Imager::ExtUtils->includes; ok($includes =~ s/^-I//, "has the -I"); ok(-e File::Spec->catfile($includes, "imext.h"), "found a header"); } { # typemap my $typemap = Imager::ExtUtils->typemap; ok($typemap, "got a typemap path"); ok(-f $typemap, "it exists"); open TYPEMAP, "< $typemap"; my $tm_content = do { local $/; ; }; close TYPEMAP; cmp_ok($tm_content, '=~', "Imager::Color\\s+T_PTROBJ", "it seems to be the right file"); } libimager-perl-1.004+dfsg.orig/t/900-util/040-limit.t0000644000175000017500000000445212263740601021121 0ustar gregoagregoa#!perl -w use strict; # avoiding this prologue would be nice, but it seems to be unavoidable, # see "It is also important to note ..." in perldoc threads use Config; my $loaded_threads; BEGIN { if ($Config{useithreads} && $] > 5.008007) { $loaded_threads = eval { require threads; threads->import; 1; }; } } use Test::More; $Config{useithreads} or plan skip_all => "can't test Imager's threads support with no threads"; $] > 5.008007 or plan skip_all => "require a perl with CLONE_SKIP to test Imager's threads support"; $loaded_threads or plan skip_all => "couldn't load threads"; $INC{"Devel/Cover.pm"} and plan skip_all => "threads and Devel::Cover don't get along"; use Imager; # test that image file limits are localized to a thread plan tests => 31; Imager->open_log(log => "testout/t082limit.log"); ok(Imager->set_file_limits(width => 10, height => 10, bytes => 300), "set limits to 10, 10, 300"); ok(Imager->check_file_limits(width => 10, height => 10), "successful check limits in parent"); ok(!Imager->check_file_limits(width => 10, height => 10, sample_size => 2), "failed check limits in parent"); my @threads; for my $tid (1..5) { my $t1 = threads->create ( sub { my $id = shift; my $dlimit = $tid * 5; my $blimit = $dlimit * $dlimit * 3; ok(Imager->set_file_limits(width => $dlimit, height => $dlimit, bytes => $blimit), "$tid: set limits to $dlimit x $dlimit, $blimit bytes"); ok(Imager->check_file_limits(width => $dlimit, height => $dlimit), "$tid: successful check $dlimit x $dlimit"); ok(!Imager->check_file_limits(width => $dlimit, height => $dlimit, sample_size => 2), "$tid: failed check $dlimit x $dlimit, ssize 2"); is_deeply([ Imager->get_file_limits ], [ $dlimit, $dlimit, $blimit ], "check limits are still $dlimit x $dlimit , $blimit bytes"); }, $tid ); push @threads, [ $tid, $t1 ]; } for my $thread (@threads) { my ($id, $t1) = @$thread; ok($t1->join, "join child $id"); } ok(Imager->check_file_limits(width => 10, height => 10), "test we still pass"); ok(!Imager->check_file_limits(width => 10, height => 10, sample_size => 2), "test we still fail"); is_deeply([ Imager->get_file_limits ], [ 10, 10, 300 ], "check original main thread limits still set"); libimager-perl-1.004+dfsg.orig/t/900-util/050-matrix.t0000644000175000017500000001001512460670607021307 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 25; use Imager; use constant EPSILON => 0.000001; BEGIN { use_ok('Imager::Matrix2d', ':handy') } my $id = Imager::Matrix2d->identity; ok(almost_equal($id, [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]), "identity matrix"); my $trans = Imager::Matrix2d->translate('x'=>10, 'y'=>-11); ok(almost_equal($trans, [ 1, 0, 10, 0, 1, -11, 0, 0, 1 ]), "translate matrix"); my $trans_x = Imager::Matrix2d->translate(x => 10); ok(almost_equal($trans_x, [ 1, 0, 10, 0, 1, 0, 0, 0, 1 ]), "translate just x"); my $trans_y = Imager::Matrix2d->translate('y' => 11); ok(almost_equal($trans_y, [ 1, 0, 0, 0, 1, 11, 0, 0, 1 ]), "translate just y"); my $rotate = Imager::Matrix2d->rotate(degrees=>90); ok(almost_equal($rotate, [ 0, -1, 0, 1, 0, 0, 0, 0, 1 ]), "rotate matrix"); my $shear = Imager::Matrix2d->shear('x'=>0.2, 'y'=>0.3); ok(almost_equal($shear, [ 1, 0.2, 0, 0.3, 1, 0, 0, 0, 1 ]), "shear matrix"); my $scale = Imager::Matrix2d->scale('x'=>1.2, 'y'=>0.8); ok(almost_equal($scale, [ 1.2, 0, 0, 0, 0.8, 0, 0, 0, 1 ]), "scale matrix"); my $custom = Imager::Matrix2d->matrix(1, 0, 0, 0, 1, 0, 0, 0, 1); ok(almost_equal($custom, [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]), "custom matrix"); my $trans_called; $rotate = Imager::Matrix2d::Test->rotate(degrees=>90, x=>50); ok($trans_called, "translate called on rotate with just x"); $trans_called = 0; $rotate = Imager::Matrix2d::Test->rotate(degrees=>90, 'y'=>50); ok($trans_called, "translate called on rotate with just y"); ok(!Imager::Matrix2d->matrix(), "bad custom matrix"); is(Imager->errstr, "9 coefficients required", "check error"); { my @half = ( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 1 ); my @quart = ( 0, 0.25, 0, 1, 0, 0, 0, 0, 1 ); my $half_matrix = Imager::Matrix2d->matrix(@half); my $quart_matrix = Imager::Matrix2d->matrix(@quart); my $result = $half_matrix * $quart_matrix; is_deeply($half_matrix * \@quart, $result, "mult by unblessed matrix"); is_deeply(\@half * $quart_matrix, $result, "mult with unblessed matrix"); my $half_three = Imager::Matrix2d->matrix(1.5, 0, 0, 0, 1.5, 0, 0, 0, 3); is_deeply($half_matrix * 3, $half_three, "mult by three"); is_deeply(3 * $half_matrix, $half_three, "mult with three"); { # check error handling - bad ref type my $died = !eval { my $foo = $half_matrix * +{}; 1; }; ok($died, "mult by hash ref died"); like($@, qr/multiply by array ref or number/, "check message"); } { # check error handling - bad array $@ = ''; my $died = !eval { my $foo = $half_matrix * [ 1 .. 8 ]; 1; }; ok($died, "mult by short array ref died"); like($@, qr/9 elements required in array ref/, "check message"); } { # check error handling - bad value $@ = ''; my $died = !eval { my $foo = $half_matrix * "abc"; 1; }; ok($died, "mult by bad scalar died"); like($@, qr/multiply by array ref or number/, "check message"); } } { # rt #99959 Imager::Matrix2d->rotate about (x, y) bug my $rm = Imager::Matrix2d->rotate(degrees => 180, x => 10, y => 5); my ($rx, $ry) = $rm->transform(0, 0); ok(abs($rx - 20) < EPSILON, "x from rotate (0,0) around (10, 5)") or print "# x = $rx\n"; ok(abs($ry - 10) < EPSILON, "y from rotate (0,0) around (10, 5)") or print "# y = $ry\n"; } sub almost_equal { my ($m1, $m2) = @_; for my $i (0..8) { abs($m1->[$i] - $m2->[$i]) < 0.00001 or return undef; } return 1; } # this is used to ensure translate() is called correctly by rotate package Imager::Matrix2d::Test; use vars qw(@ISA); BEGIN { @ISA = qw(Imager::Matrix2d); } sub translate { my ($class, %opts) = @_; ++$trans_called; return $class->SUPER::translate(%opts); } libimager-perl-1.004+dfsg.orig/t/900-util/020-error.t0000644000175000017500000000202012263740601021117 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 7; BEGIN { use_ok("Imager", ":all") } -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t05error.log"); # try to read an invalid pnm file open FH, "< testimg/junk.ppm" or die "Cannot open testin/junk: $!"; binmode(FH); my $IO = Imager::io_new_fd(fileno(FH)); my $im = i_readpnm_wiol($IO, -1); SKIP:{ ok(!$im, "read of junk.ppm should have failed") or skip("read didn't fail!", 5); my @errors = Imager::i_errors(); is(scalar @errors, 1, "got the errors") or skip("no errors to check", 4); SKIP: { my $error0 = $errors[0]; is(ref $error0, "ARRAY", "entry 0 is an array ref") or skip("entry 0 not an array", 3); is(scalar @$error0, 2, "entry 0 has 2 elements") or skip("entry 0 doesn't have enough elements", 2); is($error0->[0], "while skipping to height", "check message"); is($error0->[1], "0", "error code should be 0"); } } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t05error.log"; } libimager-perl-1.004+dfsg.orig/t/900-util/030-log.t0000644000175000017500000000150012263740601020552 0ustar gregoagregoa#!perl -w use strict; use Imager; use Test::More tests => 6; my $log_name = "testout/t95log.log"; my $log_message = "test message 12345"; SKIP: { skip("Logging not build", 3) unless Imager::i_log_enabled(); ok(Imager->open_log(log => $log_name), "open log") or diag("Open log: " . Imager->errstr); ok(-f $log_name, "file is there"); Imager->log($log_message); Imager->close_log(); my $data = ''; if (open LOG, "< $log_name") { $data = do { local $/; }; close LOG; } like($data, qr/\Q$log_message/, "check message made it to the log"); } SKIP: { skip("Logging built", 3) if Imager::i_log_enabled(); ok(!Imager->open_log(log => $log_name), "should be no logfile"); is(Imager->errstr, "Logging disabled", "check error message"); ok(!-f $log_name, "file shouldn't be there"); } libimager-perl-1.004+dfsg.orig/t/900-util/060-hlines.t0000644000175000017500000000541612263740601021270 0ustar gregoagregoa#!perl -w use strict; use Test::More; use Imager; # this script tests an internal set of functions for Imager, they # aren't intended to be used at the perl level. # these functions aren't present in all Imager builds unless (Imager::Internal::Hlines::testing()) { plan skip_all => 'Imager not built to run this test'; } plan tests => 17; my $hline = Imager::Internal::Hlines::new(0, 100, 0, 100); my $base_text = 'start_y: 0 limit_y: 100 start_x: 0 limit_x: 100'; ok($hline, "made hline"); is($hline->dump, "$base_text\n", "check values"); $hline->add(5, -5, 7); is($hline->dump, <add(5, 8, 4); is($hline->dump, <add(5, 3, 3); is($hline->dump, <add(5, 2, 6); is($hline->dump, <add(6, -5, 5); is($hline->dump, $current, "check (6, -5, 5) not added"); $hline->add(6, 100, 5); is($hline->dump, $current, "check (6, 100, 5) not added"); $hline->add(-1, 5, 2); is($hline->dump, $current, "check (-1, 5, 2) not added"); $hline->add(100, 5, 2); is($hline->dump, $current, "check (10, 5, 2) not added"); # overlapped add check $hline->add(6, 2, 6); $hline->add(6, 3, 4); is($hline->dump, <add(7, $i*2, 1); } is($hline->dump, <add(7, 1, 39); is($hline->dump, <add(51, 45, 10); $hline->add(51, 55, 4); is($hline->dump, <add(52, 90, 5); $hline->add(52, 87, 5); is($hline->dump, <new(xsize => 50, ysize => 60); my $hl = Imager::Internal::Hlines::new_img($im->{IMG}); ok($hl, "make hlines object from image"); is($hl->dump, "start_y: 0 limit_y: 60 start_x: 0 limit_x: 50\n", "check initialized properly"); } libimager-perl-1.004+dfsg.orig/t/900-util/010-test.t0000644000175000017500000000500112263740601020746 0ustar gregoagregoa#!perl -w use strict; use Imager; use Imager::Test qw(test_image test_image_16 test_image_mono test_image_gray test_image_gray_16 test_image_double test_image_named); use Test::More tests => 60; # test Imager::Test for my $named (0, 1) { my $named_desc = $named ? " (by name)" : ""; { my $im = $named ? test_image_named("basic") : test_image(); ok($im, "got basic test image$named_desc"); is($im->type, "direct", "check basic image type"); is($im->getchannels, 3, "check basic image channels"); is($im->bits, 8, "check basic image bits"); ok(!$im->is_bilevel, "check basic isn't mono"); } { my $im = $named ? test_image_named("basic16") : test_image_16(); ok($im, "got 16-bit basic test image$named_desc"); is($im->type, "direct", "check 16-bit basic image type"); is($im->getchannels, 3, "check 16-bit basic image channels"); is($im->bits, 16, "check 16-bit basic image bits"); ok(!$im->is_bilevel, "check 16-bit basic isn't mono"); } { my $im = $named ? test_image_named("basic_double") : test_image_double(); ok($im, "got double basic test image$named_desc"); is($im->type, "direct", "check double basic image type"); is($im->getchannels, 3, "check double basic image channels"); is($im->bits, "double", "check double basic image bits"); ok(!$im->is_bilevel, "check double basic isn't mono"); } { my $im = $named ? test_image_named("gray") : test_image_gray(); ok($im, "got gray test image$named_desc"); is($im->type, "direct", "check gray image type"); is($im->getchannels, 1, "check gray image channels"); is($im->bits, 8, "check gray image bits"); ok(!$im->is_bilevel, "check gray isn't mono"); $im->write(file => "testout/t03gray.pgm"); } { my $im = $named ? test_image_named("gray16") : test_image_gray_16(); ok($im, "got gray test image$named_desc"); is($im->type, "direct", "check 16-bit gray image type"); is($im->getchannels, 1, "check 16-bit gray image channels"); is($im->bits, 16, "check 16-bit gray image bits"); ok(!$im->is_bilevel, "check 16-bit isn't mono"); $im->write(file => "testout/t03gray16.pgm"); } { my $im = $named ? test_image_named("mono") : test_image_mono(); ok($im, "got mono image$named_desc"); is($im->type, "paletted", "check mono image type"); is($im->getchannels, 3, "check mono image channels"); is($im->bits, 8, "check mono image bits"); ok($im->is_bilevel, "check mono is mono"); $im->write(file => "testout/t03mono.pbm"); } } libimager-perl-1.004+dfsg.orig/t/000-load.t0000644000175000017500000000071412263740601017430 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 15; use_ok('Imager'); use_ok('Imager::Font'); use_ok('Imager::Color'); use_ok('Imager::Color::Float'); use_ok('Imager::Color::Table'); use_ok('Imager::Matrix2d'); use_ok('Imager::ExtUtils'); use_ok('Imager::Expr'); use_ok('Imager::Expr::Assem'); use_ok('Imager::Font::BBox'); use_ok('Imager::Font::Wrap'); use_ok('Imager::Fountain'); use_ok('Imager::Regops'); use_ok('Imager::Test'); use_ok('Imager::Transform'); libimager-perl-1.004+dfsg.orig/t/300-transform/0000755000175000017500000000000012617614576020356 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/300-transform/500-trans.t0000644000175000017500000000242112263740601022155 0ustar gregoagregoa#!perl -w use strict; use Test::More; use Imager; eval "use Affix::Infix2Postfix; 1;" or plan skip_all => "No Affix::Infix2Postfix"; plan tests => 8; #$Imager::DEBUG=1; -d "testout" or mkdir "testout"; Imager->open_log('log'=>'testout/t55trans.log'); my $img=Imager->new(); SKIP: { ok($img, "make image object") or skip("can't make image object", 5); ok($img->open(file=>'testimg/scale.ppm',type=>'pnm'), "read sample image") or skip("couldn't load test image", 4); SKIP: { my $nimg=$img->transform(xexpr=>'x',yexpr=>'y+10*sin((x+y)/10)'); ok($nimg, "do transformation") or skip ( "warning ".$img->errstr, 1 ); # xopcodes=>[qw( x y Add)],yopcodes=>[qw( x y Sub)],parm=>[] ok($nimg->write(type=>'pnm',file=>'testout/t55.ppm'), "save to file"); } SKIP: { my $nimg=$img->transform(xexpr=>'x+0.1*y+5*sin(y/10.0+1.57)', yexpr=>'y+10*sin((x+y-0.785)/10)'); ok($nimg, "more complex transform") or skip("couldn't make image", 1); ok($nimg->write(type=>'pnm',file=>'testout/t55b.ppm'), "save to file"); } } { my $empty = Imager->new; ok(!$empty->transform(xexpr => "x", yexpr => "y"), "fail to transform an empty image"); is($empty->errstr, "transform: empty input image", "check error message"); } libimager-perl-1.004+dfsg.orig/t/300-transform/620-infix.t0000644000175000017500000000175012263740601022152 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 7; BEGIN { use_ok('Imager::Expr') } # only test this if Parse::RecDescent was loaded successfully SKIP: { Imager::Expr->type_registered('expr') or skip("Imager::Expr::Infix not available", 6); my $opts = {expr=>'z=0.8;return hsv(x/w*360,y/h,z)', variables=>[ qw(x y) ], constants=>{h=>100,w=>100}}; my $expr = Imager::Expr->new($opts); ok($expr, "make infix expression") or skip("Could not make infix expression", 5); my $code = $expr->dumpcode(); my @code = split /\n/,$code; #print $code; ok($code[-1] =~ /:\s+ret/, "final op a ret"); ok(grep(/:\s+mult.*360/, @code), "mult by 360 found"); # strength reduction converts these to mults #print grep(/:\s+div.*x/, @code) ? "ok 5\n" : "not ok 5\n"; #print grep(/:\s+div.*y/, @code) ? "ok 6\n" : "not ok 6\n"; ok(grep(/:\s+mult.*x/, @code), "mult by x found"); ok(grep(/:\s+mult.*y/, @code), "mult by y found"); ok(grep(/:\s+hsv.*0\.8/, @code), "hsv op found"); } libimager-perl-1.004+dfsg.orig/t/300-transform/010-scale.t0000644000175000017500000002314512263740601022117 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 232; BEGIN { use_ok(Imager=>':all') } use Imager::Test qw(is_image is_color4 is_image_similar); -d "testout" or mkdir "testout"; Imager::init('log'=>'testout/t40scale.log'); my $img=Imager->new(); ok($img->open(file=>'testimg/scale.ppm',type=>'pnm'), "load test image") or print "# ",$img->errstr,"\n"; my $scaleimg=$img->scale(scalefactor=>0.25) or print "# ",$img->errstr,"\n"; ok($scaleimg, "scale it (good mode)"); ok($scaleimg->write(file=>'testout/t40scale1.ppm',type=>'pnm'), "save scaled image") or print "# ",$img->errstr,"\n"; $scaleimg=$img->scale(scalefactor=>0.25,qtype=>'preview'); ok($scaleimg, "scale it (preview)") or print "# ",$img->errstr,"\n"; ok($scaleimg->write(file=>'testout/t40scale2.ppm',type=>'pnm'), "write preview scaled image") or print "# ",$img->errstr,"\n"; $scaleimg = $img->scale(scalefactor => 0.25, qtype => 'mixing'); ok($scaleimg, "scale it (mixing)") or print "# ", $img->errstr, "\n"; ok($scaleimg->write(file=>'testout/t40scale3.ppm', type=>'pnm'), "write mixing scaled image") or print "# ", $img->errstr, "\n"; { # double image scaling with mixing, since it has code to handle it my $dimg = Imager->new(xsize => $img->getwidth, ysize => $img->getheight, channels => $img->getchannels, bits => 'double'); ok($dimg, "create double/sample image"); $dimg->paste(src => $img); $scaleimg = $dimg->scale(scalefactor => 0.25, qtype => 'mixing'); ok($scaleimg, "scale it (mixing, double)"); ok($scaleimg->write(file => 'testout/t40mixdbl.ppm', type => 'pnm'), "write double/mixing scaled image"); is($scaleimg->bits, 'double', "got the right image type as output"); # hscale only, mixing $scaleimg = $dimg->scale(xscalefactor => 0.33, yscalefactor => 1.0, qtype => 'mixing'); ok($scaleimg, "scale it (hscale, mixing, double)"); is($scaleimg->getheight, $dimg->getheight, "same height"); ok($scaleimg->write(file => 'testout/t40hscdmix.ppm', type => 'pnm'), "save it"); # vscale only, mixing $scaleimg = $dimg->scale(xscalefactor => 1.0, yscalefactor => 0.33, qtype => 'mixing'); ok($scaleimg, "scale it (vscale, mixing, double)"); is($scaleimg->getwidth, $dimg->getwidth, "same width"); ok($scaleimg->write(file => 'testout/t40vscdmix.ppm', type => 'pnm'), "save it"); } { # check for a warning when scale() is called in void context my $warning; local $SIG{__WARN__} = sub { $warning = "@_"; my $printed = $warning; $printed =~ s/\n$//; $printed =~ s/\n/\n\#/g; print "# ",$printed, "\n"; }; $img->scale(scalefactor=>0.25); cmp_ok($warning, '=~', qr/void/, "check warning"); cmp_ok($warning, '=~', qr/scale\.t/, "check filename"); $warning = ''; $img->scaleX(scalefactor=>0.25); cmp_ok($warning, '=~', qr/void/, "check warning"); cmp_ok($warning, '=~', qr/scale\.t/, "check filename"); $warning = ''; $img->scaleY(scalefactor=>0.25); cmp_ok($warning, '=~', qr/void/, "check warning"); cmp_ok($warning, '=~', qr/scale\.t/, "check filename"); } { # https://rt.cpan.org/Ticket/Display.html?id=7467 # segfault in Imager 0.43 # make sure scale() doesn't let us make an image zero pixels high or wide # it does this by making the given axis as least 1 pixel high my $out = $img->scale(scalefactor=>0.00001); is($out->getwidth, 1, "min scale width"); is($out->getheight, 1, "min scale height"); $out = $img->scale(scalefactor=>0.00001, qtype => 'preview'); is($out->getwidth, 1, "min scale width (preview)"); is($out->getheight, 1, "min scale height (preview)"); $out = $img->scale(scalefactor=>0.00001, qtype => 'mixing'); is($out->getwidth, 1, "min scale width (mixing)"); is($out->getheight, 1, "min scale height (mixing)"); } { # error handling - NULL image my $im = Imager->new; ok(!$im->scale(scalefactor => 0.5), "try to scale empty image"); is($im->errstr, "scale: empty input image", "check error message"); # scaleX/scaleY ok(!$im->scaleX(scalefactor => 0.5), "try to scaleX empty image"); is($im->errstr, "scaleX: empty input image", "check error message"); ok(!$im->scaleY(scalefactor => 0.5), "try to scaleY empty image"); is($im->errstr, "scaleY: empty input image", "check error message"); } { # invalid qtype value my $im = Imager->new(xsize => 100, ysize => 100); ok(!$im->scale(scalefactor => 0.5, qtype=>'unknown'), "unknown qtype"); is($im->errstr, "invalid value for qtype parameter", "check error message"); # invalid type value ok(!$im->scale(xpixels => 10, ypixels=>50, type=>"unknown"), "unknown type"); is($im->errstr, "invalid value for type parameter", "check error message"); } SKIP: { # Image::Math::Constrain support eval "require Image::Math::Constrain;"; $@ and skip "optional module Image::Math::Constrain not installed", 3; my $constrain = Image::Math::Constrain->new(20, 100); my $im = Imager->new(xsize => 160, ysize => 96); my $result = $im->scale(constrain => $constrain); ok($result, "successful scale with Image::Math::Constrain"); is($result->getwidth, 20, "check result width"); is($result->getheight, 12, "check result height"); } { # scale size checks my $im = Imager->new(xsize => 160, ysize => 96); # some random size scale_test($im, 'scale', 80, 48, "48 x 48 def type", xpixels => 48, ypixels => 48); scale_test($im, 'scale', 80, 48, "48 x 48 max type", xpixels => 48, ypixels => 48, type => 'max'); scale_test($im, 'scale', 80, 48, "80 x 80 min type", xpixels => 80, ypixels => 80, type => 'min'); scale_test($im, 'scale', 80, 48, "no scale parameters (default to 0.5 scalefactor)"); scale_test($im, 'scale', 120, 72, "0.75 scalefactor", scalefactor => 0.75); scale_test($im, 'scale', 80, 48, "80 width", xpixels => 80); scale_test($im, 'scale', 120, 72, "72 height", ypixels => 72); # new scaling parameters in 0.54 scale_test($im, 'scale', 80, 48, "xscale 0.5", xscalefactor => 0.5); scale_test($im, 'scale', 80, 48, "yscale 0.5", yscalefactor => 0.5); scale_test($im, 'scale', 40, 48, "xscale 0.25 yscale 0.5", xscalefactor => 0.25, yscalefactor => 0.5); scale_test($im, 'scale', 160, 48, "xscale 1.0 yscale 0.5", xscalefactor => 1.0, yscalefactor => 0.5); scale_test($im, 'scale', 160, 48, "xpixels 160 ypixels 48 type nonprop", xpixels => 160, ypixels => 48, type => 'nonprop'); scale_test($im, 'scale', 160, 96, "xpixels 160 ypixels 96", xpixels => 160, ypixels => 96); scale_test($im, 'scale', 80, 96, "xpixels 80 ypixels 96 type nonprop", xpixels => 80, ypixels => 96, type => 'nonprop'); # scaleX scale_test($im, 'scaleX', 80, 96, "defaults"); scale_test($im, 'scaleX', 40, 96, "0.25 scalefactor", scalefactor => 0.25); scale_test($im, 'scaleX', 120, 96, "pixels 120", pixels => 120); # scaleY scale_test($im, 'scaleY', 160, 48, "defaults"); scale_test($im, 'scaleY', 160, 192, "2.0 scalefactor", scalefactor => 2.0); scale_test($im, 'scaleY', 160, 144, "pixels 144", pixels => 144); } { # check proper alpha handling for mixing my $im = Imager->new(xsize => 40, ysize => 40, channels => 4); $im->box(filled => 1, color => 'C0C0C0'); my $rot = $im->rotate(degrees => -4) or die; $rot = $rot->to_rgb16; my $sc = $rot->scale(qtype => 'mixing', xpixels => 40); my $out = Imager->new(xsize => $sc->getwidth, ysize => $sc->getheight); $out->box(filled => 1, color => 'C0C0C0'); my $cmp = $out->copy; $out->rubthrough(src => $sc); is_image($out, $cmp, "check we get the right image after scaling (mixing)"); # we now set alpha=0 pixels to zero on scaling is_color4($sc->getpixel('x' => 39, 'y' => 39), 0, 0, 0, 0, "check we set alpha=0 pixels to zero on scaling"); } { # check proper alpha handling for default scaling my $im = Imager->new(xsize => 40, ysize => 40, channels => 4); $im->box(filled => 1, color => 'C0C0C0'); my $rot = $im->rotate(degrees => -4) or die; my $sc = $rot->scale(qtype => "normal", xpixels => 40); my $out = Imager->new(xsize => $sc->getwidth, ysize => $sc->getheight); $out->box(filled => 1, color => 'C0C0C0'); my $cmp = $out->copy; $out->rubthrough(src => $sc); is_image_similar($out, $cmp, 100, "check we get the right image after scaling (normal)"); # we now set alpha=0 pixels to zero on scaling is_color4($sc->getpixel('x' => 39, 'y' => 39), 0, 0, 0, 0, "check we set alpha=0 pixels to zero on scaling"); } { # scale_calculate my $im = Imager->new(xsize => 100, ysize => 120); is_deeply([ $im->scale_calculate(scalefactor => 0.5) ], [ 0.5, 0.5, 50, 60 ], "simple scale_calculate"); is_deeply([ Imager->scale_calculate(scalefactor => 0.5) ], [], "failed scale_calculate"); is_deeply([ Imager->scale_calculate(width => 120, height => 150, xpixels => 240) ], [ 2.0, 2.0, 240, 300 ], "class method scale_factor"); } { # passing a reference for scaling parameters should fail # RT #35172 my $im = Imager->new(xsize => 100, ysize => 100); ok(!$im->scale(xpixels => {}), "can't use a reference as a size"); cmp_ok($im->errstr, '=~', "xpixels parameter cannot be a reference", "check error message"); } sub scale_test { my ($in, $method, $exp_width, $exp_height, $note, @parms) = @_; print "# $note: @parms\n"; for my $qtype (qw(normal preview mixing)) { SKIP: { my $scaled = $in->$method(@parms, qtype => $qtype); ok($scaled, "$method $note qtype $qtype") or skip("failed to scale", 2); is($scaled->getwidth, $exp_width, "check width"); is($scaled->getheight, $exp_height, "check height"); } } } libimager-perl-1.004+dfsg.orig/t/300-transform/630-assem.t0000644000175000017500000000142512263740601022145 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 6; BEGIN { use_ok('Imager::Expr::Assem') } SKIP: { my $expr = Imager::Expr->new ({assem=><[qw(x y)], constants=>{totalcount=>5} }); ok($expr, "compile simple assembler") or do { print "# ", Imager::Expr->error, "\n"; skip("didn't compile", 4); }; my $code = $expr->dumpcode(); my @code = split /\n/, $code; ok($code[-1] =~ /:\s+ret/, "last op is a ret"); ok($code[0] =~ /:\s+set/, "first op is a set"); ok($code[1] =~ /:\s+getp1/, "next is a getp1"); ok($code[3] =~ /:\s+lt/, "found comparison"); } libimager-perl-1.004+dfsg.orig/t/300-transform/050-convert.t0000644000175000017500000001170312263740601022511 0ustar gregoagregoa#!perl -w use strict; use Imager qw(:all :handy); use Test::More tests => 31; use Imager::Test qw(test_colorf_gpix is_fcolor1 is_fcolor3); -d "testout" or mkdir "testout"; Imager::init("log"=>'testout/t67convert.log'); my $imbase = Imager::ImgRaw::new(200,300,3); # first a basic test, make sure the basic things happen ok # make a 1 channel image from the above (black) image # but with 1 as the 'extra' value SKIP: { my $im_white = i_convert($imbase, [ [ 0, 0, 0, 1 ] ]); skip("convert to white failed", 3) unless ok($im_white, "convert to white"); my ($w, $h, $ch) = i_img_info($im_white); # the output image should now have one channel is($ch, 1, "one channel image now"); # should have the same width and height ok($w == 200 && $h == 300, "check converted size is the same"); # should be a white image now, let's check my $c = Imager::i_get_pixel($im_white, 20, 20); my @c = $c->rgba; print "# @c\n"; is($c[0], 255, "check image is white"); } # test the highlevel interface # currently this requires visual inspection of the output files my $im = Imager->new; SKIP: { skip("could not load scale.ppm", 3) unless $im->read(file=>'testimg/scale.ppm'); my $out = $im->convert(preset=>'gray'); ok($out, "convert preset gray"); ok($out->write(file=>'testout/t67_gray.ppm', type=>'pnm'), "save grey image"); $out = $im->convert(preset=>'blue'); ok($out, "convert preset blue"); ok($out->write(file=>'testout/t67_blue.ppm', type=>'pnm'), "save blue image"); } # test against 16-bit/sample images { SKIP: { my $imbase16 = Imager::i_img_16_new(200, 200, 3); my $im16targ = i_convert($imbase16, [ [ 0, 0, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ]); ok($im16targ, "convert 16/bit sample image") or skip("could not convert 16-bit image", 2); # image should still be 16-bit is(Imager::i_img_bits($im16targ), 16, "Image still 16-bit/sample"); # make sure that it's roughly red test_colorf_gpix($im16targ, 0, 0, NCF(1, 0, 0), 0.001, "image roughly red"); } SKIP: { my $imbase16 = Imager->new(xsize => 10, ysize => 10, bits => 16); ok($imbase16->setpixel (x => 5, y => 2, color => Imager::Color::Float->new(0.1, 0.2, 0.3)), "set a sample pixel"); my $c1 = $imbase16->getpixel(x => 5, y => 2, type => "float"); is_fcolor3($c1, 0.1, 0.2, 0.3, "check it was set") or print "#", join(",", $c1->rgba), "\n"; my $targ16 = $imbase16->convert(matrix => [ [ 0.05, 0.15, 0.01, 0.5 ] ]); ok($targ16, "convert another 16/bit sample image") or skip("could not convert", 3); is($targ16->getchannels, 1, "convert should be 1 channel"); is($targ16->bits, 16, "and 16-bits"); my $c = $targ16->getpixel(x => 5, y => 2, type => "float"); is_fcolor1($c, 0.538, 1/32768, "check grey value"); } } # test against palette based images my $impal = Imager::i_img_pal_new(200, 300, 3, 256); my $black = NC(0, 0, 0); my $blackindex = Imager::i_addcolors($impal, $black); ok($blackindex, "add black to paletted"); for my $y (0..299) { Imager::i_ppal($impal, 0, $y, ($blackindex) x 200); } SKIP: { my $impalout = i_convert($impal, [ [ 0, 0, 0, 0 ], [ 0, 0, 0, 1 ], [ 0, 0, 0, 0 ] ]); skip("could not convert paletted", 3) unless ok($impalout, "convert paletted"); is(Imager::i_img_type($impalout), 1, "image still paletted"); is(Imager::i_colorcount($impalout), 1, "still only one colour"); my $c = Imager::i_getcolors($impalout, $blackindex); ok($c, "get color from palette"); my @ch = $c->rgba; print "# @ch\n"; ok($ch[0] == 0 && $ch[1] == 255 && $ch[2] == 0, "colour is as expected"); } { # http://rt.cpan.org/NoAuth/Bug.html?id=9672 # methods that return a new image should warn in void context my $warning; local $SIG{__WARN__} = sub { $warning = "@_"; my $printed = $warning; $printed =~ s/\n$//; $printed =~ s/\n/\n\#/g; print "# ",$printed, "\n"; }; my $img = Imager->new(xsize=>10, ysize=>10); $img->convert(preset=>"grey"); cmp_ok($warning, '=~', 'void', "correct warning"); cmp_ok($warning, '=~', 'convert\\.t', "correct file"); } { # http://rt.cpan.org/NoAuth/Bug.html?id=28492 # convert() doesn't preserve image sample size my $im = Imager->new(xsize => 20, ysize => 20, channels => 3, bits => 'double'); is($im->bits, 'double', 'check source bits'); my $conv = $im->convert(preset => 'grey'); is($conv->bits, 'double', 'make sure result has extra bits'); } { # http://rt.cpan.org/NoAuth/Bug.html?id=79922 # Segfault in convert with bad params my $im = Imager->new(xsize => 10, ysize => 10); ok(!$im->convert(matrix => [ 10, 10, 10 ]), "this would crash"); is($im->errstr, "convert: invalid matrix: element 0 is not an array ref", "check the error message"); } { my $empty = Imager->new; ok(!$empty->convert(preset => "addalpha"), "can't convert an empty image"); is($empty->errstr, "convert: empty input image", "check error message"); } libimager-perl-1.004+dfsg.orig/t/300-transform/040-crop.t0000644000175000017500000001253112263740601021773 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 66; use Imager; use Imager::Test qw(test_image); #$Imager::DEBUG=1; -d "testout" or mkdir "testout"; Imager::init('log'=>'testout/t65crop.log'); my $img=Imager->new() || die "unable to create image object\n"; ok($img, "created image ph"); SKIP: { skip("couldn't load source image", 2) unless ok($img->open(file=>'testimg/scale.ppm',type=>'pnm'), "loaded source"); my $nimg = $img->crop(top=>10, left=>10, bottom=>25, right=>25); ok($nimg, "got an image"); ok($nimg->write(file=>"testout/t65.ppm"), "save to file"); } { # https://rt.cpan.org/Ticket/Display.html?id=7578 # make sure we get the right type of image on crop my $src = Imager->new(xsize=>50, ysize=>50, channels=>2, bits=>16); is($src->getchannels, 2, "check src channels"); is($src->bits, 16, "check src bits"); my $out = $src->crop(left=>10, right=>40, top=>10, bottom=>40); is($out->getchannels, 2, "check out channels"); is($out->bits, 16, "check out bits"); } { # https://rt.cpan.org/Ticket/Display.html?id=7578 print "# try it for paletted too\n"; my $src = Imager->new(xsize=>50, ysize=>50, channels=>3, type=>'paletted'); # make sure color index zero is defined so there's something to copy $src->addcolors(colors=>[Imager::Color->new(0,0,0)]); is($src->type, 'paletted', "check source type"); my $out = $src->crop(left=>10, right=>40, top=>10, bottom=>40); is($out->type, 'paletted', 'check output type'); } { # https://rt.cpan.org/Ticket/Display.html?id=7581 # crop() documentation says width/height takes precedence, but is unclear # from looking at the existing code, setting width/height will go from # the left of the image, even if left/top are provided, despite the # sample in the docs # Let's make sure that things happen as documented my $src = test_image(); # make sure we get what we want is($src->getwidth, 150, "src width"); is($src->getheight, 150, "src height"); # the test data is: # - description # - hash ref containing args to crop() # - expected left, top, right, bottom values # we call crop using the given arguments then call it using the # hopefully stable left/top/right/bottom/arguments # this is kind of lame, but I don't want to include a rewritten # crop in this file my @tests = ( [ "basic", { left=>10, top=>10, right=>70, bottom=>80 }, 10, 10, 70, 80, ], [ "middle", { width=>50, height=>50 }, 50, 50, 100, 100, ], [ "lefttop", { left=>20, width=>70, top=>30, height=>90 }, 20, 30, 90, 120, ], [ "bottomright", { right=>140, width=>50, bottom=>130, height=>60 }, 90, 70, 140, 130, ], [ "acrossmiddle", { top=>40, bottom=>110 }, 0, 40, 150, 110, ], [ "downmiddle", { left=>40, right=>110 }, 40, 0, 110, 150, ], [ "rightside", { left=>80, }, 80, 0, 150, 150, ], [ "leftside", { right=>40 }, 0, 0, 40, 150, ], [ "topside", { bottom=>40, }, 0, 0, 150, 40, ], [ "bottomside", { top=>90 }, 0, 90, 150, 150, ], [ "overright", { left=>100, right=>200 }, 100, 0, 150, 150, ], [ "overtop", { bottom=>50, height=>70 }, 0, 0, 150, 50, ], [ "overleft", { right=>30, width=>60 }, 0, 0, 30, 150, ], [ "overbottom", { top=>120, height=>60 }, 0, 120, 150, 150, ], ); for my $test (@tests) { my ($desc, $args, $left, $top, $right, $bottom) = @$test; my $out = $src->crop(%$args); ok($out, "got output for $desc"); my $cmp = $src->crop(left=>$left, top=>$top, right=>$right, bottom=>$bottom); ok($cmp, "got cmp for $desc"); # make sure they're the same my $diff = Imager::i_img_diff($out->{IMG}, $cmp->{IMG}); is($diff, 0, "difference should be 0 for $desc"); } } { # https://rt.cpan.org/Ticket/Display.html?id=7581 # previously we didn't check that the result had some pixels # make sure we do my $src = test_image(); ok(!$src->crop(left=>50, right=>50), "nothing across"); cmp_ok($src->errstr, '=~', qr/resulting image would have no content/, "and message"); ok(!$src->crop(top=>60, bottom=>60), "nothing down"); cmp_ok($src->errstr, '=~', qr/resulting image would have no content/, "and message"); } { # http://rt.cpan.org/NoAuth/Bug.html?id=9672 my $warning; local $SIG{__WARN__} = sub { $warning = "@_"; my $printed = $warning; $printed =~ s/\n$//; $printed =~ s/\n/\n\#/g; print "# ",$printed, "\n"; }; my $img = Imager->new(xsize=>10, ysize=>10); $img->crop(left=>5); cmp_ok($warning, '=~', 'void', "correct warning"); cmp_ok($warning, '=~', 'crop\\.t', "correct file"); } { my $src = test_image(); ok(!$src->crop( top=>1000, bottom=>1500, left=>0, right=>100 ), "outside of image" ); cmp_ok($src->errstr, '=~', qr/outside of the image/, "and message"); ok(!$src->crop( top=>100, bottom=>1500, left=>1000, right=>1500 ), "outside of image" ); cmp_ok($src->errstr, '=~', qr/outside of the image/, "and message"); } { my $empty = Imager->new; ok(!$empty->crop(left => 10), "can't crop an empty image"); is($empty->errstr, "crop: empty input image", "check message"); } libimager-perl-1.004+dfsg.orig/t/300-transform/020-combine.t0000644000175000017500000000613012263740601022440 0ustar gregoagregoa#!perl -w use strict; use Imager; use Test::More tests => 31; use Imager::Test qw/test_image test_image_double is_image/; my $test_im = test_image; my $test_im_dbl = test_image_double; { # split out channels and put it back together my $red = Imager->combine(src => [ $test_im ]); ok($red, "extracted the red channel"); is($red->getchannels, 1, "red should be a single channel"); my $green = Imager->combine(src => [ $test_im ], channels => [ 1 ]); ok($green, "extracted the green channel"); is($green->getchannels, 1, "green should be a single channel"); my $blue = $test_im->convert(preset => "blue"); ok($blue, "extracted blue (via convert)"); # put them back together my $combined = Imager->combine(src => [ $red, $green, $blue ]); is($combined->getchannels, 3, "check we got a three channel image"); is_image($combined, $test_im, "presto! check it's the same"); } { # no src ok(!Imager->combine(), "no src"); is(Imager->errstr, "src parameter missing", "check message"); } { # bad image error my $im = Imager->new; ok(!Imager->combine(src => [ $im ]), "empty image"); is(Imager->errstr, "combine: empty input image (src->[0])", "check message"); } { # not an image my $im = {}; ok(!Imager->combine(src => [ $im ]), "not an image"); is(Imager->errstr, "src must contain image objects", "check message"); } { # no images ok(!Imager->combine(src => []), "no images"); is(Imager->errstr, "At least one image must be supplied", "check message"); } { # too many images ok(!Imager->combine(src => [ ($test_im) x 5 ]), "too many source images"); is(Imager->errstr, "Maximum of 4 channels, you supplied 5", "check message"); } { # negative channel ok(!Imager->combine(src => [ $test_im ], channels => [ -1 ]), "negative channel"); is(Imager->errstr, "Channel numbers must be zero or positive", "check message"); } { # channel too high ok(!Imager->combine(src => [ $test_im ], channels => [ 3 ]), "too high channel"); is(Imager->errstr, "Channel 3 for image 0 is too high (3 channels)", "check message"); } { # make sure we get the higher of the bits my $out = Imager->combine(src => [ $test_im, $test_im_dbl ]); ok($out, "make from 8 and double/sample images"); is($out->bits, "double", "check output bits"); } { # check high-bit processing # split out channels and put it back together my $red = Imager->combine(src => [ $test_im_dbl ]); ok($red, "extracted the red channel"); is($red->getchannels, 1, "red should be a single channel"); my $green = Imager->combine(src => [ $test_im_dbl ], channels => [ 1 ]); ok($green, "extracted the green channel"); is($green->getchannels, 1, "green should be a single channel"); my $blue = $test_im_dbl->convert(preset => "blue"); ok($blue, "extracted blue (via convert)"); # put them back together my $combined = Imager->combine(src => [ $red, $green, $blue ]); is($combined->getchannels, 3, "check we got a three channel image"); is_image($combined, $test_im_dbl, "presto! check it's the same"); is($combined->bits, "double", "and we got a double image output"); } libimager-perl-1.004+dfsg.orig/t/300-transform/600-trans2.t0000644000175000017500000001317112263740601022244 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 40; BEGIN { use_ok('Imager'); } use Imager::Test qw(is_color3); -d "testout" or mkdir "testout"; Imager::init('log'=>'testout/t58trans2.log'); my $im1 = Imager->new(); $im1->open(file=>'testimg/penguin-base.ppm', type=>'pnm') || die "Cannot read image"; my $im2 = Imager->new(); $im2->open(file=>'testimg/scale.ppm',type=>'pnm') || die "Cannot read testimg/scale.ppm"; # error handling my $opts = { rpnexpr=>'x x 10 / sin 10 * y + get1' }; my $im3 = Imager::transform2($opts); ok(!$im3, "returned an image on error"); ok(defined($Imager::ERRSTR), "No error message on failure"); # image synthesis my $im4 = Imager::transform2({ width=>300, height=>300, rpnexpr=>'x y cx cy distance !d y cy - x cx - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a2 cy * 3.1416 / 1 @a2 sin 1 + 2 / hsv'}); ok($im4, "synthesis failed"); if ($im4) { $im4->write(type=>'pnm', file=>'testout/t56a.ppm') || die "Cannot write testout/t56a.ppm"; } # image distortion my $im5 = Imager::transform2({ rpnexpr=>'x x 10 / sin 10 * y + getp1' }, $im1); ok($im5, "image distortion"); if ($im5) { $im5->write(type=>'pnm', file=>'testout/t56b.ppm') || die "Cannot write testout/t56b.ppm"; } # image combination $opts = { rpnexpr=>'x h / !rat x w2 % y h2 % getp2 !pat x y getp1 @rat * @pat 1 @rat - * +' }; my $im6 = Imager::transform2($opts,$im1,$im2); ok($im6, "image combination"); if ($im6) { $im6->write(type=>'pnm', file=>'testout/t56c.ppm') || die "Cannot write testout/t56c.ppm"; } # alpha $opts = { rpnexpr => '0 0 255 x y + w h + 2 - / 255 * rgba', channels => 4, width => 50, height => 50, }; my $im8 = Imager::transform2($opts); ok($im8, "alpha output"); my $c = $im8->getpixel(x=>0, 'y'=>0); is(($c->rgba)[3], 0, "zero alpha"); $c = $im8->getpixel(x=>49, 'y'=>49); is(($c->rgba)[3], 255, "max alpha"); $opts = { rpnexpr => 'x 1 + log 50 * y 1 + log 50 * getp1' }; my $im9 = Imager::transform2($opts, $im1); ok($im9, "log function"); if ($im9) { $im9->write(type=>'pnm', file=>'testout/t56-9.ppm'); } # op tests sub op_test($$$$$$); print "# op tests\n"; op_test('7F0000', <new; my $good = Imager->new(xsize => 1, ysize => 1); ok(!Imager::transform2({ rpnexpr => "x y getp1" }, $good, $empty), "can't transform an empty image"); is(Imager->errstr, "transform2: empty input image (input image 2)", "check error message"); } use Imager::Transform; # some simple tests print "# Imager::Transform\n"; my @funcs = Imager::Transform->list; ok(@funcs, "funcs"); my $tran = Imager::Transform->new($funcs[0]); ok($tran, "got tranform"); ok($tran->describe() eq Imager::Transform->describe($funcs[0]), "description"); # look for a function that takes inputs (at least one does) my @needsinputs = grep Imager::Transform->new($_)->inputs, @funcs; # make sure they're my @inputs = Imager::Transform->new($needsinputs[0])->inputs; ok($inputs[0]{desc}, "input description"); # at some point I might want to test the actual transformations # check lower level error handling my $im7 = Imager::transform2({rpnexpr=>'x y getp2', width=>100, height=>100}); ok(!$im7, "expected failure on accessing invalid image"); print "# ", Imager->errstr, "\n"; ok(Imager->errstr =~ /not enough images/, "didn't get expected error"); sub op_test ($$$$$$) { my ($in_color, $code, $r, $g, $b, $comment) = @_; my $im = Imager->new(xsize => 1, ysize => 1); $im->setpixel(x => 0, y => 0, color => $in_color); SKIP: { my $out = Imager::transform2({ rpnexpr => $code }, $im); unless ($out) { fail("$comment: could not compile $code - ".Imager->errstr); return; } my $found = $out->getpixel(x => 0, y => 0); is_color3($found, $r, $g, $b, $comment); } } libimager-perl-1.004+dfsg.orig/t/300-transform/030-copyflip.t0000644000175000017500000002304312263740601022654 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 95; use Imager; use Imager::Test qw(is_color3 is_image is_imaged test_image_double test_image isnt_image is_image_similar); #$Imager::DEBUG=1; -d "testout" or mkdir "testout"; Imager::init('log'=>'testout/t64copyflip.log'); my $img=Imager->new() or die "unable to create image object\n"; $img->open(file=>'testimg/scale.ppm',type=>'pnm'); my $nimg = $img->copy(); ok($nimg, "copy returned something"); # test if ->copy() works my $diff = Imager::i_img_diff($img->{IMG}, $nimg->{IMG}); is_image($img, $nimg, "copy matches source"); { my $empty = Imager->new; ok(!$empty->copy, "fail to copy an empty image"); is($empty->errstr, "copy: empty input image", "check error message"); } # test if ->flip(dir=>'h')->flip(dir=>'h') doesn't alter the image $nimg->flip(dir=>"h")->flip(dir=>"h"); is_image($nimg, $img, "double horiz flipped matches original"); # test if ->flip(dir=>'v')->flip(dir=>'v') doesn't alter the image $nimg->flip(dir=>"v")->flip(dir=>"v"); is_image($nimg, $img, "double vertically flipped image matches original"); # test if ->flip(dir=>'h')->flip(dir=>'v') is same as ->flip(dir=>'hv') $nimg->flip(dir=>"v")->flip(dir=>"h")->flip(dir=>"hv");; is_image($img, $nimg, "check flip with hv matches flip v then flip h"); { my $empty = Imager->new; ok(!$empty->flip(dir => "v"), "fail to flip an empty image"); is($empty->errstr, "flip: empty input image", "check error message"); } { my $imsrc = test_image_double; my $imcp = $imsrc->copy; is_imaged($imsrc, $imcp, "copy double image"); $imcp->flip(dir=>"v")->flip(dir=>"v"); is_imaged($imsrc, $imcp, "flip v twice"); $imcp->flip(dir=>"h")->flip(dir=>"h"); is_imaged($imsrc, $imcp, "flip h twice"); $imcp->flip(dir=>"h")->flip(dir=>"v")->flip(dir=>"hv"); is_imaged($imsrc, $imcp, "flip h,v,hv twice"); } { my $impal = test_image()->to_paletted; my $imcp = $impal->copy; is($impal->type, "paletted", "check paletted test image is"); is($imcp->type, "paletted", "check copy test image is paletted"); ok($impal->flip(dir => "h"), "flip paletted h"); isnt_image($impal, $imcp, "check it changed"); ok($impal->flip(dir => "v"), "flip paletted v"); ok($impal->flip(dir => "hv"), "flip paletted hv"); is_image($impal, $imcp, "should be back to original image"); is($impal->type, "paletted", "and still paletted"); } rot_test($img, 90, 4); rot_test($img, 180, 2); rot_test($img, 270, 4); rot_test($img, 0, 1); my $pimg = $img->to_paletted(); rot_test($pimg, 90, 4); rot_test($pimg, 180, 2); rot_test($pimg, 270, 4); rot_test($pimg, 0, 1); my $timg = $img->rotate(right=>90)->rotate(right=>270); is(Imager::i_img_diff($img->{IMG}, $timg->{IMG}), 0, "check rotate 90 then 270 matches original"); $timg = $img->rotate(right=>90)->rotate(right=>180)->rotate(right=>90); is(Imager::i_img_diff($img->{IMG}, $timg->{IMG}), 0, "check rotate 90 then 180 then 90 matches original"); # this could use more tests my $rimg = $img->rotate(degrees=>10); ok($rimg, "rotation by 10 degrees gave us an image"); if (!$rimg->write(file=>"testout/t64_rot10.ppm")) { print "# Cannot save: ",$rimg->errstr,"\n"; } # rotate with background $rimg = $img->rotate(degrees=>10, back=>Imager::Color->new(builtin=>'red')); ok($rimg, "rotate with background gave us an image"); if (!$rimg->write(file=>"testout/t64_rot10_back.ppm")) { print "# Cannot save: ",$rimg->errstr,"\n"; } { # rotate with text background my $rimg = $img->rotate(degrees => 45, back => '#FF00FF'); ok($rimg, "rotate with background as text gave us an image"); # check the color set correctly my $c = $rimg->getpixel(x => 0, 'y' => 0); is_deeply([ 255, 0, 255 ], [ ($c->rgba)[0, 1, 2] ], "check background set correctly"); # check error handling for background color $rimg = $img->rotate(degrees => 45, back => "some really unknown color"); ok(!$rimg, "should fail due to bad back color"); cmp_ok($img->errstr, '=~', "^No color named ", "check error message"); } SKIP: { # rotate in double mode my $dimg = $img->to_rgb16; my $rimg = $dimg->rotate(degrees => 10); ok($rimg, "rotate 16-bit image gave us an image") or skip("could not rotate", 3); ok($rimg->write(file => "testout/t64_rotf10.ppm", pnm_write_wide_data => 1), "save wide data rotated") or diag($rimg->errstr); # with a background color my $rimgb = $dimg->rotate(degrees => 10, back => "#FF8000"); ok($rimgb, "rotate 16-bit image with back gave us an image") or skip("could not rotate", 1); ok($rimgb->write(file => "testout/t64_rotfb10.ppm", pnm_write_wide_data => 1), "save wide data rotated") or diag($rimgb->errstr); } { # rotate in paletted mode my $rimg = $pimg->rotate(degrees => 10); ok($rimg, "rotated paletted image 10 degrees"); ok($rimg->write(file => "testout/t64_rotp10.ppm"), "save paletted rotated") or diag($rimg->errstr); } my $trimg = $img->matrix_transform(matrix=>[ 1.2, 0, 0, 0, 1, 0, 0, 0, 1]); ok($trimg, "matrix_transform() returned an image"); $trimg->write(file=>"testout/t64_trans.ppm") or print "# Cannot save: ",$trimg->errstr,"\n"; $trimg = $img->matrix_transform(matrix=>[ 1.2, 0, 0, 0, 1, 0, 0, 0, 1], back=>Imager::Color->new(builtin=>'blue')); ok($trimg, "matrix_transform() with back returned an image"); $trimg->write(file=>"testout/t64_trans_back.ppm") or print "# Cannot save: ",$trimg->errstr,"\n"; { my $empty = Imager->new; ok(!$empty->matrix_transform(matrix => [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]), "can't transform an empty image"); is($empty->errstr, "matrix_transform: empty input image", "check error message"); } sub rot_test { my ($src, $degrees, $count) = @_; my $cimg = $src->copy(); my $in; for (1..$count) { $in = $cimg; $cimg = $cimg->rotate(right=>$degrees) or last; } SKIP: { ok($cimg, "got a rotated image") or skip("no image to check", 4); my $diff = Imager::i_img_diff($src->{IMG}, $cimg->{IMG}); is($diff, 0, "check it matches source") or skip("didn't match", 3); # check that other parameters match is($src->type, $cimg->type, "type check"); is($src->bits, $cimg->bits, "bits check"); is($src->getchannels, $cimg->getchannels, "channels check"); } } { # http://rt.cpan.org/NoAuth/Bug.html?id=9672 my $warning; local $SIG{__WARN__} = sub { $warning = "@_"; my $printed = $warning; $printed =~ s/\n$//; $printed =~ s/\n/\n\#/g; print "# ",$printed, "\n"; }; my $img = Imager->new(xsize=>10, ysize=>10); $img->copy(); cmp_ok($warning, '=~', 'void', "correct warning"); cmp_ok($warning, '=~', 'copyflip\\.t', "correct file"); $warning = ''; $img->rotate(degrees=>5); cmp_ok($warning, '=~', 'void', "correct warning"); cmp_ok($warning, '=~', 'copyflip\\.t', "correct file"); $warning = ''; $img->matrix_transform(matrix=>[1, 1, 1]); cmp_ok($warning, '=~', 'void', "correct warning"); cmp_ok($warning, '=~', 'copyflip\\.t', "correct file"); } { # 29936 - matrix_transform() should use fabs() instead of abs() # range checking sz # this meant that when sz was < 1 (which it often is for these # transformations), it treated the values out of range, producing a # blank output image my $src = Imager->new(xsize => 20, ysize => 20); $src->box(filled => 1, color => 'FF0000'); my $out = $src->matrix_transform(matrix => [ 1, 0, 0, 0, 1, 0, 0, 0, 0.9999 ]) or print "# ", $src->errstr, "\n"; my $blank = Imager->new(xsize => 20, ysize => 20); # they have to be different, surely that would be easy my $diff = Imager::i_img_diff($out->{IMG}, $blank->{IMG}); ok($diff, "RT#29936 - check non-blank output"); } { my $im = Imager->new(xsize => 10, ysize => 10, channels => 4); $im->box(filled => 1, color => 'FF0000'); my $back = Imager::Color->new(0, 0, 0, 0); my $rot = $im->rotate(degrees => 10, back => $back); # drop the alpha and make sure there's only 2 colors used my $work = $rot->convert(preset => 'noalpha'); my $im_pal = $work->to_paletted(make_colors => 'mediancut'); my @colors = $im_pal->getcolors; is(@colors, 2, "should be only 2 colors") or do { print "# ", join(",", $_->rgba), "\n" for @colors; }; @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors; is_color3($colors[0], 0, 0, 0, "check we got black"); is_color3($colors[1], 255, 0, 0, "and red"); } { # RT #77063 rotate with degrees => 270 gives a black border # so be a little less strict about rounding up # I've also: # - improved calculation of the rotation matrix # - added rounding to interpolation for 1/3 channel images my $im = test_image; $im->box(color => "#00F"); my $right = $im->rotate(right => 270); my $deg = $im->rotate(degrees => 270, back => "#FFF"); is($deg->getwidth, 150, "check degrees => 270 width"); is($deg->getheight, 150, "check degrees => 270 height"); ok($deg->write(file => "testout/t64rotdeg270.ppm"), "save it"); $right->write(file => "testout/t64rotright270.ppm"); is_image($deg, $right, "check right and degrees result the same"); #$deg = $deg->convert(preset => "addalpha"); # $right = $right->convert(preset => "addalpha"); # my $diff = $right->difference(other => $deg, mindist => 1); # $diff->write(file => "testout/t64rotdiff.png"); } { my $empty = Imager->new; ok(!$empty->rotate(degrees => 90), "can't rotate an empty image"); is($empty->errstr, "rotate: empty input image", "check error message"); } libimager-perl-1.004+dfsg.orig/t/300-transform/060-map.t0000644000175000017500000000343012263740601021605 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 10; use Imager::Test qw(is_image); -d "testout" or mkdir "testout"; Imager::init("log"=>'testout/t68map.log'); use Imager qw(:all :handy); my $imbase = Imager::ImgRaw::new(200,300,3); my @map1 = map { int($_/2) } 0..255; my @map2 = map { 255-int($_/2) } 0..255; my @map3 = 0..255; my @maps = 0..24; my @mapl = 0..400; my $tst = 1; ok(i_map($imbase, [ [], [], \@map1 ]), "map1 in ch 3"); ok(i_map($imbase, [ \@map1, \@map1, \@map1 ]), "map1 in ch1-3"); ok(i_map($imbase, [ \@map1, \@map2, \@map3 ]), "map1-3 in ch 1-3"); ok(i_map($imbase, [ \@maps, \@mapl, \@map3 ]), "incomplete maps"); # test the highlevel interface # currently this requires visual inspection of the output files SKIP: { my $im = Imager->new; $im->read(file=>'testimg/scale.ppm') or skip "Cannot load test image testimg/scale.ppm", 2; ok( $im->map(red=>\@map1, green=>\@map2, blue=>\@map3), "test OO interface (maps by color)"); ok( $im->map(maps=>[\@map1, [], \@map2]), "test OO interface (maps by maps)"); } { my $empty = Imager->new; ok(!$empty->map(maps => [ \@map1, \@map2, \@map3 ]), "can't map an empty image"); is($empty->errstr, "map: empty input image", "check error message"); } { # a real map test my $im = Imager->new(xsize => 10, ysize => 10); $im->box(filled => 1, color => [ 255, 128, 128 ], xmax => 4, ymax => 4); $im->box(filled => 1, color => [ 0, 255, 0 ], xmin => 5); my $cmp = Imager->new(xsize => 10, ysize => 10); $cmp->box(filled => 1, color => [ 127, 64, 64 ], xmax => 4, ymax => 4); $cmp->box(filled => 1, color => [ 0, 127, 0 ], xmin => 5); my @map = ( map int $_/2, 0 .. 255 ); my $out = $im->map(maps => [ \@map, \@map, \@map ]); ok($out, "map()"); is_image($out, $cmp, "test map output"); } libimager-perl-1.004+dfsg.orig/t/300-transform/610-postfix.t0000644000175000017500000000123612263740601022527 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 6; BEGIN { use_ok('Imager::Expr') } SKIP: { my $expr = Imager::Expr->new({rpnexpr=><[ qw(x y) ], constants=>{one=>1, two=>2}}); x two * # see if comments work y one + getp1 EXPR ok($expr, "compile postfix") or print "# ", Imager::Expr->error, "\n"; $expr or skip("Could not compile", 4); # perform some basic validation on the code my $code = $expr->dumpcode(); my @code = split /\n/, $code; ok($code[-1] =~ /:\s+ret/, "ret at the end"); ok(grep(/:\s+mult.*x/, @code), "found mult"); ok(grep(/:\s+add.*y/, @code), "found add"); ok(grep(/:\s+getp1/, @code), "found getp1"); } libimager-perl-1.004+dfsg.orig/t/200-file/0000755000175000017500000000000012617614576017261 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/200-file/450-preload.t0000644000175000017500000000024412614523414021365 0ustar gregoagregoa#!perl -w use strict; use Imager; use Test::More tests => 2; $@ = "Hello"; ok(Imager->preload, "preload doesn't die"); is($@, "Hello", "check \$@ was preserved"); libimager-perl-1.004+dfsg.orig/t/200-file/210-nopng.t0000644000175000017500000000126312263740601021053 0ustar gregoagregoa#!perl -w use strict; use Imager qw(:all); use Test::More; $Imager::formats{"png"} and plan skip_all => "png available, and this tests the lack of it"; plan tests => 6; my $im = Imager->new; ok(!$im->read(file=>"testimg/test.png"), "should fail to read png"); cmp_ok($im->errstr, '=~', "format 'png' not supported", "check no png message"); $im = Imager->new(xsize=>2, ysize=>2); ok(!$im->write(file=>"testout/nopng.png"), "should fail to write png"); cmp_ok($im->errstr, '=~', "format 'png' not supported", "check no png message"); ok(!grep($_ eq 'png', Imager->read_types), "check png not in read types"); ok(!grep($_ eq 'png', Imager->write_types), "check png not in write types"); libimager-perl-1.004+dfsg.orig/t/200-file/200-nojpeg.t0000644000175000017500000000156212263740601021215 0ustar gregoagregoa#!perl -w use strict; use Test::More; use Imager qw(:all); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t101jpeg.log"); $Imager::formats{"jpeg"} and plan skip_all => "have jpeg support - this tests the lack of it"; plan tests => 6; my $im = Imager->new; ok(!$im->read(file=>"testimg/base.jpg"), "should fail to read jpeg"); cmp_ok($im->errstr, '=~', qr/format 'jpeg' not supported/, "check no jpeg message"); $im = Imager->new(xsize=>2, ysize=>2); ok(!$im->write(file=>"testout/nojpeg.jpg"), "should fail to write jpeg"); cmp_ok($im->errstr, '=~', qr/format 'jpeg' not supported/, "check no jpeg message"); ok(!grep($_ eq 'jpeg', Imager->read_types), "check jpeg not in read types"); ok(!grep($_ eq 'jpeg', Imager->write_types), "check jpeg not in write types"); Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t101jpeg.log"; } libimager-perl-1.004+dfsg.orig/t/200-file/320-bmp.t0000644000175000017500000005753112263740601020523 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 215; use Imager qw(:all); use Imager::Test qw(test_image_raw is_image is_color3 test_image); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t107bmp.log"); my @files; my $debug_writes = 0; my $base_diff = 0; # if you change this make sure you generate new compressed versions my $green=i_color_new(0,255,0,255); my $blue=i_color_new(0,0,255,255); my $red=i_color_new(255,0,0,255); my $img = test_image_raw(); Imager::i_tags_add($img, 'i_xres', 0, '300', 0); Imager::i_tags_add($img, 'i_yres', 0, undef, 300); write_test($img, "testout/t107_24bit.bmp"); push @files, "t107_24bit.bmp"; # 'webmap' is noticably faster than the default my $im8 = Imager::i_img_to_pal($img, { make_colors=>'webmap', translate=>'errdiff'}); write_test($im8, "testout/t107_8bit.bmp"); push @files, "t107_8bit.bmp"; # use a fixed palette so we get reproducible results for the compressed # version my @pal16 = map { NC($_) } qw(605844 966600 0148b2 00f800 bf0a33 5e009e 2ead1b 0000f8 004b01 fd0000 0e1695 000002); my $im4 = Imager::i_img_to_pal($img, { colors=>\@pal16, make_colors=>'none' }); write_test($im4, "testout/t107_4bit.bmp"); push @files, "t107_4bit.bmp"; my $im1 = Imager::i_img_to_pal($img, { colors=>[ NC(0, 0, 0), NC(176, 160, 144) ], make_colors=>'none', translate=>'errdiff' }); write_test($im1, "testout/t107_1bit.bmp"); push @files, "t107_1bit.bmp"; my $bi_rgb = 0; my $bi_rle8 = 1; my $bi_rle4 = 2; my $bi_bitfields = 3; read_test("testout/t107_24bit.bmp", $img, bmp_compression=>0, bmp_bit_count => 24); read_test("testout/t107_8bit.bmp", $im8, bmp_compression=>0, bmp_bit_count => 8); read_test("testout/t107_4bit.bmp", $im4, bmp_compression=>0, bmp_bit_count => 4); read_test("testout/t107_1bit.bmp", $im1, bmp_compression=>0, bmp_bit_count=>1); # the following might have slight differences $base_diff = i_img_diff($img, $im8) * 2; print "# base difference $base_diff\n"; read_test("testimg/comp4.bmp", $im4, bmp_compression=>$bi_rle4, bmp_bit_count => 4); read_test("testimg/comp8.bmp", $im8, bmp_compression=>$bi_rle8, bmp_bit_count => 8); my $imoo = Imager->new; # read via OO ok($imoo->read(file=>'testout/t107_24bit.bmp'), "read via OO") or print "# ",$imoo->errstr,"\n"; ok($imoo->write(file=>'testout/t107_oo.bmp'), "write via OO") or print "# ",$imoo->errstr,"\n"; push @files, "t107_oo.bmp"; # various invalid format tests # we have so many different test images to try to detect all the possible # failure paths in the code, adding these did detect real problems print "# catch various types of invalid bmp files\n"; my @tests = ( # entries in each array ref are: # - basename of an invalid BMP file # - error message that should be produced # - description of what is being tested # - possible flag to indicate testing only on 32-bit machines [ 'badplanes.bmp', 'not a BMP file', "invalid planes value" ], [ 'badbits.bmp', 'unknown bit count for BMP file (5)', 'should fail to read invalid bits' ], # 1-bit/pixel BMPs [ 'badused1.bmp', 'out of range colors used (3)', 'out of range palette size (1-bit)' ], [ 'badcomp1.bmp', 'unknown 1-bit BMP compression (1)', 'invalid compression value (1-bit)' ], [ 'bad1wid0.bmp', 'file size limit - image width of 0 is not positive', 'width 0 (1-bit)' ], [ 'bad4oflow.bmp', 'file size limit - integer overflow calculating storage', 'overflow integers on 32-bit machines (1-bit)', '32bitonly' ], [ 'short1.bmp', 'failed reading 1-bit bmp data', 'short 1-bit' ], # 4-bit/pixel BMPs [ 'badused4a.bmp', 'out of range colors used (272)', 'should fail to read invalid pal size (272) (4-bit)' ], [ 'badused4b.bmp', 'out of range colors used (17)', 'should fail to read invalid pal size (17) (4-bit)' ], [ 'badcomp4.bmp', 'unknown 4-bit BMP compression (1)', 'invalid compression value (4-bit)' ], [ 'short4.bmp', 'failed reading 4-bit bmp data', 'short uncompressed 4-bit' ], [ 'short4rle.bmp', 'missing data during decompression', 'short compressed 4-bit' ], [ 'bad4wid0.bmp', 'file size limit - image width of 0 is not positive', 'width 0 (4-bit)' ], [ 'bad4widbig.bmp', 'file size limit - image width of -2147483628 is not positive', 'width big (4-bit)' ], [ 'bad4oflow.bmp', 'file size limit - integer overflow calculating storage', 'overflow integers on 32-bit machines (4-bit)', '32bitonly' ], # 8-bit/pixel BMPs [ 'bad8useda.bmp', 'out of range colors used (257)', 'should fail to read invalid pal size (8-bit)' ], [ 'bad8comp.bmp', 'unknown 8-bit BMP compression (2)', 'invalid compression value (8-bit)' ], [ 'short8.bmp', 'failed reading 8-bit bmp data', 'short uncompressed 8-bit' ], [ 'short8rle.bmp', 'missing data during decompression', 'short compressed 8-bit' ], [ 'bad8wid0.bmp', 'file size limit - image width of 0 is not positive', 'width 0 (8-bit)' ], [ 'bad8oflow.bmp', 'file size limit - integer overflow calculating storage', 'overflow integers on 32-bit machines (8-bit)', '32bitonly' ], # 24-bit/pixel BMPs [ 'short24.bmp', 'failed reading image data', 'short 24-bit' ], [ 'bad24wid0.bmp', 'file size limit - image width of 0 is not positive', 'width 0 (24-bit)' ], [ 'bad24oflow.bmp', 'file size limit - integer overflow calculating storage', 'overflow integers on 32-bit machines (24-bit)', '32bitonly' ], [ 'bad24comp.bmp', 'unknown 24-bit BMP compression (4)', 'bad compression (24-bit)' ], ); use Config; my $ptrsize = $Config{ptrsize}; for my $test (@tests) { my ($file, $error, $comment, $bit32only) = @$test; SKIP: { skip("only tested on 32-bit machines", 2) if $bit32only && $ptrsize != 4; ok(!$imoo->read(file=>"testimg/$file"), $comment); print "# ", $imoo->errstr, "\n"; is($imoo->errstr, $error, "check error message"); } } # previously we didn't seek to the offbits position before reading # the image data, check we handle it correctly # in each case the first is an original image with a given number of # bits and the second is the same file with data inserted before the # image bits and the offset modified to suit my @comp = ( [ 'winrgb2.bmp', 'winrgb2off.bmp', 1 ], [ 'winrgb4.bmp', 'winrgb4off.bmp', 4 ], [ 'winrgb8.bmp', 'winrgb8off.bmp', 8 ], [ 'winrgb24.bmp', 'winrgb24off.bmp', 24 ], ); for my $comp (@comp) { my ($base_file, $off_file, $bits) = @$comp; my $base_im = Imager->new; my $got_base = ok($base_im->read(file=>"testimg/$base_file"), "read original") or print "# ",$base_im->errstr,"\n"; my $off_im = Imager->new; my $got_off = ok($off_im->read(file=>"testimg/$off_file"), "read offset file") or print "# ",$off_im->errstr,"\n"; SKIP: { skip("missed one file", 1) unless $got_base && $got_off; is(i_img_diff($base_im->{IMG}, $off_im->{IMG}), 0, "compare base and offset image ($bits bits)"); } } { # check file limits are checked my $limit_file = "testout/t107_24bit.bmp"; ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149"); my $im = Imager->new; ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image width/, "check message"); ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image height/, "check message"); ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside width limit"); ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside height limit"); # 150 x 150 x 3 channel image uses 67500 bytes ok(Imager->set_file_limits(reset=>1, bytes=>67499), "set bytes limit 67499"); ok(!$im->read(file=>$limit_file), "should fail - too many bytes"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/storage size/, "check error message"); ok(Imager->set_file_limits(reset=>1, bytes=>67500), "set bytes limit 67500"); ok($im->read(file=>$limit_file), "should succeed - just inside bytes limit"); Imager->set_file_limits(reset=>1); } { # various short read failure tests, each entry has: # source filename, size, expected error # these have been selected based on code coverage, to check each # failure path is checked, where practical my @tests = ( [ "file truncated inside header", "winrgb2.bmp", 20, "file too short to be a BMP file" ], [ "1-bit, truncated inside palette", "winrgb2.bmp", 56, "reading BMP palette" ], [ "1-bit, truncated in offset region", "winrgb2off.bmp", 64, "failed skipping to image data offset" ], [ "1-bit, truncated in image data", "winrgb2.bmp", 96, "failed reading 1-bit bmp data" ], [ "4-bit, truncated inside palette", "winrgb4.bmp", 56, "reading BMP palette" ], [ "4-bit, truncated in offset region", "winrgb4off.bmp", 120, "failed skipping to image data offset", ], [ "4-bit, truncate in image data", "winrgb4.bmp", 120, "failed reading 4-bit bmp data" ], [ "4-bit RLE, truncate in uncompressed data", "comp4.bmp", 0x229, "missing data during decompression" ], [ "8-bit, truncated in palette", "winrgb8.bmp", 1060, "reading BMP palette" ], [ "8-bit, truncated in offset region", "winrgb8off.bmp", 1080, "failed skipping to image data offset" ], [ "8-bit, truncated in image data", "winrgb8.bmp", 1080, "failed reading 8-bit bmp data" ], [ "8-bit RLE, truncate in uncompressed data", "comp8.bmp", 0x68C, "missing data during decompression" ], [ "24-bit, truncate in offset region", "winrgb24off.bmp", 56, "failed skipping to image data offset", ], [ "24-bit, truncate in image data", "winrgb24.bmp", 100, "failed reading image data", ], ); my $test_index = 0; for my $test (@tests) { my ($desc, $srcfile, $size, $error) = @$test; my $im = Imager->new; open IMDATA, "< testimg/$srcfile" or die "$test_index - $desc: Cannot open testimg/$srcfile: $!"; binmode IMDATA; my $data; read(IMDATA, $data, $size) == $size or die "$test_index - $desc: Could not read $size data from $srcfile"; close IMDATA; ok(!$im->read(data => $data, type =>'bmp'), "$test_index - $desc: Should fail to read"); is($im->errstr, $error, "$test_index - $desc: check message"); ++$test_index; } } { # various short read success tests, each entry has: # source filename, size, expected tags print "# allow_incomplete tests\n"; my @tests = ( [ "1-bit", "winrgb2.bmp", 96, { bmp_compression_name => 'BI_RGB', bmp_compression => 0, bmp_used_colors => 2, i_lines_read => 8, }, ], [ "4-bit", "winrgb4.bmp", 250, { bmp_compression_name => 'BI_RGB', bmp_compression => 0, bmp_used_colors => 16, i_lines_read => 11, }, ], [ "4-bit RLE - uncompressed seq", "comp4.bmp", 0x229, { bmp_compression_name => 'BI_RLE4', bmp_compression => 2, bmp_used_colors => 16, i_lines_read => 44, }, ], [ "4-bit RLE - start seq", "comp4.bmp", 0x97, { bmp_compression_name => 'BI_RLE4', bmp_compression => 2, bmp_used_colors => 16, i_lines_read => 8, }, ], [ "8-bit", "winrgb8.bmp", 1250, { bmp_compression_name => 'BI_RGB', bmp_compression => 0, bmp_used_colors => 256, i_lines_read => 8, }, ], [ "8-bit RLE - uncompressed seq", "comp8.bmp", 0x68C, { bmp_compression_name => 'BI_RLE8', bmp_compression => 1, bmp_used_colors => 256, i_lines_read => 27, }, ], [ "8-bit RLE - initial seq", "comp8.bmp", 0x487, { bmp_compression_name => 'BI_RLE8', bmp_compression => 1, bmp_used_colors => 256, i_lines_read => 20, }, ], [ "24-bit", "winrgb24.bmp", 800, { bmp_compression_name => 'BI_RGB', bmp_compression => 0, bmp_used_colors => 0, i_lines_read => 12, }, ], ); my $test_index = 0; for my $test (@tests) { my ($desc, $srcfile, $size, $tags) = @$test; my $im = Imager->new; open IMDATA, "< testimg/$srcfile" or die "$test_index - $desc: Cannot open testimg/$srcfile: $!"; binmode IMDATA; my $data; read(IMDATA, $data, $size) == $size or die "$test_index - $desc: Could not read $size data from $srcfile"; close IMDATA; ok($im->read(data => $data, type =>'bmp', allow_incomplete => 1), "$test_index - $desc: Should read successfully"); # check standard tags are set is($im->tags(name => 'i_format'), 'bmp', "$test_index - $desc: i_format set"); is($im->tags(name => 'i_incomplete'), 1, "$test_index - $desc: i_incomplete set"); my %check_tags; for my $key (keys %$tags) { $check_tags{$key} = $im->tags(name => $key); } is_deeply(\%check_tags, $tags, "$test_index - $desc: check tags"); ++$test_index; } } { # check handling of reading images with negative height # each entry is: # source file, description print "# check handling of negative height values\n"; my @tests = ( [ "winrgb2.bmp", "1-bit, uncompressed" ], [ "winrgb4.bmp", "4-bit, uncompressed" ], [ "winrgb8.bmp", "8-bit, uncompressed" ], [ "winrgb24.bmp", "24-bit, uncompressed" ], [ "comp4.bmp", "4-bit, RLE" ], [ "comp8.bmp", "8-bit, RLE" ], ); my $test_index = 0; for my $test (@tests) { my ($file, $desc) = @$test; open IMDATA, "< testimg/$file" or die "$test_index - Cannot open $file: $!"; binmode IMDATA; my $data = do { local $/; }; close IMDATA; my $im_orig = Imager->new; $im_orig->read(data => $data) or die "Cannot load original $file: ", $im_orig->errstr; # now negate the height my $orig_height = unpack("V", substr($data, 0x16, 4)); my $neg_height = 0xFFFFFFFF & ~($orig_height - 1); substr($data, 0x16, 4) = pack("V", $neg_height); # and read the modified image my $im = Imager->new; ok($im->read(data => $data), "$test_index - $desc: read negated height image") or print "# ", $im->errstr, "\n"; # flip orig to match what we should get $im_orig->flip(dir => 'v'); # check it out is_image($im, $im_orig, "$test_index - $desc: check image"); ++$test_index; } } { print "# patched data read failure tests\n"; # like the "various invalid format" tests, these generate fail # images from other images included with Imager without providing a # full bmp source, saving on dist size and focusing on the changes needed # to cause the failure # each entry is: source file, patches, expected error, description my @tests = ( # low image data offsets [ "winrgb2.bmp", { 10 => "3d 00 00 00" }, "image data offset too small (61)", "1-bit, small image offset" ], [ "winrgb4.bmp", { 10 => "75 00 00 00" }, "image data offset too small (117)", "4-bit, small image offset" ], [ "winrgb8.bmp", { 10 => "35 04 00 00" }, "image data offset too small (1077)", "8-bit, small image offset" ], [ "winrgb24.bmp", { 10 => "35 00 00 00" }, "image data offset too small (53)", "24-bit, small image offset" ], # compression issues [ "comp8.bmp", { 0x436 => "97" }, "invalid data during decompression", "8bit, RLE run beyond edge of image" ], [ # caused glibc malloc or valgrind to complain "comp8.bmp", { 0x436 => "94 00 00 03" }, "invalid data during decompression", "8bit, literal run beyond edge of image" ], [ "comp4.bmp", { 0x76 => "FF bb FF BB" }, "invalid data during decompression", "4bit - RLE run beyond edge of image" ], [ "comp4.bmp", { 0x76 => "94 bb 00 FF" }, "invalid data during decompression", "4bit - literal run beyond edge of image" ], ); my $test_index = 0; for my $test (@tests) { my ($filename, $patches, $error, $desc) = @$test; my $data = load_patched_file("testimg/$filename", $patches); my $im = Imager->new; ok(!$im->read(data => $data, type=>'bmp'), "$test_index - $desc:should fail to read"); is($im->errstr, $error, "$test_index - $desc:check message"); ++$test_index; } } { # various write failure tests # each entry is: # source, limit, expected error, description my @tests = ( [ "winrgb2.bmp", 1, "cannot write bmp header: limit reached", "1-bit, writing header" ], [ "winrgb4.bmp", 1, "cannot write bmp header: limit reached", "4-bit, writing header" ], [ "winrgb8.bmp", 1, "cannot write bmp header: limit reached", "8-bit, writing header" ], [ "winrgb24.bmp", 1, "cannot write bmp header: limit reached", "24-bit, writing header" ], [ "winrgb2.bmp", 0x38, "cannot write palette entry: limit reached", "1-bit, writing palette" ], [ "winrgb4.bmp", 0x38, "cannot write palette entry: limit reached", "4-bit, writing palette" ], [ "winrgb8.bmp", 0x38, "cannot write palette entry: limit reached", "8-bit, writing palette" ], [ "winrgb2.bmp", 0x40, "writing 1 bit/pixel packed data: limit reached", "1-bit, writing image data" ], [ "winrgb4.bmp", 0x80, "writing 4 bit/pixel packed data: limit reached", "4-bit, writing image data" ], [ "winrgb8.bmp", 0x440, "writing 8 bit/pixel packed data: limit reached", "8-bit, writing image data" ], [ "winrgb24.bmp", 0x39, "writing image data: limit reached", "24-bit, writing image data" ], ); print "# write failure tests\n"; my $test_index = 0; for my $test (@tests) { my ($file, $limit, $error, $desc) = @$test; my $im = Imager->new; $im->read(file => "testimg/$file") or die "Cannot read $file: ", $im->errstr; my $io = Imager::io_new_cb(limited_write($limit), undef, undef, undef, 1); $io->set_buffered(0); print "# writing with limit of $limit\n"; ok(!$im->write(type => 'bmp', io => $io), "$test_index - $desc: write should fail"); is($im->errstr, $error, "$test_index - $desc: check error message"); ++$test_index; } } { ok(grep($_ eq 'bmp', Imager->read_types), "check bmp in read types"); ok(grep($_ eq 'bmp', Imager->write_types), "check bmp in write types"); } { # RT #30075 # give 4/2 channel images a background color when saving to BMP my $im = Imager->new(xsize=>16, ysize=>16, channels=>4); $im->box(filled => 1, xmin => 8, color => '#FFE0C0'); $im->box(filled => 1, color => NC(0, 192, 192, 128), ymin => 8, xmax => 7); ok($im->write(file=>"testout/t107_alpha.bmp", type=>'bmp'), "should succeed writing 4 channel image"); push @files, "t107_alpha.bmp"; my $imread = Imager->new; ok($imread->read(file => 'testout/t107_alpha.bmp'), "read it back"); is_color3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0, "check transparent became black"); is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192, "check color came through"); is_color3($imread->getpixel('x' => 0, 'y' => 15), 0, 96, 96, "check translucent came through"); my $data; ok($im->write(data => \$data, type => 'bmp', i_background => '#FF0000'), "write with red background"); ok($imread->read(data => $data, type => 'bmp'), "read it back"); is_color3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0, "check transparent became red"); is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192, "check color came through"); is_color3($imread->getpixel('x' => 0, 'y' => 15), 127, 96, 96, "check translucent came through"); } { # RT 41406 my $data; my $im = test_image(); ok($im->write(data => \$data, type => 'bmp'), "write using OO"); my $size = unpack("V", substr($data, 34, 4)); is($size, 67800, "check data size"); } { # check close failures are handled correctly my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; ok(!$im->write(type => "bmp", callback => sub { 1 }, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink map "testout/$_", @files; unlink "testout/t107bmp.log"; } sub write_test { my ($im, $filename) = @_; local *FH; if (open FH, "> $filename") { binmode FH; my $IO = Imager::io_new_fd(fileno(FH)); unless (ok(Imager::i_writebmp_wiol($im, $IO), $filename)) { print "# ",Imager->_error_as_msg(),"\n"; } undef $IO; close FH; } else { fail("could not open $filename: $!"); } } sub read_test { my ($filename, $im, %tags) = @_; local *FH; print "# read_test: $filename\n"; $tags{i_format} = "bmp"; if (open FH, "< $filename") { binmode FH; my $IO = Imager::io_new_fd(fileno(FH)); my $im_read = Imager::i_readbmp_wiol($IO); if ($im_read) { my $diff = i_img_diff($im, $im_read); if ($diff > $base_diff) { fail("image mismatch reading $filename"); } else { my $tags_ok = 1; for my $tag (keys %tags) { if (my $index = Imager::i_tags_find($im_read, $tag, 0)) { my ($name, $value) = Imager::i_tags_get($im_read, $index); my $exp_value = $tags{$tag}; print "# tag $name = '$value' - expect '$exp_value'\n"; if ($exp_value =~ /\d/) { if ($value != $tags{$tag}) { print "# tag $tag value mismatch $tags{$tag} != $value\n"; $tags_ok = 0; } } else { if ($value ne $tags{$tag}) { print "# tag $tag value mismatch $tags{$tag} != $value\n"; $tags_ok = 0; } } } } ok($tags_ok, "reading $filename"); # for my $i (0 .. Imager::i_tags_count($im_read)-1) { # my ($name, $value) = Imager::i_tags_get($im_read, $i); # print "# tag '$name' => '$value'\n"; #} } } else { fail("could not read $filename: ".Imager->_error_as_msg()); } undef $IO; close FH; } else { fail("could not open $filename: $!"); } } sub limited_write { my ($limit) = @_; return sub { my ($data) = @_; $limit -= length $data; if ($limit >= 0) { print "# write of ", length $data, " bytes successful ($limit left)\n" if $debug_writes; return 1; } else { print "# write of ", length $data, " bytes failed\n"; Imager::i_push_error(0, "limit reached"); return; } }; } sub load_patched_file { my ($filename, $patches) = @_; open IMDATA, "< $filename" or die "Cannot open $filename: $!"; binmode IMDATA; my $data = do { local $/; }; for my $offset (keys %$patches) { (my $hdata = $patches->{$offset}) =~ tr/ //d; my $pdata = pack("H*", $hdata); substr($data, $offset, length $pdata) = $pdata; } return $data; } libimager-perl-1.004+dfsg.orig/t/200-file/300-raw.t0000644000175000017500000003051712617316526020537 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 56; use Imager qw(:all); use Imager::Test qw/is_color3 is_color4 test_image test_image_mono is_image/; -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t103raw.log"); $| = 1; my $green=i_color_new(0,255,0,255); my $blue=i_color_new(0,0,255,255); my $red=i_color_new(255,0,0,255); my $img=Imager::ImgRaw::new(150,150,3); my $cmpimg=Imager::ImgRaw::new(150,150,3); i_box_filled($img,70,25,130,125,$green); i_box_filled($img,20,25,80,125,$blue); i_arc($img,75,75,30,0,361,$red); i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]); my $timg = Imager::ImgRaw::new(20, 20, 4); my $trans = i_color_new(255, 0, 0, 127); i_box_filled($timg, 0, 0, 20, 20, $green); i_box_filled($timg, 2, 2, 18, 18, $trans); open(FH,">testout/t103.raw") || die "Cannot open testout/t103.raw for writing\n"; binmode(FH); my $IO = Imager::io_new_fd( fileno(FH) ); ok(i_writeraw_wiol($img, $IO), "write raw low") or print "# Cannot write testout/t103.raw\n"; close(FH); open(FH,"testout/t103.raw") || die "Cannot open testout/t103.raw\n"; binmode(FH); $IO = Imager::io_new_fd( fileno(FH) ); $cmpimg = i_readraw_wiol($IO, 150, 150, 3, 3, 0); ok($cmpimg, "read raw low") or print "# Cannot read testout/t103.raw\n"; close(FH); print "# raw average mean square pixel difference: ",sqrt(i_img_diff($img,$cmpimg))/150*150,"\n"; # I could have kept the raw images for these tests in binary files in # testimg/, but I think keeping them as hex encoded data in here makes # it simpler to add more if necessary # Later we may change this to read from a scalar instead save_data('testout/t103_base.raw'); save_data('testout/t103_3to4.raw'); save_data('testout/t103_line_int.raw'); save_data('testout/t103_img_int.raw'); # load the base image open FH, "testout/t103_base.raw" or die "Cannot open testout/t103_base.raw: $!"; binmode FH; $IO = Imager::io_new_fd( fileno(FH) ); my $baseimg = i_readraw_wiol( $IO, 4, 4, 3, 3, 0); ok($baseimg, "read base raw image") or die "Cannot read base raw image"; close FH; # the actual read tests # each read_test() call does 2 tests: # - check if the read succeeds # - check if it matches $baseimg read_test('testout/t103_3to4.raw', 4, 4, 4, 3, 0, $baseimg); read_test('testout/t103_line_int.raw', 4, 4, 3, 3, 1, $baseimg); # intrl==2 is documented in raw.c but doesn't seem to be implemented #read_test('testout/t103_img_int.raw', 4, 4, 3, 3, 2, $baseimg, 7); # paletted images SKIP: { my $palim = Imager::i_img_pal_new(20, 20, 3, 256); ok($palim, "make paletted image") or skip("couldn't make paletted image", 2); my $redindex = Imager::i_addcolors($palim, $red); my $blueindex = Imager::i_addcolors($palim, $blue); for my $y (0..9) { Imager::i_ppal($palim, 0, $y, ($redindex) x 20); } for my $y (10..19) { Imager::i_ppal($palim, 0, $y, ($blueindex) x 20); } open FH, "> testout/t103_pal.raw" or die "Cannot create testout/t103_pal.raw: $!"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); ok(i_writeraw_wiol($palim, $IO), "write low paletted"); close FH; open FH, "testout/t103_pal.raw" or die "Cannot open testout/t103_pal.raw: $!"; binmode FH; my $data = do { local $/; }; is($data, "\x0" x 200 . "\x1" x 200, "compare paletted data written"); close FH; } # 16-bit image # we don't have 16-bit reads yet SKIP: { my $img16 = Imager::i_img_16_new(150, 150, 3); ok($img16, "make 16-bit/sample image") or skip("couldn't make 16 bit/sample image", 1); i_box_filled($img16,70,25,130,125,$green); i_box_filled($img16,20,25,80,125,$blue); i_arc($img16,75,75,30,0,361,$red); i_conv($img16,[0.1, 0.2, 0.4, 0.2, 0.1]); open FH, "> testout/t103_16.raw" or die "Cannot create testout/t103_16.raw: $!"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); ok(i_writeraw_wiol($img16, $IO), "write low 16 bit image"); close FH; } # try a simple virtual image SKIP: { my $maskimg = Imager::i_img_masked_new($img, undef, 0, 0, 150, 150); ok($maskimg, "make masked image") or skip("couldn't make masked image", 3); open FH, "> testout/t103_virt.raw" or die "Cannot create testout/t103_virt.raw: $!"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); ok(i_writeraw_wiol($maskimg, $IO), "write virtual raw"); close FH; open FH, "testout/t103_virt.raw" or die "Cannot open testout/t103_virt.raw: $!"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); my $cmpimgmask = i_readraw_wiol($IO, 150, 150, 3, 3, 0); ok($cmpimgmask, "read result of masked write"); my $diff = i_img_diff($maskimg, $cmpimgmask); print "# difference for virtual image $diff\n"; is($diff, 0, "compare masked to read"); # check that i_format is set correctly my $index = Imager::i_tags_find($cmpimgmask, 'i_format', 0); if ($index) { my $value = Imager::i_tags_get($cmpimgmask, $index); is($value, 'raw', "check i_format value"); } else { fail("couldn't find i_format tag"); } } { # error handling checks # should get an error writing to a open for read file # make a empty file open RAW, "> testout/t103_empty.raw" or die "Cannot create testout/t103_empty.raw: $!"; close RAW; open RAW, "< testout/t103_empty.raw" or die "Cannot open testout/t103_empty.raw: $!"; my $im = Imager->new(xsize => 50, ysize=>50); ok(!$im->write(fh => \*RAW, type => 'raw', buffered => 0), "write to open for read handle"); cmp_ok($im->errstr, '=~', '^Could not write to file: write\(\) failure', "check error message"); close RAW; # should get an error reading an empty file ok(!$im->read(file => 'testout/t103_empty.raw', xsize => 50, ysize=>50, type=>'raw', interleave => 1), 'read an empty file'); is($im->errstr, 'premature end of file', "check message"); SKIP: { # see 862083f7e40bc2a9e3b94aedce56c1336e7bdb25 in perl5 git $] >= 5.010 or skip "5.8.x and earlier don't treat a read on a WRONLY file as an error", 2; open RAW, "> testout/t103_empty.raw" or die "Cannot create testout/t103_empty.raw: $!"; ok(!$im->read(fh => \*RAW, , xsize => 50, ysize=>50, type=>'raw', interleave => 1), 'read a file open for write'); cmp_ok($im->errstr, '=~', '^error reading file: read\(\) failure', "check message"); close RAW; # avoid a message on 5.22+ } } { ok(grep($_ eq 'raw', Imager->read_types), "check raw in read types"); ok(grep($_ eq 'raw', Imager->write_types), "check raw in write types"); } { # OO no interleave warning my $im = Imager->new; my $msg; local $SIG{__WARN__} = sub { $msg = "@_" }; ok($im->read(file => "testout/t103_line_int.raw", xsize => 4, ysize => 4, type => "raw"), "read without interleave parameter") or print "# ", $im->errstr, "\n"; ok($msg, "should have warned"); like($msg, qr/interleave/, "check warning is ok"); # check we got the right value is_color3($im->getpixel(x => 0, y => 0), 0x00, 0x11, 0x22, "check the image was read correctly"); # check no warning if either is supplied $im = Imager->new; undef $msg; ok($im->read(file => "testout/t103_base.raw", xsize => 4, ysize => 4, type => "raw", interleave => 0), "read with interleave 0"); is($msg, undef, "no warning"); is_color3($im->getpixel(x => 0, y => 0), 0x00, 0x11, 0x22, "check read non-interleave"); $im = Imager->new; undef $msg; ok($im->read(file => "testout/t103_base.raw", xsize => 4, ysize => 4, type => "raw", raw_interleave => 0), "read with raw_interleave 0"); is($msg, undef, "no warning"); is_color3($im->getpixel(x => 1, y => 0), 0x01, 0x12, 0x23, "check read non-interleave"); # make sure set to 1 is sane $im = Imager->new; undef $msg; ok($im->read(file => "testout/t103_line_int.raw", xsize => 4, ysize => 4, type => "raw", raw_interleave => 1), "read with raw_interleave 1"); is($msg, undef, "no warning"); is_color3($im->getpixel(x => 2, y => 0), 0x02, 0x13, 0x24, "check read interleave = 1"); } { # invalid interleave error handling my $im = Imager->new; ok(!$im->read(file => "testout/t103_base.raw", raw_interleave => 2, type => "raw", xsize => 4, ysize => 4), "invalid interleave"); is($im->errstr, "raw_interleave must be 0 or 1", "check message"); } { # store/data channel behaviour my $im = Imager->new; ok($im->read(file => "testout/t103_3to4.raw", xsize => 4, ysize => 4, raw_datachannels => 4, raw_interleave => 0, type => "raw"), "read 4 channel file as 3 channels") or print "# ", $im->errstr, "\n"; is_color3($im->getpixel(x => 2, y => 1), 0x12, 0x23, 0x34, "check read correctly"); } { # should fail to read with storechannels > 4 my $im = Imager->new; ok(!$im->read(file => "testout/t103_line_int.raw", type => "raw", raw_interleave => 1, xsize => 4, ysize => 4, raw_storechannels => 5), "read with large storechannels"); is($im->errstr, "raw_storechannels must be between 1 and 4", "check error message"); } { # should zero spare channels if storechannels > datachannels my $im = Imager->new; ok($im->read(file => "testout/t103_base.raw", type => "raw", raw_interleave => 0, xsize => 4, ysize => 4, raw_storechannels => 4), "read with storechannels > datachannels"); is($im->getchannels, 4, "should have 4 channels"); is_color4($im->getpixel(x => 2, y => 1), 0x12, 0x23, 0x34, 0x00, "check last channel zeroed"); } { my @ims = ( basic => test_image(), mono => test_image_mono() ); push @ims, masked => test_image()->masked(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; while (my ($type, $im) = splice(@ims, 0, 2)) { my $io = Imager::io_new_cb(sub { 1 }, undef, undef, $fail_close); ok(!$im->write(io => $io, type => "raw"), "write $type image with a failing close handler"); like($im->errstr, qr/synthetic close failure/, "check error message"); } } { # https://rt.cpan.org/Ticket/Display.html?id=106836 my $im = test_image; my $data; ok($im->write(data => \$data, type => "raw", raw_interleave => 0), "save some raw image") or diag $im->errstr; my $im2 = Imager->new ( data => \$data, filetype => "raw", xsize => $im->getwidth, ysize => $im->getheight, raw_datachannels => $im->getchannels, raw_storechannels => $im->getchannels, raw_interleave => 0, ); ok($im2, "read raw image using new() method"); is_image($im, $im2, "check they match"); } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t103raw.log"; unlink(qw(testout/t103_base.raw testout/t103_3to4.raw testout/t103_line_int.raw testout/t103_img_int.raw)) } sub read_test { my ($in, $xsize, $ysize, $data, $store, $intrl, $base) = @_; open FH, $in or die "Cannot open $in: $!"; binmode FH; my $IO = Imager::io_new_fd( fileno(FH) ); my $img = i_readraw_wiol($IO, $xsize, $ysize, $data, $store, $intrl); SKIP: { ok($img, "read_test $in read") or skip("couldn't read $in", 1); is(i_img_diff($img, $baseimg), 0, "read_test $in compare"); } } sub save_data { my $outname = shift; my $data = load_data(); open FH, "> $outname" or die "Cannot create $outname: $!"; binmode FH; print FH $data; close FH; } sub load_data { my $hex = ''; while () { next if /^#/; last if /^EOF/; chomp; $hex .= $_; } $hex =~ tr/ //d; my $result = pack("H*", $hex); #print unpack("H*", $result),"\n"; return $result; } # FIXME: may need tests for 1,2,4 channel images __DATA__ # we keep some packed raw images here # we decode this in the code, ignoring lines starting with #, a subfile # ends with EOF, data is HEX encoded (spaces ignored) # basic 3 channel version of the image 001122 011223 021324 031425 102132 112233 122334 132435 203142 213243 223344 233445 304152 314253 324354 334455 EOF # test image for reading a 4 channel image into a 3 channel image # 4 x 4 pixels 00112233 01122334 02132435 03142536 10213243 11223344 12233445 13243546 20314253 21324354 22334455 23344556 30415263 31425364 32435465 33445566 EOF # test image for line based interlacing # 4 x 4 pixels # first line 00 01 02 03 11 12 13 14 22 23 24 25 # second line 10 11 12 13 21 22 23 24 32 33 34 35 # third line 20 21 22 23 31 32 33 34 42 43 44 45 # fourth line 30 31 32 33 41 42 43 44 52 53 54 55 EOF # test image for image based interlacing # first channel 00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33 # second channel 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43 44 # third channel 22 23 24 25 32 33 34 35 42 43 44 45 52 53 54 55 EOF libimager-perl-1.004+dfsg.orig/t/200-file/100-files.t0000644000175000017500000002742112263740601021036 0ustar gregoagregoa#!perl -w # This file is for testing file functionality that is independent of # the file format use strict; use Test::More tests => 89; use Imager; -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t1000files.log"); SKIP: { # Test that i_test_format_probe() doesn't pollute stdout # Initally I tried to write this test using open to redirect files, # but there was a buffering problem that made it so the data wasn't # being written to the output file. This external perl call avoids # that problem my $test_script = 'testout/t1000files_probe.pl'; # build a temp test script to use ok(open(SCRIPT, "> $test_script"), "open test script") or skip("no test script $test_script: $!", 2); print SCRIPT <<'PERL'; #!perl use Imager; use strict; my $file = shift or die "No file supplied"; open FH, "< $file" or die "Cannot open file: $!"; binmode FH; my $io = Imager::io_new_fd(fileno(FH)); Imager::i_test_format_probe($io, -1); PERL close SCRIPT; my $perl = $^X; $perl = qq/"$perl"/ if $perl =~ / /; print "# script: $test_script\n"; my $cmd = "$perl -Mblib $test_script t/200-file/100-files.t"; print "# command: $cmd\n"; my $out = `$cmd`; is($?, 0, "command successful"); is($out, '', "output should be empty"); } # test the file limit functions # by default the limits are zero (unlimited) print "# image file limits\n"; is_deeply([ Imager->get_file_limits() ], [0, 0, 0x40000000 ], "check defaults"); ok(Imager->set_file_limits(width=>100), "set only width"); is_deeply([ Imager->get_file_limits() ], [100, 0, 0x40000000 ], "check width set"); ok(Imager->set_file_limits(height=>150, bytes=>10000), "set height and bytes"); is_deeply([ Imager->get_file_limits() ], [ 100, 150, 10000 ], "check all values now set"); ok(Imager->check_file_limits(width => 100, height => 30), "check 100 x 30 (def channels, sample_size) ok") or diag(Imager->errstr); ok(Imager->check_file_limits(width => 100, height => 100, channels => 1), "check 100 x 100 x 1 (def sample_size) ok") or diag(Imager->errstr); ok(Imager->check_file_limits(width => 100, height => 100, channels => 1), "check 100 x 100 x 1 (def sample_size) ok") or diag(Imager->errstr); ok(!Imager->check_file_limits(width => 100, height => 100, channels => 1, sample_size => "float"), "check 100 x 100 x 1 x float should fail"); ok(!Imager->check_file_limits(width => 100, height => 100, channels => 0), "0 channels should fail"); is(Imager->errstr, "file size limit - channels 0 out of range", "check error message"); ok(!Imager->check_file_limits(width => 0, height => 100), "0 width should fail"); is(Imager->errstr, "file size limit - image width of 0 is not positive", "check error message"); ok(!Imager->check_file_limits(width => 100, height => 0), "0 height should fail"); is(Imager->errstr, "file size limit - image height of 0 is not positive", "check error message"); ok(!Imager->check_file_limits(width => 10, height => 10, sample_size => 0), "0 sample_size should fail"); is(Imager->errstr, "file size limit - sample_size 0 out of range", "check error message"); ok(!Imager->check_file_limits(width => 10, height => 10, sample_size => 1000), "1000 sample_size should fail"); is(Imager->errstr, "file size limit - sample_size 1000 out of range", "check error message"); ok(Imager->set_file_limits(reset=>1, height => 99), "set height and reset"); is_deeply([ Imager->get_file_limits() ], [ 0, 99, 0x40000000 ], "check only height is set"); ok(Imager->set_file_limits(reset=>1), "just reset"); is_deeply([ Imager->get_file_limits() ], [ 0, 0, 0x40000000 ], "check all are reset"); # bad parameters is_deeply([ Imager->check_file_limits() ], [], "missing size paramaters"); is(Imager->errstr, "check_file_limits: width must be defined", "check message"); is_deeply([ Imager->check_file_limits(width => 100.5) ], [], "non-integer parameter"); is(Imager->errstr, "check_file_limits: width must be a positive integer", "check message"); # test error handling for loading file handers { # first, no module at all { my $data = "abc"; ok(!Imager->new(data => $data, filetype => "unknown"), "try to read an unknown file type"); like(Imager->errstr, qr(^format 'unknown' not supported - formats .* - Can't locate Imager/File/UNKNOWN.pm or Imager/File/UNKNOWNReader.pm$), "check error message"); } { my $data; my $im = Imager->new(xsize => 10, ysize => 10); ok(!$im->write(data => \$data, type => "unknown"), "try to write an unknown file type"); like($im->errstr, qr(^format 'unknown' not supported - formats .* - Can't locate Imager/File/UNKNOWN.pm or Imager/File/UNKNOWNWriter.pm$), "check error message"); } push @INC, "t/t1000lib"; { my $data = "abc"; ok(!Imager->new(data => $data, filetype => "bad"), "try to read an bad (other load failure) file type"); like(Imager->errstr, qr(^format 'bad' not supported - formats .* available for reading - This module fails to load loading Imager/File/BAD.pm$), "check error message"); } { my $data; my $im = Imager->new(xsize => 10, ysize => 10); ok(!$im->write(data => \$data, type => "bad"), "try to write an bad file type"); like($im->errstr, qr(^format 'bad' not supported - formats .* available for writing - This module fails to load loading Imager/File/BAD.pm$), "check error message"); } } { # test empty image handling for write()/write_multi() my $empty = Imager->new; my $data; ok(!$empty->write(data => \$data, type => "pnm"), "fail to write an empty image"); is($empty->errstr, "write: empty input image", "check error message"); my $good = Imager->new(xsize => 1, ysize => 1); ok(!Imager->write_multi({ data => \$data, type => "pnm" }, $good, $empty), "fail to write_multi an empty image"); is(Imager->errstr, "write_multi: empty input image (image 2)"); } # check file type probe probe_ok("49492A41", undef, "not quite tiff"); probe_ok("4D4D0041", undef, "not quite tiff"); probe_ok("49492A00", "tiff", "tiff intel"); probe_ok("4D4D002A", "tiff", "tiff motorola"); probe_ok("474946383961", "gif", "gif 89"); probe_ok("474946383761", "gif", "gif 87"); probe_ok(<read_multi(data => $data); is(@mult_data, 0, "read_multi with non-image input data should fail"); is(Imager->errstr, "type parameter missing and it couldn't be determined from the file contents", "check the error message"); my @mult_file = Imager->read_multi(file => "t/200-file/100-files.t"); is(@mult_file, 0, "read_multi with non-image filename should fail"); is(Imager->errstr, "type parameter missing and it couldn't be determined from the file contents or file name", "check the error message"); my $im = Imager->new; ok(!$im->read(data => $data), "read from non-image data should fail"); is($im->errstr, "type parameter missing and it couldn't be determined from the file contents", "check the error message"); ok(!$im->read(file => "t/200-file/100-files.t"), "read from non-image file should fail"); is($im->errstr, "type parameter missing and it couldn't be determined from the file contents or file name", "check the error message"); } { # test def_guess_type my @tests = ( pnm => "pnm", GIF => "gif", tif => "tiff", TIFF => "tiff", JPG => "jpeg", rle => "utah", bmp => "bmp", dib => "bmp", rgb => "sgi", BW => "sgi", TGA => "tga", CUR => "cur", ico => "ico", ILBM => "ilbm", pcx => "pcx", psd => "psd", ); while (my ($ext, $expect) = splice(@tests, 0, 2)) { my $filename = "foo.$ext"; is(Imager::def_guess_type($filename), $expect, "type for $filename should be $expect"); } } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t1000files.log"; } sub probe_ok { my ($packed, $exp_type, $name) = @_; my $builder = Test::Builder->new; $packed =~ tr/ \r\n//d; # remove whitespace used for layout my $data = pack("H*", $packed); my $io = Imager::io_new_buffer($data); my $result = Imager::i_test_format_probe($io, -1); return $builder->is_eq($result, $exp_type, $name) } libimager-perl-1.004+dfsg.orig/t/200-file/010-iolayer.t0000644000175000017500000007657012370401737021414 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 288; use Imager::Test qw(is_image); # for SEEK_SET etc, Fcntl doesn't provide these in 5.005_03 use IO::Seekable; use Config; BEGIN { use_ok(Imager => ':all') }; -d "testout" or mkdir "testout"; $| = 1; Imager->open_log(log => "testout/t07iolayer.log"); undef($/); # start by testing io buffer my $data="P2\n2 2\n255\n 255 0\n0 255\n"; my $IO = Imager::io_new_buffer($data); my $im = Imager::i_readpnm_wiol($IO, -1); ok($im, "read from data io"); open(FH, ">testout/t07.ppm") or die $!; binmode(FH); my $fd = fileno(FH); my $IO2 = Imager::io_new_fd( $fd ); Imager::i_writeppm_wiol($im, $IO2); close(FH); undef($im); open(FH, "; close(FH); my $IO3 = Imager::IO->new_buffer($data); #undef($data); $im = Imager::i_readpnm_wiol($IO3, -1); ok($im, "read from buffer, for compare"); undef $IO3; open(FH, "new_fd( $fd ); my $im2 = Imager::i_readpnm_wiol($IO4, -1); close(FH); undef($IO4); ok($im2, "read from file, for compare"); is(i_img_diff($im, $im2), 0, "compare images"); undef($im2); my $IO5 = Imager::io_new_bufchain(); Imager::i_writeppm_wiol($im, $IO5) or diag("failed to write to bufchain: " . Imager->_error_as_msg); my $data2 = Imager::io_slurp($IO5); undef($IO5); ok(defined $data2, "check we got data from bufchain"); ok(length $data2, "check it's non-zero length"); my $IO6 = Imager::io_new_buffer($data2); my $im3 = Imager::i_readpnm_wiol($IO6, -1) or diag("failed to read from buffer: " . Imager->_error_as_msg); unless ($im3) { # getting a strange failure on some CPAN testers print STDERR join(" ", map sprintf("%02x", ord), split //, substr($data2, 0, 30)), "\n"; } SKIP: { $im or skip "no \$im", 1; $im3 or skip "no \$im3", 1; is(Imager::i_img_diff($im, $im3), 0, "read from buffer"); } my $work = $data; my $pos = 0; sub io_reader { my ($size, $maxread) = @_; my $out = substr($work, $pos, $maxread); $pos += length $out; $out; } sub io_reader2 { my ($size, $maxread) = @_; my $out = substr($work, $pos, $maxread); $pos += length $out; $out; } my $IO7 = Imager::IO->new_cb(undef, \&io_reader, undef, undef); ok($IO7, "making readcb object"); my $im4 = Imager::i_readpnm_wiol($IO7, -1); ok($im4, "read from cb"); ok(Imager::i_img_diff($im, $im4) == 0, "read from cb image match"); $pos = 0; $IO7 = Imager::io_new_cb(undef, \&io_reader2, undef, undef); ok($IO7, "making short readcb object"); my $im5 = Imager::i_readpnm_wiol($IO7, -1); ok($im4, "read from cb2"); is(Imager::i_img_diff($im, $im5), 0, "read from cb2 image match"); sub io_writer { my ($what) = @_; substr($work, $pos, $pos+length $what) = $what; $pos += length $what; 1; } my $did_close; sub io_close { ++$did_close; } my $IO8 = Imager::io_new_cb(\&io_writer, undef, undef, \&io_close); ok($IO8, "making writecb object"); $pos = 0; $work = ''; ok(Imager::i_writeppm_wiol($im, $IO8), "write to cb"); # I originally compared this to $data, but that doesn't include the # Imager header is($work, $data2, "write image match"); ok($did_close, "did close"); # with a short buffer, no closer my $IO9 = Imager::io_new_cb(\&io_writer, undef, undef, undef, 1); ok($IO9, "making short writecb object"); $pos = 0; $work = ''; ok(Imager::i_writeppm_wiol($im, $IO9), "write to short cb"); is($work, $data2, "short write image match"); { my $buf_data = "Test data"; my $io9 = Imager::io_new_buffer($buf_data); is(ref $io9, "Imager::IO", "check class"); my $work; is($io9->raw_read($work, 4), 4, "read 4 from buffer object"); is($work, "Test", "check data read"); is($io9->raw_read($work, 5), 5, "read the rest"); is($work, " data", "check data read"); is($io9->raw_seek(5, SEEK_SET), 5, "seek"); is($io9->raw_read($work, 5), 4, "short read"); is($work, "data", "check data read"); is($io9->raw_seek(-1, SEEK_CUR), 8, "seek relative"); is($io9->raw_seek(-5, SEEK_END), 4, "seek relative to end"); is($io9->raw_seek(-10, SEEK_CUR), -1, "seek failure"); undef $io9; } { my $io = Imager::IO->new_bufchain(); is(ref $io, "Imager::IO", "check class"); is($io->raw_write("testdata"), 8, "check write"); is($io->raw_seek(-8, SEEK_CUR), 0, "seek relative"); my $work; is($io->raw_read($work, 8), 8, "check read"); is($work, "testdata", "check data read"); is($io->raw_seek(-3, SEEK_END), 5, "seek end relative"); is($io->raw_read($work, 5), 3, "short read"); is($work, "ata", "check read data"); is($io->raw_seek(4, SEEK_SET), 4, "absolute seek to write some"); is($io->raw_write("testdata"), 8, "write"); is($io->raw_seek(0, SEEK_CUR), 12, "check size"); $io->raw_close(); # grab the data my $data = Imager::io_slurp($io); is($data, "testtestdata", "check we have the right data"); } { # callback failure checks my $fail_io = Imager::io_new_cb(\&fail_write, \&fail_read, \&fail_seek, undef, 1); # scalar context my $buffer; my $read_result = $fail_io->raw_read($buffer, 10); is($read_result, undef, "read failure undef in scalar context"); my @read_result = $fail_io->raw_read($buffer, 10); is(@read_result, 0, "empty list in list context"); $read_result = $fail_io->raw_read2(10); is($read_result, undef, "raw_read2 failure (scalar)"); @read_result = $fail_io->raw_read2(10); is(@read_result, 0, "raw_read2 failure (list)"); my $write_result = $fail_io->raw_write("test"); is($write_result, -1, "failed write"); my $seek_result = $fail_io->raw_seek(-1, SEEK_SET); is($seek_result, -1, "failed seek"); } { # callback success checks my $good_io = Imager::io_new_cb(\&good_write, \&good_read, \&good_seek, undef, 1); # scalar context my $buffer; my $read_result = $good_io->raw_read($buffer, 10); is($read_result, 8, "read success (scalar)"); is($buffer, "testdata", "check data"); my @read_result = $good_io->raw_read($buffer, 10); is_deeply(\@read_result, [ 8 ], "read success (list)"); is($buffer, "testdata", "check data"); $read_result = $good_io->raw_read2(10); is($read_result, "testdata", "read2 success (scalar)"); @read_result = $good_io->raw_read2(10); is_deeply(\@read_result, [ "testdata" ], "read2 success (list)"); } { # end of file my $eof_io = Imager::io_new_cb(undef, \&eof_read, undef, undef, 1); my $buffer; my $read_result = $eof_io->raw_read($buffer, 10); is($read_result, 0, "read eof (scalar)"); is($buffer, '', "check data"); my @read_result = $eof_io->raw_read($buffer, 10); is_deeply(\@read_result, [ 0 ], "read eof (list)"); is($buffer, '', "check data"); } { # no callbacks my $none_io = Imager::io_new_cb(undef, undef, undef, undef, 0); is($none_io->raw_write("test"), -1, "write with no writecb should fail"); my $buffer; is($none_io->raw_read($buffer, 10), undef, "read with no readcb should fail"); is($none_io->raw_seek(0, SEEK_SET), -1, "seek with no seekcb should fail"); } SKIP: { # make sure we croak when trying to write a string with characters over 0xff # the write callback shouldn't get called skip("no native UTF8 support in this version of perl", 2) unless $] >= 5.006; my $io = Imager::io_new_cb(\&good_write, undef, undef, 1); my $data = chr(0x100); is(ord $data, 0x100, "make sure we got what we expected"); my $result = eval { $io->raw_write($data); 1; }; ok(!$result, "should have croaked") and print "# $@\n"; } { # 0.52 left some debug code in a path that wasn't tested, make sure # that path is tested # http://rt.cpan.org/Ticket/Display.html?id=20705 my $io = Imager::io_new_cb ( sub { print "# write $_[0]\n"; 1 }, sub { print "# read $_[0], $_[1]\n"; "x" x $_[1] }, sub { print "# seek\n"; 0 }, sub { print "# close\n"; 1 }); my $buffer; is($io->raw_read($buffer, 10), 10, "read 10"); is($buffer, "xxxxxxxxxx", "read value"); ok($io->raw_write("foo"), "write"); is($io->raw_close, 0, "close"); } SKIP: { # fd_seek write failure -c "/dev/full" or skip("No /dev/full", 3); open my $fh, "> /dev/full" or skip("Can't open /dev/full: $!", 3); my $io = Imager::io_new_fd(fileno($fh)); ok($io, "make fd io for /dev/full"); Imager::i_clear_error(); is($io->raw_write("test"), -1, "fail to write"); my $msg = Imager->_error_as_msg; like($msg, qr/^write\(\) failure: /, "check error message"); print "# $msg\n"; # /dev/full succeeds on seek on Linux undef $io; } SKIP: { # fd_seek seek failure my $seekfail = "testout/t07seekfail.dat"; open my $fh, "> $seekfail" or skip("Can't open $seekfail: $!", 3); my $io = Imager::io_new_fd(fileno($fh)); ok($io, "make fd io for $seekfail"); Imager::i_clear_error(); is($io->raw_seek(-1, SEEK_SET), -1, "shouldn't be able to seek to -1"); my $msg = Imager->_error_as_msg; like($msg, qr/^lseek\(\) failure: /, "check error message"); print "# $msg\n"; undef $io; close $fh; unlink $seekfail; } SKIP: { # fd_seek read failure open my $fh, "> testout/t07writeonly.txt" or skip("Can't open testout/t07writeonly.txt: $!", 3); my $io = Imager::io_new_fd(fileno($fh)); ok($io, "make fd io for write-only"); Imager::i_clear_error(); my $buf; is($io->raw_read($buf, 10), undef, "file open for write shouldn't be readable"); my $msg = Imager->_error_as_msg; like($msg, qr/^read\(\) failure: /, "check error message"); print "# $msg\n"; undef $io; } SKIP: { # fd_seek eof open my $fh, "> testout/t07readeof.txt" or skip("Can't open testout/t07readeof.txt: $!", 5); binmode $fh; print $fh "test"; close $fh; open my $fhr, "< testout/t07readeof.txt", or skip("Can't open testout/t07readeof.txt: $!", 5); my $io = Imager::io_new_fd(fileno($fhr)); ok($io, "make fd io for read eof"); Imager::i_clear_error(); my $buf; is($io->raw_read($buf, 10), 4, "10 byte read on 4 byte file should return 4"); my $msg = Imager->_error_as_msg; is($msg, "", "should be no error message") or print STDERR "# read(4) message is: $msg\n"; Imager::i_clear_error(); $buf = ''; is($io->raw_read($buf, 10), 0, "10 byte read at end of 4 byte file should return 0 (eof)"); $msg = Imager->_error_as_msg; is($msg, "", "should be no error message") or print STDERR "# read(4), eof message is: $msg\n"; undef $io; } { # buffered I/O my $data="P2\n2 2\n255\n 255 0\n0 255\n"; my $io = Imager::io_new_buffer($data); my $c = $io->getc(); is($c, ord "P", "getc"); my $peekc = $io->peekc(); is($peekc, ord "2", "peekc"); my $peekn = $io->peekn(2); is($peekn, "2\n", "peekn"); $c = $io->getc(); is($c, ord "2", "getc after peekc/peekn"); is($io->seek(0, SEEK_SET), "0", "seek"); is($io->getc, ord "P", "check we got back to the start"); } { # test closecb result is propagated my $success_cb = sub { 1 }; my $failure_cb = sub { 0 }; { my $io = Imager::io_new_cb(undef, $success_cb, undef, $success_cb); is($io->close(), 0, "test successful close"); } { my $io = Imager::io_new_cb(undef, $success_cb, undef, $failure_cb); is($io->close(), -1, "test failed close"); } } { # buffered coverage/function tests # some data to play with my $base = pack "C*", map rand(26) + ord("a"), 0 .. 20_001; { # buffered accessors my $io = Imager::io_new_buffer($base); ok($io->set_buffered(0), "set unbuffered"); ok(!$io->is_buffered, "verify unbuffered"); ok($io->set_buffered(1), "set buffered"); ok($io->is_buffered, "verify buffered"); } { # initial i_io_read(), buffered my $pos = 0; my $ops = ""; my $work = $base; my $read = sub { my ($size) = @_; my $req_size = $size; if ($pos + $size > length $work) { $size = length($work) - $pos; } my $result = substr($work, $pos, $size); $pos += $size; $ops .= "R$req_size>$size;"; print "# read $req_size>$size\n"; return $result; }; my $write = sub { my ($data) = @_; substr($work, $pos, length($data), $data); return 1; }; { my $io = Imager::io_new_cb(undef, $read, undef, undef); my $buf; is($io->read($buf, 1000), 1000, "read initial 1000"); is($buf, substr($base, 0, 1000), "check data read"); is($ops, "R8192>8192;", "check read op happened to buffer size"); undef $buf; is($io->read($buf, 1001), 1001, "read another 1001"); is($buf, substr($base, 1000, 1001), "check data read"); is($ops, "R8192>8192;", "should be no further reads"); undef $buf; is($io->read($buf, 40_000), length($base) - 2001, "read the rest in one chunk"); is($buf, substr($base, 2001), "check the data read"); my $buffer_left = 8192 - 2001; my $after_buffer = length($base) - 8192; is($ops, "R8192>8192;R".(40_000 - $buffer_left).">$after_buffer;R21999>0;", "check we tried to read the remainder"); } { # read after write errors my $io = Imager::io_new_cb($write, $read, undef, undef); is($io->write("test"), 4, "write 4 bytes, io in write mode"); is($io->read2(10), undef, "read should fail"); is($io->peekn(10), undef, "peekn should fail"); is($io->getc(), -1, "getc should fail"); is($io->peekc(), -1, "peekc should fail"); } } { my $io = Imager::io_new_buffer($base); print "# buffer fill check\n"; ok($io, "make memory io"); my $buf; is($io->read($buf, 4096), 4096, "read 4k"); is($buf, substr($base, 0, 4096), "check data is correct"); # peek a bit undef $buf; is($io->peekn(5120), substr($base, 4096, 5120), "peekn() 5120, which should exceed the buffer, and only read the left overs"); } { # initial peekn my $io = Imager::io_new_buffer($base); is($io->peekn(10), substr($base, 0, 10), "make sure initial peekn() is sane"); is($io->read2(10), substr($base, 0, 10), "and that reading 10 gets the expected data"); } { # oversize peekn my $io = Imager::io_new_buffer($base); is($io->peekn(10_000), substr($base, 0, 8192), "peekn() larger than buffer should return buffer-size bytes"); } { # small peekn then large peekn with a small I/O back end # this might happen when reading from a socket my $work = $base; my $pos = 0; my $ops = ''; my $reader = sub { my ($size) = @_; my $req_size = $size; # do small reads, to trigger a possible bug if ($size > 10) { $size = 10; } if ($pos + $size > length $work) { $size = length($work) - $pos; } my $result = substr($work, $pos, $size); $pos += $size; $ops .= "R$req_size>$size;"; print "# read $req_size>$size\n"; return $result; }; my $io = Imager::io_new_cb(undef, $reader, undef, undef); ok($io, "small reader io"); is($io->peekn(25), substr($base, 0, 25), "peek 25"); is($ops, "R8192>10;R8182>10;R8172>10;", "check we got the raw calls expected"); is($io->peekn(65), substr($base, 0, 65), "peek 65"); is($ops, "R8192>10;R8182>10;R8172>10;R8162>10;R8152>10;R8142>10;R8132>10;", "check we got the raw calls expected"); } for my $buffered (1, 0) { # peekn followed by errors my $buffered_desc = $buffered ? "buffered" : "unbuffered"; my $read = 0; my $base = "abcdef"; my $pos = 0; my $reader = sub { my $size = shift; my $req_size = $size; if ($pos + $size > length $base) { $size = length($base) - $pos; } # error instead of eof if ($size == 0) { print "# read $req_size>error\n"; return; } my $result = substr($base, $pos, $size); $pos += $size; print "# read $req_size>$size\n"; return $result; }; my $io = Imager::io_new_cb(undef, $reader, undef, undef); ok($io, "make $buffered_desc cb with error after 6 bytes"); is($io->peekn(5), "abcde", "peekn until just before error ($buffered_desc)"); is($io->peekn(6), "abcdef", "peekn until error ($buffered_desc)"); is($io->peekn(7), "abcdef", "peekn past error ($buffered_desc)"); ok(!$io->error, "should be no error indicator, since data buffered ($buffered_desc)"); ok(!$io->eof, "should be no eof indicator, since data buffered ($buffered_desc)"); # consume it is($io->read2(6), "abcdef", "consume the buffer ($buffered_desc)"); is($io->peekn(10), undef, "peekn should get an error indicator ($buffered_desc)"); ok($io->error, "should be an error state ($buffered_desc)"); ok(!$io->eof, "but not eof ($buffered_desc)"); } { # peekn on an empty file my $io = Imager::io_new_buffer(""); is($io->peekn(10), "", "peekn on empty source"); ok($io->eof, "should be in eof state"); ok(!$io->error, "but not error"); } { # peekn on error source my $io = Imager::io_new_cb(undef, sub { return; }, undef, undef); is($io->peekn(10), undef, "peekn on empty source"); ok($io->error, "should be in error state"); ok(!$io->eof, "but not eof"); } { # peekn on short source my $io = Imager::io_new_buffer("abcdef"); is($io->peekn(4), "abcd", "peekn 4 on 6 byte source"); is($io->peekn(10), "abcdef", "followed by peekn 10 on 6 byte source"); is($io->peekn(10), "abcdef", "and again, now eof is set"); } { # peekn(0) Imager::i_clear_error(); my $io = Imager::io_new_buffer("abcdef"); is($io->peekn(0), undef, "peekn 0 on 6 byte source"); my $msg = Imager->_error_as_msg; is($msg, "peekn size must be positive"); } { # getc through a whole file (buffered) my $io = Imager::io_new_buffer($base); my $out = ''; while ((my $c = $io->getc()) != -1) { $out .= chr($c); } is($out, $base, "getc should return the file byte by byte (buffered)"); is($io->getc, -1, "another getc after eof should fail too"); ok($io->eof, "should be marked eof"); ok(!$io->error, "shouldn't be marked in error"); } { # getc through a whole file (unbuffered) my $io = Imager::io_new_buffer($base); $io->set_buffered(0); my $out = ''; while ((my $c = $io->getc()) != -1) { $out .= chr($c); } is($out, $base, "getc should return the file byte by byte (unbuffered)"); is($io->getc, -1, "another getc after eof should fail too"); ok($io->eof, "should be marked eof"); ok(!$io->error, "shouldn't be marked in error"); } { # buffered getc with an error my $io = Imager::io_new_cb(undef, sub { return; }, undef, undef); is($io->getc, -1, "buffered getc error"); ok($io->error, "io marked in error"); ok(!$io->eof, "but not eof"); } { # unbuffered getc with an error my $io = Imager::io_new_cb(undef, sub { return; }, undef, undef); $io->set_buffered(0); is($io->getc, -1, "unbuffered getc error"); ok($io->error, "io marked in error"); ok(!$io->eof, "but not eof"); } { # initial peekc - buffered my $io = Imager::io_new_buffer($base); my $c = $io->peekc; is($c, ord($base), "buffered peekc matches"); is($io->peekc, $c, "duplicate peekc matchess"); } { # initial peekc - unbuffered my $io = Imager::io_new_buffer($base); $io->set_buffered(0); my $c = $io->peekc; is($c, ord($base), "unbuffered peekc matches"); is($io->peekc, $c, "duplicate peekc matchess"); } { # initial peekc eof - buffered my $io = Imager::io_new_cb(undef, sub { "" }, undef, undef); my $c = $io->peekc; is($c, -1, "buffered eof peekc is -1"); is($io->peekc, $c, "duplicate matches"); ok($io->eof, "io marked eof"); ok(!$io->error, "but not error"); } { # initial peekc eof - unbuffered my $io = Imager::io_new_cb(undef, sub { "" }, undef, undef); $io->set_buffered(0); my $c = $io->peekc; is($c, -1, "buffered eof peekc is -1"); is($io->peekc, $c, "duplicate matches"); ok($io->eof, "io marked eof"); ok(!$io->error, "but not error"); } { # initial peekc error - buffered my $io = Imager::io_new_cb(undef, sub { return; }, undef, undef); my $c = $io->peekc; is($c, -1, "buffered error peekc is -1"); is($io->peekc, $c, "duplicate matches"); ok($io->error, "io marked error"); ok(!$io->eof, "but not eof"); } { # initial peekc error - unbuffered my $io = Imager::io_new_cb(undef, sub { return; }, undef, undef); $io->set_buffered(0); my $c = $io->peekc; is($c, -1, "unbuffered error peekc is -1"); is($io->peekc, $c, "duplicate matches"); ok($io->error, "io marked error"); ok(!$io->eof, "but not eof"); } { # initial putc my $io = Imager::io_new_bufchain(); is($io->putc(ord "A"), ord "A", "initial putc buffered"); is($io->close, 0, "close it"); is(Imager::io_slurp($io), "A", "check it was written"); } { # initial putc - unbuffered my $io = Imager::io_new_bufchain(); $io->set_buffered(0); is($io->putc(ord "A"), ord "A", "initial putc unbuffered"); is($io->close, 0, "close it"); is(Imager::io_slurp($io), "A", "check it was written"); } { # putc unbuffered with error my $io = Imager::io_new_cb(undef, undef, undef, undef); $io->set_buffered(0); is($io->putc(ord "A"), -1, "initial putc unbuffered error"); ok($io->error, "io in error"); is($io->putc(ord "B"), -1, "still in error"); } { # writes while in read state my $io = Imager::io_new_cb(sub { 1 }, sub { return "AA" }, undef, undef); is($io->getc, ord "A", "read to setup read buffer"); is($io->putc(ord "B"), -1, "putc should fail"); is($io->write("test"), -1, "write should fail"); } { # buffered putc error handling # tests the check for error state in the buffered putc code my $io = Imager::io_new_cb(undef, undef, undef, undef); $io->putc(ord "A"); ok(!$io->flush, "flush should fail"); ok($io->error, "should be in error state"); is($io->putc(ord "B"), -1, "check for error"); } { # buffered putc flush error handling # test handling of flush failure and of the error state resulting # from that my $io = Imager::io_new_cb(undef, undef, undef, undef); my $i = 0; while (++$i < 100_000 && $io->putc(ord "A") == ord "A") { # until we have to flush and fail doing do } is($i, 8193, "should have failed on 8193rd byte"); ok($io->error, "should be in error state"); is($io->putc(ord "B"), -1, "next putc should fail"); } { # buffered write flush error handling # test handling of flush failure and of the error state resulting # from that my $io = Imager::io_new_cb(undef, undef, undef, undef); my $i = 0; while (++$i < 100_000 && $io->write("A") == 1) { # until we have to flush and fail doing do } is($i, 8193, "should have failed on 8193rd byte"); ok($io->error, "should be in error state"); is($io->write("B"), -1, "next write should fail"); } { # buffered read error my $io = Imager::io_new_cb(undef, undef, undef, undef); is($io->read2(10), undef, "initial read returning error"); ok($io->error, "should be in error state"); } { # unbuffered read error my $io = Imager::io_new_cb(undef, undef, undef, undef); $io->set_buffered(0); is($io->read2(10), undef, "initial read returning error"); ok($io->error, "should be in error state"); } { # unbuffered write error my $count = 0; my $io = Imager::io_new_cb(sub { return $count++; }, undef, undef, undef); $io->set_buffered(0); is($io->write("A"), -1, "unbuffered write failure"); ok($io->error, "should be in error state"); is($io->write("BC"), -1, "should still fail"); } { # buffered write + large write my $io = Imager::io_new_bufchain(); is($io->write(substr($base, 0, 4096)), 4096, "should be buffered"); is($io->write(substr($base, 4096)), length($base) - 4096, "large write, should fill buffer and fall back to direct write"); is($io->close, 0, "close it"); is(Imager::io_slurp($io), $base, "make sure the data is correct"); } { # initial large write with failure # tests error handling for the case where we bypass the buffer # when the write is too large to fit my $io = Imager::io_new_cb(undef, undef, undef, undef); ok($io->flush, "flush with nothing buffered should succeed"); is($io->write($base), -1, "large write failure"); ok($io->error, "should be in error state"); is($io->close, -1, "should fail to close"); } { # write that causes a flush then fills the buffer a bit my $io = Imager::io_new_bufchain(); is($io->write(substr($base, 0, 6000)), 6000, "fill the buffer a bit"); is($io->write(substr($base, 6000, 4000)), 4000, "cause it to flush and then fill some more"); is($io->write(substr($base, 10000)), length($base)-10000, "write out the rest of our test data"); is($io->close, 0, "close the stream"); is(Imager::io_slurp($io), $base, "make sure the data is right"); } { # failure on flush on close my $io = Imager::io_new_cb(undef, undef, undef, undef); is($io->putc(ord "A"), ord "A", "something in the buffer"); ok(!$io->error, "should be no error yet"); is($io->close, -1, "close should failure due to flush error"); } { # seek failure my $io = Imager::io_new_cb(undef, undef, undef, undef); is($io->seek(0, SEEK_SET), -1, "seek failure"); } { # read a little and seek my $io = Imager::io_new_buffer($base); is($io->getc, ord $base, "read one"); is($io->getc, ord substr($base, 1, 1), "read another"); is($io->seek(-1, SEEK_CUR), 1, "seek relative back to origin+1"); is($io->getc, ord substr($base, 1, 1), "read another again"); } { # seek with failing flush my $io = Imager::io_new_cb(undef, undef, undef, undef); is($io->putc(ord "A"), ord "A", "write one"); ok(!$io->error, "not in error mode (yet)"); is($io->seek(0, SEEK_SET), -1, "seek failure due to flush"); ok($io->error, "in error mode"); } { # gets() my $data = "test1\ntest2\ntest3"; my $io = Imager::io_new_buffer($data); is($io->gets(6), "test1\n", "gets(6)"); is($io->gets(5), "test2", "gets(5) (short for the line)"); is($io->gets(10), "\n", "gets(10) the rest of the line (the newline)"); is($io->gets(), "test3", "gets(default) unterminated line"); } { # more gets() my $data = "test1\ntest2\ntest3"; my $io = Imager::io_new_buffer($data); is($io->gets(6, ord("1")), "test1", "gets(6) (line terminator 1)"); is($io->gets(6, ord("2")), "\ntest2", "gets(6) (line terminator 2)"); is($io->gets(6, ord("3")), "\ntest3", "gets(6) (line terminator 3)"); is($io->getc, -1, "should be eof"); } } { # based on discussion on IRC, user was attempting to write a TIFF # image file with only a write callback, but TIFF requires seek and # read callbacks when writing. # https://rt.cpan.org/Ticket/Display.html?id=76782 my $cb = Imager::io_new_cb(undef, undef, undef, undef); { Imager::i_clear_error(); my $data; is($cb->read($data, 10), undef, "default read callback should fail"); is(Imager->_error_as_msg(), "read callback called but no readcb supplied", "check error message"); } { Imager::i_clear_error(); is($cb->raw_write("abc"), -1, "default write callback should fail"); is(Imager->_error_as_msg(), "write callback called but no writecb supplied", "check error message"); } { Imager::i_clear_error(); is($cb->seek(0, 0), -1, "default seek callback should fail"); is(Imager->_error_as_msg(), "seek callback called but no seekcb supplied", "check error message"); } } SKIP: { $Config{useperlio} or skip "PerlIO::scalar requires perlio", 13; my $foo; open my $fh, "+<", \$foo; my $io = Imager::IO->_new_perlio($fh); ok($io, "perlio: make a I/O object for a perl scalar fh"); is($io->write("test"), 4, "perlio: check we can write"); is($io->seek(2, SEEK_SET), 2, "perlio: check we can seek"); is($io->write("more"), 4, "perlio: write some more"); is($io->seek(0, SEEK_SET), 0, "perlio: seek back to start"); my $data; is($io->read($data, 10), 6, "perlio: read everything back"); is($data, "temore", "perlio: check we read back what we wrote"); is($io->close, 0, "perlio: close it"); is($foo, "temore", "perlio: check it got to the scalar properly"); my $io2 = Imager::IO->new_fh($fh); ok($io2, "new_fh() can make an I/O layer object from a scalar fh"); close $fh; my $im = Imager->new(xsize => 10, ysize => 10); $foo = ""; open my $fh2, ">", \$foo; ok($im->write(fh => $fh2, type => "pnm"), "can write image to scalar fh") or print "# ", $im->errstr, "\n"; close $fh2; open my $fh3, "<", \$foo; my $im2 = Imager->new(fh => $fh3); ok($im2, "read image from a scalar fh"); is_image($im, $im2, "check they match"); } { tie *FOO, "IO::Tied"; my $io = Imager::IO->new_fh(\*FOO); ok($io, "tied: make a I/O object for a tied fh"); is($io->write("test"), 4, "tied: check we can write"); is($io->seek(2, SEEK_SET), 2, "tied: check we can seek"); is($io->write("more"), 4, "tied: write some more"); is($io->seek(0, SEEK_SET), 0, "tied: seek back to start"); my $data; is($io->read($data, 10), 6, "tied: read everything back"); is($data, "temore", "tied: check we read back what we wrote"); is($io->close, 0, "tied: close it"); is(tied(*FOO)->[0], "temore", "tied: check it got to the output properly"); } { # pass buffer by reference my $data = "This is a test"; my $data2 = $data; my $io = Imager::IO->new_buffer(\$data2) or diag "Can't create from SV REF:", Imager->_error_as_msg; undef $data2; my $tmp = $io->read2(1000); is($tmp, $data, "buffer io created by reference"); } { my @buffer_tests = ( [ 1000, "IV" ], [ 1000.1, "NV" ], [ qr/abcd/, "regexp", $] < 5.014 && "Can't use regexps as a buffer before 5.14" ], ); for my $test (@buffer_tests) { my ($val, $note, $skip) = @$test; SKIP: { $skip and skip $skip, 4; SKIP: { my $temp = $val; my $io = Imager::IO->new_buffer(\$temp); ok($io, "$note/ref: open_buffer") or skip "couldn't open", 1; my $read = $io->read2(1000); is($read, "$val", "$note/ref: read result"); } SKIP: { my $temp = $val; my $io = Imager::IO->new_buffer($temp); ok($io, "$note: open_buffer") or skip "couldn't open", 1; my $read = $io->read2(1000); is($read, "$val", "$note: read result"); } } } } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t07.ppm", "testout/t07iolayer.log"; } sub eof_read { my ($max_len) = @_; return ''; } sub good_read { my ($max_len) = @_; my $data = "testdata"; length $data <= $max_len or substr($data, $max_len) = ''; print "# good_read ($max_len) => $data\n"; return $data; } sub fail_write { return; } sub fail_read { return; } sub fail_seek { return -1; } package IO::Tied; use base 'Tie::Handle'; use IO::Seekable; sub TIEHANDLE { return bless [ "", 0 ]; } sub PRINT { for my $entry (@_[1 .. $#_]) { substr($_[0][0], $_[0][1], length $entry, $entry); $_[0][1] += length $entry; } return 1; } sub SEEK { my ($self, $offset, $whence) = @_; my $newpos; if ($whence == SEEK_SET) { $newpos = $offset; } elsif ($whence == SEEK_CUR) { $newpos = $self->[1] + $offset; } elsif ($whence == SEEK_END) { $newpos = length($self->[0]) + $newpos; } else { return -1; } if ($newpos < 0) { return 0; } $self->[1] = $newpos; return 1; } sub TELL { return $_[0][1]; } sub READ { my $self = shift; my $outlen = $_[1]; my $offset = @_ > 2 ? $_[2] : 0; if ($self->[1] + $outlen > length $self->[0]) { $outlen = length($self->[0]) - $self->[1]; $outlen <= 0 and return ""; } defined $_[0] or $_[0] = ""; substr($_[0], $offset, $outlen) = substr($self->[0], $self->[1], $outlen); $self->[1] += $outlen; return $outlen; } libimager-perl-1.004+dfsg.orig/t/200-file/230-notiff.t0000644000175000017500000000231512263740601021220 0ustar gregoagregoa#!perl -w use strict; use Test::More; use Imager qw(:all); $Imager::formats{"tiff"} and plan skip_all => "tiff support available - this tests the lack of it"; plan tests => 12; my $im = Imager->new; ok(!$im->read(file=>"TIFF/testimg/comp4.tif"), "should fail to read tif"); cmp_ok($im->errstr, '=~', "format 'tiff' not supported", "check no tiff message"); ok(!$im->read_multi(file => "TIFF/testimg/comp4.tif"), "should fail to read multi tiff"); cmp_ok($im->errstr, '=~', "format 'tiff' not supported", "check no tiff message"); $im = Imager->new(xsize=>2, ysize=>2); ok(!$im->write(file=>"testout/notiff.tif"), "should fail to write tiff"); cmp_ok($im->errstr, '=~', "format 'tiff' not supported", "check no tiff message"); ok(!-e "testout/notiff.tif", "file shouldn't be created"); ok(!Imager->write_multi({file=>"testout/notiff.tif"}, $im, $im), "should fail to write multi tiff"); cmp_ok($im->errstr, '=~', "format 'tiff' not supported", "check no tiff message"); ok(!-e "testout/notiff.tif", "file shouldn't be created"); ok(!grep($_ eq 'tiff', Imager->read_types), "check tiff not in read types"); ok(!grep($_ eq 'tiff', Imager->write_types), "check tiff not in write types"); libimager-perl-1.004+dfsg.orig/t/200-file/220-nogif.t0000644000175000017500000000230012263740601021026 0ustar gregoagregoa#!perl -w use strict; $|=1; use Test::More; use Imager qw(:all); $Imager::formats{"gif"} and plan skip_all => "gif support available and this tests the lack of it"; plan tests => 12; my $im = Imager->new; ok(!$im->read(file=>"GIF/testimg/scale.gif"), "should fail to read gif"); cmp_ok($im->errstr, '=~', "format 'gif' not supported", "check no gif message"); ok(!Imager->read_multi(file=>"GIF/testimg/scale.gif"), "should fail to read multi gif"); cmp_ok($im->errstr, '=~', "format 'gif' not supported", "check no gif message"); $im = Imager->new(xsize=>2, ysize=>2); ok(!$im->write(file=>"testout/nogif.gif"), "should fail to write gif"); ok(!-e "testout/nogif.gif", "shouldn't create the file"); cmp_ok($im->errstr, '=~', "format 'gif' not supported", "check no gif message"); ok(!Imager->write_multi({file => "testout/nogif.gif"}, $im, $im), "should fail to write multi gif"); ok(!-e "testout/nogif.gif", "shouldn't create the file"); cmp_ok($im->errstr, '=~', "format 'gif' not supported", "check no gif message"); ok(!grep($_ eq 'gif', Imager->read_types), "check gif not in read types"); ok(!grep($_ eq 'gif', Imager->write_types), "check gif not in write types"); libimager-perl-1.004+dfsg.orig/t/200-file/310-pnm.t0000644000175000017500000005417212263740601020534 0ustar gregoagregoa#!perl -w use Imager ':all'; use Test::More tests => 205; use strict; use Imager::Test qw(test_image_raw test_image_16 is_color3 is_color1 is_image test_image_named); $| = 1; -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t104ppm.log"); my $green = i_color_new(0,255,0,255); my $blue = i_color_new(0,0,255,255); my $red = i_color_new(255,0,0,255); my @files; my $img = test_image_raw(); my $fh = openimage(">testout/t104.ppm"); push @files, "t104.ppm"; my $IO = Imager::io_new_fd(fileno($fh)); ok(i_writeppm_wiol($img, $IO), "write pnm low") or die "Cannot write testout/t104.ppm\n"; close($fh); $IO = Imager::io_new_bufchain(); ok(i_writeppm_wiol($img, $IO), "write to bufchain") or die "Cannot write to bufchain"; my $data = Imager::io_slurp($IO); $fh = openimage("testout/t104.ppm"); $IO = Imager::io_new_fd( fileno($fh) ); my $cmpimg = i_readpnm_wiol($IO,-1); ok($cmpimg, "read image we wrote") or die "Cannot read testout/t104.ppm\n"; close($fh); is(i_img_diff($img, $cmpimg), 0, "compare written and read images"); my $rdata = slurp("testout/t104.ppm"); is($data, $rdata, "check data read from file and bufchain data"); # build a grayscale image my $gimg = Imager::ImgRaw::new(150, 150, 1); my $gray = i_color_new(128, 0, 0, 255); my $dgray = i_color_new(64, 0, 0, 255); my $white = i_color_new(255, 0, 0, 255); i_box_filled($gimg, 20, 20, 130, 130, $gray); i_box_filled($gimg, 40, 40, 110, 110, $dgray); i_arc($gimg, 75, 75, 30, 0, 361, $white); push @files, "t104_gray.pgm"; open FH, "> testout/t104_gray.pgm" or die "Cannot create testout/t104_gray.pgm: $!\n"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); ok(i_writeppm_wiol($gimg, $IO), "write grayscale"); close FH; open FH, "< testout/t104_gray.pgm" or die "Cannot open testout/t104_gray.pgm: $!\n"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); my $gcmpimg = i_readpnm_wiol($IO, -1); ok($gcmpimg, "read grayscale"); is(i_img_diff($gimg, $gcmpimg), 0, "compare written and read greyscale images"); my $ooim = Imager->new; ok($ooim->read(file=>"testimg/simple.pbm"), "read simple pbm, via OO") or print "# ", $ooim->errstr, "\n"; check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 0), 0); check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 1), 255); check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 0), 255); check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 1), 0); is($ooim->type, 'paletted', "check pbm read as paletted"); is($ooim->tags(name=>'pnm_type'), 1, "check pnm_type tag"); { # https://rt.cpan.org/Ticket/Display.html?id=7465 # the pnm reader ignores the maxval that it reads from the pnm file my $maxval = Imager->new; ok($maxval->read(file=>"testimg/maxval.ppm"), "read testimg/maxval.ppm"); # this image contains three pixels, with each sample from 0 to 63 # the pixels are (63, 63, 63), (32, 32, 32) and (31, 31, 0) # check basic parameters is($maxval->getchannels, 3, "channel count"); is($maxval->getwidth, 3, "width"); is($maxval->getheight, 1, "height"); # check the pixels ok(my ($white, $grey, $green) = $maxval->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels"); is_color3($white, 255, 255, 255, "white pixel"); is_color3($grey, 130, 130, 130, "grey pixel"); is_color3($green, 125, 125, 0, "green pixel"); is($maxval->tags(name=>'pnm_type'), 6, "check pnm_type tag on maxval"); # and do the same for ASCII images my $maxval_asc = Imager->new; ok($maxval_asc->read(file=>"testimg/maxval_asc.ppm"), "read testimg/maxval_asc.ppm"); # this image contains three pixels, with each sample from 0 to 63 # the pixels are (63, 63, 63), (32, 32, 32) and (31, 31, 0) # check basic parameters is($maxval_asc->getchannels, 3, "channel count"); is($maxval_asc->getwidth, 3, "width"); is($maxval_asc->getheight, 1, "height"); is($maxval->tags(name=>'pnm_type'), 6, "check pnm_type tag on maxval"); # check the pixels ok(my ($white_asc, $grey_asc, $green_asc) = $maxval_asc->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels"); is_color3($white_asc, 255, 255, 255, "white asc pixel"); is_color3($grey_asc, 130, 130, 130, "grey asc pixel"); is_color3($green_asc, 125, 125, 0, "green asc pixel"); } { # previously we didn't validate maxval at all, make sure it's # validated now my $maxval0 = Imager->new; ok(!$maxval0->read(file=>'testimg/maxval_0.ppm'), "should fail to read maxval 0 image"); print "# ", $maxval0->errstr, "\n"; like($maxval0->errstr, qr/maxval is zero - invalid pnm file/, "error expected from reading maxval_0.ppm"); my $maxval65536 = Imager->new; ok(!$maxval65536->read(file=>'testimg/maxval_65536.ppm'), "should fail reading maxval 65536 image"); print "# ",$maxval65536->errstr, "\n"; like($maxval65536->errstr, qr/maxval of 65536 is over 65535 - invalid pnm file/, "error expected from reading maxval_65536.ppm"); # maxval of 256 is valid, and handled as of 0.56 my $maxval256 = Imager->new; ok($maxval256->read(file=>'testimg/maxval_256.ppm'), "should succeed reading maxval 256 image"); is_color3($maxval256->getpixel(x => 0, 'y' => 0), 0, 0, 0, "check black in maxval_256"); is_color3($maxval256->getpixel(x => 0, 'y' => 1), 255, 255, 255, "check white in maxval_256"); is($maxval256->bits, 16, "check bits/sample on maxval 256"); # make sure we handle maxval > 255 for ascii my $maxval4095asc = Imager->new; ok($maxval4095asc->read(file=>'testimg/maxval_4095_asc.ppm'), "read maxval_4095_asc.ppm"); is($maxval4095asc->getchannels, 3, "channels"); is($maxval4095asc->getwidth, 3, "width"); is($maxval4095asc->getheight, 1, "height"); is($maxval4095asc->bits, 16, "check bits/sample on maxval 4095"); ok(my ($white, $grey, $green) = $maxval4095asc->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels"); is_color3($white, 255, 255, 255, "white 4095 pixel"); is_color3($grey, 128, 128, 128, "grey 4095 pixel"); is_color3($green, 127, 127, 0, "green 4095 pixel"); } { # check i_format is set when reading a pnm file # doesn't really matter which file. my $maxval = Imager->new; ok($maxval->read(file=>"testimg/maxval.ppm"), "read test file"); my ($type) = $maxval->tags(name=>'i_format'); is($type, 'pnm', "check i_format"); } { # check file limits are checked my $limit_file = "testout/t104.ppm"; ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149"); my $im = Imager->new; ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image width/, "check message"); ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image height/, "check message"); ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside width limit"); ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside height limit"); # 150 x 150 x 3 channel image uses 67500 bytes ok(Imager->set_file_limits(reset=>1, bytes=>67499), "set bytes limit 67499"); ok(!$im->read(file=>$limit_file), "should fail - too many bytes"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/storage size/, "check error message"); ok(Imager->set_file_limits(reset=>1, bytes=>67500), "set bytes limit 67500"); ok($im->read(file=>$limit_file), "should succeed - just inside bytes limit"); Imager->set_file_limits(reset=>1); } { # check we correctly sync with the data stream my $im = Imager->new; ok($im->read(file => 'testimg/pgm.pgm', type => 'pnm'), "read pgm.pgm") or print "# cannot read pgm.pgm: ", $im->errstr, "\n"; print "# ", $im->getsamples('y' => 0), "\n"; is_color1($im->getpixel(x=>0, 'y' => 0), 254, "check top left"); } { # check error messages set correctly my $im = Imager->new; ok(!$im->read(file=>'t/200-file/310-pnm.t', type=>'pnm'), 'should fail to read script as an image file'); is($im->errstr, 'unable to read pnm image: bad header magic, not a PNM file', "check error message"); } { # RT #30074 # give 4/2 channel images a background color when saving to pnm my $im = Imager->new(xsize=>16, ysize=>16, channels=>4); $im->box(filled => 1, xmin => 8, color => '#FFE0C0'); $im->box(filled => 1, color => NC(0, 192, 192, 128), ymin => 8, xmax => 7); push @files, "t104_alpha.ppm"; ok($im->write(file=>"testout/t104_alpha.ppm", type=>'pnm'), "should succeed writing 4 channel image"); my $imread = Imager->new; ok($imread->read(file => 'testout/t104_alpha.ppm'), "read it back") or print "# ", $imread->errstr, "\n"; is_color3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0, "check transparent became black"); is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192, "check color came through"); is_color3($imread->getpixel('x' => 0, 'y' => 15), 0, 96, 96, "check translucent came through"); my $data; ok($im->write(data => \$data, type => 'pnm', i_background => '#FF0000'), "write with red background"); ok($imread->read(data => $data, type => 'pnm'), "read it back"); is_color3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0, "check transparent became red"); is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192, "check color came through"); is_color3($imread->getpixel('x' => 0, 'y' => 15), 127, 96, 96, "check translucent came through"); } { # more RT #30074 - 16 bit images my $im = Imager->new(xsize=>16, ysize=>16, channels=>4, bits => 16); $im->box(filled => 1, xmin => 8, color => '#FFE0C0'); $im->box(filled => 1, color => NC(0, 192, 192, 128), ymin => 8, xmax => 7); push @files, "t104_alp16.ppm"; ok($im->write(file=>"testout/t104_alp16.ppm", type=>'pnm', pnm_write_wide_data => 1), "should succeed writing 4 channel image"); my $imread = Imager->new; ok($imread->read(file => 'testout/t104_alp16.ppm'), "read it back"); is($imread->bits, 16, "check we did produce a 16 bit image"); is_color3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0, "check transparent became black"); is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192, "check color came through"); is_color3($imread->getpixel('x' => 0, 'y' => 15), 0, 96, 96, "check translucent came through"); my $data; ok($im->write(data => \$data, type => 'pnm', i_background => '#FF0000', pnm_write_wide_data => 1), "write with red background"); ok($imread->read(data => $data, type => 'pnm'), "read it back"); is($imread->bits, 16, "check it's 16-bit"); is_color3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0, "check transparent became red"); is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192, "check color came through"); is_color3($imread->getpixel('x' => 0, 'y' => 15), 127, 96, 96, "check translucent came through"); } # various bad input files print "# check error handling\n"; { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_bin.ppm', type=>'pnm'), "fail to read short bin ppm"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_bin16.ppm', type=>'pnm'), "fail to read short bin ppm (maxval 65535)"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_bin.pgm', type=>'pnm'), "fail to read short bin pgm"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_bin16.pgm', type=>'pnm'), "fail to read short bin pgm (maxval 65535)"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_bin.pbm', type => 'pnm'), "fail to read a short bin pbm"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_asc.ppm', type => 'pnm'), "fail to read a short asc ppm"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_asc.pgm', type => 'pnm'), "fail to read a short asc pgm"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/short_asc.pbm', type => 'pnm'), "fail to read a short asc pbm"); cmp_ok($im->errstr, '=~', 'short read - file truncated', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/bad_asc.ppm', type => 'pnm'), "fail to read a bad asc ppm"); cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/bad_asc.pgm', type => 'pnm'), "fail to read a bad asc pgm"); cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm', "check error message"); } { my $im = Imager->new; ok(!$im->read(file => 'testimg/bad_asc.pbm', type => 'pnm'), "fail to read a bad asc pbm"); cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm', "check error message"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_bin.ppm', type => 'pnm', allow_incomplete => 1), "partial read bin ppm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_bin16.ppm', type => 'pnm', allow_incomplete => 1), "partial read bin16 ppm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); is($im->bits, 16, "check correct bits"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_bin.pgm', type => 'pnm', allow_incomplete => 1), "partial read bin pgm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_bin16.pgm', type => 'pnm', allow_incomplete => 1), "partial read bin16 pgm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_bin.pbm', type => 'pnm', allow_incomplete => 1), "partial read bin pbm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_asc.ppm', type => 'pnm', allow_incomplete => 1), "partial read asc ppm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_asc.pgm', type => 'pnm', allow_incomplete => 1), "partial read asc pgm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/short_asc.pbm', type => 'pnm', allow_incomplete => 1), "partial read asc pbm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my @imgs = Imager->read_multi(file => 'testimg/multiple.ppm'); is( 0+@imgs, 3, "Read 3 images"); is( $imgs[0]->tags( name => 'pnm_type' ), 1, "Image 1 is type 1" ); is( $imgs[0]->getwidth, 2, " ... width=2" ); is( $imgs[0]->getheight, 2, " ... width=2" ); is( $imgs[1]->tags( name => 'pnm_type' ), 6, "Image 2 is type 6" ); is( $imgs[1]->getwidth, 164, " ... width=164" ); is( $imgs[1]->getheight, 180, " ... width=180" ); is( $imgs[2]->tags( name => 'pnm_type' ), 5, "Image 3 is type 5" ); is( $imgs[2]->getwidth, 2, " ... width=2" ); is( $imgs[2]->getheight, 2, " ... width=2" ); } { my $im = Imager->new; ok($im->read(file => 'testimg/bad_asc.ppm', type => 'pnm', allow_incomplete => 1), "partial read bad asc ppm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/bad_asc.pgm', type => 'pnm', allow_incomplete => 1), "partial read bad asc pgm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { my $im = Imager->new; ok($im->read(file => 'testimg/bad_asc.pbm', type => 'pnm', allow_incomplete => 1), "partial read bad asc pbm"); is($im->tags(name => 'i_incomplete'), 1, "partial flag set"); is($im->tags(name => 'i_lines_read'), 1, "lines_read set"); } { print "# monochrome output\n"; my $im = Imager->new(xsize => 10, ysize => 10, channels => 1, type => 'paletted'); ok($im->addcolors(colors => [ '#000000', '#FFFFFF' ]), "add black and white"); $im->box(filled => 1, xmax => 4, color => '#000000'); $im->box(filled => 1, xmin => 5, color => '#FFFFFF'); is($im->type, 'paletted', 'mono still paletted'); push @files, "t104_mono.pbm"; ok($im->write(file => 'testout/t104_mono.pbm', type => 'pnm'), "save as pbm"); # check it my $imread = Imager->new; ok($imread->read(file => 'testout/t104_mono.pbm', type=>'pnm'), "read it back in") or print "# ", $imread->errstr, "\n"; is($imread->type, 'paletted', "check result is paletted"); is($imread->tags(name => 'pnm_type'), 4, "check type"); is_image($im, $imread, "check image matches"); } { print "# monochrome output - reversed palette\n"; my $im = Imager->new(xsize => 10, ysize => 10, channels => 1, type => 'paletted'); ok($im->addcolors(colors => [ '#FFFFFF', '#000000' ]), "add white and black"); $im->box(filled => 1, xmax => 4, color => '#000000'); $im->box(filled => 1, xmin => 5, color => '#FFFFFF'); is($im->type, 'paletted', 'mono still paletted'); push @files, "t104_mono2.pbm"; ok($im->write(file => 'testout/t104_mono2.pbm', type => 'pnm'), "save as pbm"); # check it my $imread = Imager->new; ok($imread->read(file => 'testout/t104_mono2.pbm', type=>'pnm'), "read it back in") or print "# ", $imread->errstr, "\n"; is($imread->type, 'paletted', "check result is paletted"); is($imread->tags(name => 'pnm_type'), 4, "check type"); is_image($im, $imread, "check image matches"); } { print "# 16-bit output\n"; my $data; my $im = test_image_16(); # without tag, it should do 8-bit output ok($im->write(data => \$data, type => 'pnm'), "write 16-bit image as 8-bit/sample ppm"); my $im8 = Imager->new; ok($im8->read(data => $data), "read it back"); is($im8->tags(name => 'pnm_maxval'), 255, "check maxval"); is_image($im, $im8, "check image matches"); # try 16-bit output $im->settag(name => 'pnm_write_wide_data', value => 1); $data = ''; ok($im->write(data => \$data, type => 'pnm'), "write 16-bit image as 16-bit/sample ppm"); push @files, "t104_16.ppm"; $im->write(file=>'testout/t104_16.ppm'); my $im16 = Imager->new; ok($im16->read(data => $data), "read it back"); is($im16->tags(name => 'pnm_maxval'), 65535, "check maxval"); push @files, "t104_16b.ppm"; $im16->write(file=>'testout/t104_16b.ppm'); is_image($im, $im16, "check image matches"); } { ok(grep($_ eq 'pnm', Imager->read_types), "check pnm in read types"); ok(grep($_ eq 'pnm', Imager->write_types), "check pnm in write types"); } { # test new() loading an image my $im = Imager->new(file => "testimg/penguin-base.ppm"); ok($im, "received an image"); is($im->getwidth, 164, "check width matches image"); # fail to load an image my $im2 = Imager->new(file => "Imager.pm", filetype => "pnm"); ok(!$im2, "no image when file failed to load"); cmp_ok(Imager->errstr, '=~', "bad header magic, not a PNM file", "check error message transferred"); # load from data SKIP: { ok(open(FH, "< testimg/penguin-base.ppm"), "open test file") or skip("couldn't open data source", 4); binmode FH; my $imdata = do { local $/; }; close FH; ok(length $imdata, "we got the data"); my $im3 = Imager->new(data => $imdata); ok($im3, "read the file data"); is($im3->getwidth, 164, "check width matches image"); } } { # image too large handling { ok(!Imager->new(file => "testimg/toowide.ppm", filetype => "pnm"), "fail to read a too wide image"); is(Imager->errstr, "unable to read pnm image: could not read image width: integer overflow", "check error message"); } { ok(!Imager->new(file => "testimg/tootall.ppm", filetype => "pnm"), "fail to read a too wide image"); is(Imager->errstr, "unable to read pnm image: could not read image height: integer overflow", "check error message"); } } { # make sure close is checked for each image type my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; for my $type (qw(basic basic16 gray gray16 mono)) { my $im = test_image_named($type); my $io = Imager::io_new_cb(sub { 1 }, undef, undef, $fail_close); ok(!$im->write(io => $io, type => "pnm"), "write $type image with a failing close handler"); like($im->errstr, qr/synthetic close failure/, "check error message"); } } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t104ppm.log"; unlink map "testout/$_", @files; } sub openimage { my $fname = shift; local(*FH); open(FH, $fname) or die "Cannot open $fname: $!\n"; binmode(FH); return *FH; } sub slurp { my $fh = openimage(shift); local $/; my $data = <$fh>; close($fh); return $data; } sub check_gray { my ($c, $gray) = @_; my ($g) = $c->rgba; is($g, $gray, "compare gray"); } libimager-perl-1.004+dfsg.orig/t/200-file/400-basic.t0000644000175000017500000002333012263740601021013 0ustar gregoagregoa#!perl -w ######################### We start with some black magic to print on failure. # this used to do the check for the load of Imager, but I want to be able # to count tests, which means I need to load Imager first # since many of the early tests already do this, we don't really need to use strict; use Imager; use IO::Seekable; my $buggy_giflib_file = "buggy_giflib.txt"; -d "testout" or mkdir "testout"; Imager::init("log"=>"testout/t50basicoo.log"); # single image/file types my @types = qw( jpeg png raw pnm gif tiff bmp tga ); # multiple image/file formats my @mtypes = qw(tiff gif); my %hsh=%Imager::formats; my $test_num = 0; my $count; for my $type (@types) { $count += 31 if $hsh{$type}; } for my $type (@mtypes) { $count += 7 if $hsh{$type}; } print "1..$count\n"; print "# avaliable formats:\n"; for(keys %hsh) { print "# $_\n"; } #print Dumper(\%hsh); my $img = Imager->new(); my %files; @files{@types} = ({ file => "JPEG/testimg/209_yonge.jpg" }, { file => "testimg/test.png" }, { file => "testimg/test.raw", xsize=>150, ysize=>150, type=>'raw', interleave => 0}, { file => "testimg/penguin-base.ppm" }, { file => "GIF/testimg/expected.gif" }, { file => "TIFF/testimg/comp8.tif" }, { file => "testimg/winrgb24.bmp" }, { file => "testimg/test.tga" }, ); my %writeopts = ( gif=> { make_colors=>'webmap', translate=>'closest', gifquant=>'gen', gif_delay=>20 }, ); for my $type (@types) { next unless $hsh{$type}; print "# type $type\n"; my %opts = %{$files{$type}}; my @a = map { "$_=>${opts{$_}}" } keys %opts; print "#opening Format: $type, options: @a\n"; ok($img->read( %opts ), "reading from file", $img); #or die "failed: ",$img->errstr,"\n"; my %mopts = %opts; delete $mopts{file}; # read from a file handle my $fh = IO::File->new($opts{file}, "r"); if (ok($fh, "opening $opts{file}")) { binmode $fh; my $fhimg = Imager->new; if (ok($fhimg->read(fh=>$fh, %mopts), "read from fh")) { ok($fh->seek(0, SEEK_SET), "seek after read"); if (ok($fhimg->read(fh=>$fh, %mopts, type=>$type), "read from fh")) { ok(Imager::i_img_diff($img->{IMG}, $fhimg->{IMG}) == 0, "image comparison after fh read"); } else { skip("no image to compare"); } ok($fh->seek(0, SEEK_SET), "seek after read"); } # read from a fd my $fdimg = Imager->new; if (ok($fdimg->read(fd=>fileno($fh), %mopts, type=>$type), "read from fd")) { ok(Imager::i_img_diff($img->{IMG}, $fdimg->{IMG}) == 0, "image comparistion after fd read"); } else { skip("no image to compare"); } ok($fh->seek(0, SEEK_SET), "seek after fd read"); ok($fh->close, "close fh after reads"); } else { skip("couldn't open the damn file: $!", 7); } # read from a memory buffer open DATA, "< $opts{file}" or die "Cannot open $opts{file}: $!"; binmode DATA; my $data = do { local $/; }; close DATA; my $bimg = Imager->new; if (ok($bimg->read(data=>$data, %mopts, type=>$type), "read from buffer", $img)) { ok(Imager::i_img_diff($img->{IMG}, $bimg->{IMG}) == 0, "comparing buffer read image"); } else { skip("nothing to compare"); } # read from callbacks, both with minimum and maximum reads my $buf = $data; my $seekpos = 0; my $reader_min = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $size); $seekpos += length $out; $out; }; my $reader_max = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $maxread); $seekpos += length $out; $out; }; my $seeker = sub { my ($offset, $whence) = @_; #print "io_seeker($offset, $whence)\n"; if ($whence == SEEK_SET) { $seekpos = $offset; } elsif ($whence == SEEK_CUR) { $seekpos += $offset; } else { # SEEK_END $seekpos = length($buf) + $offset; } #print "-> $seekpos\n"; $seekpos; }; my $cbimg = Imager->new; ok($cbimg->read(callback=>$reader_min, seekcb=>$seeker, type=>$type, %mopts), "read from callback min", $cbimg); ok(Imager::i_img_diff($cbimg->{IMG}, $img->{IMG}) == 0, "comparing mincb image"); $seekpos = 0; ok($cbimg->read(callback=>$reader_max, seekcb=>$seeker, type=>$type, %mopts), "read from callback max", $cbimg); ok(Imager::i_img_diff($cbimg->{IMG}, $img->{IMG}) == 0, "comparing maxcb image"); } for my $type (@types) { next unless $hsh{$type}; print "# write tests for $type\n"; # test writes next unless $hsh{$type}; my $file = "testout/t50out.$type"; my $wimg = Imager->new; # if this doesn't work, we're so screwed up anyway ok($wimg->read(file=>"testimg/penguin-base.ppm"), "cannot read base file", $wimg); # first to a file print "# writing $type to a file\n"; my %extraopts; %extraopts = %{$writeopts{$type}} if $writeopts{$type}; ok($wimg->write(file=>$file, %extraopts), "writing $type to a file $file", $wimg); print "# writing $type to a FH\n"; # to a FH my $fh = IO::File->new($file, "w+") or die "Could not create $file: $!"; binmode $fh; ok($wimg->write(fh=>$fh, %extraopts, type=>$type), "writing $type to a FH", $wimg); ok($fh->seek(0, SEEK_END) > 0, "seek after writing $type to a FH"); ok(print($fh "SUFFIX\n"), "write to FH after writing $type"); ok($fh->close, "closing FH after writing $type"); if (ok(open(DATA, "< $file"), "opening data source")) { binmode DATA; my $data = do { local $/; }; close DATA; # writing to a buffer print "# writing $type to a buffer\n"; my $buf = ''; ok($wimg->write(data=>\$buf, %extraopts, type=>$type), "writing $type to a buffer", $wimg); $buf .= "SUFFIX\n"; open DATA, "> testout/t50_buf.$type" or die "Cannot create $type buffer file: $!"; binmode DATA; print DATA $buf; close DATA; ok($data eq $buf, "comparing file data to buffer"); $buf = ''; my $seekpos = 0; my $did_close; my $writer = sub { my ($what) = @_; if ($seekpos > length $buf) { $buf .= "\0" x ($seekpos - length $buf); } substr($buf, $seekpos, length $what) = $what; $seekpos += length $what; $did_close = 0; # the close must be last 1; }; my $reader_min = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $size); $seekpos += length $out; $out; }; my $reader_max = sub { my ($size, $maxread) = @_; my $out = substr($buf, $seekpos, $maxread); $seekpos += length $out; $out; }; use IO::Seekable; my $seeker = sub { my ($offset, $whence) = @_; #print "io_seeker($offset, $whence)\n"; if ($whence == SEEK_SET) { $seekpos = $offset; } elsif ($whence == SEEK_CUR) { $seekpos += $offset; } else { # SEEK_END $seekpos = length($buf) + $offset; } #print "-> $seekpos\n"; $seekpos; }; my $closer = sub { ++$did_close; }; print "# writing $type via callbacks (mb=1)\n"; ok($wimg->write(writecb=>$writer, seekcb=>$seeker, closecb=>$closer, readcb=>$reader_min, %extraopts, type=>$type, maxbuffer=>1), "writing $type to callback (mb=1)", $wimg); ok($did_close, "checking closecb called"); $buf .= "SUFFIX\n"; ok($data eq $buf, "comparing callback output to file data"); print "# writing $type via callbacks (no mb)\n"; $buf = ''; $did_close = 0; $seekpos = 0; # we don't use the closecb here - used to make sure we don't get # a warning/error on an attempt to call an undef close sub ok($wimg->write(writecb=>$writer, seekcb=>$seeker, readcb=>$reader_min, %extraopts, type=>$type), "writing $type to callback (no mb)", $wimg); $buf .= "SUFFIX\n"; ok($data eq $buf, "comparing callback output to file data"); } else { skip("couldn't open data source", 7); } } my $img2 = $img->crop(width=>50, height=>50); $img2 -> write(file=> 'testout/t50.ppm', type=>'pnm'); undef($img); # multi image/file tests print "# multi-image write tests\n"; for my $type (@mtypes) { next unless $hsh{$type}; print "# $type\n"; my $file = "testout/t50out.$type"; my $wimg = Imager->new; # if this doesn't work, we're so screwed up anyway ok($wimg->read(file=>"testout/t50out.$type"), "reading base file", $wimg); ok(my $wimg2 = $wimg->copy, "copying base image", $wimg); ok($wimg2->flip(dir=>'h'), "flipping base image", $wimg2); my @out = ($wimg, $wimg2); my %extraopts; %extraopts = %{$writeopts{$type}} if $writeopts{$type}; ok(Imager->write_multi({ file=>"testout/t50_multi.$type", %extraopts }, @out), "writing multiple to a file", "Imager"); # make sure we get the same back my @images = Imager->read_multi(file=>"testout/t50_multi.$type"); if (ok(@images == @out, "checking read image count")) { for my $i (0 .. $#out) { my $diff = Imager::i_img_diff($out[$i]{IMG}, $images[$i]{IMG}); print "# diff $diff\n"; ok($diff == 0, "comparing image $i"); } } else { skip("wrong number of images read", 2); } } Imager::malloc_state(); #print "ok 2\n"; sub ok { my ($ok, $msg, $img, $why, $skipcount) = @_; ++$test_num; if ($ok) { print "ok $test_num # $msg\n"; Imager::i_log_entry("ok $test_num # $msg\n", 0); } else { my $err; $err = $img->errstr if $img; # VMS (if we ever support it) wants the whole line in one print my $line = "not ok $test_num # line ".(caller)[2].": $msg"; $line .= ": $err" if $err; print $line, "\n"; Imager::i_log_entry($line."\n", 0); } skip($why, $skipcount) if defined $why; $ok; } sub skip { my ($why, $skipcount) = @_; $skipcount ||= 1; for (1.. $skipcount) { ++$test_num; print "ok $test_num # skipped $why\n"; } } libimager-perl-1.004+dfsg.orig/t/200-file/330-tga.t0000644000175000017500000002270512263740601020514 0ustar gregoagregoa#!perl -w use Imager qw(:all); use strict; use Test::More tests=>68; use Imager::Test qw(is_color4 is_image test_image); -d "testout" or mkdir "testout"; init_log("testout/t108tga.log",1); my $img = create_test_image(); my $base_diff = 0; write_test($img, "testout/t108_24bit.tga", 0, 0, ""); write_test($img, "testout/t108_24bit_rle.tga", 0, 1, ""); write_test($img, "testout/t108_15bit.tga", 1, 1, ""); write_test($img, "testout/t108_15bit_rle.tga", 1, 1, ""); # 'webmap' is noticably faster than the default my $im8 = Imager::i_img_to_pal($img, { make_colors=>'webmap', translate=>'errdiff'}); write_test($im8, "testout/t108_8bit.tga", 0, 0, ""); write_test($im8, "testout/t108_8bit_rle.tga", 0, 1, ""); write_test($im8, "testout/t108_8_15bit.tga", 1, 0, ""); write_test($im8, "testout/t108_8_15bit_rle.tga", 1, 1, ""); # use a fixed palette so we get reproducible results for the compressed # version my @bit4 = map { NC($_) } qw(605844 966600 0148b2 00f800 bf0a33 5e009e 2ead1b 0000f8 004b01 fd0000 0e1695 000002); my @bit1 = (NC(0, 0, 0), NC(176, 160, 144)); my $im4 = Imager::i_img_to_pal($img, { colors=>\@bit4, make_colors=>'none' }); my $im1 = Imager::i_img_to_pal($img, { colors=>\@bit1, make_colors=>'none', translate=>'errdiff' }); write_test($im4, "testout/t108_4bit.tga", 0, 1, ""); write_test($im1, "testout/t108_1bit.tga", 0, 1, "This is a comment!"); read_test("testout/t108_24bit.tga", $img); read_test("testout/t108_8bit.tga", $im8); read_test("testout/t108_4bit.tga", $im4); read_test("testout/t108_1bit.tga", $im1); # the following might have slight differences $base_diff = i_img_diff($img, $im8) * 2; print "# base difference $base_diff\n"; my $imoo = Imager->new; ok($imoo->read(file=>'testout/t108_24bit.tga'), "OO read image") or print "# ",$imoo->errstr,"\n"; ok($imoo->write(file=>'testout/t108_oo.tga'), "OO write image") or print "# ",$imoo->errstr,"\n"; my ($type) = $imoo->tags(name=>'i_format'); is($type, 'tga', "check i_format tag"); # in 0.44 and earlier, reading an image with an idstring of 128 or more # bytes would result in an allocation error, if the platform char type # was signed $imoo = Imager->new; ok($imoo->read(file=>'testimg/longid.tga'), "read long id image"); my ($id) = $imoo->tags(name=>'tga_idstring'); is($id, "X" x 128, "check tga_idstring tag"); my ($bitspp) = $imoo->tags(name=>'tga_bitspp'); is($bitspp, 24, "check tga_bitspp tag"); my ($compressed) = $imoo->tags(name=>'compressed'); is($compressed, 1, "check compressed tag"); { # check file limits are checked my $limit_file = "testout/t108_24bit.tga"; ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149"); my $im = Imager->new; ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image width/, "check message"); ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image height/, "check message"); ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside width limit"); ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside height limit"); # 150 x 150 x 3 channel image uses 67500 bytes ok(Imager->set_file_limits(reset=>1, bytes=>67499), "set bytes limit 67499"); ok(!$im->read(file=>$limit_file), "should fail - too many bytes"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/storage size/, "check error message"); ok(Imager->set_file_limits(reset=>1, bytes=>67500), "set bytes limit 67500"); ok($im->read(file=>$limit_file), "should succeed - just inside bytes limit"); Imager->set_file_limits(reset=>1); } { # Issue # 18397 # the issue is for 4 channel images to jpeg, but 2 channel images have # a similar problem on tga my $im = Imager->new(xsize=>100, ysize=>100, channels => 2); my $data; ok(!$im->write(data => \$data, type=>'tga'), "check failure of writing a 2 channel image"); is($im->errstr, "Cannot store 2 channel image in targa format", "check the error message"); } { ok(grep($_ eq 'tga', Imager->read_types), "check tga in read types"); ok(grep($_ eq 'tga', Imager->write_types), "check tga in write types"); } { # Issue #32926 # a sample image was read as all transparent # it had bitsperpixel = 16 and atribute channel set to 1, so it # should have an alpha channel. # So we'll do what the gimp does and treat a zero value as opaque. my $im = Imager->new; ok($im->read(file => 'testimg/alpha16.tga'), "read 16-bit/pixel alpha image"); my $c1 = $im->getpixel('x' => 0, 'y' => 0); is_color4($c1, 0, 0, 0, 0, "check transparent pixel"); my $c2 = $im->getpixel('x' => 19, 'y' => 0); is_color4($c2, 255, 0, 0, 255, "check opaque pixel"); # since this has an effect on writing too, write,it, read it, check it my $data; ok($im->write(data => \$data, type => 'tga', wierdpack => 1), "write 16-bit/pixel w/alpha"); my $im2 = Imager->new; ok($im2->read(data => $data), "read it back"); is_image($im, $im2, "check they match"); } { # prior to the types re-work we treated the tga xsize/ysize as # signed short, which is wrong SKIP: { my $im = Imager->new(xsize => 40960, ysize => 1); my $data; ok($im->write(data => \$data, type => "tga"), "write a wide (but not too wide) image out"); my $im2 = Imager->new(data => $data); ok($im2, "read it back in") or skip("Couldn't read the wide image", 2); is($im2->getwidth, 40960, "make sure the width survived the trip"); is($im2->getheight, 1, "make sure the height survived the trip"); } SKIP: { my $im = Imager->new(xsize => 1, ysize => 40960); my $data; ok($im->write(data => \$data, type => "tga"), "write a tall (but not too tall) image out"); my $im2 = Imager->new(data => $data); ok($im2, "read it back in") or skip("Couldn't read the tall image", 2); is($im2->getwidth, 1, "make sure the width survived the trip"); is($im2->getheight, 40960, "make sure the height survived the trip"); } } { # TGA files are limited to 0xFFFF x 0xFFFF pixels my $max_dim = 0xFFFF; { my $im = Imager->new(xsize => 1+$max_dim, ysize => 1); my $data = ''; ok(!$im->write(data => \$data, type => "tga"), "fail to write too wide an image"); is($im->errstr, "image too large for TGA", "check error message"); } SKIP: { my $im = Imager->new(xsize => $max_dim, ysize => 1); $im->box(fill => { hatch => "check4x4" }); my $data = ''; ok($im->write(data => \$data, type => "tga"), "write image at width limit") or print "# ", $im->errstr, "\n"; my $im2 = Imager->new(data => $data, ftype => "tga"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is($im->getwidth, $max_dim, "check width"); is($im->getheight, 1, "check height"); } { my $im = Imager->new(xsize => 1, ysize => 1+$max_dim); my $data = ''; ok(!$im->write(data => \$data, type => "tga"), "fail to write too tall an image"); is($im->errstr, "image too large for TGA", "check error message"); } SKIP: { my $im = Imager->new(xsize => 1, ysize => $max_dim); $im->box(fill => { hatch => "check2x2" }); my $data = ''; ok($im->write(data => \$data, type => "tga"), "write image at width limit"); my $im2 = Imager->new(data => $data, ftype => "tga"); ok($im2, "read it ok") or skip("cannot load the wide image", 1); is($im->getwidth, 1, "check width"); is($im->getheight, $max_dim, "check height"); } } { # check close failures are handled correctly my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; ok(!$im->write(type => "tga", callback => sub { 1 }, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } sub write_test { my ($im, $filename, $wierdpack, $compress, $idstring) = @_; local *FH; if (open FH, "> $filename") { binmode FH; my $IO = Imager::io_new_fd(fileno(FH)); ok(Imager::i_writetga_wiol($im, $IO, $wierdpack, $compress, $idstring), "write $filename") or print "# ",Imager->_error_as_msg(),"\n"; undef $IO; close FH; } else { fail("write $filename: open failed: $!"); } } sub read_test { my ($filename, $im, %tags) = @_; local *FH; if (open FH, "< $filename") { binmode FH; my $IO = Imager::io_new_fd(fileno(FH)); my $im_read = Imager::i_readtga_wiol($IO,-1); if ($im_read) { my $diff = i_img_diff($im, $im_read); cmp_ok($diff, '<=', $base_diff, "check read image vs original"); } else { fail("read $filename ".Imager->_error_as_msg()); } undef $IO; close FH; } else { fail("read $filename, open failure: $!"); } } sub create_test_image { my $green = i_color_new(0,255,0,255); my $blue = i_color_new(0,0,255,255); my $red = i_color_new(255,0,0,255); my $img = Imager::ImgRaw::new(150,150,3); i_box_filled($img, 70, 25, 130, 125, $green); i_box_filled($img, 20, 25, 80, 125, $blue); i_arc($img, 75, 75, 30, 0, 361, $red); i_conv($img, [0.1, 0.2, 0.4, 0.2, 0.1]); return $img; } libimager-perl-1.004+dfsg.orig/t/350-font/0000755000175000017500000000000012617614576017316 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/350-font/020-tt.t0000644000175000017500000003040212263740601020412 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 97; $|=1; BEGIN { use_ok(Imager => ':all') } use Imager::Test qw(diff_text_with_nul is_color3 is_image); -d "testout" or mkdir "testout"; init_log("testout/t35ttfont.log",2); SKIP: { skip("freetype 1.x unavailable or disabled", 96) unless $Imager::formats{"tt"}; print "# has tt\n"; my $deffont = './fontfiles/dodge.ttf'; my $fontname=$ENV{'TTFONTTEST'} || $deffont; if (!ok(-f $fontname, "check test font file exists")) { print "# cannot find fontfile for truetype test $fontname\n"; skip('Cannot load test font', 89); } #i_init_fonts(); # i_tt_set_aa(1); my $bgcolor = i_color_new(255,0,0,0); my $overlay = Imager::ImgRaw::new(320,140,3); i_box_filled($overlay, 0, 0, 319, 139, i_color_new(128, 128, 128)); my $ttraw = Imager::i_tt_new($fontname); ok($ttraw, "create font"); my @bbox = i_tt_bbox($ttraw,50.0,'XMCLH',0); is(@bbox, 8, "bounding box"); print "#bbox: ($bbox[0], $bbox[1]) - ($bbox[2], $bbox[3])\n"; ok(i_tt_cp($ttraw,$overlay,5,50,1,50.0,'XM CLH',6,1,0), "cp output"); ok(i_tt_cp($ttraw,$overlay,5,120,1,50.0,'XM CLH',6,0,0), "cp output (non AA)"); i_line($overlay,0,50,100,50,$bgcolor,1); open(FH,">testout/t35ttfont.ppm") || die "cannot open testout/t35ttfont.ppm\n"; binmode(FH); my $IO = Imager::io_new_fd( fileno(FH) ); ok(i_writeppm_wiol($overlay, $IO), "save t35ttfont.ppm"); close(FH); $bgcolor=i_color_set($bgcolor,200,200,200,0); my $backgr=Imager::ImgRaw::new(500,300,3); # i_tt_set_aa(2); ok(i_tt_text($ttraw,$backgr,100,120,$bgcolor,50.0,'te st',5,1,0), "normal output"); ok(i_tt_text($ttraw,$backgr,100,200,$bgcolor,50.0,'te st',5,0,0), "normal output (non AA)"); my $ugly = Imager::i_tt_new("./fontfiles/ImUgly.ttf"); ok($ugly, "create ugly font"); # older versions were dropping the bottom of g and the right of a ok(i_tt_text($ugly, $backgr,100, 80, $bgcolor, 14, 'g%g', 3, 1, 0), "draw g%g"); ok(i_tt_text($ugly, $backgr,150, 80, $bgcolor, 14, 'delta', 6, 1, 0), "draw delta"); i_line($backgr,0,20,499,20,i_color_new(0,127,0,0),1); ok(i_tt_text($ttraw, $backgr, 20, 20, $bgcolor, 14, 'abcdefghijklmnopqrstuvwxyz{|}', 29, 1, 0), "alphabet"); ok(i_tt_text($ttraw, $backgr, 20, 50, $bgcolor, 14, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 26, 1, 0), "ALPHABET"); # UTF8 tests # for perl < 5.6 we can hand-encode text # the following is "A\x{2010}A" # my $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41); my $alttext = "A-A"; my @utf8box = i_tt_bbox($ttraw, 50.0, $text, 1); is(@utf8box, 8, "utf8 bbox element count"); my @base = i_tt_bbox($ttraw, 50.0, $alttext, 0); is(@base, 8, "alt bbox element count"); my $maxdiff = $fontname eq $deffont ? 0 : $base[2] / 3; print "# (@utf8box vs @base)\n"; ok(abs($utf8box[2] - $base[2]) <= $maxdiff, "compare box sizes $utf8box[2] vs $base[2] (maxerror $maxdiff)"); # hand-encoded UTF8 drawing ok(i_tt_text($ttraw, $backgr, 200, 80, $bgcolor, 14, $text, length($text), 1, 1), "draw hand-encoded UTF8"); ok(i_tt_cp($ttraw, $backgr, 250, 80, 1, 14, $text, length($text), 1, 1), "cp hand-encoded UTF8"); # ok, try native perl UTF8 if available SKIP: { skip("perl too old to test native UTF8 support", 5) unless $] >= 5.006; my $text; # we need to do this in eval to prevent compile time errors in older # versions eval q{$text = "A\x{2010}A"}; # A, HYPHEN, A in our test font #$text = "A".chr(0x2010)."A"; # this one works too ok(i_tt_text($ttraw, $backgr, 300, 80, $bgcolor, 14, $text, 0, 1, 0), "draw UTF8"); ok(i_tt_cp($ttraw, $backgr, 350, 80, 0, 14, $text, 0, 1, 0), "cp UTF8"); @utf8box = i_tt_bbox($ttraw, 50.0, $text, 0); is(@utf8box, 8, "native utf8 bbox element count"); ok(abs($utf8box[2] - $base[2]) <= $maxdiff, "compare box sizes native $utf8box[2] vs $base[2] (maxerror $maxdiff)"); eval q{$text = "A\x{0905}\x{0906}\x{0103}A"}; # Devanagari ok(i_tt_text($ugly, $backgr, 100, 160, $bgcolor, 36, $text, 0, 1, 0), "more complex output"); } open(FH,">testout/t35ttfont2.ppm") || die "cannot open testout/t35ttfont.ppm\n"; binmode(FH); $IO = Imager::io_new_fd( fileno(FH) ); ok(i_writeppm_wiol($backgr, $IO), "save t35ttfont2.ppm"); close(FH); my $exists_font = "fontfiles/ExistenceTest.ttf"; my $hcfont = Imager::Font->new(file=>$exists_font, type=>'tt'); SKIP: { ok($hcfont, "loading existence test font") or skip("could not load test font", 20); # list interface my @exists = $hcfont->has_chars(string=>'!A'); ok(@exists == 2, "check return count"); ok($exists[0], "we have an exclamation mark"); ok(!$exists[1], "we have no exclamation mark"); # scalar interface my $exists = $hcfont->has_chars(string=>'!A'); ok(length($exists) == 2, "check return length"); ok(ord(substr($exists, 0, 1)), "we have an exclamation mark"); ok(!ord(substr($exists, 1, 1)), "we have no upper-case A"); my $face_name = Imager::i_tt_face_name($hcfont->{id}); print "# face $face_name\n"; is($face_name, 'ExistenceTest', "face name (function)"); $face_name = $hcfont->face_name; is($face_name, 'ExistenceTest', "face name (OO)"); # FT 1.x cheats and gives names even if the font doesn't have them my @glyph_names = $hcfont->glyph_names(string=>"!J/"); is($glyph_names[0], 'exclam', "check exclam name OO"); ok(!defined($glyph_names[1]), "check for no J name OO"); is($glyph_names[2], 'slash', "check slash name OO"); print "# ** name table of the test font **\n"; Imager::i_tt_dump_names($hcfont->{id}); # the test font is known to have a shorter advance width for that char my @bbox = $hcfont->bounding_box(string=>"/", size=>100); is(@bbox, 8, "should be 8 entries"); isnt($bbox[6], $bbox[2], "different advance width from pos width"); print "# @bbox\n"; my $bbox = $hcfont->bounding_box(string=>"/", size=>100); isnt($bbox->pos_width, $bbox->advance_width, "OO check"); cmp_ok($bbox->right_bearing, '<', 0, "check right bearing"); cmp_ok($bbox->display_width, '>', $bbox->advance_width, "check display width (roughly)"); # check with a char that fits inside the box $bbox = $hcfont->bounding_box(string=>"!", size=>100); print "# @$bbox\n"; print "# pos width ", $bbox->pos_width, "\n"; is($bbox->pos_width, $bbox->advance_width, "check backwards compatibility"); cmp_ok($bbox->left_bearing, '>', 0, "left bearing positive"); cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive"); cmp_ok($bbox->display_width, '<', $bbox->advance_width, "display smaller than advance"); } undef $hcfont; my $name_font = "fontfiles/NameTest.ttf"; $hcfont = Imager::Font->new(file=>$name_font, type=>'tt'); SKIP: { ok($hcfont, "loading name font") or skip("could not load name font $name_font", 3); # make sure a missing string parameter is handled correctly eval { $hcfont->glyph_names(); }; is($@, "", "correct error handling"); cmp_ok(Imager->errstr, '=~', qr/no string parameter/, "error message"); my $text = pack("C*", 0xE2, 0x80, 0x90); # "\x{2010}" as utf-8 my @names = $hcfont->glyph_names(string=>$text, utf8=>1); is($names[0], "hyphentwo", "check utf8 glyph name"); } undef $hcfont; SKIP: { print "# alignment tests\n"; my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt'); ok($font, "loaded deffont OO") or skip("could not load font:".Imager->errstr, 4); my $im = Imager->new(xsize=>140, ysize=>150); my %common = ( font=>$font, size=>40, aa=>1, ); $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue'); $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue'); $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); for my $args ([ x=>5, text=>"A", color=>"white" ], [ x=>40, text=>"y", color=>"white" ], [ x=>75, text=>"A", channel=>1 ], [ x=>110, text=>"y", channel=>1 ]) { ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); } ok($im->write(file=>'testout/t35align.ppm'), "save align image"); } { # Ticket #14804 Imager::Font->new() doesn't report error details # when using freetype 1 # make sure we're using C locale for messages use POSIX qw(setlocale LC_ALL); setlocale(LC_ALL, "C"); my $font = Imager::Font->new(file=>'t/350-font/020-tt.t', type=>'tt'); ok(!$font, "font creation should have failed for invalid file"); cmp_ok(Imager->errstr, 'eq', 'Invalid file format.', "test error message"); setlocale(LC_ALL, ""); } { # check errstr set correctly my $font = Imager::Font->new(file=>$fontname, type=>'tt', size => undef); ok($font, "made size error test font"); my $im = Imager->new(xsize=>100, ysize=>100); ok($im, "made size error test image"); ok(!$im->string(font=>$font, x=>10, 'y'=>50, string=>"Hello"), "drawing should fail with no size"); is($im->errstr, "No font size provided", "check error message"); # try no string ok(!$im->string(font=>$font, x=>10, 'y'=>50, size=>15), "drawing should fail with no string"); is($im->errstr, "missing required parameter 'string'", "check error message"); } { # introduced in 0.46 - outputting just space crashes my $im = Imager->new(xsize=>100, ysize=>100); my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', size=>14); ok($im->string(font=>$font, x=> 5, 'y' => 50, string=>' '), "outputting just a space was crashing"); } { # string output cut off at NUL ('\0') # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt'); ok($font, "loaded imugly"); diff_text_with_nul("a\\0b vs a", "a\0b", "a", font => $font, color => '#FFFFFF'); diff_text_with_nul("a\\0b vs a", "a\0b", "a", font => $font, channel => 1); # UTF8 encoded \x{2010} my $dash = pack("C*", 0xE2, 0x80, 0x90); diff_text_with_nul("utf8 dash\\0dash vs dash", "$dash\0$dash", $dash, font => $font, color => '#FFFFFF', utf8 => 1); diff_text_with_nul("utf8 dash\\0dash vs dash", "$dash\0$dash", $dash, font => $font, channel => 1, utf8 => 1); } SKIP: { # RT 11972 # when rendering to a transparent image the coverage should be # expressed in terms of the alpha channel rather than the color my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt'); ok($font, "loaded fontfiles/ImUgly.ttf") or skip("Could not load test font: ".Imager->errstr, 4); my $im = Imager->new(xsize => 40, ysize => 20, channels => 4); ok($im->string(string => "AB", size => 20, aa => 1, color => '#F00', x => 0, y => 15, font => $font), "draw to transparent image"); #$im->write(file => "foo.png"); my $im_noalpha = $im->convert(preset => 'noalpha'); my $im_pal = $im->to_paletted(make_colors => 'mediancut'); my @colors = $im_pal->getcolors; is(@colors, 2, "should be only 2 colors"); @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors; is_color3($colors[0], 0, 0, 0, "check we got black"); is_color3($colors[1], 255, 0, 0, "and red"); } SKIP: { # RT 71564 my $noalpha = Imager::Color->new(255, 255, 255, 0); my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt', color => $noalpha); ok($font, "loaded fontfiles/ImUgly.ttf") or skip("Could not load test font: ".Imager->errstr, 4); { my $im = Imager->new(xsize => 40, ysize => 20); my $copy = $im->copy; ok($im->string(string => "AB", size => 20, aa => 1, x => 0, y => 15, font => $font), "draw with transparent color, aa"); is_image($im, $copy, "should draw nothing"); } { my $im = Imager->new(xsize => 40, ysize => 20); my $copy = $im->copy; ok($im->string(string => "AB", size => 20, aa => 0, x => 0, y => 15, font => $font), "draw with transparent color, non-aa"); is_image($im, $copy, "should draw nothing"); } } ok(1, "end of code"); } libimager-perl-1.004+dfsg.orig/t/350-font/030-ttoo.t0000644000175000017500000001122312263740601020751 0ustar gregoagregoa#!/usr/bin/perl -w use strict; #use lib qw(blib/lib blib/arch); # Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) use Test::More tests => 25; use Imager; use Imager::Test qw(isnt_image is_image); -d "testout" or mkdir "testout"; Imager->open_log(log => "testout/t36oofont.log"); my @test_output; my $fontname_tt=$ENV{'TTFONTTEST'}||'./fontfiles/dodge.ttf'; my $green=Imager::Color->new(92,205,92,128); die $Imager::ERRSTR unless $green; my $red=Imager::Color->new(205, 92, 92, 255); die $Imager::ERRSTR unless $red; SKIP: { $Imager::formats{"tt"} && -f $fontname_tt or skip("FT1.x missing or disabled", 25); my $img=Imager->new(xsize=>300, ysize=>100) or die "$Imager::ERRSTR\n"; my $font=Imager::Font->new(file=>$fontname_tt,size=>25) or die $img->{ERRSTR}; ok(1, "create TT font object"); ok($img->string(font=>$font, text=>"XMCLH", 'x'=>100, 'y'=>100), "draw text"); $img->line(x1=>0, x2=>300, y1=>50, y2=>50, color=>$green); my $text="LLySja"; my @bbox=$font->bounding_box(string=>$text, 'x'=>0, 'y'=>50); is(@bbox, 8, "bbox list size"); $img->box(box=>\@bbox, color=>$green); $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41); ok($img->string(font=>$font, text=>$text, 'x'=>100, 'y'=>50, utf8=>1), "draw hand-encoded UTF8 text"); SKIP: { $] >= 5.006 or skip("perl too old for native utf8", 1); eval q{$text = "A\x{2010}A"}; ok($img->string(font=>$font, text=>$text, 'x'=>200, 'y'=>50), "draw native UTF8 text"); } ok($img->write(file=>"testout/t36oofont2.ppm", type=>'pnm'), "write t36oofont2.ppm") or print "# ", $img->errstr,"\n"; ok($font->utf8, "make sure utf8 method returns true"); my $has_chars = $font->has_chars(string=>"\x01A"); is($has_chars, "\x00\x01", "has_chars scalar"); my @has_chars = $font->has_chars(string=>"\x01A"); ok(!$has_chars[0], "has_chars list 0"); ok($has_chars[1], "has_chars list 1"); { # RT 71469 my $font1 = Imager::Font->new(file => $fontname_tt, type => "tt"); my $font2 = Imager::Font::Truetype->new(file => $fontname_tt); for my $font ($font1, $font2) { print "# ", join(",", $font->{color}->rgba), "\n"; my $im = Imager->new(xsize => 20, ysize => 20, channels => 4); ok($im->string(text => "T", font => $font, y => 15), "draw with default color") or print "# ", $im->errstr, "\n"; my $work = Imager->new(xsize => 20, ysize => 20); my $cmp = $work->copy; $work->rubthrough(src => $im); isnt_image($work, $cmp, "make sure something was drawn"); } } { # RT 73359 # non-AA font drawing isn't normal mode Imager->log("testing no-aa normal output\n"); my $font = Imager::Font->new(file => "fontfiles/ImUgly.ttf", type => "tt"); ok($font, "make a work font"); my %common = ( x => 10, font => $font, size => 25, aa => 0, align => 0, ); # build our comparison image my $cmp = Imager->new(xsize => 120, ysize => 100); my $layer = Imager->new(xsize => 120, ysize => 100, channels => 4); ok($layer->string(%common, y => 10, text => "full", color => "#8080FF"), "draw non-aa text at full coverage to layer image"); ok($layer->string(%common, y => 40, text => "half", color => "#FF808080"), "draw non-aa text at half coverage to layer image"); ok($layer->string(%common, y => 70, text => "quarter", color => "#80FF8040"), "draw non-aa text at zero coverage to layer image"); ok($cmp->rubthrough(src => $layer), "rub layer onto comparison image"); my $im = Imager->new(xsize => 120, ysize => 100); ok($im->string(%common, y => 10, text => "full", color => "#8080FF"), "draw non-aa text at full coverage"); ok($im->string(%common, y => 40, text => "half", color => "#FF808080"), "draw non-aa text at half coverage"); ok($im->string(%common, y => 70, text => "quarter", color => "#80FF8040"), "draw non-aa text at zero coverage"); is_image($im, $cmp, "check the result"); push @test_output, "ttaanorm.ppm", "ttaacmp.ppm"; ok($cmp->write(file => "testout/ttaacmp.ppm"), "save cmp image") or diag "Saving cmp image: ", $cmp->errstr; ok($im->write(file => "testout/ttaanorm.ppm"), "save test image") or diag "Saving result image: ", $im->errstr; } } Imager->close_log; END { unless ($ENV{IMAGER_KEEP_FILES}) { unlink map "testout/$_", @test_output; } } libimager-perl-1.004+dfsg.orig/t/350-font/100-texttools.t0000644000175000017500000000746512263740601022044 0ustar gregoagregoa#!perl -w use strict; use Test::More tests => 14; BEGIN { use_ok('Imager') } -d "testout" or mkdir "testout"; require_ok('Imager::Font::Wrap'); my $img = Imager->new(xsize=>400, ysize=>400); my $text = <new(file=>$fontfile); SKIP: { $Imager::formats{'tt'} || $Imager::formats{'ft2'} or skip("Need Freetype 1.x or 2.x to test", 12); ok($font, "loading font") or skip("Could not load test font", 8); Imager::Font->priorities(qw(t1 ft2 tt)); ok(scalar Imager::Font::Wrap->wrap_text(string => $text, font=>$font, image=>$img, size=>13, width => 380, aa=>1, x=>10, 'y'=>10, justify=>'fill', color=>'FFFFFF'), "basic test"); ok($img->write(file=>'testout/t80wrapped.ppm'), "save to file"); ok(scalar Imager::Font::Wrap->wrap_text(string => $text, font=>$font, image=>undef, size=>13, width => 380, x=>10, 'y'=>10, justify=>'left', color=>'FFFFFF'), "no image test"); ok(scalar Imager::Font::Wrap->wrap_text(string => $text, font=>$font, size=>13, width => 380, x=>10, 'y'=>10, justify=>'left', color=>'FFFFFF'), "no image parameter test"); my $bbox = $font->bounding_box(string=>"Xx", size=>13); ok($bbox, "get height for check"); my $used; ok(scalar Imager::Font::Wrap->wrap_text (string=>$text, font=>$font, image=>undef, size=>13, width=>380, savepos=> \$used, height => $bbox->font_height), "savepos call"); ok($used > 20 && $used < length($text), "savepos value"); print "# $used\n"; my @box = Imager::Font::Wrap->wrap_text (string=>substr($text, 0, $used), font=>$font, image=>undef, size=>13, width=>380); ok(@box == 4, "bounds list count"); print "# @box\n"; ok($box[3] == $bbox->font_height, "check height"); { # regression # http://rt.cpan.org/Ticket/Display.html?id=29771 # the length of the trailing line wasn't included in the text consumed my $used; ok(scalar Imager::Font::Wrap->wrap_text ( string => "test", font => $font, image => undef, size => 12, width => 200, savepos => \$used, height => $bbox->font_height), "regression 29771 - call wrap_text"); is($used, 4, "all text should be consumed"); } } libimager-perl-1.004+dfsg.orig/t/350-font/040-ttstd.t0000644000175000017500000000126512263740601021134 0ustar gregoagregoa#!perl -w use strict; use Imager::Test qw(std_font_tests std_font_test_count); use Imager::Font; use Test::More; $Imager::formats{tt} or plan skip_all => "No tt available"; Imager->open_log(log => "testout/t37std.log"); plan tests => std_font_test_count(); my $font = Imager::Font->new(file => "fontfiles/dodge.ttf", type => "tt"); my $name_font = Imager::Font->new(file => "fontfiles/ImUgly.ttf", type => "tt"); SKIP: { $font or skip "Cannot load font", std_font_test_count(); std_font_tests ({ font => $font, has_chars => [ 1, 1, 1 ], glyph_name_font => $name_font, glyph_names => [ qw(A uni2010 A) ], }); } Imager->close_log; libimager-perl-1.004+dfsg.orig/t/350-font/010-font.t0000644000175000017500000000331712263740601020735 0ustar gregoagregoa#!perl -w use strict; use Imager; use Test::More tests => 14; unshift @INC, "t"; ok(Imager::Font->register(type => "test", class=>"GoodTestFont", files => "\\.ppm\$"), "register a test font"); ok(Imager::Font->register(type => "bad", class => "BadTestFont", files => "\\.ppm\$"), "register a bad test font"); ok(!Imager::Font->register(), "no register parameters"); like(Imager->errstr, qr/No type parameter/, "check message"); ok(!Imager::Font->register(type => "bad1"), "no class parameter"); like(Imager->errstr, qr/No class parameter/, "check message"); ok(!Imager::Font->register(type => "bad2", class => "BadFont", files => "**"), "bad files parameter"); is(Imager->errstr, "files isn't a valid regexp", "check message"); Imager::Font->priorities("bad", "test"); # RT #62855 # previously we'd select the first file matched font driver, even if # it wasn't available, then crash loading it. SKIP: { my $good; ok(eval { $good = Imager::Font->new(file => "testimg/penguin-base.ppm"); }, "load good font avoiding RT 62855") or skip("Failed to load", 1); ok($good->isa("GoodTestFont"), "and it's the right type"); } use Imager::Font::Test; # check string() and align_string() handle an empty image { my $font = Imager::Font::Test->new; my $empty = Imager->new; ok(!$empty->string(text => "foo", x => 0, y => 10, size => 10, font => $font), "can't draw text on an empty image"); is($empty->errstr, "string: empty input image", "check error message"); ok(!$empty->align_string(text => "foo", x => 0, y => 10, size => 10, font => $font), "can't draw text on an empty image"); is($empty->errstr, "align_string: empty input image", "check error message"); } libimager-perl-1.004+dfsg.orig/t/t1000lib/0000755000175000017500000000000012617614576017276 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/t1000lib/Imager/0000755000175000017500000000000012617614576020502 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/t1000lib/Imager/File/0000755000175000017500000000000012617614576021361 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/t/t1000lib/Imager/File/BAD.pm0000644000175000017500000000011712263740601022266 0ustar gregoagregoapackage Imager::File::BAD; use strict; die "This module fails to load\n"; 1; libimager-perl-1.004+dfsg.orig/lib/0000755000175000017500000000000012617614576016346 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/lib/Imager/0000755000175000017500000000000012617614576017552 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/lib/Imager/Probe.pm0000644000175000017500000003632612460670607021162 0ustar gregoagregoapackage Imager::Probe; use strict; use File::Spec; use Config; use Cwd (); our $VERSION = "1.004"; my @alt_transfer = qw/altname incsuffix libbase/; sub probe { my ($class, $req) = @_; $req->{verbose} ||= $ENV{IM_VERBOSE}; my $name = $req->{name}; my $result; if ($req->{code}) { $result = _probe_code($req); } if (!$result && $req->{pkg}) { $result = _probe_pkg($req); } if (!$result && $req->{inccheck} && ($req->{libcheck} || $req->{libbase})) { $req->{altname} ||= "main"; $result = _probe_check($req); } if ($result && $req->{testcode}) { $result = _probe_test($req, $result); } if (!$result && $req->{alternatives}) { ALTCHECK: my $index = 1; for my $alt (@{$req->{alternatives}}) { $req->{altname} = $alt->{altname} || "alt $index"; $req->{verbose} and print "$req->{name}: Trying alternative $index\n"; my %work = %$req; for my $key (@alt_transfer) { exists $alt->{$key} and $work{$key} = $alt->{$key}; } $result = _probe_check(\%work); if ($result && $req->{testcode}) { $result = _probe_test(\%work, $result); } $result and last; ++$index; } } if (!$result && $req->{testcode}) { $result = _probe_fake($req); $result or return; $result = _probe_test($req, $result); } $result or return; return $result; } sub _probe_code { my ($req) = @_; my $code = $req->{code}; my @probes = ref $code eq "ARRAY" ? @$code : $code; my $result; for my $probe (@probes) { $result = $probe->($req) and return $result; } return; } sub is_exe { my ($name) = @_; my @exe_suffix = $Config{_exe}; if ($^O eq 'MSWin32') { push @exe_suffix, qw/.bat .cmd/; } for my $dir (File::Spec->path) { for my $suffix (@exe_suffix) { -x File::Spec->catfile($dir, "$name$suffix") and return 1; } } return; } sub _probe_pkg { my ($req) = @_; # Setup pkg-config's environment variable to search non-standard paths # which may be provided by --libdirs. my @pkgcfg_paths = map { "$_/pkgconfig" } _lib_paths( $req ); push @pkgcfg_paths, $ENV{ 'PKG_CONFIG_PATH' } if $ENV{ 'PKG_CONFIG_PATH' }; local $ENV{ 'PKG_CONFIG_PATH' } = join $Config{path_sep}, @pkgcfg_paths; is_exe('pkg-config') or return; my $redir = $^O eq 'MSWin32' ? '' : '2>/dev/null'; my @pkgs = @{$req->{pkg}}; for my $pkg (@pkgs) { if (!system("pkg-config $pkg --exists $redir")) { # if we find it, but the following fail, then pkg-config is too # broken to be useful my $cflags = `pkg-config $pkg --cflags` and !$? or return; my $lflags = `pkg-config $pkg --libs` and !$? or return; my $defines = ''; $cflags =~ s/(-D\S+)/$defines .= " $1"; ''/ge; chomp $cflags; chomp $lflags; print "$req->{name}: Found via pkg-config $pkg\n"; print <{verbose}; cflags: $cflags defines: $defines lflags: $lflags EOS # rt 75869 # if Win32 doesn't provide this information, too bad if (!grep(/^-L/, split " ", $lflags) && $^O ne 'MSWin32') { # pkg-config told us about the library, make sure it's # somewhere EU::MM can find it print "Checking if EU::MM can find $lflags\n" if $req->{verbose}; my ($extra, $bs_load, $ld_load, $ld_run_path) = ExtUtils::Liblist->ext($lflags, $req->{verbose}); unless ($ld_run_path) { # search our standard places $lflags = _resolve_libs($req, $lflags); } } return { INC => $cflags, LIBS => $lflags, DEFINE => $defines, }; } } print "$req->{name}: Not found via pkg-config\n"; return; } sub _is_msvc { return $Config{cc} eq "cl"; } sub _lib_basename { my ($base) = @_; if (_is_msvc()) { return $base; } else { return "lib$base"; } } sub _lib_option { my ($base) = @_; if (_is_msvc()) { return $base . $Config{_a}; } else { return "-l$base"; } } sub _quotearg { my ($opt) = @_; return $opt =~ /\s/ ? qq("$opt") : $opt; } sub _probe_check { my ($req) = @_; my @libcheck; my @libbase; if ($req->{libcheck}) { if (ref $req->{libcheck} eq "ARRAY") { push @libcheck, @{$req->{libcheck}}; } else { push @libcheck, $req->{libcheck}; } } elsif ($req->{libbase}) { @libbase = ref $req->{libbase} ? @{$req->{libbase}} : $req->{libbase}; my $lext=$Config{'so'}; # Get extensions of libraries my $aext=$Config{'_a'}; for my $libbase (@libbase) { my $basename = _lib_basename($libbase); push @libcheck, sub { -e File::Spec->catfile($_[0], "$basename$aext") || -e File::Spec->catfile($_[0], "$basename.$lext") }; } } else { print "$req->{name}: No libcheck or libbase, nothing to search for\n" if $req->{verbose}; return; } my @found_libpath; my @lib_search = _lib_paths($req); print "$req->{name}: Searching directories for libraries:\n" if $req->{verbose}; for my $libcheck (@libcheck) { for my $path (@lib_search) { print "$req->{name}: $path\n" if $req->{verbose}; if ($libcheck->($path)) { print "$req->{name}: Found!\n" if $req->{verbose}; push @found_libpath, $path; last; } } } my $found_incpath; my $inccheck = $req->{inccheck}; my @inc_search = _inc_paths($req); print "$req->{name}: Searching directories for headers:\n" if $req->{verbose}; for my $path (@inc_search) { print "$req->{name}: $path\n" if $req->{verbose}; if ($inccheck->($path)) { print "$req->{name}: Found!\n" if $req->{verbose}; $found_incpath = $path; last; } } my $alt = ""; if ($req->{altname}) { $alt = " $req->{altname}:"; } print "$req->{name}:$alt includes ", $found_incpath ? "" : "not ", "found - libraries ", @found_libpath == @libcheck ? "" : "not ", "found\n"; @found_libpath == @libcheck && $found_incpath or return; my @libs = map "-L$_", @found_libpath; if ($req->{libopts}) { push @libs, $req->{libopts}; } elsif (@libbase) { push @libs, map _lib_option($_), @libbase; } else { die "$req->{altname}: inccheck but no libbase or libopts"; } return { INC => _quotearg("-I$found_incpath"), LIBS => join(" ", map _quotearg($_), @libs), DEFINE => "", }; } sub _probe_fake { my ($req) = @_; # the caller provided test code, and the compiler may look in # places we don't, see Imager-Screenshot ticket 56793, # so fake up a result so the test code can my $lopts; if ($req->{libopts}) { $lopts = $req->{libopts}; } elsif (defined $req->{libbase}) { # might not need extra libraries, eg. Win32 perl already links # everything $lopts = $req->{libbase} ? "-l$req->{libbase}" : ""; } if (defined $lopts) { print "$req->{name}: Checking if the compiler can find them on its own\n"; return { INC => "", LIBS => $lopts, DEFINE => "", }; } else { print "$req->{name}: Can't fake it - no libbase or libopts\n" if $req->{verbose}; return; } } sub _probe_test { my ($req, $result) = @_; require Devel::CheckLib; # setup LD_RUN_PATH to match link time print "Asking liblist for LD_RUN_PATH:\n" if $req->{verbose}; my ($extra, $bs_load, $ld_load, $ld_run_path) = ExtUtils::Liblist->ext($result->{LIBS}, $req->{verbose}); local $ENV{LD_RUN_PATH}; if ($ld_run_path) { print "Setting LD_RUN_PATH=$ld_run_path for $req->{name} probe\n" if $req->{verbose}; $ENV{LD_RUN_PATH} = $ld_run_path; if ($Config{lddlflags} =~ /([^ ]*-(?:rpath|R)[,=]?)([^ ]+)/ && -d $2) { # hackety, hackety # LD_RUN_PATH is ignored when there's already an -rpath option # so provide one my $prefix = $1; $result->{LDDLFLAGS} = $Config{lddlflags} . " " . join " ", map "$prefix$_", split $Config{path_sep}, $ld_run_path; } } my $good = Devel::CheckLib::check_lib ( debug => $req->{verbose}, LIBS => [ $result->{LIBS} ], INC => $result->{INC}, header => $req->{testcodeheaders}, function => $req->{testcode}, prologue => $req->{testcodeprologue}, ); unless ($good) { print "$req->{name}: Test code failed: $@"; return; } print "$req->{name}: Passed code check\n"; return $result; } sub _resolve_libs { my ($req, $lflags) = @_; my @libs = grep /^-l/, split ' ', $lflags; my %paths; my @paths = _lib_paths($req); my $so = $Config{so}; my $libext = $Config{_a}; for my $lib (@libs) { $lib =~ s/^-l/lib/; for my $path (@paths) { if (-e "$path/$lib.$so" || -e "$path/$lib$libext") { $paths{$path} = 1; } } } return join(" ", ( map "-L$_", keys %paths ), $lflags ); } sub _lib_paths { my ($req) = @_; print "$req->{name} IM_LIBPATH: $ENV{IM_LIBPATH}\n" if $req->{verbose} && defined $ENV{IM_LIBPATH}; print "$req->{name} LIB: $ENV{IM_LIBPATH}\n" if $req->{verbose} && defined $ENV{LIB} && $^O eq "MSWin32"; my $lp = $req->{libpath}; print "$req->{name} libpath: ", ref $lp ? join($Config{path_sep}, @$lp) : $lp, "\n" if $req->{verbose} && defined $lp; return _paths ( $ENV{IM_LIBPATH}, $req->{libpath}, ( map { split ' ' } grep $_, @Config{qw/loclibpth libpth libspath/} ), $^O eq "MSWin32" ? $ENV{LIB} : "", $^O eq "cygwin" ? "/usr/lib/w32api" : "", "/usr/lib", "/usr/local/lib", _gcc_lib_paths(), _dyn_lib_paths(), ); } sub _gcc_lib_paths { $Config{gccversion} or return; my ($base_version) = $Config{gccversion} =~ /^([0-9]+)/ or return; $base_version >= 4 or return; local $ENV{LANG} = "C"; local $ENV{LC_ALL} = "C"; my ($lib_line) = grep /^libraries:/, `$Config{cc} -print-search-dirs` or return; $lib_line =~ s/^libraries: =//; chomp $lib_line; return grep !/gcc/ && -d, split /:/, $lib_line; } sub _dyn_lib_paths { return map { defined() ? split /\Q$Config{path_sep}/ : () } map $ENV{$_}, qw(LD_RUN_PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH LIBRARY_PATH); } sub _inc_paths { my ($req) = @_; print "$req->{name} IM_INCPATH: $ENV{IM_INCPATH}\n" if $req->{verbose} && defined $ENV{IM_INCPATH}; print "$req->{name} INCLUDE: $ENV{INCLUDE}\n" if $req->{verbose} && defined $ENV{INCLUDE} && $^O eq "MSWin32"; my $ip = $req->{incpath}; print "$req->{name} incpath: ", ref $ip ? join($Config{path_sep}, @$ip) : $ip, "\n" if $req->{verbose} && defined $req->{incpath}; my @paths = _paths ( $ENV{IM_INCPATH}, $req->{incpath}, $^O eq "MSWin32" ? $ENV{INCLUDE} : "", $^O eq "cygwin" ? "/usr/include/w32api" : "", ( map { split ' ' } grep $_, @Config{qw/locincpth incpath/} ), "/usr/include", "/usr/local/include", _dyn_inc_paths(), ); if ($req->{incsuffix}) { @paths = map File::Spec->catdir($_, $req->{incsuffix}), @paths; } return @paths; } sub _dyn_inc_paths { return map { my $tmp = $_; $tmp =~ s/\blib$/include/ ? $tmp : () } _dyn_lib_paths(); } sub _paths { my (@in) = @_; my @out; # expand any array refs @in = map { ref() ? @$_ : $_ } @in; for my $path (@in) { $path or next; $path = _tilde_expand($path); push @out, grep -d $_, split /\Q$Config{path_sep}/, $path; } @out = map Cwd::realpath($_), @out; my %seen; @out = grep !$seen{$_}++, @out; return @out; } my $home; sub _tilde_expand { my ($path) = @_; if ($path =~ m!^~[/\\]!) { defined $home or $home = $ENV{HOME}; if (!defined $home && $^O eq 'MSWin32' && defined $ENV{HOMEDRIVE} && defined $ENV{HOMEPATH}) { $home = $ENV{HOMEDRIVE} . $ENV{HOMEPATH}; } unless (defined $home) { $home = eval { (getpwuid($<))[7] }; } defined $home or die "You supplied $path, but I can't find your home directory\n"; $path =~ s/^~//; $path = File::Spec->catdir($home, $path); } return $path; } 1; __END__ =head1 NAME Imager::Probe - hot needle of inquiry for libraries =head1 SYNOPSIS require Imager::Probe; my %probe = ( # short name of what we're looking for (displayed to user) name => "FOO", # pkg-config lookup pkg => [ qw/name1 name2 name3/ ], # perl subs that probe for the library code => [ \&foo_probe1, \&foo_probe2 ], # or just: code => \&foo_probe, inccheck => sub { ... }, libcheck => sub { ... }, # search for this library if libcheck not supplied libbase => "foo", # library link time options, uses libbase to build options otherwise libopts => "-lfoo", # C code to check the library is sane testcode => "...", # header files needed testcodeheaders => [ "stdio.h", "foo.h" ], ); my $result = Imager::Probe->probe(\%probe) or print "Foo library not found: ",Imager::Probe->error; =head1 DESCRIPTION Does the probes that were hidden in Imager's F, pulled out so the file format libraries can be externalized. The return value is either nothing if the probe fails, or a hash containing: =over =item * C - C<-I> and other C options =item * C - C<-L>, C<-l> and other link-time options =item * C - C<-D> options, if any. =back The possible values for the hash supplied to the probe() method are: =over =item * C - an array of F names to probe for. If the F checks pass, C and C aren't used. =item * C - a code reference that checks if the supplied include directory contains the required header files. =item * C - a code reference that checks if the supplied library directory contains the required library files. Note: the F version of this was supplied all of the library file names instead. C can also be an arrayref of library check code references, all of which must find a match for the library to be considered "found". =item * C - if C is supplied, but C isn't, then a C that checks for CII<$Config{_a}> and CI.I<$Config{so}> is created. If C isn't supplied then that can be synthesized as C<< -lI >>. C can also be an arrayref of library base names to search for, in which case all of the libraries mentioned must be found for the probe to succeed. =item * C - if the libraries are found via C/C, these are the C<-l> options to supply during the link phase. =item * C - a code reference to perform custom checks. Returns the probe result directly. Can also be an array ref of functions to call. =item * C - test C code that is run with Devel::CheckLib. You also need to set C. =item * C - C code to insert between the headers and the main function. =item * C - C<$Config{path_sep}> separated list of header file directories to check, or a reference to an array of such. =item * C - C<$Config{path_sep}> separated list of library file directories to check, or a reference to an array of such. =item * C - an optional array reference of alternate configurations (as hash references) to test if the primary configuration isn't successful. Each alternative should include an C key describing the alternative. Any key not mentioned in an alternative defaults to the value from the main configuration. =back =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Color/0000755000175000017500000000000012617614576020630 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/lib/Imager/Color/Float.pm0000644000175000017500000000527112031434615022220 0ustar gregoagregoapackage Imager::Color::Float; use Imager; use strict; use vars qw($VERSION); $VERSION = "1.005"; # It's just a front end to the XS creation functions. # Parse color spec into an a set of 4 colors sub _pspec { return (@_,1) if @_ == 3; return (@_ ) if @_ == 4; if ($_[0] =~ /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) { return (hex($1)/255,hex($2)/255,hex($3)/255,hex($4)/255); } if ($_[0] =~ /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) { return (hex($1)/255,hex($2)/255,hex($3)/255,1); } return (); } sub new { shift; # get rid of class name. my @arg = _pspec(@_); return @arg ? new_internal($arg[0],$arg[1],$arg[2],$arg[3]) : (); } sub set { my $self = shift; my @arg = _pspec(@_); return @arg ? set_internal($self, $arg[0],$arg[1],$arg[2],$arg[3]) : (); } sub CLONE_SKIP { 1 } 1; __END__ =head1 NAME Imager::Color::Float - Rough floating point sample color handling =head1 SYNOPSIS $color = Imager::Color->new($red, $green, $blue); $color = Imager::Color->new($red, $green, $blue, $alpha); $color = Imager::Color->new("#C0C0FF"); # html color specification $color->set($red, $green, $blue); $color->set($red, $green, $blue, $alpha); $color->set("#C0C0FF"); # html color specification ($red, $green, $blue, $alpha) = $color->rgba(); @hsv = $color->hsv(); # not implemented but proposed $color->info(); =head1 DESCRIPTION This module handles creating color objects used by Imager. The idea is that in the future this module will be able to handle color space calculations as well. A floating point Imager color consists of up to four components, each in the range 0.0 to 1.0. Unfortunately the meaning of the components can change depending on the type of image you're dealing with: =over =item * for 3 or 4 channel images the color components are red, green, blue, alpha. =item * for 1 or 2 channel images the color components are gray, alpha, with the other two components ignored. =back An alpha value of zero is fully transparent, an alpha value of 1.0 is fully opaque. =head1 METHODS =over 4 =item new This creates a color object to pass to functions that need a color argument. =item set This changes an already defined color. Note that this does not affect any places where the color has been used previously. =item rgba() This returns the red, green, blue and alpha channels of the color the object contains. =item info Calling info merely dumps the relevant color to the log. =back =head1 AUTHOR Arnar M. Hrafnkelsson, addi@umich.edu And a great deal of help from others - see the C for a complete list. =head1 SEE ALSO Imager(3), Imager::Color. http://imager.perl.org/ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Color/Table.pm0000644000175000017500000004672412031434615022212 0ustar gregoagregoapackage Imager::Color::Table; use strict; use vars qw($VERSION); $VERSION = "1.003"; my %colors; { local $_; while () { next if /^#/ or !/\S/; chomp; my ($r, $g, $b, $name) = split ' ', $_, 4; if ($name) { $colors{lc $name} = [ $r, $g, $b ]; } } } sub get { my ($class, $name) = @_; exists $colors{lc $name} or return; return @{$colors{lc $name}}; } 1; __DATA__ # This color data was extracted from the freedesktop.org CVS tree, and # appears to be under the following license: # # Copyright (C) 2004 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # X Window System is a trademark of X Consortium, Inc. 255 250 250 snow 248 248 255 ghost white 248 248 255 GhostWhite 245 245 245 white smoke 245 245 245 WhiteSmoke 220 220 220 gainsboro 255 250 240 floral white 255 250 240 FloralWhite 253 245 230 old lace 253 245 230 OldLace 250 240 230 linen 250 235 215 antique white 250 235 215 AntiqueWhite 255 239 213 papaya whip 255 239 213 PapayaWhip 255 235 205 blanched almond 255 235 205 BlanchedAlmond 255 228 196 bisque 255 218 185 peach puff 255 218 185 PeachPuff 255 222 173 navajo white 255 222 173 NavajoWhite 255 228 181 moccasin 255 248 220 cornsilk 255 255 240 ivory 255 250 205 lemon chiffon 255 250 205 LemonChiffon 255 245 238 seashell 240 255 240 honeydew 245 255 250 mint cream 245 255 250 MintCream 240 255 255 azure 240 248 255 alice blue 240 248 255 AliceBlue 230 230 250 lavender 255 240 245 lavender blush 255 240 245 LavenderBlush 255 228 225 misty rose 255 228 225 MistyRose 255 255 255 white 0 0 0 black 47 79 79 dark slate gray 47 79 79 DarkSlateGray 47 79 79 dark slate grey 47 79 79 DarkSlateGrey 105 105 105 dim gray 105 105 105 DimGray 105 105 105 dim grey 105 105 105 DimGrey 112 128 144 slate gray 112 128 144 SlateGray 112 128 144 slate grey 112 128 144 SlateGrey 119 136 153 light slate gray 119 136 153 LightSlateGray 119 136 153 light slate grey 119 136 153 LightSlateGrey 190 190 190 gray 190 190 190 grey 211 211 211 light grey 211 211 211 LightGrey 211 211 211 light gray 211 211 211 LightGray 25 25 112 midnight blue 25 25 112 MidnightBlue 0 0 128 navy 0 0 128 navy blue 0 0 128 NavyBlue 100 149 237 cornflower blue 100 149 237 CornflowerBlue 72 61 139 dark slate blue 72 61 139 DarkSlateBlue 106 90 205 slate blue 106 90 205 SlateBlue 123 104 238 medium slate blue 123 104 238 MediumSlateBlue 132 112 255 light slate blue 132 112 255 LightSlateBlue 0 0 205 medium blue 0 0 205 MediumBlue 65 105 225 royal blue 65 105 225 RoyalBlue 0 0 255 blue 30 144 255 dodger blue 30 144 255 DodgerBlue 0 191 255 deep sky blue 0 191 255 DeepSkyBlue 135 206 235 sky blue 135 206 235 SkyBlue 135 206 250 light sky blue 135 206 250 LightSkyBlue 70 130 180 steel blue 70 130 180 SteelBlue 176 196 222 light steel blue 176 196 222 LightSteelBlue 173 216 230 light blue 173 216 230 LightBlue 176 224 230 powder blue 176 224 230 PowderBlue 175 238 238 pale turquoise 175 238 238 PaleTurquoise 0 206 209 dark turquoise 0 206 209 DarkTurquoise 72 209 204 medium turquoise 72 209 204 MediumTurquoise 64 224 208 turquoise 0 255 255 cyan 224 255 255 light cyan 224 255 255 LightCyan 95 158 160 cadet blue 95 158 160 CadetBlue 102 205 170 medium aquamarine 102 205 170 MediumAquamarine 127 255 212 aquamarine 0 100 0 dark green 0 100 0 DarkGreen 85 107 47 dark olive green 85 107 47 DarkOliveGreen 143 188 143 dark sea green 143 188 143 DarkSeaGreen 46 139 87 sea green 46 139 87 SeaGreen 60 179 113 medium sea green 60 179 113 MediumSeaGreen 32 178 170 light sea green 32 178 170 LightSeaGreen 152 251 152 pale green 152 251 152 PaleGreen 0 255 127 spring green 0 255 127 SpringGreen 124 252 0 lawn green 124 252 0 LawnGreen 0 255 0 green 127 255 0 chartreuse 0 250 154 medium spring green 0 250 154 MediumSpringGreen 173 255 47 green yellow 173 255 47 GreenYellow 50 205 50 lime green 50 205 50 LimeGreen 154 205 50 yellow green 154 205 50 YellowGreen 34 139 34 forest green 34 139 34 ForestGreen 107 142 35 olive drab 107 142 35 OliveDrab 189 183 107 dark khaki 189 183 107 DarkKhaki 240 230 140 khaki 238 232 170 pale goldenrod 238 232 170 PaleGoldenrod 250 250 210 light goldenrod yellow 250 250 210 LightGoldenrodYellow 255 255 224 light yellow 255 255 224 LightYellow 255 255 0 yellow 255 215 0 gold 238 221 130 light goldenrod 238 221 130 LightGoldenrod 218 165 32 goldenrod 184 134 11 dark goldenrod 184 134 11 DarkGoldenrod 188 143 143 rosy brown 188 143 143 RosyBrown 205 92 92 indian red 205 92 92 IndianRed 139 69 19 saddle brown 139 69 19 SaddleBrown 160 82 45 sienna 205 133 63 peru 222 184 135 burlywood 245 245 220 beige 245 222 179 wheat 244 164 96 sandy brown 244 164 96 SandyBrown 210 180 140 tan 210 105 30 chocolate 178 34 34 firebrick 165 42 42 brown 233 150 122 dark salmon 233 150 122 DarkSalmon 250 128 114 salmon 255 160 122 light salmon 255 160 122 LightSalmon 255 165 0 orange 255 140 0 dark orange 255 140 0 DarkOrange 255 127 80 coral 240 128 128 light coral 240 128 128 LightCoral 255 99 71 tomato 255 69 0 orange red 255 69 0 OrangeRed 255 0 0 red 255 105 180 hot pink 255 105 180 HotPink 255 20 147 deep pink 255 20 147 DeepPink 255 192 203 pink 255 182 193 light pink 255 182 193 LightPink 219 112 147 pale violet red 219 112 147 PaleVioletRed 176 48 96 maroon 199 21 133 medium violet red 199 21 133 MediumVioletRed 208 32 144 violet red 208 32 144 VioletRed 255 0 255 magenta 238 130 238 violet 221 160 221 plum 218 112 214 orchid 186 85 211 medium orchid 186 85 211 MediumOrchid 153 50 204 dark orchid 153 50 204 DarkOrchid 148 0 211 dark violet 148 0 211 DarkViolet 138 43 226 blue violet 138 43 226 BlueViolet 160 32 240 purple 147 112 219 medium purple 147 112 219 MediumPurple 216 191 216 thistle 255 250 250 snow1 238 233 233 snow2 205 201 201 snow3 139 137 137 snow4 255 245 238 seashell1 238 229 222 seashell2 205 197 191 seashell3 139 134 130 seashell4 255 239 219 AntiqueWhite1 238 223 204 AntiqueWhite2 205 192 176 AntiqueWhite3 139 131 120 AntiqueWhite4 255 228 196 bisque1 238 213 183 bisque2 205 183 158 bisque3 139 125 107 bisque4 255 218 185 PeachPuff1 238 203 173 PeachPuff2 205 175 149 PeachPuff3 139 119 101 PeachPuff4 255 222 173 NavajoWhite1 238 207 161 NavajoWhite2 205 179 139 NavajoWhite3 139 121 94 NavajoWhite4 255 250 205 LemonChiffon1 238 233 191 LemonChiffon2 205 201 165 LemonChiffon3 139 137 112 LemonChiffon4 255 248 220 cornsilk1 238 232 205 cornsilk2 205 200 177 cornsilk3 139 136 120 cornsilk4 255 255 240 ivory1 238 238 224 ivory2 205 205 193 ivory3 139 139 131 ivory4 240 255 240 honeydew1 224 238 224 honeydew2 193 205 193 honeydew3 131 139 131 honeydew4 255 240 245 LavenderBlush1 238 224 229 LavenderBlush2 205 193 197 LavenderBlush3 139 131 134 LavenderBlush4 255 228 225 MistyRose1 238 213 210 MistyRose2 205 183 181 MistyRose3 139 125 123 MistyRose4 240 255 255 azure1 224 238 238 azure2 193 205 205 azure3 131 139 139 azure4 131 111 255 SlateBlue1 122 103 238 SlateBlue2 105 89 205 SlateBlue3 71 60 139 SlateBlue4 72 118 255 RoyalBlue1 67 110 238 RoyalBlue2 58 95 205 RoyalBlue3 39 64 139 RoyalBlue4 0 0 255 blue1 0 0 238 blue2 0 0 205 blue3 0 0 139 blue4 30 144 255 DodgerBlue1 28 134 238 DodgerBlue2 24 116 205 DodgerBlue3 16 78 139 DodgerBlue4 99 184 255 SteelBlue1 92 172 238 SteelBlue2 79 148 205 SteelBlue3 54 100 139 SteelBlue4 0 191 255 DeepSkyBlue1 0 178 238 DeepSkyBlue2 0 154 205 DeepSkyBlue3 0 104 139 DeepSkyBlue4 135 206 255 SkyBlue1 126 192 238 SkyBlue2 108 166 205 SkyBlue3 74 112 139 SkyBlue4 176 226 255 LightSkyBlue1 164 211 238 LightSkyBlue2 141 182 205 LightSkyBlue3 96 123 139 LightSkyBlue4 198 226 255 SlateGray1 185 211 238 SlateGray2 159 182 205 SlateGray3 108 123 139 SlateGray4 202 225 255 LightSteelBlue1 188 210 238 LightSteelBlue2 162 181 205 LightSteelBlue3 110 123 139 LightSteelBlue4 191 239 255 LightBlue1 178 223 238 LightBlue2 154 192 205 LightBlue3 104 131 139 LightBlue4 224 255 255 LightCyan1 209 238 238 LightCyan2 180 205 205 LightCyan3 122 139 139 LightCyan4 187 255 255 PaleTurquoise1 174 238 238 PaleTurquoise2 150 205 205 PaleTurquoise3 102 139 139 PaleTurquoise4 152 245 255 CadetBlue1 142 229 238 CadetBlue2 122 197 205 CadetBlue3 83 134 139 CadetBlue4 0 245 255 turquoise1 0 229 238 turquoise2 0 197 205 turquoise3 0 134 139 turquoise4 0 255 255 cyan1 0 238 238 cyan2 0 205 205 cyan3 0 139 139 cyan4 151 255 255 DarkSlateGray1 141 238 238 DarkSlateGray2 121 205 205 DarkSlateGray3 82 139 139 DarkSlateGray4 127 255 212 aquamarine1 118 238 198 aquamarine2 102 205 170 aquamarine3 69 139 116 aquamarine4 193 255 193 DarkSeaGreen1 180 238 180 DarkSeaGreen2 155 205 155 DarkSeaGreen3 105 139 105 DarkSeaGreen4 84 255 159 SeaGreen1 78 238 148 SeaGreen2 67 205 128 SeaGreen3 46 139 87 SeaGreen4 154 255 154 PaleGreen1 144 238 144 PaleGreen2 124 205 124 PaleGreen3 84 139 84 PaleGreen4 0 255 127 SpringGreen1 0 238 118 SpringGreen2 0 205 102 SpringGreen3 0 139 69 SpringGreen4 0 255 0 green1 0 238 0 green2 0 205 0 green3 0 139 0 green4 127 255 0 chartreuse1 118 238 0 chartreuse2 102 205 0 chartreuse3 69 139 0 chartreuse4 192 255 62 OliveDrab1 179 238 58 OliveDrab2 154 205 50 OliveDrab3 105 139 34 OliveDrab4 202 255 112 DarkOliveGreen1 188 238 104 DarkOliveGreen2 162 205 90 DarkOliveGreen3 110 139 61 DarkOliveGreen4 255 246 143 khaki1 238 230 133 khaki2 205 198 115 khaki3 139 134 78 khaki4 255 236 139 LightGoldenrod1 238 220 130 LightGoldenrod2 205 190 112 LightGoldenrod3 139 129 76 LightGoldenrod4 255 255 224 LightYellow1 238 238 209 LightYellow2 205 205 180 LightYellow3 139 139 122 LightYellow4 255 255 0 yellow1 238 238 0 yellow2 205 205 0 yellow3 139 139 0 yellow4 255 215 0 gold1 238 201 0 gold2 205 173 0 gold3 139 117 0 gold4 255 193 37 goldenrod1 238 180 34 goldenrod2 205 155 29 goldenrod3 139 105 20 goldenrod4 255 185 15 DarkGoldenrod1 238 173 14 DarkGoldenrod2 205 149 12 DarkGoldenrod3 139 101 8 DarkGoldenrod4 255 193 193 RosyBrown1 238 180 180 RosyBrown2 205 155 155 RosyBrown3 139 105 105 RosyBrown4 255 106 106 IndianRed1 238 99 99 IndianRed2 205 85 85 IndianRed3 139 58 58 IndianRed4 255 130 71 sienna1 238 121 66 sienna2 205 104 57 sienna3 139 71 38 sienna4 255 211 155 burlywood1 238 197 145 burlywood2 205 170 125 burlywood3 139 115 85 burlywood4 255 231 186 wheat1 238 216 174 wheat2 205 186 150 wheat3 139 126 102 wheat4 255 165 79 tan1 238 154 73 tan2 205 133 63 tan3 139 90 43 tan4 255 127 36 chocolate1 238 118 33 chocolate2 205 102 29 chocolate3 139 69 19 chocolate4 255 48 48 firebrick1 238 44 44 firebrick2 205 38 38 firebrick3 139 26 26 firebrick4 255 64 64 brown1 238 59 59 brown2 205 51 51 brown3 139 35 35 brown4 255 140 105 salmon1 238 130 98 salmon2 205 112 84 salmon3 139 76 57 salmon4 255 160 122 LightSalmon1 238 149 114 LightSalmon2 205 129 98 LightSalmon3 139 87 66 LightSalmon4 255 165 0 orange1 238 154 0 orange2 205 133 0 orange3 139 90 0 orange4 255 127 0 DarkOrange1 238 118 0 DarkOrange2 205 102 0 DarkOrange3 139 69 0 DarkOrange4 255 114 86 coral1 238 106 80 coral2 205 91 69 coral3 139 62 47 coral4 255 99 71 tomato1 238 92 66 tomato2 205 79 57 tomato3 139 54 38 tomato4 255 69 0 OrangeRed1 238 64 0 OrangeRed2 205 55 0 OrangeRed3 139 37 0 OrangeRed4 255 0 0 red1 238 0 0 red2 205 0 0 red3 139 0 0 red4 255 20 147 DeepPink1 238 18 137 DeepPink2 205 16 118 DeepPink3 139 10 80 DeepPink4 255 110 180 HotPink1 238 106 167 HotPink2 205 96 144 HotPink3 139 58 98 HotPink4 255 181 197 pink1 238 169 184 pink2 205 145 158 pink3 139 99 108 pink4 255 174 185 LightPink1 238 162 173 LightPink2 205 140 149 LightPink3 139 95 101 LightPink4 255 130 171 PaleVioletRed1 238 121 159 PaleVioletRed2 205 104 137 PaleVioletRed3 139 71 93 PaleVioletRed4 255 52 179 maroon1 238 48 167 maroon2 205 41 144 maroon3 139 28 98 maroon4 255 62 150 VioletRed1 238 58 140 VioletRed2 205 50 120 VioletRed3 139 34 82 VioletRed4 255 0 255 magenta1 238 0 238 magenta2 205 0 205 magenta3 139 0 139 magenta4 255 131 250 orchid1 238 122 233 orchid2 205 105 201 orchid3 139 71 137 orchid4 255 187 255 plum1 238 174 238 plum2 205 150 205 plum3 139 102 139 plum4 224 102 255 MediumOrchid1 209 95 238 MediumOrchid2 180 82 205 MediumOrchid3 122 55 139 MediumOrchid4 191 62 255 DarkOrchid1 178 58 238 DarkOrchid2 154 50 205 DarkOrchid3 104 34 139 DarkOrchid4 155 48 255 purple1 145 44 238 purple2 125 38 205 purple3 85 26 139 purple4 171 130 255 MediumPurple1 159 121 238 MediumPurple2 137 104 205 MediumPurple3 93 71 139 MediumPurple4 255 225 255 thistle1 238 210 238 thistle2 205 181 205 thistle3 139 123 139 thistle4 0 0 0 gray0 0 0 0 grey0 3 3 3 gray1 3 3 3 grey1 5 5 5 gray2 5 5 5 grey2 8 8 8 gray3 8 8 8 grey3 10 10 10 gray4 10 10 10 grey4 13 13 13 gray5 13 13 13 grey5 15 15 15 gray6 15 15 15 grey6 18 18 18 gray7 18 18 18 grey7 20 20 20 gray8 20 20 20 grey8 23 23 23 gray9 23 23 23 grey9 26 26 26 gray10 26 26 26 grey10 28 28 28 gray11 28 28 28 grey11 31 31 31 gray12 31 31 31 grey12 33 33 33 gray13 33 33 33 grey13 36 36 36 gray14 36 36 36 grey14 38 38 38 gray15 38 38 38 grey15 41 41 41 gray16 41 41 41 grey16 43 43 43 gray17 43 43 43 grey17 46 46 46 gray18 46 46 46 grey18 48 48 48 gray19 48 48 48 grey19 51 51 51 gray20 51 51 51 grey20 54 54 54 gray21 54 54 54 grey21 56 56 56 gray22 56 56 56 grey22 59 59 59 gray23 59 59 59 grey23 61 61 61 gray24 61 61 61 grey24 64 64 64 gray25 64 64 64 grey25 66 66 66 gray26 66 66 66 grey26 69 69 69 gray27 69 69 69 grey27 71 71 71 gray28 71 71 71 grey28 74 74 74 gray29 74 74 74 grey29 77 77 77 gray30 77 77 77 grey30 79 79 79 gray31 79 79 79 grey31 82 82 82 gray32 82 82 82 grey32 84 84 84 gray33 84 84 84 grey33 87 87 87 gray34 87 87 87 grey34 89 89 89 gray35 89 89 89 grey35 92 92 92 gray36 92 92 92 grey36 94 94 94 gray37 94 94 94 grey37 97 97 97 gray38 97 97 97 grey38 99 99 99 gray39 99 99 99 grey39 102 102 102 gray40 102 102 102 grey40 105 105 105 gray41 105 105 105 grey41 107 107 107 gray42 107 107 107 grey42 110 110 110 gray43 110 110 110 grey43 112 112 112 gray44 112 112 112 grey44 115 115 115 gray45 115 115 115 grey45 117 117 117 gray46 117 117 117 grey46 120 120 120 gray47 120 120 120 grey47 122 122 122 gray48 122 122 122 grey48 125 125 125 gray49 125 125 125 grey49 127 127 127 gray50 127 127 127 grey50 130 130 130 gray51 130 130 130 grey51 133 133 133 gray52 133 133 133 grey52 135 135 135 gray53 135 135 135 grey53 138 138 138 gray54 138 138 138 grey54 140 140 140 gray55 140 140 140 grey55 143 143 143 gray56 143 143 143 grey56 145 145 145 gray57 145 145 145 grey57 148 148 148 gray58 148 148 148 grey58 150 150 150 gray59 150 150 150 grey59 153 153 153 gray60 153 153 153 grey60 156 156 156 gray61 156 156 156 grey61 158 158 158 gray62 158 158 158 grey62 161 161 161 gray63 161 161 161 grey63 163 163 163 gray64 163 163 163 grey64 166 166 166 gray65 166 166 166 grey65 168 168 168 gray66 168 168 168 grey66 171 171 171 gray67 171 171 171 grey67 173 173 173 gray68 173 173 173 grey68 176 176 176 gray69 176 176 176 grey69 179 179 179 gray70 179 179 179 grey70 181 181 181 gray71 181 181 181 grey71 184 184 184 gray72 184 184 184 grey72 186 186 186 gray73 186 186 186 grey73 189 189 189 gray74 189 189 189 grey74 191 191 191 gray75 191 191 191 grey75 194 194 194 gray76 194 194 194 grey76 196 196 196 gray77 196 196 196 grey77 199 199 199 gray78 199 199 199 grey78 201 201 201 gray79 201 201 201 grey79 204 204 204 gray80 204 204 204 grey80 207 207 207 gray81 207 207 207 grey81 209 209 209 gray82 209 209 209 grey82 212 212 212 gray83 212 212 212 grey83 214 214 214 gray84 214 214 214 grey84 217 217 217 gray85 217 217 217 grey85 219 219 219 gray86 219 219 219 grey86 222 222 222 gray87 222 222 222 grey87 224 224 224 gray88 224 224 224 grey88 227 227 227 gray89 227 227 227 grey89 229 229 229 gray90 229 229 229 grey90 232 232 232 gray91 232 232 232 grey91 235 235 235 gray92 235 235 235 grey92 237 237 237 gray93 237 237 237 grey93 240 240 240 gray94 240 240 240 grey94 242 242 242 gray95 242 242 242 grey95 245 245 245 gray96 245 245 245 grey96 247 247 247 gray97 247 247 247 grey97 250 250 250 gray98 250 250 250 grey98 252 252 252 gray99 252 252 252 grey99 255 255 255 gray100 255 255 255 grey100 169 169 169 dark grey 169 169 169 DarkGrey 169 169 169 dark gray 169 169 169 DarkGray 0 0 139 dark blue 0 0 139 DarkBlue 0 139 139 dark cyan 0 139 139 DarkCyan 139 0 139 dark magenta 139 0 139 DarkMagenta 139 0 0 dark red 139 0 0 DarkRed 144 238 144 light green 144 238 144 LightGreen __END__ =head1 NAME Imager::Color::Table - built-in Imager color table =head1 SYNOPSIS use Imager::Color::Table; my @rgb = Imager::Color::Table->get($name) or die "Color $name not found"; =head1 DESCRIPTION This class provides a base color table for use in resolving color names. The table contains the standard X11 C colors. This table is not included as part of Imager::Color itself since it's moderately large. There is only one method: =over =item get my @rgb = Imager::Color::Table->get('red') or die "No red found"; Retrieves a color from Imager::Color::Tables built-in color table. =back =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Fountain.pm0000644000175000017500000002241212031434615021654 0ustar gregoagregoapackage Imager::Fountain; use strict; use Imager::Color::Float; use vars qw($VERSION); $VERSION = "1.007"; =head1 NAME Imager::Fountain - a class for building fountain fills suitable for use by the fountain filter. =head1 SYNOPSIS use Imager::Fountain; my $f1 = Imager::Fountain->read(gimp=>$filename); $f->write(gimp=>$filename); my $f1 = Imager::Fountain->new; $f1->add(start=>0, middle=>0.5, end=>1.0, c0=>Imager::Color->new(...), c1=>Imager::Color->new(...), type=>$trans_type, color=>$color_trans_type); =head1 DESCRIPTION Provide an interface to build arrays suitable for use by the Imager fountain filter. These can be loaded from or saved to a GIMP gradient file or you can build them from scratch. =over =item read(gimp=>$filename) =item read(gimp=>$filename, name=>\$name) Loads a gradient from the given GIMP gradient file, and returns a new Imager::Fountain object. If the name parameter is supplied as a scalar reference then any name field from newer GIMP gradient files will be returned in it. my $gradient = Imager::Fountain->read(gimp=>'foo.ggr'); my $name; my $gradient2 = Imager::Fountain->read(gimp=>'bar.ggr', name=>\$name); =cut sub read { my ($class, %opts) = @_; if ($opts{gimp}) { my $fh; $fh = ref($opts{gimp}) ? $opts{gimp} : IO::File->new($opts{gimp}); unless ($fh) { $Imager::ERRSTR = "Cannot open $opts{gimp}: $!"; return; } my $trash_name; my $name_ref = $opts{name} && ref $opts{name} ? $opts{name} : \$trash_name; return $class->_load_gimp_gradient($fh, $opts{gimp}, $name_ref); } else { warn "${class}::read: Nothing to do!"; return; } } =item write(gimp=>$filename) =item write(gimp=>$filename, name=>$name) Save the gradient to a GIMP gradient file. The second variant allows the gradient name to be set (for newer versions of the GIMP). $gradient->write(gimp=>'foo.ggr') or die Imager->errstr; $gradient->write(gimp=>'bar.ggr', name=>'the bar gradient') or die Imager->errstr; =cut sub write { my ($self, %opts) = @_; if ($opts{gimp}) { my $fh; $fh = ref($opts{gimp}) ? $opts{gimp} : IO::File->new("> ".$opts{gimp}); unless ($fh) { $Imager::ERRSTR = "Cannot open $opts{gimp}: $!"; return; } return $self->_save_gimp_gradient($fh, $opts{gimp}, $opts{name}); } else { warn "Nothing to do\n"; return; } } =item new Create an empty fountain fill description. =cut sub new { my ($class) = @_; return bless [], $class; } sub _first { for (@_) { return $_ if defined; } return undef; } =item add(start=>$start, middle=>$middle, end=>1.0, c0=>$start_color, c1=>$end_color, type=>$trans_type, color=>$color_trans_type) Adds a new segment to the fountain fill, the possible options are: =over =item * C - the start position in the gradient where this segment takes effect between 0 and 1. Default: 0. =item * C - the mid-point of the transition between the 2 colors, between 0 and 1. Default: average of C and C. =item * C - the end of the gradient, from 0 to 1. Default: 1. =item * C - the color of the fountain fill where the fill parameter is equal to I. Default: opaque black. =item * C - the color of the fountain fill where the fill parameter is equal to I. Default: opaque black. =item * C - the type of segment, controls the way in which the fill parameter moves from 0 to 1. Default: linear. This can take any of the following values: =over =item * C =item * C - unimplemented so far. =item * C =item * C =item * C =back =item * C - the way in which the color transitions between C and C. Default: direct. This can take any of the following values: =over =item * C - each channel is simple scaled between c0 and c1. =item * C - the color is converted to a HSV value and the scaling is done such that the hue increases as the fill parameter increases. =item * C - the color is converted to a HSV value and the scaling is done such that the hue decreases as the fill parameter increases. =back =back In most cases you can ignore some of the arguments, eg. # assuming $f is a new Imager::Fountain in each case here use Imager ':handy'; # simple transition from red to blue $f->add(c0=>NC('#FF0000'), c1=>NC('#0000FF')); # simple 2 stages from red to green to blue $f->add(end=>0.5, c0=>NC('#FF0000'), c1=>NC('#00FF00')) $f->add(start=>0.5, c0=>NC('#00FF00'), c1=>NC('#0000FF')); =cut # used to translate segment types and color transition types to numbers my %type_names = ( linear => 0, curved => 1, sine => 2, sphereup=> 3, spheredown => 4, ); my %color_names = ( direct => 0, hueup => 1, huedown => 2 ); sub add { my ($self, %opts) = @_; my $start = _first($opts{start}, 0); my $end = _first($opts{end}, 1); my $middle = _first($opts{middle}, ($start+$end)/2); my @row = ( $start, $middle, $end, _first($opts{c0}, Imager::Color::Float->new(0,0,0,1)), _first($opts{c1}, Imager::Color::Float->new(1,1,1,0)), _first($opts{type} && $type_names{$opts{type}}, $opts{type}, 0), _first($opts{color} && $color_names{$opts{color}}, $opts{color}, 0) ); push(@$self, \@row); $self; } =item simple(positions=>[ ... ], colors=>[...]) Creates a simple fountain fill object consisting of linear segments. The array references passed as positions and colors must have the same number of elements. They must have at least 2 elements each. colors must contain Imager::Color or Imager::Color::Float objects. eg. my $f = Imager::Fountain->simple(positions=>[0, 0.2, 1.0], colors=>[ NC(255,0,0), NC(0,255,0), NC(0,0,255) ]); =cut sub simple { my ($class, %opts) = @_; if ($opts{positions} && $opts{colors}) { my $positions = $opts{positions}; my $colors = $opts{colors}; unless (@$positions == @$colors) { $Imager::ERRSTR = "positions and colors must be the same size"; return; } unless (@$positions >= 2) { $Imager::ERRSTR = "not enough segments"; return; } my $f = $class->new; for my $i (0.. $#$colors-1) { $f->add(start=>$positions->[$i], end=>$positions->[$i+1], c0 => $colors->[$i], c1=>$colors->[$i+1]); } return $f; } else { warn "Nothing to do"; return; } } =back =head2 Implementation Functions Documented for internal use. =over =item _load_gimp_gradient($class, $fh, $name) Does the work of loading a GIMP gradient file. =cut sub _load_gimp_gradient { my ($class, $fh, $filename, $name) = @_; my $head = <$fh>; chomp $head; unless ($head eq 'GIMP Gradient') { $Imager::ERRSTR = "$filename is not a GIMP gradient file"; return; } my $count = <$fh>; chomp $count; if ($count =~ /^name:\s?(.*)/i) { ref $name and $$name = $1; $count = <$fh>; # try again chomp $count; } unless ($count =~ /^\d+$/) { $Imager::ERRSTR = "$filename is missing the segment count"; return; } my @result; for my $i (1..$count) { my $row = <$fh>; chomp $row; my @row = split ' ', $row; unless (@row == 13) { $Imager::ERRSTR = "Bad segment definition"; return; } my ($start, $middle, $end) = splice(@row, 0, 3); my $c0 = Imager::Color::Float->new(splice(@row, 0, 4)); my $c1 = Imager::Color::Float->new(splice(@row, 0, 4)); my ($type, $color) = @row; push(@result, [ $start, $middle, $end, $c0, $c1, $type, $color ]); } return bless \@result, } =item _save_gimp_gradient($self, $fh, $name) Does the work of saving to a GIMP gradient file. =cut sub _save_gimp_gradient { my ($self, $fh, $filename, $name) = @_; print $fh "GIMP Gradient\n"; defined $name or $name = ''; $name =~ tr/ -~/ /cds; if ($name) { print $fh "Name: $name\n"; } print $fh scalar(@$self),"\n"; for my $row (@$self) { printf $fh "%.6f %.6f %.6f ",@{$row}[0..2]; for my $i (0, 1) { for ($row->[3+$i]->rgba) { printf $fh "%.6f ", $_/255.0; } } print $fh "@{$row}[5,6]"; unless (print $fh "\n") { $Imager::ERRSTR = "write error: $!"; return; } } return 1; } =back =head1 FILL PARAMETER The add() documentation mentions a fill parameter in a few places, this is as good a place as any to discuss it. The process of deciding the color produced by the gradient works through the following steps: =over =item 1. calculate the base value, which is typically a distance or an angle of some sort. This can be positive or occasionally negative, depending on the type of fill being performed (linear, radial, etc). =item 2. clamp or convert the base value to the range 0 through 1, how this is done depends on the repeat parameter. I'm calling this result the fill parameter. =item 3. the appropriate segment is found. This is currently done with a linear search, and the first matching segment is used. If there is no matching segment the pixel is not touched. =item 4. the fill parameter is scaled from 0 to 1 depending on the segment type. =item 5. the color produced, depending on the segment color type. =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Engines.pod0000644000175000017500000003215212263740601021633 0ustar gregoagregoa=head1 NAME Imager::Engines - Programmable transformation operations =head1 SYNOPSIS use Imager; my %opts; my @imgs; my $img; ... my $newimg = $img->transform( xexpr=>'x', yexpr=>'y+10*sin((x+y)/10)') or die $img->errstr; my $newimg = Imager::transform2(\%opts, @imgs) or die "transform2 failed: $Imager::ERRSTR"; my $newimg = $img->matrix_transform( matrix=>[ -1, 0, $img->getwidth-1, 0, 1, 0, 0, 0, 1 ]); =head1 DESCRIPTION =head2 transform() The C function can be used to generate spatial warps and rotations and such effects. It only operates on a single image and its only function is to displace pixels. It can be given the operations in postfix notation or the module Affix::Infix2Postfix can be used to generate postfix code from infix code. Look in the test case t/t55trans.t for an example. C needs expressions (or opcodes) that determine the source pixel for each target pixel. Source expressions are infix expressions using any of the +, -, *, / or ** binary operators, the - unary operator, ( and ) for grouping and the C and C functions. The target pixel is input as the variables x and y. You specify the x and y expressions as C and C respectively. You can also specify opcodes directly, but that's magic deep enough that you can look at the source code. Note: You can still use the transform() function, but the transform2() function is just as fast and is more likely to be enhanced and maintained. $new_img=$img->transform(xexpr=>'x',yexpr=>'y+10*sin((x+y)/10)') $new_img=$img->transform(xexpr=>'x+0.1*y+5*sin(y/10.0+1.57)', yexpr=>'y+10*sin((x+y-0.785)/10)') =head2 transform2() Imager also supports a C class method which allows you perform a more general set of operations, rather than just specifying a spatial transformation as with the transform() method, you can also perform color transformations, image synthesis and image combinations from multiple source images. C takes an reference to an options hash, and a list of images to operate one (this list may be empty): my %opts; my @imgs; ... my $img = Imager::transform2(\%opts, @imgs) or die "transform2 failed: $Imager::ERRSTR"; The options hash may define a transformation function, and optionally: =over =item * width - the width of the image in pixels. If this isn't supplied the width of the first input image is used. If there are no input images an error occurs. =item * height - the height of the image in pixels. If this isn't supplied the height of the first input image is used. If there are no input images an error occurs. =item * constants - a reference to hash of constants to define for the expression engine. Some extra constants are defined by Imager =item * channels - the number of channels in the output image. If this isn't supplied a 3 channel image will be created. =back The transformation function is specified using either the C or C member of the options. =head3 Infix expressions You can supply infix expressions to transform 2 with the C keyword. $opts{expr} = 'return getp1(w-x, h-y)' The 'expression' supplied follows this general grammar: ( identifier '=' expr ';' )* 'return' expr This allows you to simplify your expressions using variables. A more complex example might be: $opts{expr} = 'pix = getp1(x,y); return if(value(pix)>0.8,pix*0.8,pix)' Currently to use infix expressions you must have the L module installed (available from CPAN). There is also what might be a significant delay the first time you run the infix expression parser due to the compilation of the expression grammar. =head3 Postfix expressions You can supply postfix or reverse-polish notation expressions to transform2() through the C keyword. The parser for C emulates a stack machine, so operators will expect to see their parameters on top of the stack. A stack machine isn't actually used during the image transformation itself. You can store the value at the top of the stack in a variable called C using C and retrieve that value again using @foo. The !foo notation will pop the value from the stack. An example equivalent to the infix expression above: $opts{rpnexpr} = 'x y getp1 !pix @pix value 0.8 gt @pix 0.8 * @pix ifp' At the end of the expression there should be a single pixel value left on the stack, which is used as the output pixel. =head3 Operators transform2() has a fairly rich range of operators. Each entry below includes the usage with C, formatted as: =over I I ... B> -- I =back If the operand or result begins with "N" it is a numeric value, if it begins with "C" it is a color or pixel value. =over =item +, *, -, /, %, ** multiplication, addition, subtraction, division, remainder and exponentiation. Multiplication, addition and subtraction can be used on color values too - though you need to be careful - adding 2 white values together and multiplying by 0.5 will give you gray, not white. Division by zero (or a small number) just results in a large number. Modulo zero (or a small number) results in zero. % is implemented using fmod() so you can use this to take a value mod a floating point value. =for stopwords N1 N2 N uminus C usage: =over I I B<+> -- I I I B<*> -- I I I B<-> -- I I I B -- I I I B<**> -- I I B -- I =back =item sin(N), cos(N), atan2(y,x) Some basic trig functions. They work in radians, so you can't just use the hue values. =for stopwords Ny Nx atan2 C usage: =over I B -- I I B -- I I I B -- I =back =item distance(x1, y1, x2, y2) Find the distance between two points. This is handy (along with atan2()) for producing circular effects. =for stopwords Nx1 Ny1 Nx2 Ny2 C usage: =over I I I I B -- I =back =item sqrt(n) Find the square root. I haven't had much use for this since adding the distance() function. C usage: =over I B -- I =back =item abs(n) Find the absolute value. C usage: =over I B -- I =back =item getp1(x,y), getp2(x,y), getp3(x, y) Get the pixel at position (x,y) from the first, second or third image respectively. I may add a getpn() function at some point, but this prevents static checking of the instructions against the number of images actually passed in. =for stopwords getp1 getp2 getp3 C usage: =over I I B -- I I I B -- I I I B -- I =back =item value(c), hue(c), sat(c), hsv(h,s,v), hsva(h,s,v,alpha) Separates a color value into it's value (brightness), hue (color) and saturation elements. Use hsv() to put them back together (after suitable manipulation), or hsva() to include a transparency value. =for stopwords Nh Ns Nv hsv hsva Nr Ng Nb rgb rgba C usage: =over I B -- I I B -- I I B -- I I I I B -- I I I I I B -- I =back =item red(c), green(c), blue(c), rgb(r,g,b), rgba(r,g,b,a) Separates a color value into it's red, green and blue colors. Use rgb(r,g,b) to put it back together, or rgba() to include a transparency value. C usage: =over I B -- I I B -- I I B -- I I I I B -- I I I I I B -- I =back =item alpha(c) Retrieve the alpha value from a color. C usage: =over I B -- I =back =item int(n) Convert a value to an integer. Uses a C int cast, so it may break on large values. C usage: =over I B -- I =back =item if(cond,ntrue,nfalse), if(cond,ctrue,cfalse) A simple (and inefficient) if function. =for stopwords Ncond ifp C usage: =over I I I B -- I I I I B -- I I I I B -- I =back =item <=,<,==,>=,>,!= Relational operators (typically used with if()). Since we're working with floating point values the equalities are 'near equalities' - an epsilon value is used. =over I I B<< <= >> -- I I I B<< < >> -- I I I B<< >= >> -- I I I B<< > >> -- I I I B<< == >> -- I I I B<< != >> -- I =back =item &&, ||, not(n) Basic logical operators. C usage: =over I I B -- I I I B -- I I B -- I =back =item log(n), exp(n) Natural logarithm and exponential. C usage: =over I B -- I I B -- I =back =item det(a, b, c, d) Calculate the determinant of the 2 x 2 matrix; a b c d =for stopwords Na Nv Nc Nd det C usage: =over I I I I B -- I =back =back =head3 Constants transform2() defines the following constants: =over =item C The classical constant. =item C =item C The width and height of the output image. =item C =item C The center of the output image. =item CI =item CI The width and height of each of the input images, C is the width of the first input image and so on. =item CI =item CI The center of each of the input images, (C, C) is the center of the first input image and so on. =back A few examples: =over rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat x y getp1 !pix @pix sat 0.7 gt @pat @pix ifp' tiles a smaller version of the input image over itself where the color has a saturation over 0.7. rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat y 360 / !rat x y getp1 1 @rat - pmult @pat @rat pmult padd' tiles the input image over itself so that at the top of the image the full-size image is at full strength and at the bottom the tiling is most visible. rpnexpr=>'x y getp1 !pix @pix value 0.96 gt @pix sat 0.1 lt and 128 128 255 rgb @pix ifp' replace pixels that are white or almost white with a palish blue rpnexpr=>'x 35 % 10 * y 45 % 8 * getp1 !pat x y getp1 !pix @pix sat 0.2 lt @pix value 0.9 gt and @pix @pat @pix value 2 / 0.5 + pmult ifp' Tiles the input image over it self where the image isn't white or almost white. rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a2 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv' Produces a spiral. rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv' A spiral built on top of a color wheel. =back For details on expression parsing see L. For details on the virtual machine used to transform the images, see L. # generate a colorful spiral # requires that Parse::RecDescent be installed my $newimg = Imager::transform2({ width => 160, height=>160, expr => < <matrix_transform(matrix=>[ -1, 0, $img->getwidth-1, 0, 1, 0, 0, 0, 1 ]); By default the output image will be the same size as the input image, but you can supply the C and C parameters to change the size. Rather than building matrices by hand you can use the Imager::Matrix2d module to build the matrices. This class has methods to allow you to scale, shear, rotate, translate and reflect, and you can combine these with an overloaded multiplication operator. WARNING: the matrix you provide in the matrix operator transforms the co-ordinates within the B image to the co-ordinates within the I image. This can be confusing. You can also supply a C argument which acts as a background color for the areas of the image with no samples available (outside the rectangle of the source image.) This can be either an Imager::Color or Imager::Color::Float object. This is B mixed transparent pixels in the middle of the source image, it is B used for pixels where there is no corresponding pixel in the source image. =back =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Transform.pm0000644000175000017500000003015612263740601022052 0ustar gregoagregoapackage Imager::Transform; use strict; use Imager; use Imager::Expr::Assem; use vars qw($VERSION); $VERSION = "1.006"; my %funcs = ( mandel=> { desc=>"Mandelbrot set", type=>'assem', assem=>< # (nx*nx-ny*ny+x, 2.nx.ny+y) var wx:n ; var wy:n ; var work:n wx = mult nx nx wy = mult ny ny wx = subtract wx wy ny = mult ny nx ny = mult ny 2 nx = wx nx = add nx conx ny = add ny cony work = distance nx ny 0 0 work = gt work 2 jumpnz work docol count = add count 1 work = lt count maxcount jumpnz work loop jumpnz insideangle doinang var workp:p workp = rgb 0 0 0 ret workp doinang: var ang:n ang = atan2 ny nx ang = mult ang 360 ang = div ang pi workp = hsv ang 255 0.5 ret workp docol: var outvalue:n outvalue = mult outsidevaluestep count outvalue = add outvalue outsidevalue outvalue = mod outvalue 1.01 jumpnz outsideangle do_outang work = mult count huestep work = add work huebase work = mod work 360 workp = hsv work 1 outvalue ret workp do_outang: ang = atan2 ny nx ang = mult ang 360 ang = div ang pi ang = add ang outsidebase workp = hsv ang outsidesat outvalue ret workp EOS constants=> { minx=>{ default=>-2, desc=>'Left of rendered area', }, miny=>{ default=>-1.5, desc=>'Top of rendered area', }, maxx=>{ default=>1, desc=>'Right of rendered area', }, maxy=>{ default=>1.5, desc=>'Bottom of rendered area', }, maxcount=>{ default=>100, desc=>'Maximum iterations', }, huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', }, huebase=>{ default=>0, desc=>'Base hue for number of iterations', }, insideangle=> { default=>0, desc=>'Non-zero to use angle of final as hue for inside', }, insidebase=> { default=>0, desc=>'Base angle for inside colours if insideangle is non-zero', }, outsideangle=> { default=>0, desc=>'Non-zero to use angle of final as hue for outside', }, outsidebase=> { default=>0, desc=>'Base angle if outsideangle is true', }, outsidevalue=> { default=>1, desc=>'Brightness for outside pixels', }, outsidevaluestep=> { default=>0, desc=>'Brightness step for each count for outside pixels', }, outsidesat=> { default=>1, desc=>'Saturation for outside pixels', }, }, inputs=>[], }, julia=> { desc=>"Julia set", type=>'assem', assem=>< # (nx*nx-ny*ny+x, 2.nx.ny+y) var wx:n ; var wy:n ; var work:n wx = mult nx nx wy = mult ny ny wx = subtract wx wy ny = mult ny nx ny = mult ny 2 nx = wx nx = add nx zx ny = add ny zy work = distance nx ny 0 0 work = gt work 2 jumpnz work docol count = add count 1 work = lt count maxcount jumpnz work loop jumpnz insideangle doinang var workp:p workp = rgb 0 0 0 ret workp doinang: var ang:n ang = atan2 ny nx ang = mult ang 360 ang = div ang pi workp = hsv ang 255 0.5 ret workp docol: var outvalue:n outvalue = mult outsidevaluestep count outvalue = add outvalue outsidevalue outvalue = mod outvalue 1.01 jumpnz outsideangle do_outang work = mult count huestep work = add work huebase work = mod work 360 workp = hsv work 1 outvalue ret workp do_outang: ang = atan2 ny nx ang = mult ang 360 ang = div ang pi ang = add ang outsidebase workp = hsv ang outsidesat outvalue ret workp EOS constants=> { zx=>{default=>0.7, desc=>'Real part of initial Z', }, zy=>{default=>0.2, desc=>'Imaginary part of initial Z', }, minx=>{ default=>-1.5, desc=>'Left of rendered area', }, miny=>{ default=>-1.5, desc=>'Top of rendered area', }, maxx=>{ default=>1.5, desc=>'Right of rendered area', }, maxy=>{ default=>1.5, desc=>'Bottom of rendered area', }, maxcount=>{ default=>100, desc=>'Maximum iterations', }, huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', }, huebase=>{ default=>0, desc=>'Base hue for number of iterations', }, insideangle=> { default=>0, desc=>'Non-zero to use angle of final as hue for inside', }, insidebase=> { default=>0, desc=>'Base angle for inside colours if insideangle is non-zero', }, outsideangle=> { default=>0, desc=>'Non-zero to use angle of final as hue for outside', }, outsidebase=> { default=>0, desc=>'Base angle if outsideangle is true', }, outsidevalue=> { default=>1, desc=>'Brightness for outside pixels', }, outsidevaluestep=> { default=>0, desc=>'Brightness step for each count for outside pixels', }, outsidesat=> { default=>1, desc=>'Saturation for outside pixels', }, }, inputs=>[], }, circleripple=> { type=>'rpnexpr', desc=>'Adds a circular ripple effect', rpnexpr=><<'EOS', x y cx cy distance !dist @dist freq / sin !scale @scale depth * @dist + !adj y cy - x cx - atan2 !ang cx @ang cos @adj * + cy @ang sin @adj * + getp1 @scale shadow + shadow 1 + / * EOS constants=> { freq=> { desc=>'Frequency of ripples', default=>5 }, depth=> { desc=>'Depth of ripples', default=>10 }, shadow=> { desc=>'Fraction of shadow', default=>20 }, }, inputs=> [ { desc=>'Image to ripple' } ], }, spiral=> { type=>'rpnexpr', desc=>'Render a colorful spiral', rpnexpr=><<'EOS', x y cx cy distance !d y cy - x cx - atan2 !a @d spacing / @a + pi 2 * % !a2 @a 180 * pi / 1 @a2 sin 1 + 2 / hsv EOS constants=> { spacing=>{ desc=>'Spacing between arms', default=>10 }, }, inputs=>[], }, diagripple=> { type=>'rpnexpr', desc=>'Adds diagonal ripples to an image', rpnexpr=><<'EOS', x y + !dist @dist freq / sin !scale @scale depth * !adj x @adj + y @adj + getp1 @scale shadow + shadow 1 + / * EOS constants=> { freq=>{ desc=>'Frequency of ripples', default=>5, }, depth=>{desc=>'Depth of ripples', default=>3,}, shadow=> { desc=>'Fraction of brightness to remove for shadows', default=>20, }, }, inputs=> [ { desc=>'Image to add ripples to' } ], }, twist=> { type=>'rpnexpr', desc=>'Twist an image', rpnexpr=><<'EOS', x y cx cy distance !dist y cy - x cx - atan2 @dist twist / + !ang cx @ang cos @dist * + cy @ang sin @dist * + getp1 EOS constants=> { twist=>{ desc=>'Amount of twist', default=>2.5, }, }, inputs=> [ { desc=>'Image to twist' }, ], }, # any other functions can wait until Imager::Expr::Infix supports # jumps ); sub new { my ($class, $name) = @_; exists $funcs{$name} or return; bless { func=>$funcs{$name}, name=>$name }, $class; } sub inputs { my ($self) = @_; return @{$self->{func}{inputs}} } sub constants { my $self = shift; if (@_) { return @{$self->{func}{constants}}{@_}; } else { return keys %{$self->{func}{constants}}; } } sub transform { my ($self, $opts, $constants, @in) = @_; my $func = $self->{func}; my %opts = %$opts; $opts{$func->{type}} = $func->{$func->{type}}; my %con = %$constants; for my $name (keys %{$func->{'constants'}}) { unless (exists $con{$name}) { if (exists $func->{'constants'}{$name}{default}) { $con{$name} = $func->{'constants'}{$name}{default}; } else { $self->{error} = "No value or default for constant $name"; return; } } } $opts{'constants'} = \%con; unless (@in == @{$func->{'inputs'}}) { $self->{error} = @in." input images given, ". @{$func->{'inputs'}}." supplied"; return; } my $out = Imager::transform2(\%opts, @in); unless ($out) { $self->{error} = $Imager::ERRSTR; return; } return $out; } sub errstr { return $_[0]{error}; } sub list { return keys %funcs; } sub describe { my ($class, $name) = @_; my $func; if (ref $class && !$name) { $func = $class->{func}; $name = $class->{name} } else { $func = $funcs{$name} or return undef; } my $desc = <{desc} EOS if ($func->{'inputs'} && @{$func->{'inputs'}}) { $desc .= "Input images:\n"; my $i = 1; for my $in (@{$func->{'inputs'}}) { $desc .= " $i: $in->{desc}\n"; } } else { $desc .= "There are no input images\n"; } if ($func->{'constants'} && keys %{$func->{'constants'}}) { $desc .= "Input constants:\n"; for my $key (keys %{$func->{'constants'}}) { $desc .= " $key: $func->{'constants'}{$key}{desc}\n"; $desc .= " Default: $func->{'constants'}{$key}{default}\n"; } } else { $desc .= "There are no constants\n"; } return $desc; } 1; __END__ =head1 NAME Imager::Transform - a library of register machine image transformations =head1 SYNOPSIS # get a list of transformations my @funcs = Imager::Transform->list; # create a transformation object my $tran = Imager::Transform->new($name); # describe it print $tran->describe; # a list of constant names my @constants = $tran->constants; # information about some of the constants my @info = $tran->constants(@constants); =head1 DESCRIPTION This module provides a library of transformations that use the Imager transform2() function. The aim is to provide a place to collect these transformations. At some point there might be an interface to add new functions, but there's not a whole lot of point to that. The interface is a little sparse as yet. =head1 METHODS =over 4 =item my @names = Imager::Transform->list Returns a list of the transformations. =item my $desc = Imager::Transform->describe($name); =item my $desc = $tran->describe() Describes a transformation specified either by name (as a class method) or by reference (as an instance method). The class method returns undef if there is no such transformation. =item my $tran = Imager::Transform->new($name) Create a new transformation object. Returns undef if there is no such transformation. =item my @inputs = $tran->inputs; =item my $inputs = $tran->inputs; Returns a list of input image descriptions, or the number of them, depending on content. The list contains hash references, which current contain only one member, C, a description of the use of the input image. =item $tran->constants Returns a list of names of constants that can be set for the transformation. =item $tran->constants($name, $name, ...) Returns a hashref for each named constant, which contains the default in key C and a description in key C. =item my $out = $tran->transform(\%opts, \%constants, @imgs) Perform the image transformation. Returns the new image on success, or undef on failure, in which case you can use $tran->errstr to get an error message. =item $tran->errstr The error message, if any from the last image transformation. =back =head1 BUGS Needs more transformations. =head1 SEE ALSO Imager(3), F =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Tutorial.pod0000644000175000017500000001175012263740601022047 0ustar gregoagregoa=head1 NAME Imager::Tutorial - an introduction to Imager. =head1 DESCRIPTION =head2 Before you start If you have the necessary knowledge, install the image format libraries you want Imager image file support for, and Imager itself, otherwise arrange to have it done. =for stopwords Photoshop You will also want some sort of image viewer tool, whether an image editor like Photoshop or the GIMP, or a web browser. =head2 Hello Boxes! - A Simple Start As with any perl program it's useful to start with a #! line, and to enable strict mode: #!/usr/bin/perl -w # you might to 'use warnings;' instead of the -w above use strict; These lines will be omitted in further examples. As with any module, you need to load it: use Imager; Now create a image to draw on: my $image = Imager->new(xsize => 100, ysize => 100); and draw a couple of filled rectangles on it: $image->box(xmin => 0, ymin => 0, xmax => 99, ymax => 99, filled => 1, color => 'blue'); $image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79, filled => 1, color => 'green'); Since the first box fills the whole image, it can be simplified to: $image->box(filled => 1, color => 'blue'); and save it to a file: $image->write(file=>'tutorial1.ppm') or die 'Cannot save tutorial1.ppm: ', $image->errstr; So our completed program is: use Imager; my $image = Imager->new(xsize => 100, ysize => 100); $image->box(filled => 1, color => 'blue'); $image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79, filled => 1, color => 'green'); $image->write(file=>'tutorial1.ppm') or die 'Cannot save tutorial1.ppm: ', $image->errstr; =head2 Adding some text The first thing you need to draw text is a font object: # use a different file, depending on the font support you have in # your installed Imager. my $font_filename = 'fontfiles/ImUgly.ttf'; my $font = Imager::Font->new(file=>$font_filename) or die "Cannot load $font_filename: ", Imager->errstr; If you're on Windows, you can supply a face name instead: my $font = Imager::Font->new(face=>'Arial Bold') or die "Cannot load 'Arial Bold: ", Imager->errstr; and draw the text: my $text = "Hello Boxes!"; my $text_size = 12; $font->align(string => $text, size => $text_size, color => 'red', x => $image->getwidth/2, y => $image->getheight/2, halign => 'center', valign => 'center', image => $image); So inserting this into our existing code we have: use Imager; my $image = Imager->new(xsize => 100, ysize => 100); $image->box(xmin => 0, ymin => 0, xmax => 99, ymax => 99, filled => 1, color => 'blue'); $image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79, filled => 1, color => 'green'); # use a different file, depending on the font support you have in # your installed Imager. my $font_filename = 'fontfiles/ImUgly.ttf'; my $font = Imager::Font->new(file=>$font_filename) or die "Cannot load $font_filename: ", Imager->errstr; my $text = "Hello Boxes!"; my $text_size = 12; $font->align(string => $text, size => $text_size, color => 'red', x => $image->getwidth/2, y => $image->getheight/2, halign => 'center', valign => 'center', image => $image); $image->write(file=>'tutorial2.ppm') or die 'Cannot save tutorial2.ppm: ', $image->errstr; =head2 Using an existing image as a base To load an image from a file, first create an empty image object: my $read_image = Imager->new; then call the read method: my $image_source = shift; # from the command-line $read_image->read(file=>$image_source) or die "Cannot load $image_source: ", $image->errstr; To keep to our working size, we'll scale the image: # the scale() method always does a proportional scale, we don't want # that here my $scaled_image = $read_image->scaleX(pixels=>100)->scaleY(pixels=>100); draw our inner box on that, and save the result: $scaled_image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79, filled => 1, color => 'green'); $scaled_image->write(file=>'tutorial3.ppm') or die 'Cannot save tutorial3.ppm: ', $image->errstr; so the complete program is: use Imager; my $read_image = Imager->new; my $image_source = shift; # from the command-line $read_image->read(file=>$image_source) or die "Cannot load $image_source: ", $image->errstr; # the scale() method always does a proportional scale, we don't want # that here my $scaled_image = $read_image->scaleX(pixels=>100)->scaleY(pixels=>100); $scaled_image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79, filled => 1, color => 'green'); $scaled_image->write(file=>'tutorial3.ppm') or die 'Cannot save tutorial3.ppm: ', $image->errstr; =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Preprocess.pm0000644000175000017500000001652112322335073022223 0ustar gregoagregoapackage Imager::Preprocess; use strict; require Exporter; use vars qw(@ISA @EXPORT $VERSION); use Getopt::Long; use Text::ParseWords; @EXPORT = qw(preprocess); @ISA = qw(Exporter); $VERSION = "1.001"; sub preprocess { unshift @ARGV, grep /^-/, shellwords($ENV{IMAGER_PREPROCESS_OPTS}) if $ENV{IMAGER_PREPROCESS_OPTS}; my $skip_lines = 0; GetOptions("l" => \$skip_lines) or usage(); my $keep_lines = !$skip_lines; my $src = shift @ARGV; my $dest = shift @ARGV or usage(); open SRC, "< $src" or die "Cannot open $src: $!\n"; my $cond; my $cond_line; my $save_code; my @code; my $code_line; my @out; my $failed; push @out, "#define IM_ROUND_8(x) ((int)((x)+0.5))\n", "#define IM_ROUND_double(x) (x)\n", "#define IM_LIMIT_8(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x))\n", "#define IM_LIMIT_double(x) ((x) < 0.0 ? 0.0 : (x) > 1.0 ? 1.0 : (x))\n"; push @out, "#line 1 \"$src\"\n" if $keep_lines; while (defined(my $line = )) { if ($line =~ /^\#code\s+(\S.+)$/) { $save_code and do { warn "$src:$code_line:Unclosed #code block\n"; ++$failed; }; $cond = $1; $cond_line = $.; $code_line = $. + 1; $save_code = 1; } elsif ($line =~ /^\#code\s*$/) { $save_code and do { warn "$src:$code_line:Unclosed #code block\n"; ++$failed; }; $cond = ''; $cond_line = 0; $code_line = $. + 1; $save_code = 1; } elsif ($line =~ /^\#\/code\s*$/) { $save_code or do { warn "$src:$.:#/code without #code\n"; ++$failed; next; }; if ($cond) { push @out, "#line $cond_line \"$src\"\n" if $keep_lines; push @out, " if ($cond) {\n"; } push @out, "#undef IM_EIGHT_BIT\n", "#define IM_EIGHT_BIT 1\n", "#undef IM_FILL_COMBINE\n", "#define IM_FILL_COMBINE(fill) ((fill)->combine)\n", "#undef IM_FILL_FILLER\n", "#define IM_FILL_FILLER(fill) ((fill)->f_fill_with_color)\n"; push @out, "#line $code_line \"$src\"\n" if $keep_lines; push @out, byte_samples(@code); push @out, " }\n", " else {\n" if $cond; push @out, "#undef IM_EIGHT_BIT\n", "#undef IM_FILL_COMBINE\n", "#define IM_FILL_COMBINE(fill) ((fill)->combinef)\n", "#undef IM_FILL_FILLER\n", "#define IM_FILL_FILLER(fill) ((fill)->f_fill_with_fcolor)\n"; push @out, "#line $code_line \"$src\"\n" if $keep_lines; push @out, double_samples(@code); push @out, " }\n" if $cond; push @out, "#line ",$.+1," \"$src\"\n" if $keep_lines; @code = (); $save_code = 0; } elsif ($save_code) { push @code, $line; } else { push @out, $line; } } if ($save_code) { warn "$src:$code_line:#code block not closed by EOF\n"; ++$failed; } close SRC; $failed and die "Errors during parsing, aborting\n"; open DEST, "> $dest" or die "Cannot open $dest: $!\n"; print DEST @out; close DEST; } sub byte_samples { # important we make a copy my @lines = @_; for (@lines) { s/\bIM_GPIX\b/i_gpix/g; s/\bIM_GLIN\b/i_glin/g; s/\bIM_PPIX\b/i_ppix/g; s/\bIM_PLIN\b/i_plin/g; s/\bIM_GSAMP\b/i_gsamp/g; s/\bIM_PSAMP\b/i_psamp/g; s/\bIM_SAMPLE_MAX\b/255/g; s/\bIM_SAMPLE_MAX2\b/65025/g; s/\bIM_SAMPLE_T/i_sample_t/g; s/\bIM_COLOR\b/i_color/g; s/\bIM_WORK_T\b/int/g; s/\bIM_Sf\b/"%d"/g; s/\bIM_Wf\b/"%d"/g; s/\bIM_SUFFIX\((\w+)\)/$1_8/g; s/\bIM_ROUND\(/IM_ROUND_8(/g; s/\bIM_ADAPT_COLORS\(/i_adapt_colors(/g; s/\bIM_LIMIT\(/IM_LIMIT_8(/g; s/\bIM_RENDER_LINE\(/i_render_line(/g; s/\bIM_FILL_COMBINE_F\b/i_fill_combine_f/g; } @lines; } sub double_samples { # important we make a copy my @lines = @_; for (@lines) { s/\bIM_GPIX\b/i_gpixf/g; s/\bIM_GLIN\b/i_glinf/g; s/\bIM_PPIX\b/i_ppixf/g; s/\bIM_PLIN\b/i_plinf/g; s/\bIM_GSAMP\b/i_gsampf/g; s/\bIM_PSAMP\b/i_psampf/g; s/\bIM_SAMPLE_MAX\b/1.0/g; s/\bIM_SAMPLE_MAX2\b/1.0/g; s/\bIM_SAMPLE_T/i_fsample_t/g; s/\bIM_COLOR\b/i_fcolor/g; s/\bIM_WORK_T\b/double/g; s/\bIM_Sf\b/"%f"/g; s/\bIM_Wf\b/"%f"/g; s/\bIM_SUFFIX\((\w+)\)/$1_double/g; s/\bIM_ROUND\(/IM_ROUND_double(/g; s/\bIM_ADAPT_COLORS\(/i_adapt_fcolors(/g; s/\bIM_LIMIT\(/IM_LIMIT_double(/g; s/\bIM_RENDER_LINE\(/i_render_linef(/g; s/\bIM_FILL_COMBINE_F\b/i_fill_combinef_f/g; } @lines; } sub usage { die < currently scans the F for F<.im> files and adds Makefile files to convert these to F<.c> files. The beginning of a sample-independent section of code is preceded by: #code expression where I should return true if processing should be done at 8-bits/sample. You can also use a #code block around a function definition to produce 8-bit and double sample versions of a function. In this case #code has no expression and you will need to use IM_SUFFIX() to produce different function names. The end of a sample-independent section of code is terminated by: #/code #code sections cannot be nested. #/code without a starting #code is an error. The following types and values are defined in a #code section: =over =item * IM_GPIX(C, C, C, C<&col>) =item * IM_GLIN(C, C, C, C, C) =item * IM_PPIX(C, C, C, C<&col>) =item * IM_PLIN(C, C, C, C) =item * IM_GSAMP(C, C, C, C, C, C, C) These correspond to the appropriate image function, eg. IM_GPIX() becomes i_gpix() or i_gpixf() as appropriate. =item * IM_ADAPT_COLORS(C, C, C, C) Call i_adapt_colors() or i_adapt_fcolors(). =item * IM_FILL_COMBINE(C) - retrieve the combine function from a fill object. =item * IM_FILL_FILLER(C) - retrieve the fill_with_* function from a fill object. =item * IM_SAMPLE_MAX - maximum value for a sample =item * IM_SAMPLE_MAX2 - maximum value for a sample, squared =item * IM_SAMPLE_T - type of a sample (i_sample_t or i_fsample_t) =item * IM_COLOR - color type, either i_color or i_fcolor. =item * IM_WORK_T - working sample type, either int or double. =item * IM_Sf - format string for the sample type, C<"%d"> or C<"%f">. =item * IM_Wf - format string for the work type, C<"%d"> or C<"%f">. =item * IM_SUFFIX(identifier) - adds _8 or _double onto the end of identifier. =item * IM_EIGHT_BIT - this is a macro defined only in 8-bit/sample code. =back Other types, functions and values may be added in the future. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Test.pm0000644000175000017500000007531412614520110021012 0ustar gregoagregoapackage Imager::Test; use strict; use Test::More; use Test::Builder; require Exporter; use vars qw(@ISA @EXPORT_OK $VERSION); use Carp qw(croak carp); use Config; $VERSION = "1.003"; @ISA = qw(Exporter); @EXPORT_OK = qw( diff_text_with_nul test_image_raw test_image_16 test_image test_image_double test_image_mono test_image_gray test_image_gray_16 test_image_named is_color1 is_color3 is_color4 is_color_close3 is_fcolor1 is_fcolor3 is_fcolor4 color_cmp is_image is_imaged is_image_similar isnt_image image_bounds_checks mask_tests test_colorf_gpix test_color_gpix test_colorf_glin can_test_threads std_font_tests std_font_test_count ); sub diff_text_with_nul { my ($desc, $text1, $text2, @params) = @_; my $builder = Test::Builder->new; print "# $desc\n"; my $imbase = Imager->new(xsize => 100, ysize => 100); my $imcopy = Imager->new(xsize => 100, ysize => 100); $builder->ok($imbase->string(x => 5, 'y' => 50, size => 20, string => $text1, @params), "$desc - draw text1"); $builder->ok($imcopy->string(x => 5, 'y' => 50, size => 20, string => $text2, @params), "$desc - draw text2"); $builder->isnt_num(Imager::i_img_diff($imbase->{IMG}, $imcopy->{IMG}), 0, "$desc - check result different"); } sub is_color3($$$$$) { my ($color, $red, $green, $blue, $comment) = @_; my $builder = Test::Builder->new; unless (defined $color) { $builder->ok(0, $comment); $builder->diag("color is undef"); return; } unless ($color->can('rgba')) { $builder->ok(0, $comment); $builder->diag("color is not a color object"); return; } my ($cr, $cg, $cb) = $color->rgba; unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue, $comment)) { print <new; unless (defined $color) { $builder->ok(0, $comment); $builder->diag("color is undef"); return; } unless ($color->can('rgba')) { $builder->ok(0, $comment); $builder->diag("color is not a color object"); return; } my ($cr, $cg, $cb) = $color->rgba; unless ($builder->ok(abs($cr - $red) <= $tolerance && abs($cg - $green) <= $tolerance && abs($cb - $blue) <= $tolerance, $comment)) { $builder->diag(<new; unless (defined $color) { $builder->ok(0, $comment); $builder->diag("color is undef"); return; } unless ($color->can('rgba')) { $builder->ok(0, $comment); $builder->diag("color is not a color object"); return; } my ($cr, $cg, $cb, $ca) = $color->rgba; unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue && $ca == $alpha, $comment)) { $builder->diag(<new; unless (defined $color) { $builder->ok(0, $comment); $builder->diag("color is undef"); return; } unless ($color->can('rgba')) { $builder->ok(0, $comment); $builder->diag("color is not a color object"); return; } my ($cr, $cg, $cb, $ca) = $color->rgba; unless ($builder->ok(abs($cr - $red) <= $mindiff && abs($cg - $green) <= $mindiff && abs($cb - $blue) <= $mindiff && abs($ca - $alpha) <= $mindiff, $comment)) { $builder->diag(<new; unless (defined $color) { $builder->ok(0, $comment); $builder->diag("color is undef"); return; } unless ($color->can('rgba')) { $builder->ok(0, $comment); $builder->diag("color is not a color object"); return; } my ($cgrey) = $color->rgba; unless ($builder->ok(abs($cgrey - $grey) <= $mindiff, $comment)) { print <new; unless (defined $color) { $builder->ok(0, $comment); $builder->diag("color is undef"); return; } unless ($color->can('rgba')) { $builder->ok(0, $comment); $builder->diag("color is not a color object"); return; } my ($cr, $cg, $cb) = $color->rgba; unless ($builder->ok(abs($cr - $red) <= $mindiff && abs($cg - $green) <= $mindiff && abs($cb - $blue) <= $mindiff, $comment)) { $builder->diag(<new; unless (defined $color) { $builder->ok(0, $comment); $builder->diag("color is undef"); return; } unless ($color->can('rgba')) { $builder->ok(0, $comment); $builder->diag("color is not a color object"); return; } my ($cgrey) = $color->rgba; unless ($builder->ok($cgrey == $grey, $comment)) { $builder->diag(<new(0, 255, 0, 255); my $blue = Imager::Color->new(0, 0, 255, 255); my $red = Imager::Color->new(255, 0, 0, 255); my $img = Imager->new(xsize => 150, ysize => 150); $img->box(filled => 1, color => $green, box => [ 70, 24, 130, 124 ]); $img->box(filled => 1, color => $blue, box => [ 20, 26, 80, 126 ]); $img->arc(x => 75, y => 75, r => 30, color => $red); $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]); $img; } sub test_image_16 { my $green = Imager::Color->new(0, 255, 0, 255); my $blue = Imager::Color->new(0, 0, 255, 255); my $red = Imager::Color->new(255, 0, 0, 255); my $img = Imager->new(xsize => 150, ysize => 150, bits => 16); $img->box(filled => 1, color => $green, box => [ 70, 24, 130, 124 ]); $img->box(filled => 1, color => $blue, box => [ 20, 26, 80, 126 ]); $img->arc(x => 75, y => 75, r => 30, color => $red); $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]); $img; } sub test_image_double { my $green = Imager::Color->new(0, 255, 0, 255); my $blue = Imager::Color->new(0, 0, 255, 255); my $red = Imager::Color->new(255, 0, 0, 255); my $img = Imager->new(xsize => 150, ysize => 150, bits => 'double'); $img->box(filled => 1, color => $green, box => [ 70, 24, 130, 124 ]); $img->box(filled => 1, color => $blue, box => [ 20, 26, 80, 126 ]); $img->arc(x => 75, y => 75, r => 30, color => $red); $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]); $img; } sub test_image_gray { my $g50 = Imager::Color->new(128, 128, 128); my $g30 = Imager::Color->new(76, 76, 76); my $g70 = Imager::Color->new(178, 178, 178); my $img = Imager->new(xsize => 150, ysize => 150, channels => 1); $img->box(filled => 1, color => $g50, box => [ 70, 24, 130, 124 ]); $img->box(filled => 1, color => $g30, box => [ 20, 26, 80, 126 ]); $img->arc(x => 75, y => 75, r => 30, color => $g70); $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]); return $img; } sub test_image_gray_16 { my $g50 = Imager::Color->new(128, 128, 128); my $g30 = Imager::Color->new(76, 76, 76); my $g70 = Imager::Color->new(178, 178, 178); my $img = Imager->new(xsize => 150, ysize => 150, channels => 1, bits => 16); $img->box(filled => 1, color => $g50, box => [ 70, 24, 130, 124 ]); $img->box(filled => 1, color => $g30, box => [ 20, 26, 80, 126 ]); $img->arc(x => 75, y => 75, r => 30, color => $g70); $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]); return $img; } sub test_image_mono { require Imager::Fill; my $fh = Imager::Fill->new(hatch => 'check1x1'); my $img = Imager->new(xsize => 150, ysize => 150, type => "paletted"); my $black = Imager::Color->new(0, 0, 0); my $white = Imager::Color->new(255, 255, 255); $img->addcolors(colors => [ $black, $white ]); $img->box(fill => $fh, box => [ 70, 24, 130, 124 ]); $img->box(filled => 1, color => $white, box => [ 20, 26, 80, 126 ]); $img->arc(x => 75, y => 75, r => 30, color => $black, aa => 0); return $img; } my %name_to_sub = ( basic => \&test_image, basic16 => \&test_image_16, basic_double => \&test_image_double, gray => \&test_image_gray, gray16 => \&test_image_gray_16, mono => \&test_image_mono, ); sub test_image_named { my $name = shift or croak("No name supplied to test_image_named()"); my $sub = $name_to_sub{$name} or croak("Unknown name $name supplied to test_image_named()"); return $sub->(); } sub _low_image_diff_check { my ($left, $right, $comment) = @_; my $builder = Test::Builder->new; unless (defined $left) { $builder->ok(0, $comment); $builder->diag("left is undef"); return; } unless (defined $right) { $builder->ok(0, $comment); $builder->diag("right is undef"); return; } unless ($left->{IMG}) { $builder->ok(0, $comment); $builder->diag("left image has no low level object"); return; } unless ($right->{IMG}) { $builder->ok(0, $comment); $builder->diag("right image has no low level object"); return; } unless ($left->getwidth == $right->getwidth) { $builder->ok(0, $comment); $builder->diag("left width " . $left->getwidth . " vs right width " . $right->getwidth); return; } unless ($left->getheight == $right->getheight) { $builder->ok(0, $comment); $builder->diag("left height " . $left->getheight . " vs right height " . $right->getheight); return; } unless ($left->getchannels == $right->getchannels) { $builder->ok(0, $comment); $builder->diag("left channels " . $left->getchannels . " vs right channels " . $right->getchannels); return; } return 1; } sub is_image_similar($$$$) { my ($left, $right, $limit, $comment) = @_; { local $Test::Builder::Level = $Test::Builder::Level + 1; _low_image_diff_check($left, $right, $comment) or return; } my $builder = Test::Builder->new; my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG}); if ($diff > $limit) { $builder->ok(0, $comment); $builder->diag("image data difference > $limit - $diff"); if ($limit == 0) { # find the first mismatch PIXELS: for my $y (0 .. $left->getheight()-1) { for my $x (0.. $left->getwidth()-1) { my @lsamples = $left->getsamples(x => $x, y => $y, width => 1); my @rsamples = $right->getsamples(x => $x, y => $y, width => 1); if ("@lsamples" ne "@rsamples") { $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples"); last PIXELS; } } } } return; } return $builder->ok(1, $comment); } sub is_image($$$) { my ($left, $right, $comment) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; return is_image_similar($left, $right, 0, $comment); } sub is_imaged($$$;$) { my $epsilon = Imager::i_img_epsilonf(); if (@_ > 3) { ($epsilon) = splice @_, 2, 1; } my ($left, $right, $comment) = @_; { local $Test::Builder::Level = $Test::Builder::Level + 1; _low_image_diff_check($left, $right, $comment) or return; } my $builder = Test::Builder->new; my $same = Imager::i_img_samef($left->{IMG}, $right->{IMG}, $epsilon, $comment); if (!$same) { $builder->ok(0, $comment); $builder->diag("images different"); # find the first mismatch PIXELS: for my $y (0 .. $left->getheight()-1) { for my $x (0.. $left->getwidth()-1) { my @lsamples = $left->getsamples(x => $x, y => $y, width => 1, type => "float"); my @rsamples = $right->getsamples(x => $x, y => $y, width => 1, type => "float"); if ("@lsamples" ne "@rsamples") { $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples"); last PIXELS; } } } return; } return $builder->ok(1, $comment); } sub isnt_image { my ($left, $right, $comment) = @_; my $builder = Test::Builder->new; my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG}); return $builder->ok($diff, "$comment"); } sub image_bounds_checks { my $im = shift; my $builder = Test::Builder->new; $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0)'); $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0)'); $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1)'); $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10)'); $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0) float'); $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0) float'); $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1) float'); $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10) float'); my $black = Imager::Color->new(0, 0, 0); require Imager::Color::Float; my $blackf = Imager::Color::Float->new(0, 0, 0); $builder->ok($im->setpixel(x => -1, y => 0, color => $black) == 0, 'bounds check set (-1, 0)'); $builder->ok($im->setpixel(x => 10, y => 0, color => $black) == 0, 'bounds check set (10, 0)'); $builder->ok($im->setpixel(x => 0, y => -1, color => $black) == 0, 'bounds check set (0, -1)'); $builder->ok($im->setpixel(x => 0, y => 10, color => $black) == 0, 'bounds check set (0, 10)'); $builder->ok($im->setpixel(x => -1, y => 0, color => $blackf) == 0, 'bounds check set (-1, 0) float'); $builder->ok($im->setpixel(x => 10, y => 0, color => $blackf) == 0, 'bounds check set (10, 0) float'); $builder->ok($im->setpixel(x => 0, y => -1, color => $blackf) == 0, 'bounds check set (0, -1) float'); $builder->ok($im->setpixel(x => 0, y => 10, color => $blackf) == 0, 'bounds check set (0, 10) float'); } sub test_colorf_gpix { my ($im, $x, $y, $expected, $epsilon, $comment) = @_; my $builder = Test::Builder->new; defined $comment or $comment = ''; my $c = Imager::i_gpixf($im, $x, $y); unless ($c) { $builder->ok(0, "$comment - retrieve color at ($x,$y)"); return; } unless ($builder->ok(colorf_cmp($c, $expected, $epsilon) == 0, "$comment - got right color ($x, $y)")) { my @c = $c->rgba; my @exp = $expected->rgba; $builder->diag(<new; defined $comment or $comment = ''; my $c = Imager::i_get_pixel($im, $x, $y); unless ($c) { $builder->ok(0, "$comment - retrieve color at ($x,$y)"); return; } unless ($builder->ok(color_cmp($c, $expected) == 0, "got right color ($x, $y)")) { my @c = $c->rgba; my @exp = $expected->rgba; $builder->diag(<new; my @got = Imager::i_glinf($im, $x, $x+@$pels, $y); @got == @$pels or return $builder->is_num(scalar(@got), scalar(@$pels), "$comment - pixels retrieved"); return $builder->ok(!grep(colorf_cmp($pels->[$_], $got[$_], 0.005), 0..$#got), "$comment - check colors ($x, $y)"); } sub colorf_cmp { my ($c1, $c2, $epsilon) = @_; defined $epsilon or $epsilon = 0; my @s1 = $c1->rgba; my @s2 = $c2->rgba; # print "# (",join(",", @s1[0..2]),") <=> (",join(",", @s2[0..2]),")\n"; return abs($s1[0]-$s2[0]) >= $epsilon && $s1[0] <=> $s2[0] || abs($s1[1]-$s2[1]) >= $epsilon && $s1[1] <=> $s2[1] || abs($s1[2]-$s2[2]) >= $epsilon && $s1[2] <=> $s2[2]; } sub color_cmp { my ($c1, $c2) = @_; my @s1 = $c1->rgba; my @s2 = $c2->rgba; return $s1[0] <=> $s2[0] || $s1[1] <=> $s2[1] || $s1[2] <=> $s2[2]; } # these test the action of the channel mask on the image supplied # which should be an OO image. sub mask_tests { my ($im, $epsilon) = @_; my $builder = Test::Builder->new; defined $epsilon or $epsilon = 0; # we want to check all four of ppix() and plin(), ppix() and plinf() # basic test procedure: # first using default/all 1s mask, set to white # make sure we got white # set mask to skip a channel, set to grey # make sure only the right channels set print "# channel mask tests\n"; # 8-bit color tests my $white = Imager::NC(255, 255, 255); my $grey = Imager::NC(128, 128, 128); my $white_grey = Imager::NC(128, 255, 128); print "# with ppix\n"; $builder->ok($im->setmask(mask=>~0), "set to default mask"); $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$white), "set to white all channels"); test_color_gpix($im->{IMG}, 0, 0, $white, "ppix"); $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1"); $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$grey), "set to grey, no channel 2"); test_color_gpix($im->{IMG}, 0, 0, $white_grey, "ppix masked"); print "# with plin\n"; $builder->ok($im->setmask(mask=>~0), "set to default mask"); $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels => [$white]), "set to white all channels"); test_color_gpix($im->{IMG}, 0, 1, $white, "plin"); $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1"); $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels=>[$grey]), "set to grey, no channel 2"); test_color_gpix($im->{IMG}, 0, 1, $white_grey, "plin masked"); # float color tests my $whitef = Imager::NCF(1.0, 1.0, 1.0); my $greyf = Imager::NCF(0.5, 0.5, 0.5); my $white_greyf = Imager::NCF(0.5, 1.0, 0.5); print "# with ppixf\n"; $builder->ok($im->setmask(mask=>~0), "set to default mask"); $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$whitef), "set to white all channels"); test_colorf_gpix($im->{IMG}, 0, 2, $whitef, $epsilon, "ppixf"); $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1"); $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$greyf), "set to grey, no channel 2"); test_colorf_gpix($im->{IMG}, 0, 2, $white_greyf, $epsilon, "ppixf masked"); print "# with plinf\n"; $builder->ok($im->setmask(mask=>~0), "set to default mask"); $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels => [$whitef]), "set to white all channels"); test_colorf_gpix($im->{IMG}, 0, 3, $whitef, $epsilon, "plinf"); $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1"); $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels=>[$greyf]), "set to grey, no channel 2"); test_colorf_gpix($im->{IMG}, 0, 3, $white_greyf, $epsilon, "plinf masked"); } sub std_font_test_count { return 21; } sub std_font_tests { my ($opts) = @_; my $font = $opts->{font} or carp "Missing font parameter"; my $name_font = $opts->{glyph_name_font} || $font; my $has_chars = $opts->{has_chars} || [ 1, '', 1 ]; my $glyph_names = $opts->{glyph_names} || [ "A", undef, "A" ]; SKIP: { # check magic is handled correctly # https://rt.cpan.org/Ticket/Display.html?id=83438 skip("no native UTF8 support in this version of perl", 11) unless $] >= 5.006; skip("overloading handling of magic is broken in this version of perl", 11) unless $] >= 5.008; Imager->log("utf8 magic tests\n"); my $over = bless {}, "Imager::Test::OverUtf8"; my $text = "A".chr(0x2010)."A"; my $white = Imager::Color->new("#FFF"); my $base_draw = Imager->new(xsize => 80, ysize => 20); ok($base_draw->string(font => $font, text => $text, x => 2, y => 18, size => 15, color => $white, aa => 1), "magic: make a base image"); my $test_draw = Imager->new(xsize => 80, ysize => 20); ok($test_draw->string(font => $font, text => $over, x => 2, y => 18, size => 15, color => $white, aa => 1), "magic: draw with overload"); is_image($base_draw, $test_draw, "check they match"); if ($opts->{files}) { $test_draw->write(file => "testout/utf8tdr.ppm"); $base_draw->write(file => "testout/utf8bdr.ppm"); } my $base_cp = Imager->new(xsize => 80, ysize => 20); $base_cp->box(filled => 1, color => "#808080"); my $test_cp = $base_cp->copy; ok($base_cp->string(font => $font, text => $text, y => 2, y => 18, size => 16, channel => 2, aa => 1), "magic: make a base image (channel)"); Imager->log("magic: draw to channel with overload\n"); ok($test_cp->string(font => $font, text => $over, y => 2, y => 18, size => 16, channel => 2, aa => 1), "magic: draw with overload (channel)"); is_image($test_cp, $base_cp, "check they match"); if ($opts->{files}) { $test_cp->write(file => "testout/utf8tcp.ppm"); $base_cp->write(file => "testout/utf8bcp.ppm"); } SKIP: { Imager->log("magic: has_chars\n"); $font->can("has_chars") or skip "No has_chars aupport", 2; is_deeply([ $font->has_chars(string => $text) ], $has_chars, "magic: has_chars with normal utf8 text"); is_deeply([ $font->has_chars(string => $over) ], $has_chars, "magic: has_chars with magic utf8 text"); } Imager->log("magic: bounding_box\n"); my @base_bb = $font->bounding_box(string => $text, size => 30); is_deeply([ $font->bounding_box(string => $over, size => 30) ], \@base_bb, "check bounding box magic"); SKIP: { $font->can_glyph_names or skip "No glyph_names", 2; Imager->log("magic: glyph_names\n"); my @text_names = $name_font->glyph_names(string => $text, reliable_only => 0); is_deeply(\@text_names, $glyph_names, "magic: glyph_names with normal utf8 text"); my @over_names = $name_font->glyph_names(string => $over, reliable_only => 0); is_deeply(\@over_names, $glyph_names, "magic: glyph_names with magic utf8 text"); } } { # invalid UTF8 handling at the OO level my $im = Imager->new(xsize => 80, ysize => 20); my $bad_utf8 = pack("C", 0xC0); Imager->_set_error(""); ok(!$im->string(font => $font, size => 1, text => $bad_utf8, utf8 => 1, y => 18, x => 2), "drawing invalid utf8 should fail"); is($im->errstr, "invalid UTF8 character", "check error message"); Imager->_set_error(""); ok(!$im->string(font => $font, size => 1, text => $bad_utf8, utf8 => 1, y => 18, x => 2, channel => 1), "drawing invalid utf8 should fail (channel)"); is($im->errstr, "invalid UTF8 character", "check error message"); Imager->_set_error(""); ok(!$font->bounding_box(string => $bad_utf8, size => 30, utf8 => 1), "bounding_box() bad utf8 should fail"); is(Imager->errstr, "invalid UTF8 character", "check error message"); SKIP: { $font->can_glyph_names or skip "No glyph_names support", 2; Imager->_set_error(""); is_deeply([ $font->glyph_names(string => $bad_utf8, utf8 => 1) ], [ ], "glyph_names returns empty list for bad string"); is(Imager->errstr, "invalid UTF8 character", "check error message"); } SKIP: { $font->can("has_chars") or skip "No has_chars support", 2; Imager->_set_error(""); is_deeply([ $font->has_chars(string => $bad_utf8, utf8 => 1) ], [ ], "has_chars returns empty list for bad string"); is(Imager->errstr, "invalid UTF8 character", "check error message"); } } } package Imager::Test::OverUtf8; use overload '""' => sub { "A".chr(0x2010)."A" }; 1; __END__ =head1 NAME Imager::Test - common functions used in testing Imager =head1 SYNOPSIS use Imager::Test 'diff_text_with_nul'; diff_text_with_nul($test_name, $text1, $text2, @string_options); =head1 DESCRIPTION This is a repository of functions used in testing Imager. Some functions will only be useful in testing Imager itself, while others should be useful in testing modules that use Imager. No functions are exported by default. =head1 FUNCTIONS =head2 Test functions =for stopwords OO =over =item is_color1($color, $grey, $comment) Tests if the first channel of $color matches $grey. =item is_color3($color, $red, $green, $blue, $comment) Tests if $color matches the given ($red, $green, $blue) =item is_color4($color, $red, $green, $blue, $alpha, $comment) Tests if $color matches the given ($red, $green, $blue, $alpha) =item is_fcolor1($fcolor, $grey, $comment) =item is_fcolor1($fcolor, $grey, $epsilon, $comment) Tests if $fcolor's first channel is within $epsilon of ($grey). For the first form $epsilon is taken as 0.001. =item is_fcolor3($fcolor, $red, $green, $blue, $comment) =item is_fcolor3($fcolor, $red, $green, $blue, $epsilon, $comment) Tests if $fcolor's channels are within $epsilon of ($red, $green, $blue). For the first form $epsilon is taken as 0.001. =item is_fcolor4($fcolor, $red, $green, $blue, $alpha, $comment) =item is_fcolor4($fcolor, $red, $green, $blue, $alpha, $epsilon, $comment) Tests if $fcolor's channels are within $epsilon of ($red, $green, $blue, $alpha). For the first form $epsilon is taken as 0.001. =item is_image($im1, $im2, $comment) Tests if the 2 images have the same content. Both images must be defined, have the same width, height, channels and the same color in each pixel. The color comparison is done at 8-bits per pixel. The color representation such as direct vs paletted, bits per sample are not checked. Equivalent to is_image_similar($im1, $im2, 0, $comment). =item is_imaged($im, $im2, $comment) =item is_imaged($im, $im2, $epsilon, $comment) Tests if the two images have the same content at the double/sample level. C<$epsilon> defaults to the platform DBL_EPSILON multiplied by four. =item is_image_similar($im1, $im2, $maxdiff, $comment) Tests if the 2 images have similar content. Both images must be defined, have the same width, height and channels. The cum of the squares of the differences of each sample are calculated and must be less than or equal to I<$maxdiff> for the test to pass. The color comparison is done at 8-bits per pixel. The color representation such as direct vs paletted, bits per sample are not checked. =item isnt_image($im1, $im2, $comment) Tests that the two images are different. For regressions tests where something (like text output of "0") produced no change, but should have produced a change. =item test_colorf_gpix($im, $x, $y, $expected, $epsilon, $comment) Retrieves the pixel ($x,$y) from the low-level image $im and compares it to the floating point color $expected, with a tolerance of epsilon. =item test_color_gpix($im, $x, $y, $expected, $comment) Retrieves the pixel ($x,$y) from the low-level image $im and compares it to the floating point color $expected. =item test_colorf_glin($im, $x, $y, $pels, $comment) Retrieves the floating point pixels ($x, $y)-[$x+@$pels, $y] from the low level image $im and compares them against @$pels. =item is_color_close3($color, $red, $green, $blue, $tolerance, $comment) Tests if $color's first three channels are within $tolerance of ($red, $green, $blue). =back =head2 Test suite functions Functions that perform one or more tests, typically used to test various parts of Imager's implementation. =over =item image_bounds_checks($im) Attempts to write to various pixel positions outside the edge of the image to ensure that it fails in those locations. Any new image type should pass these tests. Does 16 separate tests. =item mask_tests($im, $epsilon) Perform a standard set of mask tests on the OO image $im. Does 24 separate tests. =item diff_text_with_nul($test_name, $text1, $text2, @options) Creates 2 test images and writes $text1 to the first image and $text2 to the second image with the string() method. Each call adds 3 C/C to the output of the test script. Extra options that should be supplied include the font and either a color or channel parameter. This was explicitly created for regression tests on #21770. =item std_font_tests({ font => $font }) Perform standard font interface tests. =item std_font_test_count() The number of tests performed by std_font_tests(). =back =head2 Helper functions =over =item test_image_raw() Returns a 150x150x3 Imager::ImgRaw test image. =item test_image() Returns a 150x150x3 8-bit/sample OO test image. Name: C. =item test_image_16() Returns a 150x150x3 16-bit/sample OO test image. Name: C =item test_image_double() Returns a 150x150x3 double/sample OO test image. Name: C. =item test_image_gray() Returns a 150x150 single channel OO test image. Name: C. =item test_image_gray_16() Returns a 150x150 16-bit/sample single channel OO test image. Name: C. =item test_image_mono() Returns a 150x150 bilevel image that passes the is_bilevel() test. Name: C. =item test_image_named($name) Return one of the other test images above based on name. =item color_cmp($c1, $c2) Performs an ordering of 3-channel colors (like <=>). =item colorf_cmp($c1, $c2) Performs an ordering of 3-channel floating point colors (like <=>). =back =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Expr.pm0000644000175000017500000003706412263740601021022 0ustar gregoagregoapackage Imager::Expr; use Imager::Regops; use strict; use vars qw($VERSION); $VERSION = "1.006"; my %expr_types; my $error; sub error { shift if UNIVERSAL::isa($_[0], 'Imager::Expr'); if (@_) { $error = "@_"; } else { return $error; } } # what else? my %default_constants = ( # too many digits, better than too few pi=>3.14159265358979323846264338327950288419716939937510582097494 ); sub new { my ($class, $opts) = @_; # possibly this is a very bad idea my ($type) = grep exists $expr_types{$_}, keys %$opts; die "Imager::Expr: No known expression type" if !defined $type; my $self = bless {}, $expr_types{$type}; $self->{variables} = [ @{$opts->{variables}} ]; $self->{constants} = { %default_constants, %{$opts->{constants} || {}} }; $self->{ops} = $self->compile($opts->{$type}, $opts) or return; $self->optimize() or return; $self->{code} = $self->assemble() or return; $self; } sub register_type { my ($pack, $name) = @_; $expr_types{$name} = $pack; } sub type_registered { my ($class, $name) = @_; $expr_types{$name}; } sub _variables { return @{$_[0]->{variables}}; } sub code { return $_[0]->{code}; } sub nregs { return $_[0]->{nregs}; } sub cregs { return $_[0]->{cregs}; } my $numre = '[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?'; sub numre { $numre; } # optimize the code sub optimize { my ($self) = @_; my @ops = @{$self->{ops}}; # this function cannot current handle code with jumps return 1 if grep $_->[0] =~ /^jump/, @ops; # optimization - common sub-expression elimination # it's possible to fold this into the code generation - but it will wait my $max_opr = $Imager::Regops::MaxOperands; my $attr = \%Imager::Regops::Attr; my $foundops = 1; while ($foundops) { $foundops = 0; my %seen; my $index; my @out; while (@ops) { my $op = shift @ops; my $desc = join(",", @{$op}[0..$max_opr]); if ($seen{$desc}) { push(@out, @ops); my $old = $op->[-1]; my $new = $seen{$desc}; for $op (@out) { for my $reg (@{$op}[1..$max_opr]) { $reg = $new if $reg eq $old; } } $foundops=1; last; } $seen{$desc} = $op->[-1]; push(@out, $op); } @ops = @out; } # strength reduction for my $op (@ops) { # reduce division by a constant to multiplication by a constant if ($op->[0] eq 'div' && $op->[2] =~ /^r(\d+)/ && defined($self->{"nregs"}[$1])) { my $newreg = @{$self->{"nregs"}}; push(@{$self->{"nregs"}}, 1.0/$self->{"nregs"}[$1]); $op->[0] = 'mult'; $op->[2] = 'r'.$newreg; } } $self->{ops} = \@ops; 1; } sub assemble { my ($self) = @_; my $attr = \%Imager::Regops::Attr; my $max_opr = $Imager::Regops::MaxOperands; my @ops = @{$self->{ops}}; for my $op (@ops) { $op->[0] = $attr->{$op->[0]}{opcode}; for (@{$op}[1..$max_opr+1]) { s/^[rpj]// } } my $pack = $Imager::Regops::PackCode x (2+$Imager::Regops::MaxOperands); return join("", ,map { pack($pack, @$_, ) } @ops); } # converts stack code to register code sub stack_to_reg { my ($self, @st_ops) = @_; my @regstack; my %nregs; my @vars = $self->_variables(); my @nregs = (0) x scalar(@vars); my @cregs; my $attr = \%Imager::Regops::Attr; my %vars; my %names; my $max_opr = $Imager::Regops::MaxOperands; @vars{@vars} = map { "r$_" } 0..$#vars; my @ops; for (@st_ops) { if (/^$numre$/) { # combining constants makes the optimization below work if (exists $nregs{$_}) { push(@regstack, $nregs{$_}); } else { $nregs{$_} = "r".@nregs; push(@regstack,"r".@nregs); push(@nregs, $_); } } elsif (exists $vars{$_}) { push(@regstack, $vars{$_}); } elsif (exists $attr->{$_} && length $attr->{$_}{types}) { if (@regstack < $attr->{$_}{parms}) { error("Imager::transform2: stack underflow on $_"); return; } my @parms = splice(@regstack, -$attr->{$_}{parms}); my $types = join("", map {substr($_,0,1)} @parms); if ($types ne $attr->{$_}{types}) { if (exists $attr->{$_.'p'} && $types eq $attr->{$_.'p'}{types}) { $_ .= 'p'; } else { error("Imager::transform2: Call to $_ with incorrect types"); return; } } my $result; if ($attr->{$_}{result} eq 'r') { $result = "r".@nregs; push(@nregs, undef); } else { $result = "p".@cregs; push(@cregs, -1); } push(@regstack, $result); push(@parms, "0") while @parms < $max_opr; push(@ops, [ $_, @parms, $result ]); #print "$result <- $_ @parms\n"; } elsif (/^!(\w+)$/) { if (!@regstack) { error("Imager::transform2: stack underflow with $_"); return; } $names{$1} = pop(@regstack); } elsif (/^\@(\w+)$/) { if (exists $names{$1}) { push(@regstack, $names{$1}); } else { error("Imager::Expr: unknown storage \@$1"); return; } } else { error("Imager::Expr: unknown operator $_"); return; } } if (@regstack != 1) { error("stack must have only one item at end"); return; } if ($regstack[0] !~ /^p/) { error("you must have a color value at the top of the stack at end"); return; } push(@ops, [ "ret", $regstack[0], (-1) x $max_opr ]); $self->{"nregs"} = \@nregs; $self->{"cregs"} = \@cregs; return \@ops; } sub dumpops { my $result = ''; for my $op (@{$_[0]->{ops}}) { $result .= "@{$op}\n"; } $result; } # unassembles the compiled code sub dumpcode { my ($self) = @_; my $code = $self->{"code"}; my $attr = \%Imager::Regops::Attr; my @code = unpack("${Imager::Regops::PackCode}*", $code); my %names = map { $attr->{$_}{opcode}, $_ } keys %Imager::Regops::Attr; my @vars = $self->_variables(); my $result = ''; my $index = 0; while (my @op = splice(@code, 0, 2+$Imager::Regops::MaxOperands)) { my $opcode = shift @op; my $name = $names{$opcode}; if ($name) { $result .= "j$index: $name($opcode)"; my @types = split //, $attr->{$name}{types}; for my $parm (@types) { my $reg = shift @op; $result .= " $parm$reg"; if ($parm eq 'r') { if ($reg < @vars) { $result.= "($vars[$reg])"; } elsif (defined $self->{"nregs"}[$reg]) { $result .= "($self->{\"nregs\"}[$reg])"; } } } $result .= " -> $attr->{$name}{result}$op[-1]" if $attr->{$name}{result}; $result .= "\n"; } else { $result .= "unknown($opcode) @op\n"; } ++$index; } $result; } package Imager::Expr::Postfix; use vars qw(@ISA); @ISA = qw(Imager::Expr); Imager::Expr::Postfix->register_type('rpnexpr'); my %op_names = ( '+'=>'add', '-'=>'subtract', '*'=>'mult', '/' => 'div', '%'=>'mod', '**'=>'pow' ); sub compile { my ($self, $expr, $opts) = @_; $expr =~ s/#.*//; # remove comments my @st_ops = split ' ', $expr; for (@st_ops) { $_ = $op_names{$_} if exists $op_names{$_}; $_ = $self->{constants}{$_} if exists $self->{constants}{$_}; } return $self->stack_to_reg(@st_ops); } package Imager::Expr::Infix; use vars qw(@ISA); @ISA = qw(Imager::Expr); use Imager::Regops qw(%Attr $MaxOperands); eval "use Parse::RecDescent;"; __PACKAGE__->register_type('expr') if !$@; # I really prefer bottom-up parsers my $grammar = <<'GRAMMAR'; code : assigns 'return' expr { $return = [ @item[1,3] ] } assigns : assign(s?) { $return = [ @{$item[1]} ] } assign : identifier '=' expr ';' { $return = [ @item[1,3] ] } expr : relation relation : addition (relstuff)(s?) { $return = $item[1]; for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] } 1; } relstuff : relop addition { $return = [ @item[1,2] ] } relop : '<=' { $return = 'le' } | '<' { $return = 'lt' } | '==' { $return = 'eq' } | '>=' { $return = 'ge' } | '>' { $return = 'gt' } | '!=' { $return = 'ne' } addition : multiply (addstuff)(s?) { $return = $item[1]; # for my $op(@{$item[2]}) { $return .= " @{$op}[1,0]"; } for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] } 1; } addstuff : addop multiply { $return = [ @item[1,2] ] } addop : '+' { $return = 'add' } | '-' { $return = 'subtract' } multiply : power mulstuff(s?) { $return = $item[1]; # for my $op(@{$item[2]}) { $return .= " @{$op}[1,0]"; } for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] } 1; } mulstuff : mulop power { $return = [ @item[1,2] ] } mulop : '*' { $return = 'mult' } | '/' { $return = 'div' } | '%' { $return = 'mod' } power : powstuff(s?) atom { $return = $item[2]; for my $op(reverse @{$item[1]}) { $return = [ @{$op}[1,0], $return ] } 1; } | atom powstuff : atom powop { $return = [ @item[1,2] ] } powop : '**' { $return = 'pow' } atom: '(' expr ')' { $return = $item[2] } | '-' atom { $return = [ uminus=>$item[2] ] } | number | funccall | identifier number : /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/ exprlist : expr ',' exprlist { $return = [ $item[1], @{$item[3]} ] } | expr { $return = [ $item[1] ] } funccall : identifier '(' exprlist ')' { $return = [ $item[1], @{$item[3]} ] } identifier : /[^\W\d]\w*/ { $return = $item[1] } GRAMMAR my $parser; sub init_parser { if (!$parser) { $parser = Parse::RecDescent->new($grammar); } } sub compile { my ($self, $expr, $opts) = @_; if (!$parser) { $parser = Parse::RecDescent->new($grammar); } my $optree = $parser->code($expr); if (!$optree) { $self->error("Error in $expr\n"); return; } @{$self->{inputs}}{$self->_variables} = (); $self->{varregs} = {}; @{$self->{varregs}}{$self->_variables} = map { "r$_" } 0..$self->_variables-1; $self->{"nregs"} = [ (undef) x $self->_variables ]; $self->{"cregs"} = []; $self->{"lits"} = {}; eval { # generate code for the assignments for my $assign (@{$optree->[0]}) { my ($varname, $tree) = @$assign; if (exists $self->{inputs}{$varname}) { $self->error("$varname is an input - you can't assign to it"); return; } $self->{varregs}{$varname} = $self->gencode($tree); } # generate the final result my $result = $self->gencode($optree->[1]); if ($result !~ /^p\d+$/) { $self->error("You must return a color value"); return; } push(@{$self->{genops}}, [ 'ret', $result, (0) x $MaxOperands ]) }; if ($@) { $self->error($@); return; } return $self->{genops}; } sub gencode { my ($self, $tree) = @_; if (ref $tree) { my ($op, @parms) = @$tree; if (!exists $Attr{$op}) { die "Unknown operator or function $op"; } for my $subtree (@parms) { $subtree = $self->gencode($subtree); } my $types = join("", map {substr($_,0,1)} @parms); if (length($types) < length($Attr{$op}{types})) { die "Too few parameters in call to $op"; } if ($types ne $Attr{$op}{types}) { # some alternate operators have the same name followed by p my $opp = $op."p"; if (exists $Attr{$opp} && $types eq $Attr{$opp}{types}) { $op = $opp; } else { die "Call to $_ with incorrect types"; } } my $result; if ($Attr{$op}{result} eq 'r') { $result = "r".@{$self->{nregs}}; push(@{$self->{nregs}}, undef); } else { $result = "p".@{$self->{cregs}}; push(@{$self->{cregs}}, undef); } push(@parms, "0") while @parms < $MaxOperands; push(@{$self->{genops}}, [ $op, @parms, $result]); return $result; } elsif (exists $self->{varregs}{$tree}) { return $self->{varregs}{$tree}; } elsif ($tree =~ /^$numre$/ || exists $self->{constants}{$tree}) { $tree = $self->{constants}{$tree} if exists $self->{constants}{$tree}; if (exists $self->{lits}{$tree}) { return $self->{lits}{$tree}; } my $reg = "r".@{$self->{nregs}}; push(@{$self->{nregs}}, $tree); $self->{lits}{$tree} = $reg; return $reg; } } 1; __END__ =head1 NAME Imager::Expr - implements expression parsing and compilation for the expression evaluation engine used by Imager::transform2() =head1 SYNOPSIS my $code = Imager::Expr->new({rpnexpr=>$someexpr}) or die "Cannot compile $someexpr: ",Imager::Expr::error(); =head1 DESCRIPTION This module is used internally by the Imager::transform2() function. You shouldn't have much need to use it directly, but you may want to extend it. To create a new Imager::Expr object, call: my %options; my $expr = Imager::Expr->new(\%options) or die Imager::Expr::error(); You will need to set an expression value and you may set any of the following: =over =item * constants A hashref defining extra constants for expression parsing. The names of the constants must be valid identifiers (/[^\W\d]\w*/) and the values must be valid numeric constants (that Perl recognizes in scalars). Imager::Expr may define it's own constants (currently just pi.) =item * variables A reference to an array of variable names. These are allocated numeric registers starting from register zero. =back =for stopwords RPN By default you can define a C key (which emulates RPN) or C (an infix expression). It's also possible to write other expression parsers that will use other keys. Only one expression key should be defined. =head2 Instance methods The Imager::Expr::error() method is used to retrieve the error if the expression object cannot be created. =head2 Methods Imager::Expr provides only a few simple methods meant for external use: =for stopwords VM =over =item Imager::Expr->type_registered($keyword) Returns true if the given expression type is available. The parameter is the key supplied to the new() method. if (Imager::Expr->type_registered('expr')) { # use infix expressions } =item $expr->code() Returns the compiled code. =item $expr->nregs() Returns a reference to the array of numeric registers. =item $expr->cregs() Returns a reference to the array of color registers. =item $expr->dumpops() Returns a string with the generated VM "machine code". =item $expr->dumpcode() Returns a string with the disassembled VM "machine code". =back =head2 Creating a new parser I'll write this one day. Methods used by parsers: =over =item compile This is the main method you'll need to implement in a parser. See the existing parsers for a guide. It's supplied the following parameters: =over =item * $expr - the expression to be parsed =item * $options - the options hash supplied to transform2. =back Return an array ref of array refs containing opcodes and operands. =item @vars = $self->_variables() A list (not a reference) of the input variables. This should be used to allocate as many registers as there are variable as input registers. =item $self->error($message) Set the return value of Imager::Expr::error() =item @ops = $self->stack_to_reg(@stack_ops) Converts marginally parsed RPN to register code. =item assemble() Called to convert op codes into byte code. =item numre() Returns a regular expression that matches floating point numbers. =item optimize() Optimizes the assembly code, including attempting common subexpression elimination and strength reducing division by a constant into multiplication by a constant. =item register_type() Called by a new expression parser implementation to register itself, call as: YourClassName->register_type('type code'); where type code is the parameter that will accept the expression. =back =head2 Future compatibility Try to avoid doing your own optimization beyond literal folding - if we add some sort of jump, the existing optimizer will need to be rewritten, and any optimization you perform may well be broken too (well, your code generation will probably be broken anyway ). =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Draw.pod0000644000175000017500000011012712614520110021126 0ustar gregoagregoa=head1 NAME Imager::Draw - Draw primitives to images =head1 SYNOPSIS use Imager; use Imager::Fill; $img = ...; $blue = Imager::Color->new( 0, 0, 255 ); $fill = Imager::Fill->new(hatch=>'stipple'); $img->line(color=>$blue, x1=>10, x2=>100, y1=>20, y2=>50, aa=>1, endp=>1 ); $img->polyline(points=>[[$x0,$y0], [$x1,$y1], [$x2,$y2]], color=>$blue); $img->polyline(x=>[$x0,$x1,$x2], y=>[$y0,$y1,$y2], aa=>1); $img->box(color=> $blue, xmin=> 10, ymin=>30, xmax=>200, ymax=>300, filled=>1); $img->box(fill=>$fill); $img->arc(color=>$blue, r=>20, x=>200, y=>100, d1=>10, d2=>20 ); $img->circle(color=>$blue, r=>50, x=>200, y=>100); $img->polygon(points=>[[$x0,$y0], [$x1,$y1], [$x2,$y2]], color=>$blue); $img->polygon(x=>[$x0,$x1,$x2], y=>[$y0,$y1,$y2]); $img->flood_fill(x=>50, y=>50, color=>$color); $img->setpixel(x=>50, y=>70, color=>$color); $img->setpixel(x=>[ 50, 60, 70 ], y=>[20, 30, 40], color=>$color); my $color = $img->getpixel(x=>50, y=>70); my @colors = $img->getpixel(x=>[ 50, 60, 70 ], y=>[20, 30, 40]); # drawing text my $font = Imager::Font->new(...) or die; $img->string(x => 50, y => 70, font => $font, string => "Hello, World!", color => 'red', size => 30, aa => 1); # bottom right-hand corner of the image $img->align_string(x => $img->getwidth() - 1, y => $img->getheight() - 1, halign => 'right', valign => 'bottom', string => 'Imager', font => $font, size => 12); # low-level functions my @colors = $img->getscanline(y=>50, x=>10, width=>20); $img->setscanline(y=>60, x=>20, pixels=>\@colors); my @samples = $img->getsamples(y=>50, x=>10, width=>20, channels=>[ 2, 0 ]); =head1 DESCRIPTION It is possible to draw with graphics primitives onto images. Such primitives include boxes, arcs, circles, polygons and lines. The coordinate system in Imager has the origin C<(0,0)> in the upper left corner of an image with co-ordinates increasing to the right and bottom. For non anti-aliasing operation all coordinates are rounded towards the nearest integer. For anti-aliased operations floating point coordinates are used. Drawing is assumed to take place in a coordinate system of infinite resolution. This is the typical convention and really only matters when it is necessary to check for off-by-one cases. Typically it's useful to think of C<(10, 20)> as C<(10.00, 20.00)> and consider the consequences. =head2 Color Parameters XThe C parameter for any of the drawing methods can be an L object, a simple scalar that Imager::Color can understand, a hashref of parameters that Imager::Color->new understands, or an arrayref of red, green, blue values, for example: $image->box(..., color=>'red'); $image->line(..., color=>'#FF0000'); $image->flood_fill(..., color=>[ 255, 0, 255 ]); While supplying colors as names, array references or CSS color specifiers is convenient, for maximum performance you should supply the color as an L object: my @colors = map Imager::Color->new($_), qw/red green blue/ for my $i (1..1000) { $image->box(..., color => $colors[rand @colors]); } =head2 Fill Parameters XAll filled primitives, i.e. C, C, C, C and the C method can take a C parameter instead of a C parameter which can either be an Imager::Fill object, or a reference to a hash containing the parameters used to create the fill, for example: $image->box(..., fill=>{ hatch => 'check1x1' }); my $fillimage = Imager->new; $fillimage->read(file=>$somefile) or die; $image->flood_fill(..., fill=>{ image=>$fillimage }); Currently you can create opaque or transparent plain color fills, hatched fills, image based fills and fountain fills. See L for more information. =head2 Polygon Fill Modes When filling a polygon that overlaps itself, or when filling several polygons with polypolygon() that overlap each other, you can supply a C parameter that controls how the overlap is resolved. This can have one of two possible values: =over =item * C - if areas overlap an odd number of times, they are filled, and are otherwise unfilled. This is the default and the historical Imager polygon fill mode. =item * C - areas that have an unbalanced clockwise and anti-clockwise boundary are filled. This is the same as C for X and C for Win32 GDI. =back C allows polygons to overlap, either with itself, or with another polygon in the same polypolygon() call, without producing unfilled area in the overlap, and also allows areas to be cut out of the area by specifying the points making up a cut-out in the opposite order. =head2 List of primitives =over =item line() $img->line(color=>$green, x1=>10, x2=>100, y1=>20, y2=>50, aa=>1, endp=>1 ); XDraws a line from (x1,y1) to (x2,y2). The endpoint (x2,y2) is drawn by default. If C of 0 is specified then the endpoint will not be drawn. If C is set then the line will be drawn anti-aliased. The C parameter is still available for backwards compatibility. Parameters: =over =item * C, C - starting point of the line. Required. =item * C, C - end point of the line. Required. =item * C - the color of the line. See L. Default: black. =item * C - if zero the end point of the line is not drawn. Default: 1 - the end point is drawn. This is useful to set to 0 when drawing a series of connected lines. =item * C - if true the line is drawn anti-aliased. Default: 0. =back =item polyline() $img->polyline(points=>[[$x0,$y0],[$x1,$y1],[$x2,$y2]],color=>$red); $img->polyline(x=>[$x0,$x1,$x2], y=>[$y0,$y1,$y2], aa=>1); XC is used to draw multiple lines between a series of points. The point set can either be specified as an arrayref to an array of array references (where each such array represents a point). The other way is to specify two array references. The C parameter is still available for backwards compatibility. =over =item * points - a reference to an array of references to arrays containing the co-ordinates of the points in the line, for example: my @points = ( [ 0, 0 ], [ 100, 0 ], [ 100, 100 ], [ 0, 100 ] ); $img->polyline(points => \@points); =item * x, y - each is an array of x or y ordinates. This is an alternative to supplying the C parameter. # same as the above points example my @x = ( 0, 100, 100, 0 ); my @y = ( 0, 0, 100, 100 ); $img->polyline(x => \@x, y => \@y); =item * C - the color of the line. See L. Default: black. =item * C - if true the line is drawn anti-aliased. Default: 0. Can also be supplied as C for backward compatibility. =back =item box() $blue = Imager::Color->new( 0, 0, 255 ); $img->box(color => $blue, xmin=>10, ymin=>30, xmax=>200, ymax=>300, filled=>1); XIf any of the edges of the box are omitted it will snap to the outer edge of the image in that direction. If C is omitted the box is drawn as an outline. Instead of a color it is possible to use a C pattern: $fill = Imager::Fill->new(hatch=>'stipple'); $img->box(fill=>$fill); # fill entire image with a given fill pattern $img->box(xmin=>10, ymin=>30, xmax=>150, ymax=>60, fill => { hatch=>'cross2' }); Also if a color is omitted a color with (255,255,255,255) is used instead. [NOTE: This may change to use C<$img-Efgcolor()> in the future]. Box does not support fractional coordinates yet. Parameters: =over =item * C - left side of the box. Default: 0 (left edge of the image) =item * C - top side of the box. Default: 0 (top edge of the image) =item * C - right side of the box. Default: C<< $img->getwidth-1 >>. (right edge of the image) =item * C - bottom side of the box. Default: C<< $img->getheight-1 >>. (bottom edge of the image) Note: C and C are I - the number of pixels drawn for a filled box is C<(xmax-xmin+1) * (ymax-ymin+1)>. =item * C - a reference to an array of (left, top, right, bottom) co-ordinates. This is an alternative to supplying C, C, C, C and overrides their values. =item * C - the color of the line. See L. Default: white. This is ignored if the filled parameter =item * C - if non-zero the box is filled with I instead of outlined. Default: an outline is drawn. =item * C - the fill for the box. If this is supplied then the box will be filled. See L. =back =item arc() $img->arc(color=>$red, r=>20, x=>200, y=>100, d1=>10, d2=>20 ); This creates a filled red arc with a 'center' at (200, 100) and spans 10 degrees and the slice has a radius of 20. It's also possible to supply a C parameter. To draw just an arc outline - just the curve, not the radius lines, set filled to 0: Parameters: $img->arc(color=>$red, r=>20, x=>200, y=>100, d1=>10, d2=>20, filled=>0 ); =over =item * C, C - center of the filled arc. Default: center of the image. =item * C - radius of the arc. Default: 1/3 of min(image height, image width). =item * C - starting angle of the arc, in degrees. Default: 0 =item * C - ending angle of the arc, in degrees. Default: 361. =item * C - the color of the filled arc. See L. Default: white. Overridden by C. =item * C - the fill for the filled arc. See L =item * C - if true the filled arc is drawn anti-aliased. Default: false. Anti-aliased arc() is experimental for now, I'm not entirely happy with the results in some cases. =item * C - set to 0 to draw only an outline. =back # arc going through angle zero: $img->arc(d1=>320, d2=>40, x=>100, y=>100, r=>50, color=>'blue'); # complex fill arc $img->arc(d1=>135, d2=>45, x=>100, y=>150, r=>50, fill=>{ solid=>'red', combine=>'diff' }); # draw an anti-aliased circle outline $img->arc(x => 100, y => 150, r => 150, filled => 0, color => '#F00', aa => 1); # draw an anti-aliased arc $img->arc(x => 100, y => 150, r => 90, filled => 0, color => '#0f0', aa => 1, d1 => 90, d2 => 180); =item circle() $img->circle(color=>$green, r=>50, x=>200, y=>100, aa=>1, filled=>1); This creates an anti-aliased green circle with its center at (200, 100) and has a radius of 50. It's also possible to supply a C parameter instead of a color parameter. $img->circle(r => 50, x=> 150, y => 150, fill=>{ hatch => 'stipple' }); To draw a circular outline, set C to 0: $img->circle(color=>$green, r=>50, x=>200, y=>100, aa=>1, filled=>0); =over =item * C, C - center of the filled circle. Default: center of the image. =item * C - radius of the circle. Default: 1/3 of min(image height, image width). =item * C - the color of the filled circle. See L. Default: white. Overridden by C. =item * C - the fill for the filled circle. See L =item * C - if true the filled circle is drawn anti-aliased. Default: false. =item * C - set to 0 to just draw an outline. =back =item polygon() $img->polygon(points=>[[$x0,$y0],[$x1,$y1],[$x2,$y2]],color=>$red); $img->polygon(x=>[$x0,$x1,$x2], y=>[$y0,$y1,$y2], fill=>$fill); Polygon is used to draw a filled polygon. Currently the polygon is always drawn anti-aliased, although that will change in the future. Like other anti-aliased drawing functions its coordinates can be specified with floating point values. As with other filled shapes it's possible to use a C instead of a color. =over =item * C - a reference to an array of references to arrays containing the co-ordinates of the points in the line, for example: my @points = ( [ 0, 0 ], [ 100, 0 ], [ 100, 100 ], [ 0, 100 ] ); $img->polygon(points => \@points); =item * C, C - each is an array of x or y ordinates. This is an alternative to supplying the C parameter. # same as the above points example my @x = ( 0, 100, 100, 0 ); my @y = ( 0, 0, 100, 100 ); $img->polygon(x => \@x, y => \@y); =item * C - the color of the filled polygon. See L. Default: black. Overridden by C. =item * C - the fill for the filled circle. See L =item * C - fill mode for the polygon. See L =back Note: the points specified are as offsets from the top-left of the image, I as pixel locations. This means that: $img->polygon(points => [ [ 0, 0 ], [ 1, 0 ], [ 1, 1 ], [ 0, 1 ] ]); fills only a single pixel at C<(0, 0)>, not four. =item polypolygon() XX $img->polypolygon(points => $points, color => $color); Draw multiple polygons, either filled or unfilled. =over =item * C - is an array reference containing polygon definitions, each polygon definition is a reference to an array containing two arrays, one each for the C and C co-ordinates. =item * C - if true, fill the polygons with the color defined by C. =item * C - the color to draw the polygons with if C is not supplied. =item * C - fill the polygons with this fill if supplied. =item * C - fill mode for the polygon. See L =back Note: the points specified are as offsets from the top-left of the image, I as pixel locations. This means that: $img->polypolygon(points => [ [ [ 0, 1, 1, 0 ], [ 0, 0, 1, 1 ] ] ], filled => 1); fills only a single pixel at C<(0, 0)>, not four. =item flood_fill() XYou can fill a region that all has the same color using the flood_fill() method, for example: $img->flood_fill(x=>50, y=>50, color=>$color); will fill all regions the same color connected to the point (50, 50). Alternatively you can fill a region limited by a given border color: # stop at the red border $im->flood_fill(x=>50, y=>50, color=>$color, border=>"red"); You can also fill with a complex fill: $img->flood_fill(x=>50, y=>50, fill=>{ hatch=>'cross1x1' }); Parameters: =over =item * C, C - the start point of the fill. =item * C - the color of the filled area. See L. Default: white. Overridden by C. =item * C - the fill for the filled area. See L =item * C - the border color of the region to be filled. If this parameter is supplied flood_fill() will stop when it finds this color. If this is not supplied then a normal fill is done. C can be supplied as a L. =back =item setpixel() $img->setpixel(x=>50, y=>70, color=>$color); $img->setpixel(x=>[ 50, 60, 70 ], y=>[20, 30, 40], color=>$color); setpixel() is used to set one or more individual pixels. You can supply a single set of co-ordinates as scalar C and C parameters, or set either to an arrayref of ordinates. If one array is shorter than another the final value in the shorter will be duplicated until they match in length. If only one of C or C is an array reference then setpixel() will behave as if the non-reference value were an array reference containing only that value. eg. my $count = $img->setpixel(x => 1, y => [ 0 .. 3 ], color => $color); behaves like: my $count = $img->setpixel(x => [ 1 ], y => [ 0 .. 3 ], color => $color); and since the final element in the shorter array is duplicated, this behaves like: my $count = $img->setpixel(x => [ 1, 1, 1, 1 ], y => [ 0 .. 3 ], color => $color); Parameters: =over =item * x, y - either integers giving the co-ordinates of the pixel to set or array references containing a set of pixels to be set. =item * color - the color of the pixels drawn. See L. Default: white. =back Returns the number of pixels drawn, if no pixels were drawn, but none of the errors below occur, returns C<"0 but true">. For other errors, setpixel() returns an empty list and sets errstr(). Possible errors conditions include: =over =item * the image supplied is empty =item * a reference to an empty array was supplied for C or C =item * C or C wasn't supplied =item * C isn't a valid color, and can't be converted to a color. =back =item getpixel() my $color = $img->getpixel(x=>50, y=>70); my @colors = $img->getpixel(x=>[ 50, 60, 70 ], y=>[20, 30, 40]); my $colors_ref = $img->getpixel(x=>[ 50, 60, 70 ], y=>[20, 30, 40]); getpixel() is used to retrieve one or more individual pixels. You can supply a single set of co-ordinates as scalar C and C parameters, or set each to an arrayref of ordinates. If one array is shorter than another the final value in the shorter will be duplicated until they match in length. If only one of C or C is an array reference then getpixel() will behave as if the non-reference value were an array reference containing only that value. eg. my @colors = $img->getpixel(x => 0, y => [ 0 .. 3 ]); behaves like: my @colors = $img->getpixel(x => [ 0 ], y => [ 0 .. 3 ]); and since the final element in the shorter array is duplicated, this behaves like: my @colors = $img->getpixel(x => [ 0, 0, 0, 0 ], y => [ 0 .. 3 ]); To receive floating point colors from getpixel(), set the C parameter to 'float'. Parameters: =over =item * C, C - either integers giving the co-ordinates of the pixel to set or array references containing a set of pixels to be set. =item * C - the type of color object to return, either C<'8bit'> for L objects or C<'float'> for L objects. Default: C<'8bit'>. =back When called with an array reference for either or C or C, getpixel() will return a list of colors in list context, and an arrayref in scalar context. If a supplied co-ordinate is outside the image then C is returned for the pixel. Each color is returned as an L object or as an L object if C is set to C<"float">. Possible errors conditions include: =over =item * the image supplied is empty =item * a reference to an empty array was supplied for C or C =item * C or C wasn't supplied =item * C isn't a valid value. =back For any of these errors getpixel() returns an empty list. =item string() my $font = Imager::Font->new(file=>"foo.ttf"); $img->string(x => 50, y => 70, string => "Hello, World!", font => $font, size => 30, aa => 1, color => 'white'); Draws text on the image. Parameters: =over =item * C, C - the point to draw the text from. If C is 0 this is the top left of the string. If C is 1 (the default) then this is the left of the string on the baseline. Required. =item * C - the text to draw. Required unless you supply the C parameter. =item * C - an L object representing the font to draw the text with. Required. =item * C - if non-zero the output will be anti-aliased. Default: the value set in Imager::Font->new() or 0 if not set. =item * C - if non-zero the point supplied in (x,y) will be on the base-line, if zero then (x,y) will be at the top-left of the string. i.e. if drawing the string C<"yA"> and align is 0 the point (x,y) will aligned with the top of the A. If align is 1 (the default) it will be aligned with the baseline of the font, typically bottom of the A, depending on the font used. Default: the value set in Imager::Font->new, or 1 if not set. =item * C - if present, the text will be written to the specified channel of the image and the color parameter will be ignore. =item * C - the color to draw the text in. Default: the color supplied to Imager::Font->new, or red if none. =item * C - the point size to draw the text at. Default: the size supplied to Imager::Font->new, or 15. =item * C - the width scaling to draw the text at. Default: the value of C. =item * C - for drivers that support it, treat the string as UTF-8 encoded. For versions of perl that support Unicode (5.6 and later), this will be enabled automatically if the C parameter is already a UTF-8 string. See L for more information. =item * C - for drivers that support it, draw the text vertically. Note: I haven't found a font that has the appropriate metrics yet. =item * C - alias for the C parameter. =back On error, string() returns false and you can use $img->errstr to get the reason for the error. =item align_string() Draws text aligned around a point on the image. # "Hello" centered at 100, 100 in the image. my ($left, $top, $right, $bottom) = $img->align_string(string=>"Hello", x=>100, y=>100, halign=>'center', valign=>'center', font=>$font); Parameters: =over =item * C, C - the point to draw the text from. If C is 0 this is the top left of the string. If C is 1 (the default) then this is the left of the string on the baseline. Required. =item * C - the text to draw. Required unless you supply the C parameter. =item * C - an L object representing the font to draw the text with. Required. =item * C - if non-zero the output will be anti-aliased =item * C - vertical alignment of the text against (x,y) =over =item * C - Point is at the top of the text. =item * C - Point is at the bottom of the text. =item * C - Point is on the baseline of the text. This is the default. =item * C
- Point is vertically centered within the text. =back =item * C - horizontal alignment of the text against (x,y) =over =item * C - The point is at the left of the text. This is the default. =item * C - The point is at the start point of the text. =item * C
- The point is horizontally centered within the text. =item * C - The point is at the right end of the text. =item * C - The point is at the end point of the text. =back =item * C - if present, the text will be written to the specified channel of the image and the color parameter will be ignore. =item * C - the color to draw the text in. Default: the color supplied to Imager::Font->new, or red if none. =item * C - the point size to draw the text at. Default: the size supplied to Imager::Font->new, or 15. =item * C - the width scaling to draw the text at. Default: the value of C. =item * C - for drivers that support it, treat the string as UTF-8 encoded. For versions of perl that support Unicode (5.6 and later), this will be enabled automatically if the C parameter is already a UTF-8 string. See L for more information. =item * C - for drivers that support it, draw the text vertically. Note: I haven't found a font that has the appropriate metrics yet. =item * C - alias for the C parameter. =back On success returns a list of bounds of the drawn text, in the order left, top, right, bottom. On error, align_string() returns an empty list and you can use C<< $img->errstr >> to get the reason for the error. =item setscanline() Set all or part of a horizontal line of pixels to an image. This method is most useful in conjunction with L. The parameters you can pass are: =over =item * C - vertical position of the scan line. This parameter is required. =item * C - position to start on the scan line. Default: 0 =item * C - either a reference to an array containing Imager::Color objects, an reference to an array containing Imager::Color::Float objects or a scalar containing packed color data. If C is C then this can either be a reference to an array of palette color indexes or a scalar containing packed indexes. See L for information on the format of packed color data. =item * C - the type of pixel data supplied. If you supply an array reference then this is determined automatically. If you supply packed color data this defaults to C<'8bit'>, if your data is packed floating point color data then you need to set this to C<'float'>. You can use C or C<8bit> samples with any image. If this is C then C should be either an array of palette color indexes or a packed string of color indexes. =back Returns the number of pixels set. Each of the following sets 5 pixels from (5, 10) through (9, 10) to blue, red, blue, red, blue: my $red_color = Imager::Color->new(255, 0, 0); my $blue_color = Imager::Color->new(0, 0, 255); $image->setscanline(y=>10, x=>5, pixels=> [ ($blue_color, $red_color) x 2, $blue_color ]); # use floating point color instead, for 16-bit plus images my $red_colorf = Imager::Color::Float->new(1.0, 0, 0); my $blue_colorf = Imager::Color::Float->new(0, 0, 1.0); $image->setscanline(y=>10, x=>5, pixels=> [ ($blue_colorf, $red_colorf) x 2, $blue_colorf ]); # packed 8-bit data $image->setscanline(y=>10, x=>5, pixels=> pack("C*", ((0, 0, 255, 255), (255, 0, 0, 255)) x 2, (0, 0, 255, 255))); # packed floating point samples $image->setscanline(y=>10, x=>5, type=>'float', pixels=> pack("d*", ((0, 0, 1.0, 1.0), (1.0, 0, 0, 1.0)) x 2, (0, 0, 1.0, 1.0))); Copy even rows from one image to another: for (my $y = 0; $y < $im2->getheight; $y+=2) { $im1->setscanline(y=>$y, pixels=>scalar($im2->getscanline(y=>$y))); } Set the blue channel to 0 for all pixels in an image. This could be done with convert too: for my $y (0..$im->getheight-1) { my $row = $im->getscanline(y=>$y); $row =~ s/(..).(.)/$1\0$2/gs; $im->setscanline(y=>$y, pixels=>$row); } =item getscanline() Read all or part of a horizontal line of pixels from an image. This method is most useful in conjunction with L. The parameters you can pass are: =over =item * C - vertical position of the scan line. This parameter is required. =item * C - position to start on the scan line. Default: 0 =item * C - number of pixels to read. Default: $img->getwidth - x =item * C - the type of pixel data to return. Default: C<8bit>. Permitted values are C<8bit> and C and C. =back In list context this method will return a list of Imager::Color objects when I is C<8bit>, or a list of Imager::Color::Float objects when I if C, or a list of integers when I is C. In scalar context this returns a packed 8-bit pixels when I is C<8bit>, or a list of packed floating point pixels when I is C, or packed palette color indexes when I is C. The values of samples for which the image does not have channels is undefined. For example, for a single channel image the values of channels 1 through 3 are undefined. Check image for a given color: my $found; YLOOP: for my $y (0..$img->getheight-1) { my @colors = $img->getscanline(y=>$y); for my $color (@colors) { my ($red, $green, $blue, $alpha) = $color->rgba; if ($red == $test_red && $green == $test_green && $blue == $test_blue && $alpha == $test_alpha) { ++$found; last YLOOP; } } } Or do it using packed data: my $found; my $test_packed = pack("CCCC", $test_red, $test_green, $test_blue, $test_alpha); YLOOP: for my $y (0..$img->getheight-1) { my $colors = $img->getscanline(y=>$y); while (length $colors) { if (substr($colors, 0, 4, '') eq $test_packed) { ++$found; last YLOOP; } } } Some of the examples for L for more examples. =item getsamples() Read specified channels from all or part of a horizontal line of pixels from an image. The parameters you can pass are: =over =item * C - vertical position of the scan line. This parameter is required. =item * C - position to start on the scan line. Default: 0 =item * C - number of pixels to read. Default: C<< $img->getwidth - x >> =item * C - the type of sample data to return. Default: C<8bit>. Permitted values are C<8bit> and C. As of Imager 0.61 this can be C<16bit> only for 16 bit images. =item * C - a reference to an array of channels to return, where 0 is the first channel. Default: C<< [ 0 .. $self->getchannels()-1 ] >> =item * C - if an array reference is supplied in target then the samples will be stored here instead of being returned. =item * C - the offset within the array referenced by I =back In list context this will return a list of integers between 0 and 255 inclusive when I is C<8bit>, or a list of floating point numbers between 0.0 and 1.0 inclusive when I is C. In scalar context this will return a string of packed bytes, as with C< pack("C*", ...) > when I is C<8bit> or a string of packed doubles as with C< pack("d*", ...) > when I is C. If the I option is supplied then only a count of samples is returned. Example: Check if any pixels in an image have a non-zero alpha channel: my $has_coverage; for my $y (0 .. $img->getheight()-1) { my $alpha = $img->getsamples(y=>$y, channels=>[0]); if ($alpha =~ /[^\0]/) { ++$has_coverage; last; } } Example: Convert a 2 channel gray image into a 4 channel RGBA image: # this could be done with convert() instead my $out = Imager->new(xsize => $src->getwidth(), ysize => $src->getheight(), channels => 4); for my $y ( 0 .. $src->getheight()-1 ) { my $data = $src->getsamples(y=>$y, channels=>[ 0, 0, 0, 1 ]); $out->setscanline(y=>$y, pixels=>$data); } Retrieve 16-bit samples: if ($img->bits == 16) { my @samples; $img->getsamples(x => 0, y => $y, target => \@samples, type => '16bit'); } =item setsamples() This allows writing of samples to an image. Parameters: =over =item * C - vertical position of the scan line. This parameter is required. =item * C - position to start on the scan line. Default: 0 =item * C - number of pixels to write. Default: C<< $img->getwidth - x >>. The minimum of this and the number of pixels represented by the samples provided will be written. =item * C - the type of sample data to write. This parameter is required. This can be C<8bit>, C or for 16-bit images only, C<16bit>. =item * C - a reference to an array of channels to return, where 0 is the first channel. Default: C<< [ 0 .. $self->getchannels()-1 ] >> =item * C - for a type of C<8bit> or C this can be a reference to an array of samples or a scalar containing packed samples. If C is a scalar it may only contain characters from \x00 to \xFF. For a type of C<16bit> this can only be a reference to an array of samples to write. Required. =item * C - the starting offset within the array referenced by I. If C is a scalar containing packed samples this offset is in samples. =back Returns the number of samples written. $targ->setsamples(y => $y, data => \@data); $targ->setsamples(y => $y, data => \@data, offset => $src->getchannels); Copy from one image to another: my $targ = Imager->new(xsize => $src->getwidth, ysize => $src->getheight, channels => $src->getchannels); for my $y (0 .. $targ->getheight()-1) { my $row = $src->getsamples(y => $y) or die $src->errstr; $targ->setsamples(y => $y, data => $row) or die $targ->errstr;; } Compose an image from separate source channels: my @src = ...; # images to work from, up to 4 my $targ = Imager->new(xsize => $src[0]->getwidth, ysize => $src[0]->getheight, channels => scalar(@src)); for my $y (0 .. $targ->getheight()-1) { for my $ch (0 .. $#src) { my $row = $src[$ch]->getsamples(y => $y, channels => [ 0 ]); $targ->setsamples(y => $y, data => $row, channels => [ $ch ] ); } } =back =head1 Packed Color Data The getscanline() and setscanline() methods can work with pixels packed into scalars. This is useful to remove the cost of creating color objects, but should only be used when performance is an issue. The getsamples() and setsamples() methods can work with samples packed into scalars. Packed data can either be 1 byte per sample or 1 double per sample. Each pixel returned by getscanline() or supplied to setscanline() contains 4 samples, even if the image has fewer then 4 channels. The values of the extra samples as returned by getscanline() is not specified. The extra samples passed to setscanline() are ignored. To produce packed 1 byte/sample pixels, use the pack C template: my $packed_8bit_pixel = pack("CCCC", $red, $blue, $green, $alpha); To produce packed double/sample pixels, use the pack C template: my $packed_float_pixel = pack("dddd", $red, $blue, $green, $alpha); Note that double/sample data is always stored using the C C type, never C, even if C is built with C<-Duselongdouble>. If you use a I parameter of C then the values are palette color indexes, not sample values: my $im = Imager->new(xsize => 100, ysize => 100, type => 'paletted'); my $black_index = $im->addcolors(colors => [ 'black' ]); my $red_index = $im->addcolors(colors => [ 'red' ]); # 2 pixels my $packed_index_data = pack("C*", $black_index, $red_index); $im->setscanline(y => $y, pixels => $packed_index_data, type => 'index'); =head1 Combine Types Some methods accept a C parameter, this can be any of the following: =over =item C The fill pixel replaces the target pixel. =item C The fill pixels alpha value is used to combine it with the target pixel. =item C =item C Each channel of fill and target is multiplied, and the result is combined using the alpha channel of the fill pixel. =item C If the alpha of the fill pixel is greater than a random number, the fill pixel is alpha combined with the target pixel. =item C The channels of the fill and target are added together, clamped to the range of the samples and alpha combined with the target. =item C The channels of the fill are subtracted from the target, clamped to be >= 0, and alpha combined with the target. =item C The channels of the fill are subtracted from the target and the absolute value taken this is alpha combined with the target. =item C The higher value is taken from each channel of the fill and target pixels, which is then alpha combined with the target. =item C The higher value is taken from each channel of the fill and target pixels, which is then alpha combined with the target. =item C The combination of the saturation and value of the target is combined with the hue of the fill pixel, and is then alpha combined with the target. =item C The combination of the hue and value of the target is combined with the saturation of the fill pixel, and is then alpha combined with the target. =item C The combination of the hue and value of the target is combined with the value of the fill pixel, and is then alpha combined with the target. =item C The combination of the value of the target is combined with the hue and saturation of the fill pixel, and is then alpha combined with the target. =back =over =item combines() Returns a list of possible combine types. =back =head1 BUGS box() does not support anti-aliasing yet. Default color is not unified yet. =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson. =head1 SEE ALSO L(3), L(3) =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Inline.pod0000644000175000017500000000304712263740601021462 0ustar gregoagregoa=head1 NAME Imager::Inline - using Imager with Inline::C. =head1 SYNOPSIS use Inline with => 'Imager'; use Inline C => <<'EOS'; Imager some_func(Imager::Color c, Imager::Fill f) { Imager img = i_img_8_new(200, 200, 3); /* fill with color */ i_box_filled(img, 0, 0, 199, 199, c); /* inner area with fill */ i_box_cfill(img, 50, 50, 149, 149, f); return img; } EOS =head1 DESCRIPTION =for stopwords inline Inline Inline's Imager hooks into Inline's C syntax to make it easier to write Inline::C code that works with Imager, you can call Imager functions without having to include headers or perform initialization. Imager's Inline C support does the following: =over =item * add the installed Imager include directory to INC =item * add the Imager typemap to TYPEMAPS =item * include the headers needed by Imager C extension modules. =item * declare and initialize the Imager API function table pointer =item * filter the supplied code to replace Imager's class names with those that Inline::C can handle. =back =head1 LIMITATIONS The filtering mechanism is global, it will replace the class names even inside string constants. If you need a string matching the name of one of Imager's classes, like C<"Imager::Color"> you will need to split it into 2 to use C's string pasting mechanism, for example: C<"Imager:" ":Color">. =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =head1 SEE ALSO Imager, Imager::ExtUtils, Imager::API, Imager::APIRef, samples/inline_replace_color.pl =cut libimager-perl-1.004+dfsg.orig/lib/Imager/IO.pod0000644000175000017500000002043512370401737020556 0ustar gregoagregoa=head1 NAME Imager::IO - Imager's io_layer object. =head1 SYNOPSIS # Imager supplies Imager::IO objects to various callbacks my $IO = ...; my $count = $IO->write($data); my $count = $IO->read($buffer, $max_count); my $position = $IO->seek($offset, $whence); my $status = $IO->close; =head1 DESCRIPTION Imager uses an abstraction when dealing with image files to allow the same code to work with disk files, in memory data and callbacks. If you're writing an Imager file handler your code will be passed an Imager::IO object to write to or read from. XXNote that Imager::IO can only work with collections of bytes - if you need to read UTF-8 data you will need to read the bytes and decode them. If you want to write UTF-8 data you will need to encode your characters to bytes and write the bytes. =head1 CONSTRUCTORS =over =item new_fd($fd) Create a new I/O layer based on a file descriptor. my $io = Imager::IO->new(fileno($fh)); =item new_buffer($data) Create a new I/O layer based on a memory buffer. Buffer I/O layers are read only. C<$data> can either a simple octet string, or a reference to an octet string. If C<$data> contains characters with a code point above C<0xFF> an exception will be thrown. =item new_cb($writecb, $readcb, $seekcb, $closecb) Create a new I/O layer based on callbacks. See L for details on the behavior of the callbacks. =item new_fh($fh) Create a new I/O layer based on a perl file handle. =item new_bufchain() Create a new C based I/O layer. This accumulates the file data as a chain of buffers starting from an empty stream. Use the L method to retrieve the accumulated content into a perl string. =back =head1 BUFFERED I/O METHODS These methods use buffered I/O to improve performance unless you call set_buffered() to disable buffering. Prior to Imager 0.86 the write and read methods performed raw I/O. =over =item write($data) Call to write to the file. Returns the number of bytes written. The data provided may contain only characters \x00 to \xFF - characters outside this range will cause this method to croak(). If you supply a UTF-8 flagged string it will be converted to a byte string, which may have a performance impact. Returns -1 on error, though in most cases if the result of the write isn't the number of bytes supplied you'll want to treat it as an error anyway. =item read($buffer, $size) my $buffer; my $count = $io->read($buffer, $max_bytes); Reads up to I<$max_bytes> bytes from the current position in the file and stores them in I<$buffer>. Returns the number of bytes read on success or an empty list on failure. Note that a read of zero bytes is B a failure, this indicates end of file. =item read2($size) my $buffer = $io->read2($max_bytes); An alternative interface to read, that might be simpler to use in some cases. Returns the data read or an empty list. At end of file the data read will be an empty string. =item seek($offset, $whence) my $new_position = $io->seek($offset, $whence); Seek to a new position in the file. Possible values for I<$whence> are: =over =item * C - I<$offset> is the new position in the file. =item * C - I<$offset> is the offset from the current position in the file. =item * C - I<$offset> is the offset relative to the end of the file. =back Note that seeking past the end of the file may or may not result in an error. Any buffered output will be flushed, if flushing fails, seek() will return -1. Returns the new position in the file, or -1 on error. =item getc() Return the next byte from the stream. Returns the ordinal of the byte or -1 on error or end of file. while ((my $c = $io->getc) != -1) { print chr($c); } =item gets() =item gets($max_size) =item gets($max_size, $end_of_line) Returns the next line of input from the stream, as terminated by C. The default C is 8192. The default C is C. Returns nothing if the stream is in error or at end of file. Returns the line as a string, including the line terminator (if one was found) on success. while (defined(my $line = $io->gets)) { # do something with $line } =item peekc() Return the buffered next character from the stream, loading the buffer if necessary. For an unbuffered stream a buffer will be setup and loaded with a single character. Returns the ordinal of the byte or -1 on error or end of file. my $c = $io->peekc; =item peekn($size) Returns up to the next C bytes from the file as a string. Only up to the stream buffer size bytes (currently 8192) can be peeked. This method ignores the buffering state of the stream. Returns nothing on EOF. my $s = $io->peekn(4); if ($s =~ /^(II|MM)\*\0/) { print "TIFF image"; } =item putc($code) Write a single character to the stream. Returns C on success, or -1 on failure. =item close() my $result = $io->close; Call when you're done with the file. If the IO object is connected to a file this won't close the file handle, but buffers may be flushed (if any). Returns 0 on success, -1 on failure. =item eof() $io->eof Test if the stream is at end of file. No further read requests will be passed to your read callback until you seek(). =item error() Test if the stream has encountered a read or write error. my $data = $io->read2(100); $io->error and die "Failed"; When the stream has the error flag set no further read or write requests will be passed to your callbacks until you seek. =item flush() $io->flush or die "Flush error"; Flush any buffered output. This will not call lower write layers when the stream has it's error flag set. Returns a true value on success. =item is_buffered() Test if buffering is enabled for this stream. Returns a true value if the stream is buffered. =item set_buffered($enabled) If C<$enabled> is a non-zero integer, enable buffering, other disable it. Disabling buffering will flush any buffered output, but any buffered input will be retained and consumed by input methods. Returns true if any buffered output was flushed successfully, false if there was an error flushing output. =back =head1 RAW I/O METHODS These call the underlying I/O abstraction directly. =over =item raw_write() Call to write to the file. Returns the number of bytes written. The data provided may contain only characters \x00 to \xFF - characters outside this range will cause this method to croak(). If you supply a UTF-8 flagged string it will be converted to a byte string, which may have a performance impact. Returns -1 on error, though in most cases if the result of the write isn't the number of bytes supplied you'll want to treat it as an error anyway. =item raw_read() my $buffer; my $count = $io->raw_read($buffer, $max_bytes); Reads up to I<$max_bytes> bytes from the current position in the file and stores them in I<$buffer>. Returns the number of bytes read on success or an empty list on failure. Note that a read of zero bytes is B a failure, this indicates end of file. =item raw_read2() my $buffer = $io->raw_read2($max_bytes); An alternative interface to raw_read, that might be simpler to use in some cases. Returns the data read or an empty list. =item raw_seek() my $new_position = $io->raw_seek($offset, $whence); Seek to a new position in the file. Possible values for I<$whence> are: =over =item * C - I<$offset> is the new position in the file. =item * C - I<$offset> is the offset from the current position in the file. =item * C - I<$offset> is the offset relative to the end of the file. =back Note that seeking past the end of the file may or may not result in an error. Returns the new position in the file, or -1 on error. =item raw_close() my $result = $io->raw_close; Call when you're done with the file. If the IO object is connected to a file this won't close the file handle. Returns 0 on success, -1 on failure. =back =head1 UTILITY METHODS =over =item slurp() Retrieve the data accumulated from an I/O layer object created with the new_bufchain() method. my $data = $io->slurp; =item dump() Dump the internal buffering state of the I/O object to C. $io->dump(); =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Files =cut libimager-perl-1.004+dfsg.orig/lib/Imager/ExtUtils.pm0000644000175000017500000000411212263740601021651 0ustar gregoagregoapackage Imager::ExtUtils; use strict; use File::Spec; use vars qw($VERSION); $VERSION = "1.002"; =head1 NAME Imager::ExtUtils - functions handy in writing Imager extensions =head1 SYNOPSIS # make Imager easier to use with Inline # perldoc Imager::Inline use Inline with => 'Imager'; =head1 DESCRIPTION =over =item base_dir Returns the base directory where Imager is installed. =cut # figure out where Imager is installed sub base_dir { for my $inc_dir (@INC) { if (-e "$inc_dir/Imager.pm") { my $base_dir = $inc_dir; unless (File::Spec->file_name_is_absolute($base_dir)) { $base_dir = File::Spec->rel2abs($base_dir); } return $base_dir; } } die "Cannot locate an installed Imager!"; } =item inline_config Implements Imager's Inline::C C hook. =cut sub inline_config { my ($class) = @_; my $base = base_dir(); return { INC => $class->includes, TYPEMAPS => $class->typemap, AUTO_INCLUDE => < 'PERL_INITIALIZE_IMAGER_CALLBACKS;', FILTERS => \&_inline_filter, }; } my @inline_replace = qw( Imager::ImgRaw Imager::Color::Float Imager::Color Imager::IO ); my %inline_replace = map { (my $tmp = $_) =~ s/::/__/g; $_ => $tmp } @inline_replace; my $inline_replace_re = "\\b(" . join('|', @inline_replace) . ")\\b"; sub _inline_filter { my $code = shift; $code =~ s/$inline_replace_re/$inline_replace{$1}/g; $code; } =item includes Returns -I options suitable for use with ExtUtils::MakeMaker's INC option. =cut sub includes { my $class = shift; my $base = $class->base_dir(); "-I" . $base . '/Imager/include', } =item typemap Returns the full path to Imager's installed typemap. =cut sub typemap { my $class = shift; my $base = $class->base_dir(); $base . '/Imager/typemap'; } 1; __END__ =back =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =head1 SEE ALSO Imager, Imager::API, Imager::Inline, Imager::APIRef. =cut libimager-perl-1.004+dfsg.orig/lib/Imager/regmach.pod0000644000175000017500000000527412263740601021656 0ustar gregoagregoa=head1 NAME Imager::regmach - documents the register virtual machine used by Imager::transform2(). =head1 SYNOPSIS The register machine is a complete rewrite of the stack machine originally used by Imager::transform(), written for use by Imager::transform2(). =head1 DESCRIPTION (This document might be a little incoherent.) The register machine is a fast implementation of a small instruction set designed for evaluating an arithmetic expression to produce a color for an image. The machine takes as input: =over 4 =item instructions An array of instructions =item numeric registers An array of numeric registers. Some registers are initialized as literals. =item color registers An array of color registers. Currently these registers aren't initialized. =item input images An array of Imager i_img pointers. The C operators read pixels from these images. =back The instructions supplied each take up to 4 input numeric or color registers with a single output numeric or color register. The machine attempts to execute instructions as safely as possible, assuming that correct instructions have been provided, eg. the machine protects against divide by zero, but doesn't check register numbers for validity. The final instruction must be a C instruction, which returns the result ;) =head2 Adding new instructions To add a new instruction: =over 4 =item 1 Add a new opcode to the enumeration in F - make sure to add comment after the enum name giving the input registers (C for numeric, C for color) that the instruction takes. These must be in the order that the instruction expects to take the. Put a letter (r or p) after -> to indicate the result type. =item 2 Add a case to F that executes the instruction. =item 3 make =back The F should rebuild the F file, and your new instruction will be added as a function. If you want to add a single alternative instruction that might take different argument types (it must take the same number of parameters), create another instruction with that name followed by a p. The current expression parsers explicitly look for such instruction names. =head2 Future directions Conditional and non-conditional jumps to implement iteration. This will break the current optimizer in L (and the compilers for both expression compilers, for that matter.) Complex arithmetic (Addi suggested this one). This would most likely be a separate machine. Otherwise we'll have a very significant performance loss. =head1 WARNINGS If you feed bad 'machine code' to the register machine, you have a good chance of a C. =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Security.pod0000644000175000017500000000327512263740601022056 0ustar gregoagregoa=head1 NAME Imager::Security - brief notes on security and image processing =head1 SYNOPSIS # keep abreast of security updates apt-get update && apt-get upgrade yum upgrade pkgin update && pkgin upgrade # or local equivalent # limit memory use use Imager; # only images that use up to 10MB Imager->set_file_limits(bytes => 10_000_000); =head1 DESCRIPTION There's two basic security considerations when dealing with images from an unknown source: =over =item * keeping your libraries up to date =item * limiting the amount of memory used to store images =back =head2 Keeping libraries up to date Image file format libraries such as C or C have relatively frequent security updates, keeping your libraries up to date is basic security. If you're using user supplied fonts, you will need to keep your font libraries up to date too. =head2 Limiting memory used With compression, and especially with pointer formats like TIFF, it's possible to store very large images in a relatively small file. If you're receiving image data from an untrusted source you should limit the amount of memory that Imager can allocate for a read in image file using the C method. Imager->set_file_limits(bytes => 10_000_000); You may also want to limit the maximum width and height of images read from files: Imager->set_file_limits(width => 10_000, height => 10_000, bytes => 10_000_000); This has no effect on images created without a file: # succeeds my $image = Imager->new(xsize => 10_001, ysize => 10_001); You can reset to the defaults with: Imager->set_file_limits(reset => 1); =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Fill.pm0000644000175000017500000003013012263740601020755 0ustar gregoagregoapackage Imager::Fill; use strict; use vars qw($VERSION); $VERSION = "1.012"; # this needs to be kept in sync with the array of hatches in fills.c my @hatch_types = qw/check1x1 check2x2 check4x4 vline1 vline2 vline4 hline1 hline2 hline4 slash1 slosh1 slash2 slosh2 grid1 grid2 grid4 dots1 dots4 dots16 stipple weave cross1 cross2 vlozenge hlozenge scalesdown scalesup scalesleft scalesright stipple2 tile_L stipple3/; my %hatch_types; @hatch_types{@hatch_types} = 0..$#hatch_types; *_color = \&Imager::_color; sub new { my ($class, %hsh) = @_; my $self = bless { }, $class; $hsh{combine} = Imager->_combine($hsh{combine}, 0); if ($hsh{solid}) { my $solid = _color($hsh{solid}); if (UNIVERSAL::isa($solid, 'Imager::Color')) { $self->{fill} = Imager::i_new_fill_solid($solid, $hsh{combine}); } elsif (UNIVERSAL::isa($solid, 'Imager::Color::Float')) { $self->{fill} = Imager::i_new_fill_solidf($solid, $hsh{combine}); } else { $Imager::ERRSTR = "solid isn't a color"; return undef; } } elsif (defined $hsh{hatch}) { $hsh{dx} ||= 0; $hsh{dy} ||= 0; $hsh{fg} ||= Imager::Color->new(0, 0, 0); if (ref $hsh{hatch}) { $hsh{cust_hatch} = pack("C8", @{$hsh{hatch}}); $hsh{hatch} = 0; } elsif ($hsh{hatch} =~ /\D/) { unless (exists($hatch_types{$hsh{hatch}})) { $Imager::ERRSTR = "Unknown hatch type $hsh{hatch}"; return undef; } $hsh{hatch} = $hatch_types{$hsh{hatch}}; } my $fg = _color($hsh{fg}); if (UNIVERSAL::isa($fg, 'Imager::Color')) { my $bg = _color($hsh{bg} || Imager::Color->new(255, 255, 255)); $self->{fill} = Imager::i_new_fill_hatch($fg, $bg, $hsh{combine}, $hsh{hatch}, $hsh{cust_hatch}, $hsh{dx}, $hsh{dy}); } elsif (UNIVERSAL::isa($fg, 'Imager::Color::Float')) { my $bg = _color($hsh{bg} || Imager::Color::Float->new(1, 1, 1)); $self->{fill} = Imager::i_new_fill_hatchf($fg, $bg, $hsh{combine}, $hsh{hatch}, $hsh{cust_hatch}, $hsh{dx}, $hsh{dy}); } else { $Imager::ERRSTR = "fg isn't a color"; return undef; } } elsif (defined $hsh{fountain}) { # make sure we track the filter's defaults my $fount = $Imager::filters{fountain}; my $def = $fount->{defaults}; my $names = $fount->{names}; $hsh{ftype} = $hsh{fountain}; # process names of values for my $name (keys %$names) { if (defined $hsh{$name} && exists $names->{$name}{$hsh{$name}}) { $hsh{$name} = $names->{$name}{$hsh{$name}}; } } # process defaults %hsh = (%$def, %hsh); my @parms = @{$fount->{callseq}}; shift @parms; for my $name (@parms) { unless (defined $hsh{$name}) { $Imager::ERRSTR = "required parameter '$name' not set for fountain fill"; return undef; } } # check that the segments supplied is an array ref unless (ref $hsh{segments} && $hsh{segments} =~ /ARRAY/) { $Imager::ERRSTR = "segments must be an array reference or Imager::Fountain object"; return; } # make sure the segments are specified with colors my @segments; for my $segment (@{$hsh{segments}}) { my @new_segment = @$segment; $_ = _color($_) or return for @new_segment[3,4]; push @segments, \@new_segment; } $self->{fill} = Imager::i_new_fill_fount($hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb}, $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample}, $hsh{ssample_param}, \@segments); } elsif (defined $hsh{image}) { $hsh{xoff} ||= 0; $hsh{yoff} ||= 0; $self->{fill} = Imager::i_new_fill_image($hsh{image}{IMG}, $hsh{matrix}, $hsh{xoff}, $hsh{yoff}, $hsh{combine}); $self->{DEPS} = [ $hsh{image}{IMG} ]; } elsif (defined $hsh{type} && $hsh{type} eq "opacity") { my $other_fill = delete $hsh{other}; unless (defined $other_fill) { Imager->_set_error("'other' parameter required to create opacity fill"); return; } unless (ref $other_fill && eval { $other_fill->isa("Imager::Fill") }) { # try to auto convert to a fill object if (ref $other_fill && $other_fill =~ /HASH/) { $other_fill = Imager::Fill->new(%$other_fill) or return; } else { undef $other_fill; } unless ($other_fill) { Imager->_set_error("'other' parameter must be an Imager::Fill object to create an opacity fill"); return; } } my $raw_fill = $other_fill->{fill}; my $opacity = delete $hsh{opacity}; defined $opacity or $opacity = 0.5; # some sort of default $self->{fill} = Imager::i_new_fill_opacity($raw_fill, $opacity); $self->{DEPS} = [ $other_fill ]; # keep reference to old fill and its deps } else { $Imager::ERRSTR = "No fill type specified"; warn "No fill type!"; return undef; } $self; } sub hatches { return @hatch_types; } sub combines { return Imager->combines; } 1; =head1 NAME Imager::Fill - general fill types =head1 SYNOPSIS use Imager; use Imager::Fill; my $fill1 = Imager::Fill->new(solid=>$color, combine=>$combine); my $fill2 = Imager::Fill->new(hatch=>'vline2', fg=>$color1, bg=>$color2, dx=>$dx, dy=>$dy); my $fill3 = Imager::Fill->new(fountain=>$type, ...); my $fill4 = Imager::Fill->new(image=>$img, ...); my $fill5 = Imager::Fill->new(type => "opacity", other => $fill, opacity => ...); =head1 DESCRIPTION Creates fill objects for use by most filled area drawing functions. All fills are created with the new method. =over =item new my $fill = Imager::Fill->new(...); The parameters depend on the type of fill being created. See below for details. =back The currently available fills are: =over =item * solid =item * hatch =item * fountain (similar to gradients in paint software) =item * image - fill with an image, possibly transformed =item * opacity - a lower opacity version of some other fill =back =head1 Common options =over =item combine The way in which the fill data is combined with the underlying image. See L. =back In general colors can be specified as L or L objects. The fill object will typically store both types and convert from one to the other. If a fill takes 2 color objects they should have the same type. =head2 Solid fills my $fill = Imager::Fill->new(solid=>$color, combine =>$combine) Creates a solid fill, the only required parameter is C which should be the color to fill with. A translucent red fill: my $red = Imager::Fill->new(solid => "FF000080", combine => "normal"); =head2 Hatched fills my $fill = Imager::Fill->new(hatch=>$type, fg=>$fgcolor, bg=>$bgcolor, dx=>$dx, $dy=>$dy); Creates a hatched fill. You can specify the following keywords: =over =item * C - The type of hatch to perform, this can either be the numeric index of the hatch (not recommended), the symbolic name of the hatch, or an array of 8 integers which specify the pattern of the hatch. Hatches are represented as cells 8x8 arrays of bits, which limits their complexity. Current hatch names are: =over =item * C, C, C - checkerboards at various sizes =item * C, C, C - 1, 2, or 4 vertical lines per cell =item * C, C, C - 1, 2, or 4 horizontal lines per cell =item * C, C - 1 or 2 / lines per cell. =item * C, C - 1 or 2 \ lines per cell =item * C, C, C - 1, 2, or 4 vertical and horizontal lines per cell =item * C, C, C - 1, 4 or 16 dots per cell =item * C, C - see the samples =item * C - I hope this one is obvious. =item * C, C - 2 densities of crosshatch =item * C, C - something like lozenge tiles =item * C, C, C, C - Vaguely like fish scales in each direction. =item * C - L-shaped tiles =back =item * C, C - The C color is rendered where bits are set in the hatch, and the C where they are clear. If you use a transparent C or C, and set combine, you can overlay the hatch onto an existing image. C defaults to black, C to white. =item * C, C - An offset into the hatch cell. Both default to zero. =back A blue and white 4-pixel check pattern: my $fill = Imager::Fill->new(hatch => "check2x2", fg => "blue"); You can call Imager::Fill->hatches for a list of hatch names. =head2 Fountain fills my $fill = Imager::Fill->new(fountain=>$ftype, xa=>$xa, ya=>$ya, xb=>$xb, yb=>$yb, segments=>$segments, repeat=>$repeat, combine=>$combine, super_sample=>$super_sample, ssample_param=>$ssample_param); This fills the given region with a fountain fill. This is exactly the same fill as the C filter, but is restricted to the shape you are drawing, and the fountain parameter supplies the fill type, and is required. A radial fill from white to transparent centered on (50, 50) with a 50 pixel radius: use Imager::Fountain; my $segs = Imager::Fountain->simple(colors => [ "FFFFFF", "FFFFFF00" ], positions => [ 0, 1 ]); my $fill = Imager::Fill->new(fountain => "radial", segments => $segs, xa => 50, ya => 50, xb => 0, yb => 50, combine => "normal"); =head2 Image Fills my $fill = Imager::Fill->new(image=>$src, xoff=>$xoff, yoff=>$yoff, matrix=>$matrix, combine => $combine); Fills the given image with a tiled version of the given image. The first non-zero value of C or C will provide an offset along the given axis between rows or columns of tiles respectively. The matrix parameter performs a co-ordinate transformation from the co-ordinates in the target image to the fill image co-ordinates. Linear interpolation is used to determine the fill pixel. You can use the L class to create transformation matrices. The matrix parameter will significantly slow down the fill. # some image to act as a texture my $txim = Imager->new(...); # simple tiling my $fill = Imager::Fill->new(image => $txim); # tile with a vertical offset my $fill = Imager::Fill->new(image => $txim, yoff => 10); # tile with a horizontal offset my $fill = Imager::Fill->new(image => $txim, xoff => 10); # rotated use Imager::Matrix2d; my $fill = Imager::Fill->new(image => $txim, matrix => Imager::Matrix2d->rotate(degrees => 20)); =head2 Opacity modification fill my $fill = Imager::Fill->new(type => "opacity", other => $fill, opacity => 0.25); This can be used to make a fill that is a more translucent or opaque version of an existing fill. This is intended for use where you receive a fill object as a parameter and need to change the opacity. Parameters: =over =item * type => "opacity" - Required =item * other - the fill to produce a modified version of. This must be an Imager::Fill object. Required. =item * opacity - multiplier for the source fill opacity. Default: 0.5. =back The source fills combine mode is used. my $hatch = Imager::Fill->new(hatch => "check4x4", combine => "normal"); my $fill = Imager::Fill->new(type => "opacity", other => $hatch); =head1 OTHER METHODS =over =item Imager::Fill->hatches A list of all defined hatch names. =item Imager::Fill->combines A list of all combine types. =back =head1 FUTURE PLANS I'm planning on adding the following types of fills: =over =item * C - combines 2 other fills in a checkerboard =item * C - combines 2 other fills using the levels of an image =item * C - uses the transform2() register machine to create fills =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Files.pod0000644000175000017500000015334312460670607021322 0ustar gregoagregoa=head1 NAME Imager::Files - working with image files =head1 SYNOPSIS use Imager; my $img = ...; $img->write(file=>$filename, type=>$type) or die "Cannot write: ",$img->errstr; # type is optional if we can guess the format from the filename $img->write(file => "foo.png") or die "Cannot write: ",$img->errstr; $img = Imager->new; $img->read(file=>$filename, type=>$type) or die "Cannot read: ", $img->errstr; # type is optional if we can guess the type from the file data # and we normally can guess $img->read(file => $filename) or die "Cannot read: ", $img->errstr; Imager->write_multi({ file=> $filename, ... }, @images) or die "Cannot write: ", Imager->errstr; my @imgs = Imager->read_multi(file=>$filename) or die "Cannot read: ", Imager->errstr; Imager->set_file_limits(width=>$max_width, height=>$max_height) my @read_types = Imager->read_types; my @write_types = Imager->write_types; # we can write/write_multi to things other than filenames my $data; $img->write(data => \$data, type => $type) or die; my $fh = ... ; # eg. IO::File $img->write(fh => $fh, type => $type) or die; $img->write(fd => fileno($fh), type => $type) or die; # some file types need seek callbacks too $img->write(callback => \&write_callback, type => $type) or die; # and similarly for read/read_multi $img->read(data => $data) or die; $img->read(fh => $fh) or die; $img->read(fd => fileno($fh)) or die; $img->read(callback => \&read_callback) or die; use Imager 0.68; my $img = Imager->new(file => $filename) or die Imager->errstr; =head1 DESCRIPTION You can read and write a variety of images formats, assuming you have the appropriate libraries, and images can be read or written to/from files, file handles, file descriptors, scalars, or through callbacks. To see which image formats Imager is compiled to support the following code snippet is sufficient: use Imager; print join " ", keys %Imager::formats; This will include some other information identifying libraries rather than file formats. For new code you might find the L or L methods useful. =over =item read() Reading writing to and from files is simple, use the C method to read an image: my $img = Imager->new; $img->read(file=>$filename, type=>$type) or die "Cannot read $filename: ", $img->errstr; In most cases Imager can auto-detect the file type, so you can just supply the file name: $img->read(file => $filename) or die "Cannot read $filename: ", $img->errstr; The read() method accepts the C parameter. If this is non-zero then read() can return true on an incomplete image and set the C tag. From Imager 0.68 you can supply most read() parameters to the new() method to read the image file on creation. If the read fails, check Imager->errstr() for the cause: use Imager 0.68; my $img = Imager->new(file => $filename) or die "Cannot read $filename: ", Imager->errstr; =item write() and the C method to write an image: $img->write(file=>$filename, type=>$type) or die "Cannot write $filename: ", $img->errstr; =item read_multi() If you're reading from a format that supports multiple images per file, use the C method: my @imgs = Imager->read_multi(file=>$filename, type=>$type) or die "Cannot read $filename: ", Imager->errstr; As with the read() method, Imager will normally detect the C automatically. =item write_multi() and if you want to write multiple images to a single file use the C method: Imager->write_multi({ file=> $filename, type=>$type }, @images) or die "Cannot write $filename: ", Imager->errstr; =item read_types() This is a class method that returns a list of the image file types that Imager can read. my @types = Imager->read_types; These types are the possible values for the C parameter, not necessarily the extension of the files you're reading. It is possible for extra file read handlers to be loaded when attempting to read a file, which may modify the list of available read types. =item write_types() This is a class method that returns a list of the image file types that Imager can write. my @types = Imager->write_types; Note that these are the possible values for the C parameter, not necessarily the extension of the files you're writing. It is possible for extra file write handlers to be loaded when attempting to write a file, which may modify the list of available write types. =back When writing, if the C includes an extension that Imager recognizes, then you don't need the C, but you may want to provide one anyway. See L for information on controlling this recognition. The C parameter is a lowercase representation of the file type, and can be any of the following: bmp Windows BitMaP (BMP) gif Graphics Interchange Format (GIF) jpeg JPEG/JFIF png Portable Network Graphics (PNG) pnm Portable aNyMap (PNM) raw Raw sgi SGI .rgb files tga TARGA tiff Tagged Image File Format (TIFF) When you read an image, Imager may set some tags, possibly including information about the spatial resolution, textual information, and animation information. See L for specifics. The open() method is a historical alias for the read() method. =head2 Input and output When reading or writing you can specify one of a variety of sources or targets: =over =item * C - The C parameter is the name of the image file to be written to or read from. If Imager recognizes the extension of the file you do not need to supply a C. # write in tiff format $image->write(file => "example.tif") or die $image->errstr; $image->write(file => 'foo.tmp', type => 'tiff') or die $image->errstr; my $image = Imager->new; $image->read(file => 'example.tif') or die $image->errstr; =item * C - C is a file handle, typically either returned from C<new()>>, or a glob from an C call. You should call C on the handle before passing it to Imager. Imager will set the handle to autoflush to make sure any buffered data is flushed , since Imager will write to the file descriptor (from fileno()) rather than writing at the perl level. $image->write(fh => \*STDOUT, type => 'gif') or die $image->errstr; # for example, a file uploaded via CGI.pm $image->read(fd => $cgi->param('file')) or die $image->errstr; =item * C - C is a file descriptor. You can get this by calling the C function on a file handle, or by using one of the standard file descriptor numbers. If you get this from a perl file handle, you may need to flush any buffered output, otherwise it may appear in the output stream after the image. $image->write(fd => file(STDOUT), type => 'gif') or die $image->errstr; =item * C - When reading data, C is a scalar containing the image file data, or a reference to such a scalar. When writing, C is a reference to the scalar to save the image file data to. my $data; $image->write(data => \$data, type => 'tiff') or die $image->errstr; my $data = $row->{someblob}; # eg. from a database my @images = Imager->read_multi(data => $data) or die Imager->errstr; # from Imager 0.99 my @images = Imager->read_multi(data => \$data) or die Imager->errstr; =item * C, C, C, C, C - Imager will make calls back to your supplied coderefs to read, write and seek from/to/through the image file. See L below for details. =item * C - an L object. =back XXBy default Imager will use buffered I/O when reading or writing an image. You can disabled buffering for output by supplying a C<< buffered => 0 >> parameter to C or C. =head2 I/O Callbacks When reading from a file you can use either C or C to supply the read callback, and when writing C or C to supply the write callback. Whether reading or writing a C image, C and C are required. If a file handler attempts to use C, C or C and you haven't supplied one, the call will fail, failing the image read or write, returning an error message indicating that the callback is missing: # attempting to read a TIFF image without a seekcb open my $fh, "<", $filename or die; my $rcb = sub { my $val; read($fh, $val, $_[0]) or return ""; return $val; }; my $im = Imager->new(callback => $rcb) or die Imager->errstr # dies with (wrapped here): # Error opening file: (Iolayer): Failed to read directory at offset 0: # (Iolayer): Seek error accessing TIFF directory: seek callback called # but no seekcb supplied You can also provide a C parameter called when writing the file is complete. If no C is supplied the default will succeed silently. # contrived my $data; sub mywrite { $data .= unpack("H*", shift); 1; } Imager->write_multi({ callback => \&mywrite, type => 'gif'}, @images) or die Imager->errstr; =head3 C The read callback is called with 2 parameters: =over =item * C - the minimum amount of data required. =item * C - previously this was the maximum amount of data returnable - currently it's always the same as C =back Your read callback should return the data as a scalar: =over =item * on success, a string containing the bytes read. =item * on end of file, an empty string =item * on error, C. =back If your return value contains more data than C Imager will panic. Your return value must not contain any characters over C<\xFF> or Imager will panic. =head3 C Your write callback takes exactly one parameter, a scalar containing the data to be written. Return true for success. =head3 C The seek callback takes 2 parameters, a I, and a I, defined in the same way as perl's seek function. Previously you always needed a C callback if you called Imager's L or L without a C parameter, but this is no longer necessary unless the file handler requires seeking, such as for TIFF files. Returns the new position in the file, or -1 on failure. =head3 C You can also supply a C which is called with no parameters when there is no more data to be written. This could be used to flush buffered data. Return true on success. =head2 Guessing types X When writing to a file, if you don't supply a C parameter Imager will attempt to guess it from the file name. This is done by calling the code reference stored in C<$Imager::FORMATGUESS>. This is only done when write() or write_multi() is called with a C parameter, or if read() or read_multi() can't determine the type from the file's header. The default function value of C<$Imager::FORMATGUESS> is C<\&Imager::def_guess_type>. =over =item def_guess_type() X This is the default function Imager uses to derive a file type from a file name. This is a function, not a method. Accepts a single parameter, the file name and returns the type or undef. =back You can replace function with your own implementation if you have some specialized need. The function takes a single parameter, the name of the file, and should return either a file type or under. # I'm writing jpegs to weird filenames local $Imager::FORMATGUESS = sub { 'jpeg' }; When reading a file Imager examines beginning of the file for identifying information. The current implementation attempts to detect the following image types beyond those supported by Imager: =for stopwords Photoshop =over C, C, C, C, C, C, C (Photoshop), C, Utah C. =back =head2 Limiting the sizes of images you read =over =item set_file_limits() In some cases you will be receiving images from an untested source, such as submissions via CGI. To prevent such images from consuming large amounts of memory, you can set limits on the dimensions of images you read from files: =over =item * width - limit the width in pixels of the image =item * height - limit the height in pixels of the image =item * bytes - limits the amount of storage used by the image. This depends on the width, height, channels and sample size of the image. For paletted images this is calculated as if the image was expanded to a direct color image. =back To set the limits, call the class method set_file_limits: Imager->set_file_limits(width=>$max_width, height=>$max_height); You can pass any or all of the limits above, any limits you do not pass are left as they were. Any limit of zero for width or height is treated as unlimited. A limit of zero for bytes is treated as one gigabyte, but higher bytes limits can be set explicitly. By default, the width and height limits are zero, or unlimited. The default memory size limit is one gigabyte. You can reset all limits to their defaults with the reset parameter: # no limits Imager->set_file_limits(reset=>1); This can be used with the other limits to reset all but the limit you pass: # only width is limited Imager->set_file_limits(reset=>1, width=>100); # only bytes is limited Imager->set_file_limits(reset=>1, bytes=>10_000_000); =item get_file_limits() You can get the current limits with the get_file_limits() method: my ($max_width, $max_height, $max_bytes) = Imager->get_file_limits(); =item check_file_limits() XX Intended for use by file handlers to check that the size of a file is within the limits set by C. Parameters: =over =item * C, C - the width and height of the image in pixels. Must be a positive integer. Required. =item * C - the number of channels in the image, including the alpha channel if any. Must be a positive integer between 1 and 4 inclusive. Default: 3. =item * C - the number of bytes stored per sample. Must be a positive integer or C<"float">. Note that this should be the sample size of the Imager image you will be creating, not the sample size in the source, eg. if the source has 32-bit samples this should be C<"float"> since Imager doesn't have 32-bit/sample images. =back =back =head1 TYPE SPECIFIC INFORMATION The different image formats can write different image type, and some have different options to control how the images are written. When you call C or C with an option that has the same name as a tag for the image format you're writing, then the value supplied to that option will be used to set the corresponding tag in the image. Depending on the image format, these values will be used when writing the image. This replaces the previous options that were used when writing GIF images. Currently if you use an obsolete option, it will be converted to the equivalent tag and Imager will produced a warning. You can suppress these warnings by calling the C function with the C option set to false: Imager::init(warn_obsolete=>0); At some point in the future these obsolete options will no longer be supported. =for stopwords aNy PixMaps BitMap =head2 PNM (Portable aNy Map) Imager can write C (Portable Gray Map) and C (Portable PixMaps) files, depending on the number of channels in the image. Currently the images are written in binary formats. Only 1 and 3 channel images can be written, including 1 and 3 channel paletted images. $img->write(file=>'foo.ppm') or die $img->errstr; Imager can read both the ASCII and binary versions of each of the C (Portable BitMap), C and C formats. $img->read(file=>'foo.ppm') or die $img->errstr; PNM does not support the spatial resolution tags. The following tags are set when reading a PNM file: =over =item * XC - the C number from the PGM/PPM header. Always set to 2 for a C file. =item * XC - the type number from the C header, 1 for ASCII C files, 2 for ASCII C files, 3 for ASCII c files, 4 for binary C files, 5 for binary C files, 6 for binary C files. =back The following tag is checked when writing an image with more than 8-bits/sample: =over =item * Xpnm_write_wide_data - if this is non-zero then write() can write C/C files with 16-bits/sample. Some applications, for example GIMP 2.2, and tools can only read 8-bit/sample binary PNM files, so Imager will only write a 16-bit image when this tag is non-zero. =back =head2 JPEG =for stopwords composited You can supply a C parameter (0-100) when writing a JPEG file, which defaults to 75%. If you write an image with an alpha channel to a JPEG file then it will be composited against the background set by the C parameter (or tag). $img->write(file=>'foo.jpg', jpegquality=>90) or die $img->errstr; Imager will read a gray scale JPEG as a 1 channel image and a color JPEG as a 3 channel image. $img->read(file=>'foo.jpg') or die $img->errstr; The following tags are set in a JPEG image when read, and can be set to control output: =over =item * C - The value of the density unit field in the C header. This is ignored on writing if the C tag is non-zero. The C and C tags are expressed in pixels per inch no matter the value of this tag, they will be converted to/from the value stored in the JPEG file. =item * C - This is set when reading a JPEG file to the name of the unit given by C. Possible results include C, C, C (the C tag is also set reading these files). If the value of C is unknown then this tag isn't set. =item * C - Text comment. =item * C - Whether the JPEG file is a progressive file. (Imager 0.84) =back JPEG supports the spatial resolution tags C, C and C. You can also set the following tags when writing to an image, they are not set in the image when reading: =over C - set to a non-zero integer to compute optimal Huffman coding tables for the image. This will increase memory usage and processing time (about 12% in my simple tests) but can significantly reduce file size without a loss of quality. =back =for stopwords EXIF If an C block containing EXIF information is found, then any of the following tags can be set when reading a JPEG image: =over exif_aperture exif_artist exif_brightness exif_color_space exif_contrast exif_copyright exif_custom_rendered exif_date_time exif_date_time_digitized exif_date_time_original exif_digital_zoom_ratio exif_exposure_bias exif_exposure_index exif_exposure_mode exif_exposure_program exif_exposure_time exif_f_number exif_flash exif_flash_energy exif_flashpix_version exif_focal_length exif_focal_length_in_35mm_film exif_focal_plane_resolution_unit exif_focal_plane_x_resolution exif_focal_plane_y_resolution exif_gain_control exif_image_description exif_image_unique_id exif_iso_speed_rating exif_make exif_max_aperture exif_metering_mode exif_model exif_orientation exif_related_sound_file exif_resolution_unit exif_saturation exif_scene_capture_type exif_sensing_method exif_sharpness exif_shutter_speed exif_software exif_spectral_sensitivity exif_sub_sec_time exif_sub_sec_time_digitized exif_sub_sec_time_original exif_subject_distance exif_subject_distance_range exif_subject_location exif_tag_light_source exif_user_comment exif_version exif_white_balance exif_x_resolution exif_y_resolution =back The following derived tags can also be set when reading a JPEG image: =over exif_color_space_name exif_contrast_name exif_custom_rendered_name exif_exposure_mode_name exif_exposure_program_name exif_flash_name exif_focal_plane_resolution_unit_name exif_gain_control_name exif_light_source_name exif_metering_mode_name exif_resolution_unit_name exif_saturation_name exif_scene_capture_type_name exif_sensing_method_name exif_sharpness_name exif_subject_distance_range_name exif_white_balance_name =back The derived tags are for enumerated fields, when the value for the base field is valid then the text that appears in the EXIF specification for that value appears in the derived field. So for example if C is C<5> then C is set to C. eg. my $image = Imager->new; $image->read(file => 'exiftest.jpg') or die "Cannot load image: ", $image->errstr; print $image->tags(name => "exif_image_description"), "\n"; print $image->tags(name => "exif_exposure_mode"), "\n"; print $image->tags(name => "exif_exposure_mode_name"), "\n"; # for the exiftest.jpg in the Imager distribution the output would be: Imager Development Notes 0 Auto exposure Imager will not write EXIF tags to any type of image, if you need more advanced EXIF handling, consider L. =for stopwords IPTC =over =item parseiptc() Historically, Imager saves IPTC data when reading a JPEG image, the parseiptc() method returns a list of key/value pairs resulting from a simple decoding of that data. Any future IPTC data decoding is likely to go into tags. =back =head2 GIF When writing one of more GIF images you can use the same L as you can when converting an RGB image into a paletted image. When reading a GIF all of the sub-images are combined using the screen size and image positions into one big image, producing an RGB image. This may change in the future to produce a paletted image where possible. When you read a single GIF with C<$img-Eread()> you can supply a reference to a scalar in the C parameter, if the image is read the scalar will be filled with a reference to an anonymous array of L objects, representing the palette of the image. This will be the first palette found in the image. If you want the palettes for each of the images in the file, use C and use the C method on each image. GIF does not support the spatial resolution tags. Imager will set the following tags in each image when reading, and can use most of them when writing to GIF: =over =item * gif_left - the offset of the image from the left of the "screen" ("Image Left Position") =item * gif_top - the offset of the image from the top of the "screen" ("Image Top Position") =item * gif_interlace - non-zero if the image was interlaced ("Interlace Flag") =item * gif_screen_width, gif_screen_height - the size of the logical screen. When writing this is used as the minimum. If any image being written would extend beyond this then the screen size is extended. ("Logical Screen Width", "Logical Screen Height"). =item * gif_local_map - Non-zero if this image had a local color map. If set for an image when writing the image is quantized separately from the other images in the file. =item * gif_background - The index in the global color map of the logical screen's background color. This is only set if the current image uses the global color map. You can set this on write too, but for it to choose the color you want, you will need to supply only paletted images and set the C tag to 0. =item * gif_trans_index - The index of the color in the color map used for transparency. If the image has a transparency then it is returned as a 4 channel image with the alpha set to zero in this palette entry. This value is not used when writing. ("Transparent Color Index") =item * gif_trans_color - A reference to an Imager::Color object, which is the color to use for the palette entry used to represent transparency in the palette. You need to set the C option (see L) for this value to be used. =item * gif_delay - The delay until the next frame is displayed, in 1/100 of a second. ("Delay Time"). =item * gif_user_input - whether or not a user input is expected before continuing (view dependent) ("User Input Flag"). =item * gif_disposal - how the next frame is displayed ("Disposal Method") =item * gif_loop - the number of loops from the Netscape Loop extension. This may be zero to loop forever. =item * gif_comment - the first block of the first GIF comment before each image. =item * gif_eliminate_unused - If this is true, when you write a paletted image any unused colors will be eliminated from its palette. This is set by default. =item * gif_colormap_size - the original size of the color map for the image. The color map of the image may have been expanded to include out of range color indexes. =back Where applicable, the ("name") is the name of that field from the C standard. The following GIF writing options are obsolete, you should set the corresponding tag in the image, either by using the tags functions, or by supplying the tag and value as options. =over =item * gif_each_palette - Each image in the GIF file has it's own palette if this is non-zero. All but the first image has a local color table (the first uses the global color table. Use C in new code. =item * interlace - The images are written interlaced if this is non-zero. Use C in new code. =item * gif_delays - A reference to an array containing the delays between images, in 1/100 seconds. Use C in new code. =item * gif_positions - A reference to an array of references to arrays which represent screen positions for each image. New code should use the C and C tags. =item * gif_loop_count - If this is non-zero the Netscape loop extension block is generated, which makes the animation of the images repeat. This is currently unimplemented due to some limitations in C. =back You can supply a C parameter to the C method to read some page other than the first. The page is 0 based: # read the second image in the file $image->read(file=>"example.gif", page=>1) or die "Cannot read second page: ",$image->errstr,"\n"; Before release 0.46, Imager would read multiple image GIF image files into a single image, overlaying each of the images onto the virtual GIF screen. As of 0.46 the default is to read the first image from the file, as if called with C<< page => 0 >>. You can return to the previous behavior by calling read with the C parameter set to a true value: $img->read(file=>$some_gif_file, gif_consolidate=>1); As with the to_paletted() method, if you supply a colors parameter as a reference to an array, this will be filled with Imager::Color objects of the color table generated for the image file. =head2 TIFF (Tagged Image File Format) Imager can write images to either paletted or RGB TIFF images, depending on the type of the source image. When writing direct color images to TIFF the sample size of the output file depends on the input: =over =item * double/sample - written as 32-bit/sample TIFF =item * 16-bit/sample - written as 16-bit/sample TIFF =item * 8-bit/sample - written as 8-bit/sample TIFF =back For paletted images: =over =item * C<< $img->is_bilevel >> is true - the image is written as bi-level =item * otherwise - image is written as paletted. =back If you are creating images for faxing you can set the I parameter set to C. By default the image is written in fine mode, but this can be overridden by setting the I parameter to zero. Since a fax image is bi-level, Imager uses a threshold to decide if a given pixel is black or white, based on a single channel. For gray scale images channel 0 is used, for color images channel 1 (green) is used. If you want more control over the conversion you can use $img->to_paletted() to product a bi-level image. This way you can use dithering: my $bilevel = $img->to_paletted(make_colors => 'mono', translate => 'errdiff', errdiff => 'stucki'); =over =item * C - If set to 'fax' the image will be written as a bi-level fax image. =item * C - By default when C is set to 'fax' the image is written in fine mode, you can select normal mode by setting C to 0. =back Imager should be able to read any TIFF image you supply. Paletted TIFF images are read as paletted Imager images, since paletted TIFF images have 16-bits/sample (48-bits/color) this means the bottom 8-bits are lost, but this shouldn't be a big deal. TIFF supports the spatial resolution tags. See the C tag for some extra options. As of Imager 0.62 Imager reads: =over =item * 8-bit/sample gray, RGB or CMYK images, including a possible alpha channel as an 8-bit/sample image. =item * 16-bit gray, RGB, or CMYK image, including a possible alpha channel as a 16-bit/sample image. =item * 32-bit gray, RGB image, including a possible alpha channel as a double/sample image. =item * bi-level images as paletted images containing only black and white, which other formats will also write as bi-level. =item * tiled paletted images are now handled correctly =item * other images are read using C's RGBA interface as 8-bit/sample images. =back The following tags are set in a TIFF image when read, and can be set to control output: =over =item * C - When reading an image this is set to the numeric value of the TIFF compression tag. On writing you can set this to either a numeric compression tag value, or one of the following values: Ident Number Description none 1 No compression packbits 32773 Macintosh RLE ccittrle 2 CCITT RLE fax3 3 CCITT Group 3 fax encoding (T.4) t4 3 As above fax4 4 CCITT Group 4 fax encoding (T.6) t6 4 As above lzw 5 LZW jpeg 7 JPEG zip 8 Deflate (GZIP) Non-standard deflate 8 As above. oldzip 32946 Deflate with an older code. ccittrlew 32771 Word aligned CCITT RLE In general a compression setting will be ignored where it doesn't make sense, eg. C will be ignored for compression if the image is being written as bilevel. =for stopwords LZW Imager attempts to check that your build of C supports the given compression, and will fallback to C if it isn't enabled. eg. older distributions didn't include LZW compression, and JPEG compression is only available if C is configured with C's location. $im->write(file => 'foo.tif', tiff_compression => 'lzw') or die $im->errstr; =item * CC - If C is C then this can be a number from 1 to 100 giving the JPEG compression quality. High values are better quality and larger files. =item * XC - The value of the C tag. This is ignored on writing if the i_aspect_only tag is non-zero. The C and C tags are expressed in pixels per inch no matter the value of this tag, they will be converted to/from the value stored in the TIFF file. =item * XC - This is set when reading a TIFF file to the name of the unit given by C. Possible results include C, C, C (the C tag is also set reading these files) or C. =item * XC - Bits per sample from the image. This value is not used when writing an image, it is only set on a read image. =item * XC - Value of the C tag from the image. This value is not used when writing an image, it is only set on a read image. =item * C, C, C, C, C, C, C, C, C - Various strings describing the image. C must be formatted as "YYYY:MM:DD HH:MM:SS". These correspond directly to the mixed case names in the TIFF specification. These are set in images read from a TIFF and saved when writing a TIFF image. =back You can supply a C parameter to the C method to read some page other than the first. The page is 0 based: # read the second image in the file $image->read(file=>"example.tif", page=>1) or die "Cannot read second page: ",$image->errstr,"\n"; If you read an image with multiple alpha channels, then only the first alpha channel will be read. When reading a C image with callbacks, the C callback parameter is also required. When writing a C image with callbacks, the C and C parameters are also required. C is a random access file format, it cannot be read from or written to unseekable streams such as pipes or sockets. =head2 BMP (Windows Bitmap) Imager can write 24-bit RGB, and 8, 4 and 1-bit per pixel paletted Windows BMP files. Currently you cannot write compressed BMP files with Imager. Imager can read 24-bit RGB, and 8, 4 and 1-bit perl pixel paletted Windows BMP files. There is some support for reading 16-bit per pixel images, but I haven't found any for testing. BMP has no support for multiple image files. BMP files support the spatial resolution tags, but since BMP has no support for storing only an aspect ratio, if C is set when you write the C and C values are scaled so the smaller is 72 DPI. The following tags are set when you read an image from a BMP file: =over =item bmp_compression The type of compression, if any. This can be any of the following values: =for stopwords RLE =over =item BI_RGB (0) Uncompressed. =item BI_RLE8 (1) 8-bits/pixel paletted value RLE compression. =item BI_RLE4 (2) 4-bits/pixel paletted value RLE compression. =item BI_BITFIELDS (3) Packed RGB values. =back =item bmp_compression_name The bmp_compression value as a BI_* string =item bmp_important_colors The number of important colors as defined by the writer of the image. =item bmp_used_colors Number of color used from the BMP header =item bmp_filesize The file size from the BMP header =item bmp_bit_count Number of bits stored per pixel. (24, 8, 4 or 1) =back =for stopwords Targa =head2 TGA (Targa) When storing Targa images RLE compression can be activated with the C parameter, the C parameter can be used to set the Targa comment field and the C option can be used to use the 15 and 16 bit Targa formats for RGB and RGBA data. The 15 bit format has 5 of each red, green and blue. The 16 bit format in addition allows 1 bit of alpha. The most significant bits are used for each channel. Tags: =over =item tga_idstring =item tga_bitspp =item compressed =back =head2 RAW When reading raw images you need to supply the width and height of the image in the C and C options: $img->read(file=>'foo.raw', xsize=>100, ysize=>100) or die "Cannot read raw image\n"; If your input file has more channels than you want, or (as is common), junk in the fourth channel, you can use the C and C options to control the number of channels in your input file and the resulting channels in your image. For example, if your input image uses 32-bits per pixel with red, green, blue and junk values for each pixel you could do: $img->read(file=>'foo.raw', xsize => 100, ysize => 100, raw_datachannels => 4, raw_storechannels => 3, raw_interleave => 0) or die "Cannot read raw image\n"; In general, if you supply C you should also supply C Read parameters: =over =item * C - controls the ordering of samples within the image. Default: 1. Alternatively and historically spelled C. Possible values: =over =item * 0 - samples are pixel by pixel, so all samples for the first pixel, then all samples for the second pixel and so on. eg. for a four pixel scan line the channels would be laid out as: 012012012012 =item * 1 - samples are line by line, so channel 0 for the entire scan line is followed by channel 1 for the entire scan line and so on. eg. for a four pixel scan line the channels would be laid out as: 000011112222 This is the default. =back Unfortunately, historically, the default C for read has been 1, while writing only supports the C = 0 format. For future compatibility, you should always supply the C (or C) parameter. As of 0.68, Imager will warn if you attempt to read a raw image without a C parameter. =item * C - the number of channels to store in the image. Range: 1 to 4. Default: 3. Alternatively and historically spelled C. =item * C - the number of channels to read from the file. Range: 1 or more. Default: 3. Alternatively and historically spelled C. =back $img->read(file=>'foo.raw', xsize=100, ysize=>100, raw_interleave=>1) or die "Cannot read raw image\n"; =head2 PNG =head3 PNG Image modes PNG files can be read and written in the following modes: =over =item * bi-level - written as a 1-bit per sample gray scale image =item * paletted - Imager gray scale paletted images are written as RGB paletted images. PNG palettes can include alpha values for each entry and this is honored as an Imager four channel paletted image. =item * 8 and 16-bit per sample gray scale, optionally with an alpha channel. =item * 8 and 16-bit per sample RGB, optionally with an alpha channel. =back Unlike GIF, there is no automatic conversion to a paletted image, since PNG supports direct color. =head3 PNG Text tags Text tags are retrieved from and written to PNG C or C chunks. The following standard tags from the PNG specification are directly supported: =over =item * CX - keyword of "Comment". =item * CX - keyword "Author". =item * CX - keyword "Copyright". =item * CX - keyword "Creation Time". =item * CX - keyword "Description". =item * CX - keyword "Disclaimer". =item * CX - keyword "Software". =item * CX - keyword "Title". =item * CX - keyword "Warning". =back Each of these tags has a corresponding C<< I_compressed >> tag, eg. C. When reading, if the PNG chunk is compressed this tag will be set to 1, but is otherwise unset. When writing, Imager will honor the compression tag if set and non-zero, otherwise the chunk text will be compressed if the value is longer than 1000 characters, as recommended by the C documentation. PNG C or C chunks outside of those above are read into or written from Imager tags named like: =over =item * C<< png_textI_key >> - the key for the text chunk. This can be 1 to 79 characters, may not contain any leading, trailing or consecutive spaces, and may contain only Latin-1 characters from 32-126, 161-255. =item * C<< png_textI_text >> - the text for the text chunk. This may not contain any C characters. =item * C<< png_textI_compressed >> - whether or not the text chunk is compressed. This behaves similarly to the C<< I_compressed >> tags described above. =back Where I starts from 0. When writing both the C<..._key> and C<..._text> tags must be present or the write will fail. If the key or text do not satisfy the requirements above the write will fail. =head3 Other PNG metadata tags =over =item * XC, C - only set when reading, C is set to the type of interlacing used by the file, 0 for one, 1 for Adam7. C is set to a keyword describing the interlacing, either C or C. =item * XC - the sRGB rendering intent for the image. an integer from 0 to 3, per the PNG specification. If this chunk is found in the PNG file the C and C are ignored and the C and C tags are not set. Similarly when writing if C is set the C and C chunks are not written. =item * XC - the gamma of the image. This value is not currently used by Imager when processing the image, but this may change in the future. =item * XC, C, C, C, C, C, C, C - the primary chromaticities of the image, defining the color model. This is currently not used by Imager when processing the image, but this may change in the future. =item * C, C, C - processed per I. =item * XC - the number of bits per sample in the representation. Ignored when writing. =item * XC - the creation time of the file formatted as C<< I-I-ITI:I:I >>. This is stored as time data structure in the file, not a string. If you set C and it cannot be parsed as above, writing the PNG file will fail. =item * C - set from the C when reading an image file. =back =for stopwords CRC XIf you're using F 1.6 or later, or an earlier release configured with C, you can choose to ignore file format errors the authors of F consider I, this includes at least CRC errors and palette index overflows. Do this by supplying a true value for the C parameter to the read() method: $im->read(file => "foo.png", png_ignore_benign_errors => 1) or die $im->errstr; =head2 ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor) Icon and Cursor files are very similar, the only differences being a number in the header and the storage of the cursor hot spot. I've treated them separately so that you're not messing with tags to distinguish between them. The following tags are set when reading an icon image and are used when writing it: =over =item ico_mask This is the AND mask of the icon. When used as an icon in Windows 1 bits in the mask correspond to pixels that are modified by the source image rather than simply replaced by the source image. Rather than requiring a binary bitmap this is accepted in a specific format: =over =item * first line consisting of the 0 placeholder, the 1 placeholder and a newline. =item * following lines which contain 0 and 1 placeholders for each scan line of the image, starting from the top of the image. =back When reading an image, '.' is used as the 0 placeholder and '*' as the 1 placeholder. An example: .* ..........................****** ..........................****** ..........................****** ..........................****** ...........................***** ............................**** ............................**** .............................*** .............................*** .............................*** .............................*** ..............................** ..............................** ...............................* ...............................* ................................ ................................ ................................ ................................ ................................ ................................ *............................... **.............................. **.............................. ***............................. ***............................. ****............................ ****............................ *****........................... *****........................... *****........................... *****........................... =back The following tags are set when reading an icon: =over =item ico_bits The number of bits per pixel used to store the image. =back For cursor files the following tags are set and read when reading and writing: =over =item cur_mask This is the same as the ico_mask above. =item cur_hotspotx =item cur_hotspoty The "hot" spot of the cursor image. This is the spot on the cursor that you click with. If you set these to out of range values they are clipped to the size of the image when written to the file. =back The following parameters can be supplied to read() or read_multi() to control reading of ICO/CUR files: =over =item * C - if true, the default, then the icon/cursors mask is applied as an alpha channel to the image, unless that image already has an alpha channel. This may result in a paletted image being returned as a direct color image. Default: 1 # retrieve the image as stored, without using the mask as an alpha # channel $img->read(file => 'foo.ico', ico_masked => 0) or die $img->errstr; This was introduced in Imager 0.60. Previously reading ICO images acted as if C 0>. =item * C - if true, then the icon/cursor mask is applied as an alpha channel to images that already have an alpha mask. Note that this will only make pixels transparent, not opaque. Default: 0. Note: If you get different results between C being set to 0 and 1, your mask may broke when used with the Win32 API. =back C is set when reading a cursor. Examples: my $img = Imager->new(xsize => 32, ysize => 32, channels => 4); $im->box(color => 'FF0000'); $im->write(file => 'box.ico'); $im->settag(name => 'cur_hotspotx', value => 16); $im->settag(name => 'cur_hotspoty', value => 16); $im->write(file => 'box.cur'); =for stopwords BW =head2 SGI (RGB, BW) SGI images, often called by the extensions, RGB or BW, can be stored either uncompressed or compressed using an RLE compression. By default, when saving to an extension of C, C, C, C the file will be saved in SGI format. The file extension is otherwise ignored, so saving a 3-channel image to a C<.bw> file will result in a 3-channel image on disk. The following tags are set when reading a SGI image: =over =item * i_comment - the C field from the image. Also written to the file when writing. =item * sgi_pixmin, sgi_pixmax - the C and C fields from the image. On reading image data is expanded from this range to the full range of samples in the image. =item * sgi_bpc - the number of bytes per sample for the image. Ignored when writing. =item * sgi_rle - whether or not the image is compressed. If this is non-zero when writing the image will be compressed. =back =head1 ADDING NEW FORMATS To support a new format for reading, call the register_reader() class method: =over =item register_reader() Registers single or multiple image read functions. Parameters: =over =item * type - the identifier of the file format, if Imager's i_test_format_probe() can identify the format then this value should match i_test_format_probe()'s result. This parameter is required. =item * single - a code ref to read a single image from a file. This is supplied: =over =item * the object that read() was called on, =item * an Imager::IO object that should be used to read the file, and =item * all the parameters supplied to the read() method. =back The single parameter is required. =item * multiple - a code ref which is called to read multiple images from a file. This is supplied: =over =item * an Imager::IO object that should be used to read the file, and =item * all the parameters supplied to the read_multi() method. =back =back Example: # from Imager::File::ICO Imager->register_reader ( type=>'ico', single => sub { my ($im, $io, %hsh) = @_; $im->{IMG} = i_readico_single($io, $hsh{page} || 0); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, multiple => sub { my ($io, %hsh) = @_; my @imgs = i_readico_multi($io); unless (@imgs) { Imager->_set_error(Imager->_error_as_msg); return; } return map { bless { IMG => $_, DEBUG => $Imager::DEBUG, ERRSTR => undef }, 'Imager' } @imgs; }, ); =item register_writer() Registers single or multiple image write functions. Parameters: =over =item * type - the identifier of the file format. This is typically the extension in lowercase. This parameter is required. =item * single - a code ref to write a single image to a file. This is supplied: =over =item * the object that write() was called on, =item * an Imager::IO object that should be used to write the file, and =item * all the parameters supplied to the write() method. =back The single parameter is required. =item * multiple - a code ref which is called to write multiple images to a file. This is supplied: =over =item * the class name write_multi() was called on, this is typically C. =item * an Imager::IO object that should be used to write the file, and =item * all the parameters supplied to the read_multi() method. =back =back =back If you name the reader module CI where I is a fully upper case version of the type value you would pass to read(), read_multi(), write() or write_multi() then Imager will attempt to load that module if it has no other way to read or write that format. For example, if you create a module Imager::File::GIF and the user has built Imager without it's normal GIF support then an attempt to read a GIF image will attempt to load Imager::File::GIF. If your module can only handle reading then you can name your module CIC and Imager will attempt to autoload it. If your module can only handle writing then you can name your module CIC and Imager will attempt to autoload it. =head1 PRELOADING FILE MODULES =over =item preload() This preloads the file support modules included with or that have been included with Imager in the past. This is intended for use in forking servers such as mod_perl. If the module is not available no error occurs. Preserves $@. use Imager; Imager->preload; =back =head1 EXAMPLES =head2 Producing an image from a CGI script Once you have an image the basic mechanism is: =for stopwords STDOUT =over =item 1. set STDOUT to autoflush =item 2. output a content-type header, and optionally a content-length header =item 3. put STDOUT into binmode =item 4. call write() with the C or C parameter. You will need to provide the C parameter since Imager can't use the extension to guess the file format you want. =back # write an image from a CGI script # using CGI.pm use CGI qw(:standard); $| = 1; binmode STDOUT; print header(-type=>'image/gif'); $img->write(type=>'gif', fd=>fileno(STDOUT)) or die $img->errstr; If you want to send a content length you can send the output to a scalar to get the length: my $data; $img->write(type=>'gif', data=>\$data) or die $img->errstr; binmode STDOUT; print header(-type=>'image/gif', -content_length=>length($data)); print $data; =head2 Writing an animated GIF The basic idea is simple, just use write_multi(): my @imgs = ...; Imager->write_multi({ file=>$filename, type=>'gif' }, @imgs); If your images are RGB images the default quantization mechanism will produce a very good result, but can take a long time to execute. You could either use the standard web color map: Imager->write_multi({ file=>$filename, type=>'gif', make_colors=>'webmap' }, @imgs); or use a median cut algorithm to built a fairly optimal color map: Imager->write_multi({ file=>$filename, type=>'gif', make_colors=>'mediancut' }, @imgs); By default all of the images will use the same global color map, which will produce a smaller image. If your images have significant color differences, you may want to generate a new palette for each image: Imager->write_multi({ file=>$filename, type=>'gif', make_colors=>'mediancut', gif_local_map => 1 }, @imgs); which will set the C tag in each image to 1. Alternatively, if you know only some images have different colors, you can set the tag just for those images: $imgs[2]->settag(name=>'gif_local_map', value=>1); $imgs[4]->settag(name=>'gif_local_map', value=>1); and call write_multi() without a C parameter, or supply an arrayref of values for the tag: Imager->write_multi({ file=>$filename, type=>'gif', make_colors=>'mediancut', gif_local_map => [ 0, 0, 1, 0, 1 ] }, @imgs); Other useful parameters include C to control the delay between frames and C to control transparency. =head2 Reading tags after reading an image This is pretty simple: # print the author of a TIFF, if any my $img = Imager->new; $img->read(file=>$filename, type='tiff') or die $img->errstr; my $author = $img->tags(name=>'tiff_author'); if (defined $author) { print "Author: $author\n"; } =head1 BUGS When saving GIF images the program does NOT try to shave off extra colors if it is possible. If you specify 128 colors and there are only 2 colors used - it will have a 128 color table anyway. =head1 SEE ALSO Imager(3) =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Transformations.pod0000644000175000017500000006661612263740601023450 0ustar gregoagregoa=head1 NAME Imager::Transformations - Simple transformations of one image into another. =head1 SYNOPSIS use Imager; $newimg = $img->copy(); $newimg = $img->scale(xpixels=>400, qtype => 'mixing'); $newimg = $img->scale(xpixels=>400, ypixels=>400); $newimg = $img->scale(xpixels=>400, ypixels=>400, type=>'min'); $newimg = $img->scale(scalefactor=>0.25); $newimg = $img->scaleX(pixels=>400); $newimg = $img->scaleX(scalefactor=>0.25); $newimg = $img->scaleY(pixels=>400); $newimg = $img->scaleY(scalefactor=>0.25); $newimg = $img->crop(left=>50, right=>100, top=>10, bottom=>100); $newimg = $img->crop(left=>50, top=>10, width=>50, height=>90); $dest->paste(left=>40,top=>20,img=>$logo); $img->rubthrough(src=>$srcimage,tx=>30, ty=>50); $img->rubthrough(src=>$srcimage,tx=>30, ty=>50, src_minx=>20, src_miny=>30, src_maxx=>20, src_maxy=>30); $img->compose(src => $src, tx => 30, ty => 20, combine => 'color'); $img->compose(src => $src, tx => 30, ty => 20, combine => 'color'); mask => $mask, opacity => 0.5); $img->flip(dir=>"h"); # horizontal flip $img->flip(dir=>"vh"); # vertical and horizontal flip $newimg = $img->copy->flip(dir=>"v"); # make a copy and flip it vertically my $rot20 = $img->rotate(degrees=>20); my $rotpi4 = $img->rotate(radians=>3.14159265/4); # Convert image to gray $new = $img->convert(preset=>'grey'); # Swap red/green channel $new = $img->convert(matrix=>[ [ 0, 1, 0 ], [ 1, 0, 0 ], [ 0, 0, 1 ] ]); # build an image using channels from multiple input images $new = $img->combine(src => [ $im1, $im2, $im3 ]); $new = $img->combine(src => [ $im1, $im2, $im3 ], channels => [ 2, 1, 0 ]); # limit the range of red channel from 0..255 to 0..127 @map = map { int( $_/2 } 0..255; $img->map( red=>\@map ); # Apply a Gamma of 1.4 my $gamma = 1.4; my @map = map { int( 0.5 + 255*($_/255)**$gamma ) } 0..255; $img->map(all=>\@map); # inplace conversion =head1 DESCRIPTION The methods described in Imager::Transformations fall into two categories. Either they take an existing image and modify it in place, or they return a modified copy. Functions that modify inplace are C, C, C and C. If the original is to be left intact it's possible to make a copy and alter the copy: $flipped = $img->copy()->flip(dir=>'h'); =head2 Image copying/resizing/cropping/rotating A list of the transformations that do not alter the source image follows: =over =item copy() To create a copy of an image use the C method. This is useful if you want to keep an original after doing something that changes the image. $newimg = $orig->copy(); =item scale() XTo scale an image so proportions are maintained use the C<$img-Escale()> method. if you give either a C or C parameter they will determine the width or height respectively. If both are given the one resulting in a larger image is used, unless you set the C parameter to C<'min'>. example: C<$img> is 700 pixels wide and 500 pixels tall. $newimg = $img->scale(xpixels=>400); # 400x285 $newimg = $img->scale(ypixels=>400); # 560x400 $newimg = $img->scale(xpixels=>400,ypixels=>400); # 560x400 $newimg = $img->scale(xpixels=>400,ypixels=>400,type=>'min'); # 400x285 $newimg = $img->scale(xpixels=>400, ypixels=>400),type=>'nonprop'); # 400x400 $newimg = $img->scale(scalefactor=>0.25); 175x125 $newimg = $img->scale(); # 350x250 If you want to create low quality previews of images you can pass C'preview'> to scale and it will use nearest neighbor sampling instead of filtering. It is much faster but also generates worse looking images - especially if the original has a lot of sharp variations and the scaled image is by more than 3-5 times smaller than the original. =over =item * C, C - desired size of the scaled image. The C parameter controls whether the larger or smaller of the two possible sizes is chosen, or if the image is scaled non-proportionally. =item * C - an Image::Math::Constrain object defining the way in which the image size should be constrained. =item * C - if none of C, C, C, C or C is supplied then this is used as the ratio to scale by. Default: 0.5. =item * C, C - if both are supplied then the image is scaled as per these parameters, whether this is proportionally or not. New in Imager 0.54. =item * C - controls whether the larger or smaller of the two possible sizes is chosen, possible values are: =over =item * C - the smaller of the 2 sizes are chosen. =item * C - the larger of the 2 sizes. This is the default. =item * C - non-proportional scaling. New in Imager 0.54. =back scale() will fail if C is set to some other value. For example, if the original image is 400 pixels wide by 200 pixels high and C is set to 300, and C is set to 160. When C is C<'min'> the resulting image is 300 x 150, when C is C<'max'> the resulting image is 320 x 160. C is only used if both C and C are supplied. =item * C - defines the quality of scaling performed. Possible values are: =over =item * C - high quality scaling. This is the default. =item * C - lower quality. When scaling down this will skip input pixels, eg. scaling by 0.5 will skip every other pixel. When scaling up this will duplicate pixels. =item * C - implements the mixing algorithm implemented by F. This retains more detail when scaling down than C. When scaling down this proportionally accumulates sample data from the pixels, resulting in a proportional mix of all of the pixels. When scaling up this will mix pixels when the sampling grid crosses a pixel boundary but will otherwise copy pixel values. =back scale() will fail if C is set to some other value. C is faster than C which is much faster than C. =back To scale an image on a given axis without maintaining proportions, it is best to call the scaleX() and scaleY() methods with the required dimensions. eg. my $scaled = $img->scaleX(pixels=>400)->scaleY(pixels=>200); From Imager 0.54 you can scale without maintaining proportions either by supplying both the C and C arguments: my $scaled = $img->scale(xscalefactor => 0.5, yscalefactor => 0.67); or by supplying C and C and setting C to : my $scaled = $im->scale(xpixels => 200, ypixels => 200, type => 'nonprop'); Returns a new scaled image on success. The source image is not modified. Returns false on failure, check the errstr() method for the reason for failure. A mandatory warning is produced if scale() is called in void context. # setup my $image = Imager->new; $image->read(file => 'somefile.jpg') or die $image->errstr; # all full quality unless indicated otherwise # half the size: my $half = $image->scale; # double the size my $double = $image->scale(scalefactor => 2.0); # so a 400 x 400 box fits in the resulting image: my $fit400x400inside = $image->scale(xpixels => 400, ypixels => 400); my $fit400x400inside2 = $image->scale(xpixels => 400, ypixels => 400, type=>'max'); # fit inside a 400 x 400 box my $inside400x400 = $image->scale(xpixels => 400, ypixels => 400, type=>'min'); # make it 400 pixels wide or high my $width400 = $image->scale(xpixels => 400); my $height400 = $image->scale(ypixels => 400); # low quality scales: # to half size my $low = $image->scale(qtype => 'preview'); # mixing method scale my $mixed = $image->scale(qtype => 'mixing', scalefactor => 0.1); # using an Image::Math::Constrain object use Image::Math::Constrain; my $constrain = Image::Math::Constrain->new(800, 600); my $scaled = $image->scale(constrain => $constrain); # same as Image::Math::Constrain version my $scaled2 = $image->scale(xpixels => 800, ypixels => 600, type => 'min'); =item scaleX() scaleX() will scale along the X dimension, return a new image with the new width: my $newimg = $img->scaleX(pixels=>400); # 400x500 $newimg = $img->scaleX(scalefactor=>0.25) # 175x500 =over =item * C - the amount to scale the X axis. Ignored if C is provided. Default: 0.5. =item * C - the new width of the image. =back Returns a new scaled image on success. The source image is not modified. Returns false on failure, check the errstr() method for the reason for failure. A mandatory warning is produced if scaleX() is called in void context. =item scaleY() scaleY() will scale along the Y dimension, return a new image with the new height: $newimg = $img->scaleY(pixels=>400); # 700x400 $newimg = $img->scaleY(scalefactor=>0.25) # 700x125 =over =item * C - the amount to scale the Y axis. Ignored if C is provided. Default: 0.5. =item * C - the new height of the image. =back Returns a new scaled image on success. The source image is not modified. Returns false on failure, check the errstr() method for the reason for failure. A mandatory warning is produced if scaleY() is called in void context. =item scale_calculate() Performs the same calculations that the scale() method does to calculate the scaling factors from the parameters you pass. scale_calculate() can be called as an object method, or as a class method. Takes the following parameters over scale(): =over =item * C, C - the image width and height to base the scaling on. Required if scale_calculate() is called as a class method. If called as an object method these default to the image width and height respectively. =back You might use scale_calculate() as a class method when generating an HTML C tag, for example. Returns an empty list on failure. Returns a list containing horizontal scale factor, vertical scale factor, new width, new height, on success. my ($x_scale, $y_scale, $new_width, $new_height) = Imager->scale_calculate(width => 1024, height => 768, ypixels => 180, type => 'min'); my ($x_scale, $y_scale, $new_width, $new_height) = $img->scale_calculate(xpixels => 200, type => 'min'); =item crop() =for stopwords resize Another way to resize an image is to crop it. The parameters to crop are the edges of the area that you want in the returned image, where the right and bottom edges are non-inclusive. If a parameter is omitted a default is used instead. crop() returns the cropped image and does not modify the source image. The possible parameters are: =over =item * C - the left edge of the area to be cropped. Default: 0 =item * C - the top edge of the area to be cropped. Default: 0 =item * C - the right edge of the area to be cropped. Default: right edge of image. =item * C - the bottom edge of the area to be cropped. Default: bottom edge of image. =item * C - width of the crop area. Ignored if both C and C are supplied. Centered on the image if neither C nor C are supplied. =item * C - height of the crop area. Ignored if both C and C are supplied. Centered on the image if neither C nor C are supplied. =back For example: # these produce the same image $newimg = $img->crop(left=>50, right=>100, top=>10, bottom=>100); $newimg = $img->crop(left=>50, top=>10, width=>50, height=>90); $newimg = $img->crop(right=>100, bottom=>100, width=>50, height=>90); # and the following produce the same image $newimg = $img->crop(left=>50, right=>100); $newimg = $img->crop(left=>50, right=>100, top=>0, bottom=>$img->getheight); # grab the top left corner of the image $newimg = $img->crop(right=>50, bottom=>50); You can also specify width and height parameters which will produce a new image cropped from the center of the input image, with the given width and height. $newimg = $img->crop(width=>50, height=>50); If you supply C, C and C values, the C value will be ignored. If you supply C, C and C values, the C value will be ignored. The edges of the cropped area default to the edges of the source image, for example: # a vertical bar from the middle from top to bottom $newimg = $img->crop(width=>50); # the right half $newimg = $img->crop(left=>$img->getwidth() / 2); If the resulting image would have zero width or height then crop() returns false and $img->errstr is an appropriate error message. A mandatory warning is produced if crop() is called in void context. =item rotate() Use the rotate() method to rotate an image. This method will return a new, rotated image. To rotate by an exact amount in degrees or radians, use the 'degrees' or 'radians' parameter: my $rot20 = $img->rotate(degrees=>20); my $rotpi4 = $img->rotate(radians=>3.14159265/4); Exact image rotation uses the same underlying transformation engine as the matrix_transform() method (see Imager::Engines). You can also supply a C argument which acts as a background color for the areas of the image with no samples available (outside the rectangle of the source image.) This can be either an Imager::Color or Imager::Color::Float object. This is B mixed transparent pixels in the middle of the source image, it is B used for pixels where there is no corresponding pixel in the source image. To rotate in steps of 90 degrees, use the 'right' parameter: my $rotated = $img->rotate(right=>270); Rotations are clockwise for positive values. Parameters: =over =item * C - rotate by an exact multiple of 90 degrees, specified in degrees. =item * C - rotate by an angle specified in radians. =item * C - rotate by an angle specified in degrees. =item * C - for C and C this is the color used for the areas not covered by the original image. For example, the corners of an image rotated by 45 degrees. This can be either an Imager::Color object, an Imager::Color::Float object or any parameter that Imager can convert to a color object, see L for details. This is B mixed transparent pixels in the middle of the source image, it is B used for pixels where there is no corresponding pixel in the source image. Default: transparent black. =back # rotate 45 degrees clockwise, my $rotated = $img->rotate(degrees => 45); # rotate 10 degrees counter-clockwise # set pixels not sourced from the original to red my $rotated = $img->rotate(degrees => -10, back => 'red'); =back =head2 Image pasting/flipping A list of the transformations that alter the source image follows: =over =item paste() XTo copy an image to onto another image use the C method. $dest->paste(left=>40, top=>20, src=>$logo); That copies the entire C<$logo> image onto the C<$dest> image so that the upper left corner of the C<$logo> image is at (40,20). Parameters: =over =item * C, C - the source image. C added for compatibility with rubthrough(). =item * C, C - position in output of the top left of the pasted image. Default: (0,0) =item * C, C - the top left corner in the source image to start the paste from. Default: (0, 0) =item * C, C - the bottom right in the source image of the sub image to paste. This position is B inclusive. Default: bottom right corner of the source image. =item * C, C - if the corresponding src_maxx or src_maxy is not defined then width or height is used for the width or height of the sub image to be pasted. =back # copy the 20x20 pixel image from (20,20) in $src_image to (10,10) in $img $img->paste(src=>$src_image, left => 10, top => 10, src_minx => 20, src_miny => 20, src_maxx => 40, src_maxx => 40); If the source image has an alpha channel and the target doesn't, then the source is treated as if composed onto a black background. If the source image is color and the target is gray scale, the source is treated as if run through C<< convert(preset=>'gray') >>. =item rubthrough() A more complicated way of blending images is where one image is put 'over' the other with a certain amount of opaqueness. The method that does this is rubthrough(). $img->rubthrough(src=>$overlay, tx=>30, ty=>50, src_minx=>20, src_miny=>30, src_maxx=>20, src_maxy=>30); That will take the sub image defined by I<$overlay> and I<[src_minx,src_maxx)[src_miny,src_maxy)> and overlay it on top of I<$img> with the upper left corner at (30,50). You can rub 2 or 4 channel images onto a 3 channel image, or a 2 channel image onto a 1 channel image. The last channel is used as an alpha channel. To add an alpha channel to an image see I. Parameters: =over =item * C, C - location in the target image ($self) to render the top left corner of the source. =item * C, C - the top left corner in the source to transfer to the target image. Default: (0, 0). =item * C, C - the bottom right in the source image of the sub image to overlay. This position is B inclusive. Default: bottom right corner of the source image. =back # overlay all of $source onto $targ $targ->rubthrough(tx => 20, ty => 25, src => $source); # overlay the top left corner of $source onto $targ $targ->rubthrough(tx => 20, ty => 25, src => $source, src_maxx => 20, src_maxy => 20); # overlay the bottom right corner of $source onto $targ $targ->rubthrough(tx => 20, ty => 30, src => $src, src_minx => $src->getwidth() - 20, src_miny => $src->getheight() - 20); rubthrough() returns true on success. On failure check C<< $target->errstr >> for the reason for failure. =item compose() Draws the source image over the target image, with the source alpha channel modified by the optional mask and the opacity. $img->compose(src=>$overlay, tx=>30, ty=>50, src_minx=>20, src_miny=>30, src_maxx=>20, src_maxy=>30, mask => $mask, opacity => 0.5); That will take the sub image defined by I<$overlay> and I<[src_minx,src_maxx)[src_miny,src_maxy)> and overlay it on top of I<$img> with the upper left corner at (30,50). You can rub 2 or 4 channel images onto a 3 channel image, or a 2 channel image onto a 1 channel image. Parameters: =over =item * C - the source image to draw onto the target. Required. =item * C, C - location in the target image ($self) to render the top left corner of the source. These can also be supplied as C and C. Default: (0, 0). =item * C, C - the top left corner in the source to transfer to the target image. Default: (0, 0). =item * C, C - the bottom right in the source image of the sub image to overlay. This position is B inclusive. Default: bottom right corner of the source image. =item * C - a mask image. The first channel of this image is used to modify the alpha channel of the source image. This can be used to mask out portions of the source image. Where the first channel is zero none of the source image will be used, where the first channel is maximum the full alpha of the source image will be used, as further modified by the opacity. =item * opacity - further modifies the alpha channel of the source image, in the range 0.0 to 1.0. Default: 1.0. =item * combine - the method to combine the source pixels with the target. See the combine option documentation in Imager::Fill. Default: normal. =back Calling compose() with no mask, combine set to C, opacity set to C<1.0> is equivalent to calling rubthrough(). compose() is intended to be produce similar effects to layers in interactive paint software. # overlay all of $source onto $targ $targ->compose(tx => 20, ty => 25, src => $source); # overlay the top left corner of $source onto $targ $targ->compose(tx => 20, ty => 25, src => $source, src_maxx => 20, src_maxy => 20); # overlay the bottom right corner of $source onto $targ $targ->compose(tx => 20, ty => 30, src => $src, src_minx => $src->getwidth() - 20, src_miny => $src->getheight() - 20); compose() returns true on success. On failure check $target->errstr for the reason for failure. =item flip() An inplace horizontal or vertical flip is possible by calling the C method. If the original is to be preserved it's possible to make a copy first. The only parameter it takes is the C parameter which can take the values C, C, C and C. $img->flip(dir=>"h"); # horizontal flip $img->flip(dir=>"vh"); # vertical and horizontal flip $nimg = $img->copy->flip(dir=>"v"); # make a copy and flip it vertically flip() returns true on success. On failure check $img->errstr for the reason for failure. =back =head2 Color transformations =over =item convert() You can use the convert method to transform the color space of an image using a matrix. For ease of use some presets are provided. The convert method can be used to: =over =item * convert an RGB or RGBA image to gray scale. =item * convert a gray scale image to RGB. =item * extract a single channel from an image. =item * set a given channel to a particular value (or from another channel) =back The currently defined presets are: =over =item * C, C - converts an RGBA image into a gray scale image with alpha channel, or an RGB image into a gray scale image without an alpha channel. This weights the RGB channels at 22.2%, 70.7% and 7.1% respectively. =item * C - removes the alpha channel from a 2 or 4 channel image. An identity for other images. =item * C, C - extracts the first channel of the image into a single channel image =item * C, C - extracts the second channel of the image into a single channel image =item * C, C - extracts the third channel of the image into a single channel image =item * C - extracts the alpha channel of the image into a single channel image. If the image has 1 or 3 channels (assumed to be gray scale or RGB) then the resulting image will be all white. =item * C converts a gray scale image to RGB, preserving the alpha channel if any =item * C - adds an alpha channel to a gray scale or RGB image. Preserves an existing alpha channel for a 2 or 4 channel image. =back For example, to convert an RGB image into a gray scale image: $new = $img->convert(preset=>'grey'); # or gray or to convert a gray scale image to an RGB image: $new = $img->convert(preset=>'rgb'); The presets aren't necessary simple constants in the code, some are generated based on the number of channels in the input image. If you want to perform some other color transformation, you can use the 'matrix' parameter. For each output pixel the following matrix multiplication is done: | channel[0] | | $c00, ..., $c0k | | inchannel[0] | | ... | = | ... | x | ... | | channel[k] | | $ck0, ..., $ckk | | inchannel[k] | 1 Where Cgetchannels()-1>. So if you want to swap the red and green channels on a 3 channel image: $new = $img->convert(matrix=>[ [ 0, 1, 0 ], [ 1, 0, 0 ], [ 0, 0, 1 ] ]); or to convert a 3 channel image to gray scale using equal weightings: $new = $img->convert(matrix=>[ [ 0.333, 0.333, 0.334 ] ]) Convert a 2 channel image (gray scale with alpha) to an RGBA image with the gray converted to the specified RGB color: # set (RGB) scaled on the grey scale portion and copy the alpha # channel as is my $colored = $gray->convert(matrix=>[ [ ($red/255), 0 ], [ ($green/255), 0 ], [ ($blue/255), 0 ], [ 0, 1 ], ]); To convert a 3 channel image to a 4 channel image with a 50 percent alpha channel: my $withalpha = $rgb->convert(matrix =>[ [ 1, 0, 0, 0 ], [ 0, 1, 0, 0 ], [ 0, 0, 1, 0 ], [ 0, 0, 0, 0.5 ], ]); =item combine() X Combine channels from one or more input images into a new image. Parameters: =over =item * C - a reference to an array of input images. There must be at least one input image. A given image may appear more than once in C. =item * C - a reference to an array of channels corresponding to the source images. If C is not supplied then the first channel from each input image is used. If the array referenced by C is shorter than that referenced by C then the first channel is used from the extra images. =back # make an rgb image from red, green, and blue images my $rgb = Imager->combine(src => [ $red, $green, $blue ]); # convert a BGR image into RGB my $rgb = Imager->combine(src => [ $bgr, $bgr, $bgr ], channels => [ 2, 1, 0 ]); # add an alpha channel from another image my $rgba = Imager->combine(src => [ $rgb, $rgb, $rgb, $alpha ], channels => [ 0, 1, 2, 0 ]); =back =head2 Color Mappings =over =item map() You can use the map method to map the values of each channel of an image independently using a list of look-up tables. It's important to realize that the modification is made inplace. The function simply returns the input image again or undef on failure. Each channel is mapped independently through a look-up table with 256 entries. The elements in the table should not be less than 0 and not greater than 255. If they are out of the 0..255 range they are clamped to the range. If a table does not contain 256 entries it is silently ignored. Single channels can mapped by specifying their name and the mapping table. The channel names are C, C, C, C. @map = map { int( $_/2 } 0..255; $img->map( red=>\@map ); It is also possible to specify a single map that is applied to all channels, alpha channel included. For example this applies a gamma correction with a gamma of 1.4 to the input image. $gamma = 1.4; @map = map { int( 0.5 + 255*($_/255)**$gamma ) } 0..255; $img->map(all=> \@map); The C map is used as a default channel, if no other map is specified for a channel then the C map is used instead. If we had not wanted to apply gamma to the alpha channel we would have used: $img->map(all=> \@map, alpha=>[]); Since C<[]> contains fewer than 256 element the gamma channel is unaffected. It is also possible to simply specify an array of maps that are applied to the images in the RGBA order. For example to apply maps to the C and C channels one would use: $img->map(maps=>[\@redmap, [], \@bluemap]); =back =head1 SEE ALSO L, L =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Cookbook.pod0000644000175000017500000003614212263740601022014 0ustar gregoagregoa=head1 NAME Imager::Cookbook - recipes working with Imager =head1 DESCRIPTION Various simple and not so simple ways to do things with Imager. =head1 FILES This is described in detail in L. =head2 Reading an image from a file my $image = Imager->new; $image->read(file=>$filename) or die $image->errstr; Or: my $image = Imager->new(file => $filename) or die Imager->errstr; See L. =head2 Writing an image to a file $image->write(file=>$filename) or die $image->errstr; =head2 Write an animated GIF # build an array of images to use in the gif my @images; # synthesize the images or read them from files, it doesn't matter ... # write the gif Imager->write_multi({ file=>$filename, type=>'gif' }, @images) or die Imager->errstr; See L for a more detailed example. =head2 Reading multiple images from one file Some formats, like GIF and TIFF support multiple images per file. Use the L method to read them: my @images = Imager->read_multi(file=>$filename) or die Imager->errstr; =head2 Converting from one file format to another This is as simple as reading the original file and writing the new file, for single images: my $image = Imager->new; # Imager auto-detects the input file type $image->read(file => $input_filename) or die $image->errstr; # Imager derives the output file format from the filename $image->write(file => $output_filename) or die $image->errstr; # or you can supply a type parameter: $image->write(file => $output_filename, type => 'gif') or die $image->errstr; The main issue that can occur with this is if the input file has transparency and the output file format doesn't support that. This can be a problem when converting from GIF files to JPEG files for example. By default, if the output format doesn't support transparency, Imager will compose the image onto a black background. You can override that by supplying an C option to C or C: $image->write(file => "foo.jpg", i_background => "#808080") or die $image->errstr; Some formats support multiple files, so if you want to convert from say TIFF to JPEG, you'll need multiple output files: my @images = Imager->read_multi(file => 'input.tif') or die Imager->errstr; my $index = 1; for my $image (@images) { $image->write(file => sprintf('output%02d.jpg', $index++)) or die $image->errstr; } =head2 Transparent PNG To save to a transparent PNG (or GIF or TIFF) you need to start with an image with transparency. To make a transparent image, create an image object with 2 or 4 channels: # RGB with alpha channel my $rgba = Imager->new(xsize => $width, ysize => $height, channels => 4); # Gray with alpha channel my $graya = Imager->new(xsize => $width, ysize => $height, channels => 2); By default, the created image will be transparent. Otherwise, if you have an existing image file with transparency, simply read it, and the transparency will be preserved. =head1 IMAGE SYNTHESIS =head2 Creating an image To create a simple RGB image, supply the image width and height to the new() method: my $rgb = Imager->new(xsize=>$width, ysize=>$height); If you also want an alpha channel: my $rgb_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>4); To make a gray-scale image: my $gray = Imager->new(xsize=>$width, ysize=>$height, channels=>1); and a gray-scale image with an alpha channel: my $gray_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>2); When a new image is created this way all samples are set to zero - black for 1 or 3 channel images, transparent black for 2 or 4 channel images. You can also create paletted images and images with more than 8-bits per channel, see L for more details. =head2 Setting the background of a new image To set the background of a new image to a solid color, use the box() method with no limits, and C<< filled=>1 >>: $image->box(filled=>1, color=>$color); As always, a color can be specified as an L object: my $white = Imager::Color->new(255, 255, 255); $image->box(filled=>1, color=>$white); or you supply any single scalar that Imager::Color's new() method accepts as a color description: $image->box(filled=>1, color=>'white'); $image->box(filled=>1, color=>'#FF0000'); $image->box(filled=>1, color=>[ 255, 255, 255 ]); You can also fill the image with a fill object: use Imager::Fill; # create the fill object my $fill = Imager::Fill->new(hatch=>'check1x1') $image->box(fill=>$fill); # let Imager create one automatically $image->box(fill=>{ hatch=>'check1x1' }); See L for information on Imager's fill objects. =head1 WORLD WIDE WEB As with any CGI script it's up to you to validate data and set limits on any parameters supplied to Imager. For example, if you allow the caller to set the size of an output image you should limit the size to prevent the client from specifying an image size that will consume all available memory. This is beside any other controls you need over access to data. See L for a module useful for processing CGI submitted data. =head2 Returning an image from a CGI script This is similar to writing to a file, but you also need to supply the information needed by the web browser to identify the file format: my $img = ....; # create the image and generate the contents ++$|; # make sure the content type isn't buffered print "Content-Type: image/png\n\n"; binmode STDOUT; $img->write(fd=>fileno(STDOUT), type=>'png') or die $img->errstr; You need to set the Content-Type header depending on the file format you send to the web browser. If you want to supply a content-length header, write the image to a scalar as a buffer: my $img = ....; # create the image and generate the contents my $data; $img->write(type=>'png', data=>\$data) or die $img->errstr; print "Content-Type: image/png\n"; print "Content-Length: ",length($data),"\n\n"; binmode STDOUT; print $data; See C and C for a couple of simple examples of producing an image from CGI. =head2 Inserting a CGI image in a page There's occasionally confusion on how to display an image generated by Imager in a page generated by a CGI. Your web browser handles this process as two requests, one for the HTML page, and another for the image itself. Each request needs to perform validation since an attacker can control the values supplied to both requests. How you make the data available to the image generation code depends on your application. See C and C in the Imager distribution for one approach. The POD in C also discusses some of the issues involved. =head2 Parsing an image posted via CGI C: file format attacks have become a common attack vector, make sure you have up to date image file format libraries, otherwise trying to parse uploaded files, whether with Imager or some other tool, may result in a remote attacker being able to run their own code on your system. If your HTML form uses the correct magic, it can upload files to your CGI script, in particular, you need to use C< method="post" > and C in the C
tag, and use C in the C, for example: To process the form: =over =item 1. first check that the user supplied a file =item 2. get the file handle =item 3. have Imager read the image =back # returns the client's name for the file, don't open this locally my $cgi = CGI->new; # 1. check the user supplied a file my $filename = $cgi->param('myimage'); if ($filename) { # 2. get the file handle my $fh = $cgi->upload('myimage'); if ($fh) { binmode $fh; # 3. have Imager read the image my $img = Imager->new; if ($img->read(fh=>$fh)) { # we can now process the image } } # else, you probably have an incorrect form or input tag } # else, the user didn't select a file See C and C in the Imager distribution for example code. You may also want to set limits on the size of the image read, using Imager's C method, documented in L. For example: # limit to 10 million bytes of memory usage Imager->set_file_limits(bytes => 10_000_000); # limit to 1024 x 1024 Imager->set_file_limits(width => 1024, height => 1024); =head1 DRAWING =head2 Adding a border to an image First make a new image with space for the border: my $border_width = ...; my $border_height = ...; my $out = Imager->new(xsize => $source->getwidth() + 2 * $border_width, ysize => $source->getheight() + 2 * $border_height, bits => $source->bits, channels => $source->getchannels); Then paste the source image into the new image: $out->paste(left => $border_width, top => $border_height, img => $source); Whether you draw the border before or after pasting the original image depends on whether you want the border to overlap the image, for example a semi-transparent border drawn after pasting the source image could overlap the edge without hiding it. If you want a solid border you could just fill the image before pasting the source for simplicity: $out->box(filled=>1, color=>'red'); $out->paste(left => $border_width, top => $border_height, img => $source); =head1 TEXT =head2 Drawing text =head2 Aligning text =head2 Measuring text =head2 Word wrapping text =head2 Shearing (slanting) or Rotating text This requires that you have Imager installed with FreeType 2.x support installed, and that the font be created using the FreeType 2.x driver, for example: my $font = Imager::Font->new(file=>$fontfile, type=>'ft2'); First you need a transformation matrix, for shearing that could be: my $angle_in_radians = ...; my $tan_angle = sin($angle_rads) / cos($angle_rads); # shear horizontally, supply this as y instead to do it vertically my $matrix = Imager::Matrix2d->shear(x=>$tan_angle); For rotation that would be: my $matrix = Imager::Matrix2d->rotate(radians => $angle_in_radians); or: my $matrix = Imager::Matrix2d->rotate(degrees => $angle_in_degrees); Feed that to the font object: $font->transform(matrix => $matrix); and draw the text as normal: $image->string(string => $text, x => $where_x, y => $where_y, color => $color, font => $font); See samples/slant_text.pl for a comprehensive example, including calculating the transformed bounding box to create an image to fit the transformed text into. =head1 IMAGE TRANSFORMATION =head2 Shearing an image =head2 Convert to gray-scale To convert an RGB image to a gray-scale image, use the convert method: my $grey = $image->convert(preset => 'gray'); convert() returns a new image. See: L =head1 METADATA =head2 Image format When Imager reads a file it does a magic number check to determine the file type, so C could actually be a GIF image, and Imager will read it anyway. You can check the actual format of the image by looking at the C tag. my $format = $image->tags(name=>'i_format'); =head2 Image spatial resolution Most image file formats store information about the physical size of the pixels, though in some cases that information isn't useful. Imager stores this information in the tags C and C, and this is always stored in dots per inch. Some formats, including TIFF and JPEG allow you to change the units spatial resolution information is stored in, if you set the tag that changes this the Imager will convert C and C to those units when it writes the file. For example to set the resolution to 300 dpi: $image->settag(name => 'i_xres', value => 300); $image->settag(name => 'i_yres', value => 300); If you want the file format to store the resolution in some other unit, for example you can write a TIFF file that stores the resolution in pixels per centimeter, you would do: # 150 pixels/cm $image->settag(name => 'i_xres', value => 150 * 2.54); $image->settag(name => 'i_yres', value => 150 * 2.54); $image->settag(name => 'tiff_resolutionunit', value => 3); Keywords: DPI =head1 IMAGE MANIPULATION =head2 Replacing a color with transparency X To replace a color with transparency you can use the L method. # make a work image the same size as our input my $work = Imager->new(xsize => $in->getwidth, ysize => $in->getheight, channels => $in->getchannels); # and fill it with the color we want transparent $work->box(filled => 1, color => $color); # get an image with that color replaced with transparent black my $out = $work->difference(other => $in); =head1 SPECIAL EFFECTS =head2 Drop Shadows XX This can be used for a glow effect as well. First create a new image, either with an alpha channel (if you want transparency behind the shadow) or without, if you want a background color: my $out = Imager->new ( xsize => $shadow_size * 2 + $src->getwidth, ysize => $shadow_size * 2 + $src->getheight, channels => 4, ); # fill it with your background color, if you want one # $out->box(filled => 1, color => $back_color); Make a work image to render the shadow on: my $shadow_work = Imager->new ( xsize => $back->getwidth, ysize => $back->getheight, channels => 1, ); Extract the alpha channel from the source image, first the alpha version: my $alpha = $src->convert(preset => "alpha"); and draw that on the work shadow: $shadow_work->paste ( src => $slpha, left => $shadow_size, top => $shadow_size, ); otherwise just draw a box for the non-alpha source: $shadow_work->box ( filled => 1, color => [ 255 ], xmin => $shadow_size, ymin => $shadow_size, xmax => $shadow_size + $src->getwidth() - 1, ymax => $shadow_size + $src->getheight() - 1, ); Blur the work shadow: $shadow_work->filter(type => "gaussian", stddev => $shadow_size); Convert it to an RGB image with alpha: $shadow_work = $shadow_work->convert ( matrix => [ [ 0, $red / 255 ], [ 0, $green / 255 ], [ 0, $blue / 255 ], [ 1 ] ] ); Draw that on the output image: $out->rubthrough(src => $shadow_work); Draw our original image on the output image, perhaps with an offset: $out->rubthrough ( src => $src, tx => $shadow_size + $x_offset, ty => $shadow_size + $y_offset, ); See F for an example of this recipe. =head1 AUTHOR Tony Cook =head1 SEE ALSO L, L, L. =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Font.pm0000644000175000017500000006730212263740601021010 0ustar gregoagregoapackage Imager::Font; use Imager::Color; use strict; use vars qw($VERSION); $VERSION = "1.038"; # the aim here is that we can: # - add file based types in one place: here # - make sure we only attempt to create types that exist # - give reasonable defaults # - give the user some control over which types get used my %drivers = ( tt=>{ class=>'Imager::Font::Truetype', module=>'Imager/Font/Truetype.pm', files=>'.*\.ttf$', description => 'FreeType 1.x', checktype => 1, }, t1=>{ class=>'Imager::Font::T1', module=>'Imager/Font/T1.pm', files=>'.*\.pfb$', description => 'T1Lib', }, ft2=>{ class=>'Imager::Font::FT2', module=>'Imager/Font/FT2.pm', files=>'.*\.(pfa|pfb|otf|ttf|fon|fnt|dfont|pcf(\.gz)?)$', description => 'FreeType 2.x', }, ifs=>{ class=>'Imager::Font::Image', module=>'Imager/Font/Image.pm', files=>'.*\.ifs$', }, w32=>{ class=>'Imager::Font::W32', module=>'Imager/Font/W32.pm', description => 'Win32 GDI Fonts', }, ); # this currently should only contain file based types, don't add w32 my @priority = qw(t1 tt ft2 ifs); sub new { my $class = shift; my $self = {}; my ($file, $type, $id); my %hsh=(color => Imager::Color->new(255,0,0,255), size => 15, @_); bless $self,$class; if ($hsh{'file'}) { $file = $hsh{'file'}; $type = $hsh{'type'}; if (defined $type) { unless ($drivers{$type}) { Imager->_set_error("Unknown font type $type"); return; } unless ($Imager::formats{$type}) { Imager->_set_error("The $type {$drivers{$type}) font driver is not installed"); return; } } else { for my $drv (@priority) { undef $type; my $re = $drivers{$drv}{files} or next; if ($file =~ /$re/i) { if (eval { require $drivers{$drv}{module}; 1 } and !( $drivers{$drv}{checktype} && !$Imager::formats{$drv} )) { $type = $drv; last; } } } } if (!defined($type)) { # some types we can support, but the driver isn't available # work out which drivers support it, so we can provide the user # some useful information on how to get it working my @not_here; for my $driver_name (keys %drivers) { my $driver = $drivers{$driver_name}; push @not_here, "$driver_name ($driver->{description})" if $driver->{files} && $file =~ /$driver->{files}/i; } if (@not_here) { $Imager::ERRSTR = "No font drivers enabled that can support this file, rebuild Imager with any of ".join(", ", @not_here)." to use this font file"; } else { $Imager::ERRSTR = "No font type found for $hsh{'file'}"; } return; } } elsif ($hsh{face}) { $type = "w32"; } else { $Imager::ERRSTR="No font file specified"; return; } if ($drivers{$type}{checktype} && !$Imager::formats{$type}) { $Imager::ERRSTR = "`$type' not enabled"; return; } # here we should have the font type or be dead already. require $drivers{$type}{module}; return $drivers{$type}{class}->new(%hsh); } # returns first defined parameter sub _first { for (@_) { return $_ if defined $_; } return undef; } sub draw { my $self = shift; my %input = ('x' => 0, 'y' => 0, @_); unless ($input{image}) { $Imager::ERRSTR = 'No image supplied to $font->draw()'; return; } my $image = $input{image}; $input{string} = _first($input{string}, $input{text}); unless (defined $input{string}) { $image->_set_error("Missing required parameter 'string'"); return; } $input{aa} = _first($input{aa}, $input{antialias}, $self->{aa}, 1); # the original draw code worked this out but didn't use it $input{align} = _first($input{align}, $self->{align}); $input{color} = _first($input{color}, $self->{color}); $input{color} = Imager::_color($input{'color'}); $input{size} = _first($input{size}, $self->{size}); unless (defined $input{size}) { $image->_set_error("No font size provided"); return undef; } $input{align} = _first($input{align}, 1); $input{utf8} = _first($input{utf8}, $self->{utf8}, 0); $input{vlayout} = _first($input{vlayout}, $self->{vlayout}, 0); my $result = $self->_draw(%input); unless ($result) { $image->_set_error($image->_error_as_msg()); } return $result; } sub align { my $self = shift; my %input = ( halign => 'left', valign => 'baseline', 'x' => 0, 'y' => 0, @_ ); # image needs to be supplied, but can be supplied as undef unless (exists $input{image}) { Imager->_set_error("Missing required parameter 'image'"); return; } my $errors_to = $input{image} || 'Imager'; my $text = _first($input{string}, $input{text}); unless (defined $text) { $errors_to->_set_error("Missing required parameter 'string'"); return; } my $size = _first($input{size}, $self->{size}); my $utf8 = _first($input{utf8}, 0); my $bbox = $self->bounding_box(string=>$text, size=>$size, utf8=>$utf8); my $valign = $input{valign}; $valign = 'baseline' unless $valign && $valign =~ /^(?:top|center|bottom|baseline)$/; my $halign = $input{halign}; $halign = 'start' unless $halign && $halign =~ /^(?:left|start|center|end|right)$/; my $x = $input{'x'}; my $y = $input{'y'}; if ($valign eq 'top') { $y += $bbox->ascent; } elsif ($valign eq 'center') { $y += $bbox->ascent - $bbox->text_height / 2; } elsif ($valign eq 'bottom') { $y += $bbox->descent; } # else baseline is the default if ($halign eq 'left') { $x -= $bbox->start_offset; } elsif ($halign eq 'start') { # nothing to do } elsif ($halign eq 'center') { $x -= $bbox->start_offset + $bbox->total_width / 2; } elsif ($halign eq 'end') { $x -= $bbox->advance_width; } elsif ($halign eq 'right') { $x -= $bbox->advance_width - $bbox->right_bearing; } $x = int($x); $y = int($y); if ($input{image}) { delete @input{qw/x y/}; $self->draw(%input, 'x' => $x, 'y' => $y, align=>1) or return; } return ($x+$bbox->start_offset, $y-$bbox->ascent, $x+$bbox->end_offset, $y-$bbox->descent+1); } sub bounding_box { my $self=shift; my %input=@_; if (!exists $input{'string'}) { $Imager::ERRSTR='string parameter missing'; return; } $input{size} ||= $self->{size}; $input{sizew} = _first($input{sizew}, $self->{sizew}, 0); $input{utf8} = _first($input{utf8}, $self->{utf8}, 0); my @box = $self->_bounding_box(%input) or return; if (wantarray) { if(@box && exists $input{'x'} and exists $input{'y'}) { my($gdescent, $gascent)=@box[1,3]; $box[1]=$input{'y'}-$gascent; # top = base - ascent (Y is down) $box[3]=$input{'y'}-$gdescent; # bottom = base - descent (Y is down, descent is negative) $box[0]+=$input{'x'}; $box[2]+=$input{'x'}; } elsif (@box && $input{'canon'}) { $box[3]-=$box[1]; # make it canonical (ie (0,0) - (width, height)) $box[2]-=$box[0]; } return @box; } else { require Imager::Font::BBox; return Imager::Font::BBox->new(@box); } } sub dpi { my $self = shift; # I'm assuming a default of 72 dpi my @old = (72, 72); if (@_) { $Imager::ERRSTR = "Setting dpi not implemented for this font type"; return; } return @old; } sub transform { my $self = shift; my %hsh = @_; # this is split into transform() and _transform() so we can # implement other tags like: degrees=>12, which would build a # 12 degree rotation matrix # but I'll do that later unless ($hsh{matrix}) { $Imager::ERRSTR = "You need to supply a matrix"; return; } return $self->_transform(%hsh); } sub _transform { $Imager::ERRSTR = "This type of font cannot be transformed"; return; } sub utf8 { return 0; } sub priorities { my $self = shift; my @old = @priority; if (@_) { @priority = @_; } return @old; } sub register { my ($self, %opts) = @_; my $type = delete $opts{type}; my $class = delete $opts{class}; my $files = delete $opts{files}; my $description = delete $opts{description} || $class; defined $type or return Imager->_set_error("No type parameter supplied to Imager::Font->regster"); defined $class or return Imager->_set_error("No class parameter supplied to Imager::Font->register"); if ($files) { eval { qr/$files/ } or return Imager->_set_error("files isn't a valid regexp"); } if ($drivers{$type} && $drivers{$type}{class} ne $class) { Imager->_set_error("Font type $type already registered as $drivers{$type}{class}"); return; } (my $module = $class . ".pm") =~ s(::)(/)g; my $driver = { class => $class, module => $module, description => $description, }; $files and $driver->{files} = $files; $drivers{$type} = $driver; 1; } 1; __END__ =head1 NAME Imager::Font - Font handling for Imager. =head1 SYNOPSIS use Imager; $t1font = Imager::Font->new(file => 'pathtofont.pfb'); $ttfont = Imager::Font->new(file => 'pathtofont.ttf'); $w32font = Imager::Font->new(face => 'Times New Roman'); $blue = Imager::Color->new("#0000FF"); $font = Imager::Font->new(file => 'pathtofont.ttf', color => $blue, size => 30); ($neg_width, $global_descent, $pos_width, $global_ascent, $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string=>"Foo"); my $bbox_object = $font->bounding_box(string=>"Foo"); # documented in Imager::Draw $img->string(font => $font, text => "Model-XYZ", x => 15, y => 40, size => 40, color => $red, aa => 1); =head1 DESCRIPTION =for stopwords TrueType FreeType This module handles creating Font objects used by Imager. The module also handles querying fonts for sizes and such. If both T1lib and FreeType were available at the time of compilation then Imager should be able to work with both TrueType fonts and t1 Postscript fonts. To check if Imager is t1 or TrueType capable you can use something like this: use Imager; print "Has truetype" if $Imager::formats{tt}; print "Has t1 postscript" if $Imager::formats{t1}; print "Has Win32 fonts" if $Imager::formats{w32}; print "Has Freetype2" if $Imager::formats{ft2}; =over 4 =item new This creates a font object to pass to functions that take a font argument. $font = Imager::Font->new(file => 'denmark.ttf', index => 0, color => $blue, size => 30, aa => 1); This creates a font which is the TrueType font F. It's default color is $blue, default size is 30 pixels and it's rendered anti-aliased by default. Imager can see which type of font a file is by looking at the suffix of the file name for the font. A suffix of C is taken to mean a TrueType font while a suffix of C is taken to mean a Type 1 Postscript font. If Imager cannot tell which type a font is you can tell it explicitly by using the C parameter: $t1font = Imager::Font->new(file => 'fruitcase', type => 't1'); $ttfont = Imager::Font->new(file => 'arglebarf', type => 'tt'); The C parameter is used to select a single face from a font file containing more than one face, for example, from a Macintosh font suitcase or a C<.dfont> file. If any of the C, C or C parameters are omitted when calling C<< Imager::Font->new() >> the they take the following values: color => Imager::Color->new(255, 0, 0, 0); # this default should be changed size => 15 aa => 0 index => 0 To use Win32 fonts supply the face name of the font: $font = Imager::Font->new(face=>'Arial Bold Italic'); There isn't any access to other logical font attributes, but this typically isn't necessary for Win32 TrueType fonts, since you can construct the full name of the font as above. Other logical font attributes may be added if there is sufficient demand. Parameters: =over =item * C - name of the file to load the font from. =item * =for stopwords GDI C - face name. This is used only under Win32 to create a GDI based font. This is ignored if the C parameter is supplied. =item * C - font driver to use. Currently the permitted values for this are: =over =item * C - FreeType 1.x driver. Supports TrueType (C<.ttf>) fonts. =item * =for stopwords strikethrough overline C - T1 Lib driver. Supports Postscript Type 1 fonts. Allows for synthesis of underline, strikethrough and overline. =item * C - FreeType 2.x driver. Supports many different font formats. Also supports the transform() method. =back =item * C - the default color used with this font. Default: red. =item * C - the default size used with this font. Default: 15. =item * C - if non-zero then text supplied to $img->string(...) and $font->bounding_box(...) is assumed to be UTF-8 encoded by default. =item * C - the default value for the $img->string(...) C parameter. Default: 1. =item * C - the default value for the $img->string(...) C parameter. Default: 0. =item * C - the default value for the $im->string(...) C parameter. Default: 0. =item * C - for font file containing multiple fonts this selects which font to use. This is useful for Macintosh C (F<.dfont>) and suitcase font files. If you want to use a suitcase font you will need to tell Imager to use the FreeType 2.x driver by setting C to C<'ft2'>: my $font = Imager::Font->new(file=>$file, index => 1, type=>'ft2') or die Imager->errstr; =back Returns the new font object on success. Returns C on failure and sets an error message readable with C<< Imager->errstr >>. =item bounding_box() Returns the bounding box for the specified string. Example: my ($neg_width, $global_descent, $pos_width, $global_ascent, $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string => "A Fool"); my $bbox_object = $font->bounding_box(string => "A Fool"); =over =item C<$neg_width> the relative start of a the string. In some cases this can be a negative number, in that case the first letter stretches to the left of the starting position that is specified in the string method of the Imager class =item C<$global_descent> how far down the lowest letter of the entire font reaches below the baseline (this is often j). =item C<$pos_width> how wide the string from the starting position is. The total width of the string is C<$pos_width-$neg_width>. =item C<$descent> =item C<$ascent> the same as <$global_descent> and <$global_ascent> except that they are only for the characters that appear in the string. =item C<$advance_width> the distance from the start point that the next string output should start at, this is often the same as C<$pos_width>, but can be different if the final character overlaps the right side of its character cell. =item C<$right_bearing> The distance from the right side of the final glyph to the end of the advance width. If the final glyph overflows the advance width this value is negative. =back Obviously we can stuff all the results into an array just as well: @metrics = $font->bounding_box(string => "testing 123"); Note that extra values may be added, so $metrics[-1] isn't supported. It's possible to translate the output by a passing coordinate to the bounding box method: @metrics = $font->bounding_box(string => "testing 123", x=>45, y=>34); This gives the bounding box as if the string had been put down at C<(x,y)> By giving bounding_box 'canon' as a true value it's possible to measure the space needed for the string: @metrics = $font->bounding_box(string=>"testing",size=>15,canon=>1); This returns the same values in $metrics[0] and $metrics[1], but: $bbox[2] - horizontal space taken by glyphs $bbox[3] - vertical space taken by glyphs Returns an L object in scalar context, so you can avoid all those confusing indexes. This has methods as named above, with some extra convenience methods. Parameters are: =over =item * C - the string to calculate the bounding box for. Required. =item * C - the font size to use. Default: value set in Imager::Font->new(), or 15. =item * C - the font width to use. Default to the value of the C parameter. =item * C - For drivers that support it, treat the string as UTF-8 encoded. For versions of perl that support Unicode (5.6 and later), this will be enabled automatically if the 'string' parameter is already a UTF-8 string. See L for more information. Default: the C value passed to Imager::Font->new(...) or 0. =item * C, C - offsets applied to @box[0..3] to give you a adjusted bounding box. Ignored in scalar context. =item * C - if non-zero and the C, C parameters are not supplied, then $pos_width and $global_ascent values will returned as the width and height of the text instead. =back On success returns either the list of bounds, or a bounding box object in scalar context. Returns an empty list or C on failure and sets an error message readable with C<< Imager->errstr >>. The transformation matrix set by L has no effect on the result of this method - the bounds of the untransformed text is returned. =item string() The $img->string(...) method is now documented in L =item align(string=>$text,size=>$size,x=>...,y=>...,valign => ...,halign=>...) Higher level text output - outputs the text aligned as specified around the given point (x,y). # "Hello" centered at 100, 100 in the image. my ($left, $top, $right, $bottom) = $font->align(string=>"Hello", x=>100, y=>100, halign=>'center', valign=>'center', image=>$image); Takes the same parameters as $font->draw(), and the following extra parameters: =over =item * C - Possible values are: =over =item C Point is at the top of the text. =item C Point is at the bottom of the text. =item C Point is on the baseline of the text (default.) =item C
Point is vertically centered within the text. =back =item * C =over =item * C - the point is at the left of the text. =item * C - the point is at the start point of the text. =item * C
- the point is horizontally centered within the text. =item * C - the point is at the right end of the text. =item * C - the point is at the end point of the text. =back =item * C - The image to draw to. Set to C to avoid drawing but still calculate the bounding box. =back Returns a list specifying the bounds of the drawn text on success. Returns an empty list on failure, if an C parameter was supplied the error message can be read with C<< $image->errstr >>, otherwise it's available as C<< Imager->errstr >>. =item dpi() =item dpi(xdpi=>$xdpi, ydpi=>$ydpi) =item dpi(dpi=>$dpi) Set or retrieve the spatial resolution of the image in dots per inch. The default is 72 dpi. This isn't implemented for all font types yet. Possible parameters are: =over =item * C, C - set the horizontal and vertical resolution in dots per inch. =item * C - set both horizontal and vertical resolution to this value. =back Returns a list containing the previous C, C values on success. Returns an empty list on failure, with an error message returned in C<< Imager->errstr >>. =item transform() $font->transform(matrix=>$matrix); Applies a transformation to the font, where matrix is an array ref of numbers representing a 2 x 3 matrix: [ $matrix->[0], $matrix->[1], $matrix->[2], $matrix->[3], $matrix->[4], $matrix->[5] ] Not all font types support transformations, these will return false. It's possible that a driver will disable hinting if you use a transformation, to prevent discontinuities in the transformations. See the end of the test script t/t38ft2font.t for an example. Currently only the ft2 (FreeType 2.x) driver supports the transform() method. See samples/slant_text.pl for a sample using this function. Note that the transformation is done in font co-ordinates where y increases as you move up, not image co-ordinates where y decreases as you move up. C has no effect on the results of L. Returns true on success. Returns false on failure with the cause readable from C<< Imager->errstr >>. =item has_chars(string=>$text) Checks if the characters in $text are defined by the font. In a list context returns a list of true or false value corresponding to the characters in $text, true if the character is defined, false if not. In scalar context returns a string of C or non-C characters. Supports UTF-8 where the font driver supports UTF-8. Not all fonts support this method (use $font->can("has_chars") to check.) On error, returns an empty list or undef in scalar context, and sets an error message readable with C<< Imager->errstr >>. =over =item * C - string of characters to check for. Required. Must contain at least one character. =item * C - For drivers that support it, treat the string as UTF-8 encoded. For versions of perl that support Unicode (5.6 and later), this will be enabled automatically if the 'string' parameter is already a UTF-8 string. See L for more information. Default: the C value passed to Imager::Font->new(...) or 0. =back =item face_name() Returns the internal name of the face. Not all font types support this method yet, so you should check with C<< $font->can("face_name") >> before calling C. =item glyph_names(string=>$string [, utf8=>$utf8 ][, reliable_only=>0 ] ); Returns a list of glyph names for each of the characters in the string. If the character has no name then C is returned for the character. Some font files do not include glyph names, in this case FreeType 2 will not return any names. FreeType 1 can return standard names even if there are no glyph names in the font. FreeType 2 has an API function that returns true only if the font has "reliable glyph names", unfortunately this always returns false for TrueType fonts. This can avoid the check of this API by supplying C as 0. The consequences of using this on an unknown font may be unpredictable, since the FreeType documentation doesn't say how those name tables are unreliable, or how FT2 handles them. Both FreeType 1.x and 2.x allow support for glyph names to not be included. If the supplied C is marked as UTF-8 or the C parameter is true and the supplied string does not contain valid UTF-8, returns an empty string and set an error message readable from C<< Imager->errstr >>, =item can_glyph_names() As a class method, returns true if the underlying library supports returning glyph names. As an object method, returns true if the supplied font supports returning glyph names. =item draw This is used by Imager's string() method to implement drawing text. See L. =back =head1 MULTIPLE MASTER FONTS The FreeType 2 driver supports multiple master fonts: =over =item is_mm() Test if the font is a multiple master font. =item mm_axes() Returns a list of the axes that can be changes in the font. Each entry is an array reference which contains: =over =item 1. Name of the axis. =item 2. minimum value for this axis. =item 3. maximum value for this axis =back =item set_mm_coords(coords=>\@values) Blends an interpolated design from the master fonts. @values must contain as many values as there are axes in the font. =back For example, to select the minimum value in each axis: my @axes = $font->mm_axes; my @coords = map $_->[1], @axes; $font->set_mm_coords(coords=>\@coords); It's possible other drivers will support multiple master fonts in the future, check if your selected font object supports the is_mm() method using the can() method. =head1 UTF-8 There are 2 ways of rendering Unicode characters with Imager: =over =item * For versions of perl that support it, use perl's native UTF-8 strings. This is the simplest method. =item * Hand build your own UTF-8 encoded strings. Only recommended if your version of perl has no UTF-8 support. =back Imager won't construct characters for you, so if want to output Unicode character 00C3 "LATIN CAPITAL LETTER A WITH DIAERESIS", and your font doesn't support it, Imager will I build it from 0041 "LATIN CAPITAL LETTER A" and 0308 "COMBINING DIAERESIS". To check if a driver supports UTF-8 call the utf8() method: =over =item utf8() Return true if the font supports UTF-8. =back =head2 Native UTF-8 Support If your version of perl supports UTF-8 and the driver supports UTF-8, just use the $im->string() method, and it should do the right thing. =head2 Build your own In this case you need to build your own UTF-8 encoded characters. For example: $x = pack("C*", 0xE2, 0x80, 0x90); # character code 0x2010 HYPHEN You need to be careful with versions of perl that have UTF-8 support, since your string may end up doubly UTF-8 encoded. For example: $x = "A\xE2\x80\x90\x41\x{2010}"; substr($x, -1, 0) = ""; # at this point $x is has the UTF-8 flag set, but has 5 characters, # none, of which is the constructed UTF-8 character The test script t/t38ft2font.t has a small example of this after the comment: # an attempt using emulation of UTF-8 =head1 DRIVER CONTROL If you don't supply a 'type' parameter to Imager::Font->new(), but you do supply a 'file' parameter, Imager will attempt to guess which font driver to used based on the extension of the font file. Since some formats can be handled by more than one driver, a priority list is used to choose which one should be used, if a given format can be handled by more than one driver. =over =item priorities The current priorities can be retrieved with: @drivers = Imager::Font->priorities(); You can set new priorities and save the old priorities with: @old = Imager::Font->priorities(@drivers); If you supply driver names that are not currently supported, they will be ignored. Imager supports both T1Lib and FreeType 2 for working with Type 1 fonts, but currently only T1Lib does any caching, so by default T1Lib is given a higher priority. Since Imager's FreeType 2 support can also do font transformations, you may want to give that a higher priority: my @old = Imager::Font->priorities(qw(tt ft2 t1)); =item register Registers an extra font driver. Accepts the following parameters: =over =item * type - a brief identifier for the font driver. You can supply this value to C<< Imager::Font->new() >> to create fonts of this type. Required. =item * class - the font class name. Imager will attempted to load this module by name. Required. =item * files - a regular expression to match against file names. If supplied this must be a valid perl regular expression. If not supplied you can only create fonts of this type by supplying the C parameter to C<< Imager::Font->new() >> =item * description - a brief description of the font driver. Defaults to the value supplied in C. =back =back =head1 AUTHOR Arnar M. Hrafnkelsson, addi@umich.edu And a great deal of help from others - see the F for a complete list. =head1 BUGS The $pos_width member returned by the bounding_box() method has historically returned different values from different drivers. The FreeType 1.x and 2.x, and the Win32 drivers return the max of the advance width and the right edge of the right-most glyph. The Type 1 driver always returns the right edge of the right-most glyph. The newer advance_width and right_bearing values allow access to any of the above. =head1 REVISION $Revision$ =head1 SEE ALSO Imager(3), Imager::Font::FreeType2(3), Imager::Font::Type1(3), Imager::Font::Win32(3), Imager::Font::Truetype(3), Imager::Font::BBox(3) http://imager.perl.org/ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Threads.pod0000644000175000017500000000352612263740601021640 0ustar gregoagregoa=head1 NAME Imager::Threads - Imager and threads =head1 SYNOPSIS use Imager; use threads; Imager->preload; threads->create(...); =head1 DESCRIPTION Starting from version 0.94 Imager attempts to work safely with perl's C. Previous versions stored some state in global variables, in particular the internal error stack. However there are some limitations: =over =item * Imager's debug malloc isn't thread safe and will never be. Imager's debug malloc is disabled by default. =item * C, which Imager uses for TIFF file support is not thread safe, C works around this by single-threading its access to C. =item * C, which Imager uses for GIF support is not thread safe before version 5. C works around this by single threading its access to C. =item * C, used by one of Imager's font drivers, is not thread safe. C works around this by single threading access. =item * killing a thread reading or writing TIFF or GIF files, or using T1 fonts through C may deadlock other threads when they attempt to read or write TIFF or GIF files, or work with Type 1 fonts. =item * Fill, font, color or I/O layer objects created in one thread are not valid for use in child threads. If you manage to duplicate such an object in another thread, you get to keep both pieces when it breaks. =back Note that if you have another module using C, C or C it may interact with Imager's use of those libraries in a threaded environment, since there's no way to co-ordinate access to the global information C, C and C maintain. Imager currently doesn't use threads itself, except for testing its threads support. =head1 SEE ALSO Imager, C =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Matrix2d.pm0000644000175000017500000002431512460670607021600 0ustar gregoagregoapackage Imager::Matrix2d; use strict; use vars qw($VERSION); use Scalar::Util qw(reftype looks_like_number); use Carp qw(croak); $VERSION = "1.012"; =head1 NAME Imager::Matrix2d - simple wrapper for matrix construction =head1 SYNOPSIS use Imager::Matrix2d; $m1 = Imager::Matrix2d->identity; $m2 = Imager::Matrix2d->rotate(radians=>$angle, x=>$cx, y=>$cy); $m3 = Imager::Matrix2d->translate(x=>$dx, y=>$dy); $m4 = Imager::Matrix2d->shear(x=>$sx, y=>$sy); $m5 = Imager::Matrix2d->reflect(axis=>$axis); $m6 = Imager::Matrix2d->scale(x=>$xratio, y=>$yratio); $m8 = Imager::Matric2d->matrix($v11, $v12, $v13, $v21, $v22, $v23, $v31, $v32, $v33); $m6 = $m1 * $m2; $m7 = $m1 + $m2; use Imager::Matrix2d qw(:handy); # various m2d_* functions imported # where m2d_(.*) calls Imager::Matrix2d->$1() =head1 DESCRIPTION This class provides a simple wrapper around a reference to an array of 9 coefficients, treated as a matrix: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ] Most of the methods in this class are constructors. The others are overloaded operators. Note that since Imager represents images with y increasing from top to bottom, rotation angles are clockwise, rather than counter-clockwise. =over =cut use vars qw(@EXPORT_OK %EXPORT_TAGS @ISA); @ISA = 'Exporter'; require 'Exporter.pm'; @EXPORT_OK = qw(m2d_rotate m2d_identity m2d_translate m2d_shear m2d_reflect m2d_scale); %EXPORT_TAGS = ( handy=> [ qw(m2d_rotate m2d_identity m2d_translate m2d_shear m2d_reflect m2d_scale) ], ); use overload '*' => \&_mult, '+' => \&_add, '""'=>\&_string, "eq" => \&_eq; =item identity() Returns the identity matrix. =cut sub identity { return bless [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ], $_[0]; } =item rotate(radians=>$angle) =item rotate(degrees=>$angle) Creates a matrix that rotates around the origin, or around the point (x,y) if the 'x' and 'y' parameters are provided. =cut sub rotate { my ($class, %opts) = @_; my $angle; if (defined $opts{radians}) { $angle = $opts{radians}; } elsif (defined $opts{degrees}) { $angle = $opts{degrees} * 3.1415926535 / 180; } else { $Imager::ERRSTR = "degrees or radians parameter required"; return undef; } if ($opts{'x'} || $opts{'y'}) { $opts{'x'} ||= 0; $opts{'y'} ||= 0; return $class->translate('x'=>$opts{'x'}, 'y'=>$opts{'y'}) * $class->rotate(radians=>$angle) * $class->translate('x'=>-$opts{'x'}, 'y'=>-$opts{'y'}); } else { my $sin = sin($angle); my $cos = cos($angle); return bless [ $cos, -$sin, 0, $sin, $cos, 0, 0, 0, 1 ], $class; } } =item translate(x=>$dx, y=>$dy) =item translate(x=>$dx) =item translate(y=>$dy) Translates by the specify amounts. =cut sub translate { my ($class, %opts) = @_; if (defined $opts{'x'} || defined $opts{'y'}) { my $x = $opts{'x'} || 0; my $y = $opts{'y'} || 0; return bless [ 1, 0, $x, 0, 1, $y, 0, 0, 1 ], $class; } $Imager::ERRSTR = 'x or y parameter required'; return undef; } =item shear(x=>$sx, y=>$sy) =item shear(x=>$sx) =item shear(y=>$sy) Shear by the given amounts. =cut sub shear { my ($class, %opts) = @_; if (defined $opts{'x'} || defined $opts{'y'}) { return bless [ 1, $opts{'x'}||0, 0, $opts{'y'}||0, 1, 0, 0, 0, 1 ], $class; } $Imager::ERRSTR = 'x and y parameters required'; return undef; } =item reflect(axis=>$axis) Reflect around the given axis, either 'x' or 'y'. =item reflect(radians=>$angle) =item reflect(degrees=>$angle) Reflect around a line drawn at the given angle from the origin. =cut sub reflect { my ($class, %opts) = @_; if (defined $opts{axis}) { my $result = $class->identity; if ($opts{axis} eq "y") { $result->[0] = -$result->[0]; } elsif ($opts{axis} eq "x") { $result->[4] = -$result->[4]; } else { $Imager::ERRSTR = 'axis must be x or y'; return undef; } return $result; } my $angle; if (defined $opts{radians}) { $angle = $opts{radians}; } elsif (defined $opts{degrees}) { $angle = $opts{degrees} * 3.1415926535 / 180; } else { $Imager::ERRSTR = 'axis, degrees or radians parameter required'; return undef; } # fun with matrices return $class->rotate(radians=>-$angle) * $class->reflect(axis=>'x') * $class->rotate(radians=>$angle); } =item scale(x=>$xratio, y=>$yratio) Scales at the given ratios. You can also specify a center for the scaling with the C and C parameters. =cut sub scale { my ($class, %opts) = @_; if (defined $opts{'x'} || defined $opts{'y'}) { $opts{'x'} = 1 unless defined $opts{'x'}; $opts{'y'} = 1 unless defined $opts{'y'}; if ($opts{cx} || $opts{cy}) { return $class->translate('x'=>-$opts{cx}, 'y'=>-$opts{cy}) * $class->scale('x'=>$opts{'x'}, 'y'=>$opts{'y'}) * $class->translate('x'=>$opts{cx}, 'y'=>$opts{cy}); } else { return bless [ $opts{'x'}, 0, 0, 0, $opts{'y'}, 0, 0, 0, 1 ], $class; } } else { $Imager::ERRSTR = 'x or y parameter required'; return undef; } } =item matrix($v11, $v12, $v13, $v21, $v22, $v23, $v31, $v32, $v33) Create a matrix with custom coefficients. =cut sub matrix { my ($class, @self) = @_; if (@self == 9) { return bless \@self, $class; } else { $Imager::ERRSTR = "9 coefficients required"; return; } } =item transform($x, $y) Transform a point the same way matrix_transform does. =cut sub transform { my ($self, $x, $y) = @_; my $sz = $x * $self->[6] + $y * $self->[7] + $self->[8]; my ($sx, $sy); if (abs($sz) > 0.000001) { $sx = ($x * $self->[0] + $y * $self->[1] + $self->[2]) / $sz; $sy = ($x * $self->[3] + $y * $self->[4] + $self->[5]) / $sz; } else { $sx = $sy = 0; } return ($sx, $sy); } =item compose(matrix...) Compose several matrices together for use in transformation. For example, for three matrices: my $out = Imager::Matrix2d->compose($m1, $m2, $m3); is equivalent to: my $out = $m3 * $m2 * $m1; Returns the identity matrix if no parameters are supplied. May return the supplied matrix if only one matrix is supplied. =cut sub compose { my ($class, @in) = @_; @in or return $class->identity; my $out = pop @in; for my $m (reverse @in) { $out = $out * $m; } return $out; } =item _mult() Implements the overloaded '*' operator. Internal use. Currently both the left and right-hand sides of the operator must be an Imager::Matrix2d. When composing a matrix for transformation you should multiply the matrices in the reverse order of the transformations: my $shear = Imager::Matrix2d->shear(x => 0.1); my $rotate = Imager::Matrix2d->rotate(degrees => 45); my $shear_then_rotate = $rotate * $shear; or use the compose method: my $shear_then_rotate = Imager::Matrix2d->compose($shear, $rotate); =cut sub _mult { my ($left, $right, $order) = @_; if (ref($right)) { if (reftype($right) eq "ARRAY") { @$right == 9 or croak "9 elements required in array ref"; if ($order) { ($left, $right) = ($right, $left); } my @result; for my $i (0..2) { for my $j (0..2) { my $accum = 0; for my $k (0..2) { $accum += $left->[3*$i + $k] * $right->[3*$k + $j]; } $result[3*$i+$j] = $accum; } } return bless \@result, __PACKAGE__; } else { croak "multiply by array ref or number"; } } elsif (defined $right && looks_like_number($right)) { my @result = map $_ * $right, @$left; return bless \@result, __PACKAGE__; } else { # something we don't handle croak "multiply by array ref or number"; } } =item _add() Implements the overloaded binary '+' operator. Currently both the left and right sides of the operator must be Imager::Matrix2d objects. =cut sub _add { my ($left, $right, $order) = @_; if (ref($right) && UNIVERSAL::isa($right, __PACKAGE__)) { my @result; for (0..8) { push @result, $left->[$_] + $right->[$_]; } return bless \@result, __PACKAGE__; } else { return undef; } } =item _string() Implements the overloaded stringification operator. This returns a string containing 3 lines of text with no terminating newline. I tried to make it fairly nicely formatted. You might disagree :) =cut sub _string { my ($m) = @_; my $maxlen = 0; for (@$m[0..8]) { if (length() > $maxlen) { $maxlen = length; } } $maxlen <= 9 or $maxlen = 9; my @left = ('[ ', ' ', ' '); my @right = ("\n", "\n", ']'); my $out; my $width = $maxlen+2; for my $i (0..2) { $out .= $left[$i]; for my $j (0..2) { my $val = $m->[$i*3+$j]; if (length $val > 9) { $val = sprintf("%9f", $val); if ($val =~ /\./ && $val !~ /e/i) { $val =~ s/0+$//; $val =~ s/\.$//; } $val =~ s/^\s//; } $out .= sprintf("%-${width}s", "$val, "); } $out =~ s/ +\Z/ /; $out .= $right[$i]; } $out; } =item _eq Implement the overloaded equality operator. Provided for older perls that don't handle magic auto generation of eq from "". =cut sub _eq { my ($left, $right) = @_; return $left . "" eq $right . ""; } =back The following functions are shortcuts to the various constructors. These are not methods. You can import these methods with: use Imager::Matrix2d ':handy'; =over =item m2d_identity =item m2d_rotate() =item m2d_translate() =item m2d_shear() =item m2d_reflect() =item m2d_scale() =back =cut sub m2d_identity { return __PACKAGE__->identity; } sub m2d_rotate { return __PACKAGE__->rotate(@_); } sub m2d_translate { return __PACKAGE__->translate(@_); } sub m2d_shear { return __PACKAGE__->shear(@_); } sub m2d_reflect { return __PACKAGE__->reflect(@_); } sub m2d_scale { return __PACKAGE__->scale(@_); } 1; =head1 AUTHOR Tony Cook =head1 BUGS Needs a way to invert a matrix. =head1 SEE ALSO Imager(3), Imager::Font(3) http://imager.perl.org/ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/interface.pod0000644000175000017500000002133712263740601022206 0ustar gregoagregoa=head1 NAME Imager::interface.pod - describes the C level virtual image interface =head1 SYNOPSIS =head1 DESCRIPTION The Imager virtual interface aims to allow image types to be created for special purposes, both to allow consistent access to images with different sample sizes, and organizations, but also to allow creation of synthesized or virtual images. This is a C level interface rather than Perl. =head2 Existing Images As of this writing we have the following concrete image types: =over =item * 8-bit/sample direct images =item * 16-bit/sample direct images =item * double/sample direct images =item * 8-bit/sample 8-bit/index paletted images =back Currently there is only one virtual image type: =over =item * masked images, where a mask image can control write access to an underlying image. =back Other possible concrete images include: =over =item * "bitmaps", 1 bit/sample images (perhaps limited to a single channel) =item * 16-bit/index paletted images =back Some other possible virtual images: =for stopwords GIMP Photoshop =over =item * image alpha combining, where the combining function can be specified (see the layer modes in graphical editors like the GIMP or Photoshop. =back =head1 THE INTERFACE Each image type needs to define a number of functions which implement the image operations. The image structure includes information describes the image, which can be used to determine the structure of the image: =over =item * C - the number of samples kept for each pixel in the image. For paletted images the samples are kept for each entry in the palette. =item * C, C - the dimensions of the image in pixels. =item * C - the number of bytes of data kept for the image. Zero for virtual images. Does not include the space required for the palette for paletted images. =item * C - controls which samples will be written to for direct images. =item * C - the number of bits kept for each sample. There are enum values i_8_bits, i_16_bits and i_double_bits (64). =item * C - the type of image, either i_direct_type or i_palette_type. Direct images keep the samples for every pixel image, while i_palette_type images keep an index into a color table for each pixel. =item * C - whether the image keeps any pixel data. If this is non-zero then C points to image data, otherwise it points to implementation defined data, though C is more likely to be used for that. =item * C - image data. If the image is 8-bit direct, non-virtual, then this consists of each sample of the image stored one after another, otherwise it is implementation defined. =item * C - will be used to store meta-data for an image, eg. tags from a TIFF file, or animation information from a GIF file. This should be initialized with a call to i_tags_new() in your image constructor if creating a new image type. =item * C - for internal use of image types. This is not released by the standard i_img_exorcise() function. If you create a new image type and want to store a pointer to allocated memory here you should point i_f_destroy at a function that will release the data. =back If a caller has no knowledge of the internal format of an image, the caller must call the appropriate image function pointer. Imager provides macros that wrap these functions, so it isn't necessary to call them directly. Many functions have a similar function with an 'f' suffix, these take or return samples specified with floating point values rather than 8-bit integers (unsigned char). Floating point samples are returned in the range 0 to 1 inclusive. =over =item i_f_ppix(im,x,y,color) =item i_f_ppixf(im,x,y,fcolor) stores the specified color at pixel (x,y) in the image. If the pixel can be stored return 0, otherwise -1. An image type may choose to return 0 under some circumstances, eg. writing to a masked area of an image. The C or C always contains the actual samples to be written, rather than a palette index. =item i_f_plin(im,l,r,y,colors) =item i_f_plinf(im,l,r,y,fcolors) stores (r-l) pixels at positions (l,y) ... (r-1, y) from the array specified by C (or C). Returns the number of pixels written to. If l is negative it will return 0. If C<< r > im->xsize >> then only C<< (im->xsize - l) >> will be written. =item i_f_gpix(im,x,y,color) =item i_f_gpixf(im,x,y,fcolor) retrieves a single pixel from position (x,y). This returns the samples rather than the index for paletted images. =item i_f_glin(im,l,r,y,colors) =item i_f_glinf(im,l,r,y,fcolors) retrieves (r-l) pixels from positions (l, y) through (r-1, y) into the array specified by colors. Returns the number of pixels retrieved. If l < 0 no pixels are retrieved. If C<< r > im->xsize >> then pixels C<< (l, y) >> ... C<< (im->xsize-1, y) >> are retrieved. Retrieves the samples rather than the color indexes for paletted images. =item i_f_gsamp(im,l,r,y,samples,chans,chan_count) =item i_f_gsampf(im,l,r,y,fsamples,chans,chan_count) Retrieves samples from channels specified by C (for length C) from pixels at positions (l,y) ... (r-1, y). If C is NULL then samples from channels 0 ... C will be retrieved. Returns the number of sample retrieved (I the number of channels). If a channel in C is not present in the image or l < 0, returns 0. If C<< r > im->xsize >>, then the samples from C<(l,y)> ... C<< (im->xsize-1, y) >> are returned. =back The following are for images where type == i_palette_type only. =over =item i_f_gpal(im,l,r,y,vals) Retrieves color indexes from the image for pixels (l, y) ... (r-1, y) into C. Returns the number of indexes retrieved. =item i_f_ppal(im,l,r,y,vals) Stores color indexes into the image for pixels (l, y) ... (r-1, y) from C. Returns the number of indexes retrieved. If indexes are outside the range of the images palette, then you may have problems reading those pixels with i_gpix() or i_glin(). =item i_f_addcolors(im,colors,count) Adds the count colors to the image's palette. Returns the index of the first color added, or -1 if there is not enough space for count colors. =item i_f_getcolors(im,index,colors,count) Retrieves count colors from the image's palette starting from entry index in the palette. Returns non-zero on success. =item i_f_colorcount(im) Returns the number of colors in the image's palette. Returns -1 if this is not a paletted image. =item i_f_maxcolors(im) Returns the maximum number of colors that can fit in the image's palette. Returns -1 if this is not a paletted image. =item i_f_findcolor(im,color,entry) Searches the image's palette for the specified color, setting *entry to the index and returning non-zero. Returns zero if the color is not found. =item i_f_setcolors_t(im,index,colors,count) Sets count colors starting from index in the image from the array colors. The colors to be set must already have entries in the image's palette. Returns non-zero on success. =back Finally, the i_f_destroy function pointer can be set which is called when the image is destroyed. This can be used to release memory pointed to by ext_data or release any other resources. When writing to a paletted image with i_ppix() or i_plin() and the color you are writing doesn't exist in the image, then it's possible that the image will be internally converted to a direct image with the same number of channels. =head1 TOOLS Several functions have been written to simplify creating new image types. These tools are available by including F. =head2 Floating point wrappers These functions implement the floating point sample versions of each interface function in terms of the integer sample version. These are: =over =item i_ppixf_fp =item i_gpixf_fp =item i_plinf_fp =item i_glinf_fp =item i_gsampf_fp =back =head2 Forwarding functions These functions are used in virtual images where the call should simply be forwarded to the underlying image. The underlying image is assumed to be the first pointer in a structure pointed at by ext_data. If this is not the case then these functions will just crash :) =over =item i_addcolors_forward =item i_getcolors_forward =item i_colorcount_forward =item i_maxcolors_forward =item i_findcolor_forward =item i_setcolors_forward =back =head2 Sample macros C defines several macros for converting samples between different sizes. Each macro is of the form CICI where I is one of 8, 16, or F (for floating-point samples). =over =item SampleFTo16(sample) =item Sample16ToF(sample) =item SampleFTo8(sample) =item Sample8ToF(sample) =item Sample16To8(num) =item Sample8To16(num) =back =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Expr/0000755000175000017500000000000012617614576020470 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/lib/Imager/Expr/Assem.pm0000644000175000017500000001470712031434615022067 0ustar gregoagregoapackage Imager::Expr::Assem; use strict; use Imager::Expr; use Imager::Regops; use vars qw($VERSION); $VERSION = "1.003"; use vars qw(@ISA); @ISA = qw(Imager::Expr); __PACKAGE__->register_type('assem'); sub compile { my ($self, $expr, $opts) = @_; my %nregs; my @vars = $self->_variables(); my @nregs = (0) x @vars; my @cregs; my %vars; @vars{@vars} = map { "r$_" } 0..$#vars; my %labels; my @ops; my @msgs; my $attr = \%Imager::Regops::Attr; # initially produce [ $linenum, $result, $opcode, @parms ] my $lineno = 0; while ($expr =~ s/^([^\n]+)(?:\n|$)//) { ++$lineno; my $line = $1; $line =~ s/#.*//; next if $line =~ /^\s*$/; for my $op (split /;/, $line) { if (my ($name, $type) = $op =~ /^\s*var\s+([^:]+):(\S+)\s*$/) { if (exists $vars{$name}) { push(@msgs, "$lineno: duplicate variable name '$name'"); next; } if ($type eq 'num' || $type eq 'n') { $vars{$name} = 'r'.@nregs; push(@nregs, undef); next; } elsif ($type eq 'pixel' || $type eq 'p' || $type eq 'c') { $vars{$name} = 'p'.@cregs; push(@cregs, undef); next; } push(@msgs, "$lineno: unknown variable type $type"); next; } # any statement can have a label if ($op =~ s/^\s*(\w+):\s*//) { if ($labels{$1}) { push(@msgs, "$lineno: duplicate label $1 (previous on $labels{$1}[1])"); next; } $labels{$1} = [ scalar @ops, $lineno ]; } next if $op =~ /^\s*$/; # jumps have special operand handling if ($op =~ /^\s*jump\s+(\w+)\s*$/) { push(@ops, [$lineno, "", "jump", $1]); } elsif (my ($code, $reg, $targ) = ($op =~ /^\s*(jumpz|jumpnz)\s+(\S+)\s+(\S+)\s*$/)) { push(@ops, [$lineno, "", $code, $reg, $targ]); } elsif ($op =~ /^\s*print\s+(\S+)\s*/) { push(@ops, [$lineno, "", 'print', $1 ]); } elsif ($op =~ /^\s*ret\s+(\S+)\s*/) { push(@ops, [$lineno, "", 'ret', $1]); } elsif ($op =~ s/\s*(\S+)\s*=\s*(\S+)\s*$//) { # simple assignment push(@ops, [$lineno, $1, "set", $2]); } elsif ($op =~ s/\s*(\S+)\s*=\s*(\S+)\s*//) { # some normal ops finally my ($result, $opcode) = ($1, $2); unless ($attr->{$opcode}) { push(@msgs, "$lineno: unknown operator $opcode"); next; } my @oper; while ($op =~ s/(\S+)\s*//) { push(@oper, $1); } push(@ops, [$lineno, $result, $opcode, @oper]); } else { push(@msgs, "$lineno: invalid statement '$op'"); } } } my $max_opr = $Imager::Regops::MaxOperands; my $numre = $self->numre; my $trans = sub { # translate a name/number to a my ($name) = @_; $name = $self->{constants}{$name} if exists $self->{constants}{$name}; if ($vars{$name}) { return $vars{$name}; } elsif ($name =~ /^$numre$/) { $vars{$name} = 'r'.@nregs; push(@nregs, $name); return $vars{$name}; } else { push(@msgs, "$lineno: undefined variable $name"); return ''; } }; # now to translate symbols and so on OP: for my $op (@ops) { $lineno = shift @$op; if ($op->[1] eq 'jump') { unless (exists $labels{$op->[2]}) { push(@msgs, "$lineno: unknown label $op->[2]"); next; } $op = [ 'jump', "j$labels{$op->[2]}[0]", (0) x $max_opr ]; } elsif ($op->[1] =~ /^jump/) { unless (exists $labels{$op->[3]}) { push(@msgs, "$lineno: unknown label $op->[2]"); next; } $op = [ $op->[1], $trans->($op->[2]), "j$labels{$op->[3]}[0]", (0) x ($max_opr-1) ]; } elsif ($op->[1] eq 'print') { $op = [ $op->[1], $trans->($op->[2]), (0) x $max_opr ]; } elsif ($op->[1] eq 'ret') { $op = [ 'ret', $trans->($op->[2]), (0) x $max_opr ]; } else { # a normal operator my ($result, $name, @parms) = @$op; if ($result =~ /^$numre$/) { push(@msgs, "$lineno: target of operator cannot be a constant"); next; } $result = $trans->($result); for my $parm (@parms) { $parm = $trans->($parm); } push(@parms, (0) x ($max_opr-@parms)); $op = [ $op->[1], @parms, $result ]; } } # more validation than a real assembler # not trying to solve the halting problem... if (@ops && $ops[-1][0] ne 'ret' && $ops[-1][0] ne 'jump') { push(@msgs, ": the last instruction must be ret or jump"); } $self->{nregs} = \@nregs; $self->{cregs} = \@cregs; if (@msgs) { $self->error(join("\n", @msgs)); return 0; } return \@ops; } 1; __END__ =head1 NAME Imager::Expr::Assem - an assembler for producing code for the Imager register machine =head1 SYNOPSIS use Imager::Expr::Assem; my $expr = Imager::Expr->new(assem=>'...', ...) =head1 DESCRIPTION This module is a simple Imager::Expr compiler that compiles a low-level language that has a nearly 1-to-1 relationship to the internal representation used for compiled register machine code. =head2 Syntax Each line can contain multiple statements separated by semi-colons. Anything after '#' in a line is ignored. Types of statements: =over 4 =item variable definition =over 4 C I:I =back defines variable I to have I, which can be any of C or C for a numeric type or C, C

or C for a pixel or color type. Variable names cannot include white-space. =item operators Operators can be split into 3 basic types, those that have a result value, those that don't and the null operator, eg. jump has no value. The format for operators that return a value is typically: =over 4 I = I I ... =back and for those that don't return a value: =over 4 I I =back where operator is any valid register machine operator, result is any variable defined with C, and operands are variables, constants or literals, or for jump operators, labels. The set operator can be simplified to: =over 4 I = I =back All operators maybe preceded by a label, which is any non-white-space text immediately followed by a colon (':'). =back =head1 BUGS Note that the current optimizer may produce incorrect optimization for your code, fortunately the optimizer will disable itself if you include any jump operator in your code. A single jump to anywhere after your final C operator can be used to disable the optimizer without slowing down your code. There's currently no high-level code generation that can generate code with loops or real conditions. =head1 SEE ALSO Imager(3), F, F =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Font/0000755000175000017500000000000012617614576020460 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/lib/Imager/Font/Type1.pm0000644000175000017500000000057712263740601022013 0ustar gregoagregoapackage Imager::Font::Type1; use strict; use Imager::Font::T1; use vars qw(@ISA $VERSION); @ISA = qw(Imager::Font::FT2); $VERSION = "1.012"; 1; __END__ =head1 NAME Imager::Font::Type1 - low-level functions for T1Lib text output =head1 DESCRIPTION This is a simple wrapper around Imager::Font::T1 for backwards compatibility. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Font/Test.pm0000644000175000017500000000340212263740601021716 0ustar gregoagregoapackage Imager::Font::Test; use strict; our $VERSION = "1.0001"; use base 'Imager::Font'; sub new { my ($class, %opts) = @_; bless \%opts, shift; } sub _draw { my ($self, %input) = @_; my $text = $input{string}; my $ppn = int($input{size} * 0.5 + 0.5); my $desc = int($input{size} * 0.3 + 0.5); my $asc = $input{size} - $desc; my $width = $ppn * length $text; my $x = $input{x}; my $y = $input{'y'}; $input{align} and $y -= $asc; $input{image}->box(color => $input{color}, xmin => $x, ymin => $y, xmax => $x + $width-1, ymax => $y + $input{size} - 1); return 1; } sub _bounding_box { my ($self, %input) = @_; my $text = $input{string}; my $ppn = int($input{size} * 0.5 + 0.5); my $desc = int($input{size} * 0.3 + 0.5); my $asc = $input{size} - $desc; return ( 0, -$desc, $ppn * length $text, $asc, -$desc, $asc, $ppn * length $text, 0 ); } sub has_chars { my ($self, %input) = @_; my $text = $input{string}; defined $text or return Imager->_set_error("has_chars: No string parameter supplied"); return (1) x length $text; } sub face_name { "test"; } sub glyph_names { my ($self, %input) = @_; my $text = $input{string}; defined $text or return Imager->_set_error("glyph_names: No string parameter supplied"); return (1) x length $text; } 1; =head1 NAME Imager::Font::Test - font driver producing consistent output for tests. =head1 SYNOPSIS my $font = Imager::Font::Test->new; # use $font where you use other fonts =head1 DESCRIPTION Imager::Font::Test is intended to produce consistent output without being subject to the inconsistent output produced by different versions of font libraries. The output is simple box for the whole string. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Font/Truetype.pm0000644000175000017500000000635512263740601022632 0ustar gregoagregoapackage Imager::Font::Truetype; use strict; use vars qw(@ISA $VERSION); @ISA = qw(Imager::Font); $VERSION = "1.012"; *_first = \&Imager::Font::_first; sub new { my $class = shift; my %hsh=(color=>Imager::Color->new(255,0,0,255), size=>15, @_); unless ($hsh{file}) { $Imager::ERRSTR = "No font file specified"; return; } unless (-e $hsh{file}) { $Imager::ERRSTR = "Font file $hsh{file} not found"; return; } unless ($Imager::formats{tt}) { $Imager::ERRSTR = "Type 1 fonts not supported in this build"; return; } my $id = Imager::i_tt_new($hsh{file}); unless ($id) { # the low-level code may miss some error handling $Imager::ERRSTR = Imager::_error_as_msg(); return; } return bless { id => $id, aa => $hsh{aa} || 0, file => $hsh{file}, type => 'tt', size => $hsh{size}, color => $hsh{color}, }, $class; } sub _draw { my $self = shift; my %input = @_; if ( exists $input{channel} ) { Imager::i_tt_cp($self->{id},$input{image}{IMG}, $input{'x'}, $input{'y'}, $input{channel}, $input{size}, $input{string}, $input{aa}, $input{utf8}, $input{align}); } else { Imager::i_tt_text($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'}, $input{color}, $input{size}, $input{string}, $input{aa}, $input{utf8}, $input{align}); } } sub _bounding_box { my $self = shift; my %input = @_; my @result = Imager::i_tt_bbox($self->{id}, $input{size}, $input{string}, $input{utf8}); unless (@result) { Imager->_set_error(Imager->_error_as_msg); return; } return @result; } sub utf8 { 1 } # check if the font has the characters in the given string sub has_chars { my ($self, %hsh) = @_; unless (defined $hsh{string}) { $Imager::ERRSTR = "No string supplied to \$font->has_chars()"; return; } if (wantarray) { my @result = Imager::i_tt_has_chars($self->{id}, $hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0)); unless (@result) { Imager->_set_error(Imager->_error_as_msg); return; } return @result; } else { my $result = Imager::i_tt_has_chars($self->{id}, $hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0)); unless (defined $result) { Imager->_set_error(Imager->_error_as_msg); return; } return $result; } } sub face_name { my ($self) = @_; Imager::i_tt_face_name($self->{id}); } sub can_glyph_names { 1; } sub glyph_names { my ($self, %input) = @_; my $string = $input{string}; defined $string or return Imager->_set_error("no string parameter passed to glyph_names"); my $utf8 = _first($input{utf8} || 0); my @names = Imager::i_tt_glyph_name($self->{id}, $string, $utf8); unless (@names) { Imager->_set_error(Imager->_error_as_msg); return; } return @names; } 1; __END__ =head1 NAME Imager::Font::Truetype - low-level functions for Truetype fonts =head1 DESCRIPTION Imager::Font creates a Imager::Font::Truetype object when asked to create a font object based on a F<.ttf> file. See Imager::Font to see how to use this type. This class provides low-level functions that require the caller to perform data validation. =head1 AUTHOR Addi, Tony =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Font/Image.pm0000644000175000017500000000736612031434615022034 0ustar gregoagregoapackage Imager::Font::Image; use strict; use Imager::Color; use File::Basename; use File::Spec; use vars qw(@ISA %REQUIRED_FIELDS); @ISA = qw(Imager::Font); sub NWIDTH () { 0 } sub PWIDTH () { 2 } sub GDESCENT () { 1 } sub GASCENT () { 3 } sub DESCENT () { 4 } sub ASCENT () { 5 } %REQUIRED_FIELDS = ( Image_spec => 1, Font_size => 1, Global_ascent => 1, Global_descent => 1,); # Required fields # Fontmetrics: # Font global data: # image name # font size # max glyph height # max glyph width # # The per character data is: # left edge (inclusive) # right edge (exclusive) # top edge (inclusive) # bottom edge (exclusive) # left adjustment # forward shift # baseline adjustment (from top) # # The left adjustment is the starting # offset into the glyph, the forward shift # is the actual forward movement of the # imaginary cursor. # To calculate the size of a string use: # sum (forward_shift_i) + left_adjustment_0 + width_last - left_adjustment_last - forward_shift_last # example font spec file: # IAGRFONT # # This is an imager font definition file. This is a comment # Image_spec = foo.png # Font_size = 12 # Global_ascent = 10 # Global_descent = -2 # # Per character data # FM_65 = 20 40 30 50 3 15 # # Code for 'A' left edge = 20, right = 40, top = 30, bottom 50, leading = 3, forward = 15. # The left adjustment is the starting # offset into the glyph, the forward shift # is the actual forward movement of the # imaginary cursor. # To calculate the size of a string use: # sum (forward_shift_i) + left_adjustment_0 + width_last - left_adjustment_last - forward_shift_last sub parse_fontspec_file { my ($self, $file) = @_; local *FH; return unless open(FH, "<$file"); my %req = %REQUIRED_FIELDS; while() { next if m/^\#/; if (m/^\s*?(\S+?)\s*=\s*(.+?)\s*$/) { # Check for a required field: my $char = $1; my $metric = $2; if ($req{$char}) { $self->{$char} = $metric; delete $req{$1}; } else { next unless $char =~ s/^FM_(\d+)$/$1/; next unless $metric =~ m/(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/; $self->{fm}->{$char} = [$1, $2, $3, $4, $5, $6]; } } } close(FH); return $self; } sub new { my $self = bless {}, shift; my %opts = (color=>Imager::Color->new(255, 0, 0, 0), @_); unless ($opts{file}) { $Imager::ERRSTR = "No font file specified"; return; } unless ($self->parse_fontspec_file($opts{file})) { $Imager::ERRSTR = "Font file $opts{file} not found or bad"; return; } my $img = Imager->new(); my $img_filename = File::Spec->catfile( dirname($opts{'file'}), $self->{Image_spec} ); unless ($img->open(%opts, file=>$img_filename)) { $Imager::ERRSTR = "Font IMAGE file $img_filename not found or bad: ". $img->errstr(); return; } $self->{image} = $img; $self->{size} = $self->{Font_size}; return $self; } sub get_glyph_data { my ($self, $glyph_code) = @_; return unless exists $self->{fm}->{$glyph_code}; return @{$self->{fm}->{$glyph_code}}; } # copy_glyph # # $x, $y is left, baseline for glyphs. # sub copy_glyph { my ($self, $glyph_code, $target_img, $x, $y) = @_; my @gdata = $self->get_glyph_data($glyph_code) or return; $target_img->rubthrough(src=>$self->{image}, tx => $x + $gdata[4], ty => $y - $self->{Global_ascent},, src_minx => $gdata[0], src_maxx => $gdata[1], src_miny => $gdata[2], src_maxy => $gdata[3]); } sub _draw { my ($self, %opts) = @_; my $x = $opts{'x'}; my $y = $opts{'y'}; my @glyphs = unpack("C*", $opts{string}); my $img = $opts{image}; my $glyph; for $glyph (@glyphs) { my @gmetrics = $self->get_glyph_data($glyph) or next; $self->copy_glyph($glyph, $img, $x, $y); $x += $gmetrics[5]; } } libimager-perl-1.004+dfsg.orig/lib/Imager/Font/BBox.pm0000644000175000017500000001216112031434615021631 0ustar gregoagregoapackage Imager::Font::BBox; use strict; use vars qw($VERSION); $VERSION = "1.006"; =head1 NAME Imager::Font::BBox - objects representing the bounding box of a string. =head1 SYNOPSIS use Imager::Font; # get the object my $font = Imager::Font->new(...); my $bbox = $font->bounding_box(string=>$text, size=>$size); # methods my $start = $bbox->start_offset; my $left_bearing = $bbox->left_bearing; my $right_bearing = $bbox->right_bearing; my $end = $bbox->end_offset; my $gdescent = $box->global_descent; my $gascent = $bbox->global_ascent; my $ascent = $bbox->ascent; my $decent = $bbox->descent; my $total_width = $bbox->total_width; my $fheight = $bbox->font_height; my $theight = $bbox->text_height; my $display_width = $bbox->display_width; =head1 DESCRIPTION Objects of this class are returned by the Imager::Font bounding_box() method when it is called in scalar context. This will hopefully make the information from this method more accessible. =head1 METHODS =over =item start_offset() =item neg_width =item left_bearing Returns the horizontal offset from the selected drawing location to the left edge of the first character drawn. If this is positive, the first glyph is to the right of the drawing location. The alias neg_width() is present to match the bounding_box() documentation for list context. The alias left_bearing() is present to match font terminology. =cut sub start_offset { return $_[0][0]; } sub neg_width { return $_[0][0]; } sub left_bearing { return $_[0][0]; } =item advance_width() The advance width of the string, if the driver supports that, otherwise the same as end_offset. =cut sub advance_width { my $self = shift; @$self > 6 ? $self->[6] : $self->[2]; } =item right_bearing The distance from the right of the last glyph to the end of the advance point. If the glyph overflows the right side of the advance width this value is negative. =cut sub right_bearing { my $self = shift; @$self >= 8 && return $self->[7]; # driver gives it to us # otherwise the closest we have is the difference between the # end_pos and advance_width return $self->advance_width - $self->pos_width; } =item display_width The distance from the left-most pixel of the left-most glyph to the right-most pixel of the right-most glyph. Equals advance_width - left_bearing - right_bearing (and implemented that way.) =cut sub display_width { my ($self) = @_; $self->advance_width - $self->left_bearing - $self->right_bearing; } =item global_descent() The lowest position relative to the font baseline that any character in the font reaches in the character cell. Normally negative. At least one font we've seen has reported a positive number for this. =cut sub global_descent { return $_[0][1]; } =item global_ascent() The highest position relative to the font baseline that any character in the font reaches in the character cell. Normally positive. =cut sub global_ascent { return $_[0][3]; } =item descent() The lowest position relative to the font baseline that any character in the supplied string reaches. Negative when any character's glyph reaches below the baseline. =cut sub descent { return $_[0][4]; } =item ascent() The highest position relative to the font baseline that any character in the supplied string reaches. Positive if any character's glyph reaches above the baseline. =cut sub ascent { return $_[0][5]; } =item font_height() The maximum displayed height of any string using this font. =cut sub font_height { my $self = shift; $self->global_ascent - $self->global_descent; } =item text_height() The displayed height of the supplied string. =cut sub text_height { my $self = shift; $self->ascent - $self->descent; } =back =head1 OBSOLETE METHODS These methods include bugs kept for backwards compatibility and shouldn't be used in new code. =over =item total_width() The total displayed width of the string. New code should use display_width(). This depends on end_offset(), and is limited by it's backward compatibility. =cut sub total_width { my $self = shift; $self->end_offset - $self->start_offset; } =item end_offset =item pos_width The offset from the selected drawing location to the right edge of the last character drawn. Should always be positive. You can use the alias pos_width() if you are used to the bounding_box() documentation for list context. For backwards compatibility this method returns the maximum of the advance width and the offset of the right edge of the last glyph. =cut sub end_offset { return $_[0][2]; } sub pos_width { return $_[0][2]; } =back =head1 INTERNAL FUNCTIONS =over =item new(...) Called by Imager::Font->bounding_box() to create the object. =cut sub new { my $class = shift; return bless [ @_ ], $class; } =back =head1 BUGS Doesn't reproduce the functionality that you get using the x and y parameters to Imager::Font->bounding_box(). I considered: my ($left, $top, $right, $bottom) = $box->offset(x=>$x, y=>$y) but this is about as clumsy as the original. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3), Imager::Font(3) =cut 1; libimager-perl-1.004+dfsg.orig/lib/Imager/Font/FreeType2.pm0000644000175000017500000000210312031434615022577 0ustar gregoagregoapackage Imager::Font::FreeType2; use strict; use Imager::Font::FT2; use vars qw(@ISA $VERSION); @ISA = qw(Imager::Font::FT2); $VERSION = "1.020"; 1; __END__ =head1 NAME Imager::Font::FreeType2 - low-level functions for FreeType2 text output =head1 DESCRIPTION Imager::Font creates a Imager::Font::FreeType2 object when asked to. See Imager::Font to see how to use this type. This class provides low-level functions that require the caller to perform data validation. This driver supports: =over =item transform() =item dpi() =item draw() The following parameters: =over =item * C =item * C =item * C =back =back =head2 Special behaviors If you call transform() to set a transformation matrix, hinting will be switched off. This prevents sudden jumps in the size of the text caused by the hinting when the transformation is the identity matrix. If for some reason you want hinting enabled, use $font->hinting(hinting=>1) to re-enable hinting. This will need to be called after I call to transform(). =head1 AUTHOR Addi, Tony =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Font/Wrap.pm0000644000175000017500000002416412263740601021720 0ustar gregoagregoapackage Imager::Font::Wrap; use strict; use Imager; use Imager::Font; use vars qw($VERSION); $VERSION = "1.004"; *_first = \&Imager::Font::_first; # we can't accept the utf8 parameter, too hard at this level # the %state contains: # font - the font # im - the image # x - the left position # w - the width # justify - fill, left, right or center sub _format_line { my ($state, $spaces, $text, $fill) = @_; $text =~ s/ +$//; my $box = $state->{font}->bounding_box(string=>$text, size=>$state->{size}); my $y = $state->{linepos} + $box->global_ascent; if ($state->{bottom} && $state->{linepos} + $box->font_height > $state->{bottom}) { $state->{full} = 1; return 0; } if ($text =~ /\S/ && $state->{im}) { my $justify = $fill ? $state->{justify} : $state->{justify} eq 'fill' ? 'left' : $state->{justify}; if ($justify ne 'fill') { my $x = $state->{x}; if ($justify eq 'right') { $x += $state->{w} - $box->advance_width; } elsif ($justify eq 'center') { $x += ($state->{w} - $box->advance_width) / 2; } $state->{font}->draw(image=>$state->{im}, string=>$text, x=>$x, 'y'=>$y, size=>$state->{size}, %{$state->{input}}); } else { (my $nospaces = $text) =~ tr/ //d; my $nospace_bbox = $state->{font}->bounding_box(string=>$nospaces, size=>$state->{size}); my $gap = $state->{w} - $nospace_bbox->advance_width; my $x = $state->{x}; $spaces = $text =~ tr/ / /; while (length $text) { if ($text =~ s/^(\S+)//) { my $word = $1; my $bbox = $state->{font}->bounding_box(string=>$word, size=>$state->{size}); $state->{font}->draw(image=>$state->{im}, string=>$1, x=>$x, 'y'=>$y, size=>$state->{size}, %{$state->{input}}); $x += $bbox->advance_width; } elsif ($text =~ s/^( +)//) { my $sep = $1; my $advance = int($gap * length($sep) / $spaces); $spaces -= length $sep; $gap -= $advance; $x += $advance; } else { die "This shouldn't happen\n"; } } } } $state->{linepos} += $box->font_height + $state->{linegap}; 1; } sub wrap_text { my $class = shift; my %input = @_; # try to get something useful my $x = _first(delete $input{'x'}, 0); my $y = _first(delete $input{'y'}, 0); my $im = delete $input{image}; my $imerr = $im || 'Imager'; my $width = delete $input{width}; if (!defined $width) { defined $im && $im->getwidth > $x or return $imerr->_set_error("No width supplied and can't guess"); $width = $im->getwidth - $x; } my $font = delete $input{font} or return $imerr->_set_error("No font parameter supplied"); my $size = _first(delete $input{size}, $font->{size}); defined $size or return $imerr->_set_error("No font size supplied"); 2 * $size < $width or return $imerr->_set_error("Width too small for font size"); my $text = delete $input{string}; defined $text or return $imerr->_set_error("No string parameter supplied"); my $justify = _first($input{justify}, "left"); my %state = ( font => $font, im => $im, x => $x, w => $width, justify => $justify, 'y' => $y, linepos=>$y, size=>$size, input => \%input, linegap => delete $input{linegap} || 0, ); $state{height} = delete $input{height}; if ($state{height}) { $state{bottom} = $y + $state{height}; } my $line = ''; my $spaces = 0; my $charpos = 0; my $linepos = 0; pos($text) = 0; # avoid a warning while (pos($text) < length($text)) { #print pos($text), "\n"; if ($text =~ /\G( +)/gc) { #print "spaces\n"; $line .= $1; $spaces += length($1); } elsif ($text =~ /\G(?:\x0D\x0A?|\x0A\x0D?)/gc) { #print "newline\n"; _format_line(\%state, $spaces, $line, 0) or last; $line = ''; $spaces = 0; $linepos = pos($text); } elsif ($text =~ /\G(\S+)/gc) { #print "word\n"; my $word = $1; my $bbox = $font->bounding_box(string=>$line . $word, size=>$size); if ($bbox->advance_width > $width) { _format_line(\%state, $spaces, $line, 1) or last; $line = ''; $spaces = 0; $linepos = pos($text) - length($word); } $line .= $word; # check for long words $bbox = $font->bounding_box(string=>$line, size=>$size); while ($bbox->advance_width > $width) { my $len = length($line) - 1; $bbox = $font->bounding_box(string=>substr($line, 0, $len), size=>$size); while ($bbox->advance_width > $width) { --$len; $bbox = $font->bounding_box(string=>substr($line, 0, $len), size=>$size); } _format_line(\%state, 0, substr($line, 0, $len), 0) or last; $line = substr($line, $len); $bbox = $font->bounding_box(string=>$line, size=>$size); $linepos = pos($text) - length($line); } } elsif ($text =~ /\G\s/gc) { # skip a single unrecognized whitespace char #print "skip\n"; $linepos = pos($text); } } if (length $line && !$state{full}) { $linepos += length $line if _format_line(\%state, 0, $line, 0); } if ($input{savepos}) { ${$input{savepos}} = $linepos; } return ($x, $y, $x+$width, $state{linepos}); } 1; __END__ =head1 NAME Imager::Font::Wrap - simple wrapped text output =head1 SYNOPSIS use Imager::Font::Wrap; my $img = Imager->new(xsize=>$xsize, ysize=>$ysize); my $font = Imager::Font->new(file=>$fontfile); my $string = "..."; # text with or without newlines Imager::Font::Wrap->wrap_text( image => $img, font => $font, string => $string, x => $left, y => $top, width => $width, .... ); =head1 DESCRIPTION This is a simple text wrapper with options to control the layout of text within the line. You can control the position, width and height of the text with the C, C, C, C and C options. You can simply calculate space usage by setting C to C, or set C to see how much text can fit within the given C. =over =item wrap_text() Draw word-wrapped text. =over =item * C, C - The top-left corner of the rectangle the text is formatted into. Defaults to (0, 0). =item * C - The width of the formatted text in pixels. Defaults to the horizontal gap between the top-left corner and the right edge of the image. If no image is supplied then this is required. =item * C - The maximum height of the formatted text in pixels. Not required. =item * C - The amount of text consumed (as a count of characters) will be stored into the scalar this refers to. my $pagenum = 1; my $string = "..."; my $font = ...; my $savepos; while (length $string) { my $img = Imager->new(xsize=>$xsize, ysize=>$ysize); Imager::Font::Wrap->wrap_text(string=>$string, font=>$font, image=>$img, savepos => \$savepos) or die $img->errstr; $savepos > 0 or die "Could not fit any text on page\n"; $string = substr($string, $savepos); $img->write(file=>"page$pagenum.ppm"); } =item * C - The image to render the text to. Can be supplied as C or not provided to simply calculate the bounding box. =item * C - The font used to render the text. Required. =item * C - The size to render the font in. Defaults to the size stored in the font object. Required if it isn't stored in the font object. =item * C - The text to render. This can contain non-white-space, blanks (ASCII 0x20), and newlines. Newlines must match /(?:\x0A\x0D?|\x0D\x0A?)/. White-space other than blanks and newlines are completely ignored. =item * C The way text is formatted within each line. Possible values include: =over =item * C - left aligned against the left edge of the text box. =item * C - right aligned against the right edge of the text box. =item * C

- centered horizontally in the text box. =item * fill - all but the final line of the paragraph has spaces expanded so that the line fills from the left to the right edge of the text box. =back =item * C - Gap between lines of text in pixels. This is in addition to the size from C<< $font->font_height >>. Can be positive or negative. Default 0. =back Any other parameters are passed onto Imager::Font->draw(). Returns a list: ($left, $top, $right, $bottom) which are the bounds of the space used to layout the text. If C is set then this is the space used within that height. You can use this to calculate the space required to format the text before doing it: my ($left, $top, $right, $bottom) = Imager::Font::Wrap->wrap_text(string => $string, font => $font, width => $xsize); my $img = Imager->new(xsize=>$xsize, ysize=>$bottom); Imager::Font::Wrap->wrap_text(string => $string, font => $font, width => $xsize, image => $image); =back =head1 BUGS Imager::Font can handle UTF-8 encoded text itself, but this module doesn't support that (and probably won't). This could probably be done with regex magic. Currently ignores the C parameter, if you supply one it will be supplied to the draw() function and the text will be too short or too long for the C. Uses a simplistic text model, which is why there's no hyphenation, and no tabs. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3), Imager::Font(3) =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Handy.pod0000644000175000017500000000163412263740601021307 0ustar gregoagregoa=head1 NAME Imager::Handy - simple access to common functions =head1 SYNOPSIS use Imager ':handy'; my $color = NC(255, 0, 0); my $font = NF(1.0, 0, 0); =head1 DESCRIPTION If you use Imager with the C<:handy> import tag, it will export a number of functions that can shorter your code. =over =item NC() =item newcolor() =item newcolour() Create a new Imager::Color object, supplying any parameters to the new() method. my $color = NC('red'); =item NF() =item newfont() Create a new Imager::Font object, supplying any parameters to the new() method. my $font = NF(file => 'foo.ttf'); =item NCF() Create a new L object, supplying any parameters to the new() method. my $colorf = NCF(1.0, 0, 0); =back =head1 BUGS NC() can be mostly replaced by supplying the color name or other description directly to the drawing method. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/API.pod0000644000175000017500000002362212461136230020653 0ustar gregoagregoa=head1 NAME Imager::API - Imager's C API - introduction. =head1 SYNOPSIS #include "imext.h" #include "imperl.h" DEFINE_IMAGER_CALLBACKS; MODULE = Your::Module PACKAGE = Your::Module ... BOOT: /* any release with the API */ PERL_INITIALIZE_IMAGER_CALLBACKS; /* preferred from Imager 0.91 */ PERL_INITIALIZE_IMAGER_CALLBACKS_NAME("My::Module"); =head1 DESCRIPTION =for stopwords XS The API allows you to access Imager functions at the C level from XS and from C. The intent is to allow users to: =over =item * write C code that does Imager operations the user might do from Perl, but faster, for example, the L example. =item * write C code that implements an application specific version of some core Imager object, for example, Imager::SDL. =item * write C code that hooks into Imager's existing methods, such as filter or file format handlers. =back See L for information on using Imager's Inline::C support. =head1 Beware =over =item * don't return an object you received as a parameter - this will cause the object to be freed twice. =back =head1 Types The API makes the following types visible: =over =item * L - used to represent an image =item * L - used to represent a color with up to 8 bits per sample. =item * L - used to represent a color with a double per sample. =item * L - fill objects>> - an abstract fill =item * L - Imager's per-thread state. =back At this point there is no consolidated font object type, and hence the font functions are not visible through Imager's API. =head2 i_img This contains the dimensions of the image (C, C, C), image metadata (C, C, C, C), potentially image data (C) and a function table, with pointers to functions to perform various low level image operations. The only time you should directly write to any value in this type is if you're implementing your own image type. The typemap includes type names Imager and Imager::ImgRaw as typedefs for C. For incoming parameters the typemap will accept either Imager or Imager::ImgRaw objects. For return values the typemap will produce a full Imager object for an Imager return type and a raw image object for an Imager::ImgRaw return type. =head2 i_color Represents an 8-bit per sample color. This is a union containing several different structs for access to components of a color: =over =item * C - single member C. =item * C - C, C, C members. =item * C - C, C, C, C members. =item * C - array of channels. =back Use C for parameter and return value types. =head2 i_fcolor Similar to C except that each component is a double instead of an unsigned char. Use Imager::Color::Float for parameter and return value types. =head2 i_fill_t Abstract type containing pointers called to perform low level fill operations. Unless you're defining your own fill objects you should treat this as an opaque type. Use Imager::FillHandle for parameter and return value types. At the Perl level this is stored in the C member of the Perl level Imager::Fill object. =head2 i_io_glue_t C is Imager's I/O abstraction. Historically named C, and this name is available for backward compatibility. =head2 im_context_t This new type is an opaque type that stores Imager's per-thread state, including the error message stack, the current log file state and image size file limits. While Imager's internal typemap provides a C mapping and a DESTROY method for this type you B never return objects of this type back to perl. See L for more information. =head2 i_polygon_t Represents a single polygon supplied to i_poly_poly_aa() and i_poly_poly_aa_cfill(). This is a structure with 3 members: =over =item * C, C - pointers to the first elements of arrays of doubles that define the vertices of the polygon. =item * C - the number of values in each of the C and C arrays. =back =head2 i_poly_fill_mode_t An enumerated type of the possible fill modes for polygons: =over =item * C - if areas overlap an odd number of times, they are filled, and are otherwise unfilled. =item * C - areas that have an unbalanced clockwise and anti-clockwise boundary are filled. This is the same as C for X and C for Win32 GDI. =back =head1 Create an XS module using the Imager API =head2 Foo.pm Load Imager: use Imager 0.48; and bootstrap your XS code - see L or L. =head2 C You'll need the following in your XS source: =over =item * include the Imager external API header, and the perl interface header: #include "imext.h" #include "imperl.h" =item * create the variables used to hold the callback table: DEFINE_IMAGER_CALLBACKS; =item * initialize the callback table in your C code: BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; From Imager 0.91 you can supply your module name to improve error reporting: BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS_NAME("My::Module"); =back =head2 foo.c In any other source files where you want to access the Imager API, you'll need to: =over =item * include the Imager external API header: #include "imext.h" =back =head2 C If you're creating an XS module that depends on Imager's API your C will need to do the following: =over =item * C =item * include Imager's include directory in INC: INC => Imager::ExtUtils->includes =item * use Imager's typemap: TYPEMAPS => [ Imager::ExtUtils->typemap ] =item * include Imager 0.48 as a PREREQ_PM: PREREQ_PM => { Imager => 0.48, }, =item * Since you use Imager::ExtUtils in C (or C) you should include Imager in your configure_requires: META_MERGE => { configure_requires => { Imager => "0.48" } }, =back =head1 Context objects Starting with Imager 0.93, Imager keeps some state per-thread rather than storing it in global (or static) variables. The intent is to improve support for multi-threaded perl programs. For the typical XS or Inline::C module using Imager's API this won't matter - the changes are hidden behind macros and rebuilding your module should require no source code changes. Some operations will be slightly slower, these include: =over =item * creating an image =item * reporting errors =item * creating I/O objects =item * setting/getting/testing image file limits =item * logging =back You can avoid this fairly minor overhead by adding a C<#define>: #define IMAGER_NO_CONTEXT before including any Imager header files, but you will need to manage context objects yourself. Some functions and macros that are available without C are not available with it defined, these are: =over =item * mm_log() - to avoid using a different context object for the line header and the line text you need to use im_log() instead, with a context object visible in scope. =back =head2 C With C defined, C refers to the locally defined context object, either via one the of the C macros or as a parameter with the C macro. Without C, C is a call to C which retrieves the context object for the current thread. There is no C macro, any Imager function that can accept a context parameter always accepts it. =head2 C This macro declares a variable of type L that's accessible via the C macro. This is intended for use as a parameter declaration for functions: void f(pIMCTX) { ... use aIMCTX here } void g(...) { ... f(aIMCTX); } =head2 C Defines a local context variable and initializes it via L. =head2 C Defines a local context variable and initializes it from the context stored in an L, eg: void f(i_img *im) { dIMCTXim(im); ... } =head2 C Defines a local context variable and initializes it from the context stored in an L<< IE<47>O object|/i_io_glue_t >> object. void f(i_io_glue_t *io) { dIMCTXio(io); ... } =head2 C Defines a local context variable accessible via C in terms of an expression you supply: void f(my_object *p) { dIMCTXctx(p->context); ... } This can be used to define your own local context macro: #define dIMCTXmine(mine) ((mine)->context) void f(my_object *p) { dIMCTXmine(p); ... } =head1 Mutex Functions Since some libraries are not thread safe, Imager's API includes some simple mutex functions. To create a mutex: i_mutex_t m = i_mutex_new(); To control or lock the mutex: i_mutex_lock(m); To release or unlock the mutex: i_mutex_unlock(m); To free any resources used by the mutex: i_mutex_destroy(m); I most cases where you'd use these functions, your code would create the mutex in your BOOT section, then lock and unlock the mutex as needed to control access to the library. =head1 Context slots =for stopwords TLS APIs To avoid abstracting the platform TLS and thread clean up handling, Imager provides simple APIs for storing per-context information. To allocate a slot: im_slot_t slot = im_context_slot_new(callback) where callback is a (possibly NULL) function pointer called when the context object is destroyed. By default, the stored value for a slot is NULL, whether for a new context or for a cloned context. To store a value: im_context_slot_set(aIMCTX, slot, somevalue); where C can be represented as a C. To retrieve the value: value = im_context_slot_get(aIMCTX, slot); =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::ExtUtils, Imager::APIRef, Imager::Inline =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Color.pm0000644000175000017500000004074612263740601021163 0ustar gregoagregoapackage Imager::Color; use Imager; use strict; use vars qw($VERSION); $VERSION = "1.011"; # It's just a front end to the XS creation functions. # used in converting hsv to rgb my @hsv_map = ( 'vkm', 'nvm', 'mvk', 'mnv', 'kmv', 'vmn' ); sub _hsv_to_rgb { my ($hue, $sat, $val) = @_; # HSV conversions from pages 401-403 "Procedural Elements for Computer # Graphics", 1985, ISBN 0-07-053534-5. my @result; if ($sat <= 0) { return ( 255 * $val, 255 * $val, 255 * $val ); } else { $val >= 0 or $val = 0; $val <= 1 or $val = 1; $sat <= 1 or $sat = 1; $hue >= 360 and $hue %= 360; $hue < 0 and $hue += 360; $hue /= 60.0; my $i = int($hue); my $f = $hue - $i; $val *= 255; my $m = $val * (1.0 - $sat); my $n = $val * (1.0 - $sat * $f); my $k = $val * (1.0 - $sat * (1 - $f)); my $v = $val; my %fields = ( 'm'=>$m, 'n'=>$n, 'v'=>$v, 'k'=>$k, ); return @fields{split //, $hsv_map[$i]}; } } # cache of loaded gimp files # each key is a filename, under each key is a hashref with the following # keys: # mod_time => last mod_time of file # colors => hashref name to arrayref of colors my %gimp_cache; # palette search locations # this is pretty rude # $HOME is replaced at runtime my @gimp_search = ( '$HOME/.gimp-1.2/palettes/Named_Colors', '$HOME/.gimp-1.1/palettes/Named_Colors', '$HOME/.gimp/palettes/Named_Colors', '/usr/share/gimp/1.2/palettes/Named_Colors', '/usr/share/gimp/1.1/palettes/Named_Colors', '/usr/share/gimp/palettes/Named_Colors', ); my $default_gimp_palette; sub _load_gimp_palette { my ($filename) = @_; if (open PAL, "< $filename") { my $hdr = ; chomp $hdr; unless ($hdr =~ /GIMP Palette/) { close PAL; $Imager::ERRSTR = "$filename is not a GIMP palette file"; return; } my $line; my %pal; my $mod_time = (stat PAL)[9]; while (defined($line = )) { next if $line =~ /^#/ || $line =~ /^\s*$/; chomp $line; my ($r,$g, $b, $name) = split ' ', $line, 4; if ($name) { $name =~ s/\s*\([\d\s]+\)\s*$//; $pal{lc $name} = [ $r, $g, $b ]; } } close PAL; $gimp_cache{$filename} = { mod_time=>$mod_time, colors=>\%pal }; return 1; } else { $Imager::ERRSTR = "Cannot open palette file $filename: $!"; return; } } sub _get_gimp_color { my %args = @_; my $filename; if ($args{palette}) { $filename = $args{palette}; } elsif (defined $default_gimp_palette) { # don't search again and again and again ... if (!length $default_gimp_palette || !-f $default_gimp_palette) { $Imager::ERRSTR = "No GIMP palette found"; $default_gimp_palette = ""; return; } $filename = $default_gimp_palette; } else { # try to make one up - this is intended to die if tainting is # enabled and $ENV{HOME} is tainted. To avoid that untaint $ENV{HOME} # or set the palette parameter for my $attempt (@gimp_search) { my $work = $attempt; # don't modify the source array $work =~ /\$HOME/ && !defined $ENV{HOME} and next; $work =~ s/\$HOME/$ENV{HOME}/; if (-e $work) { $filename = $work; last; } } if (!$filename) { $Imager::ERRSTR = "No GIMP palette found"; $default_gimp_palette = ""; return (); } $default_gimp_palette = $filename; } if ((!$gimp_cache{$filename} || (stat $filename)[9] != $gimp_cache{$filename}) && !_load_gimp_palette($filename)) { return (); } if (!$gimp_cache{$filename}{colors}{lc $args{name}}) { $Imager::ERRSTR = "Color '$args{name}' isn't in $filename"; return (); } return @{$gimp_cache{$filename}{colors}{lc $args{name}}}; } my @x_search = ( '/usr/share/X11/rgb.txt', # newer Xorg X11 dists use this '/usr/lib/X11/rgb.txt', # seems fairly standard '/usr/local/lib/X11/rgb.txt', # seems possible '/usr/X11R6/lib/X11/rgb.txt', # probably the same as the first '/usr/openwin/lib/rgb.txt', '/usr/openwin/lib/X11/rgb.txt', ); my $default_x_rgb; # called by the test code to check if we can test this stuff sub _test_x_palettes { @x_search; } # x rgb.txt cache # same structure as %gimp_cache my %x_cache; sub _load_x_rgb { my ($filename) = @_; local *RGB; if (open RGB, "< $filename") { my $line; my %pal; my $mod_time = (stat RGB)[9]; while (defined($line = )) { # the version of rgb.txt supplied with GNU Emacs uses # for comments next if $line =~ /^[!#]/ || $line =~ /^\s*$/; chomp $line; my ($r,$g, $b, $name) = split ' ', $line, 4; if ($name) { $pal{lc $name} = [ $r, $g, $b ]; } } close RGB; $x_cache{$filename} = { mod_time=>$mod_time, colors=>\%pal }; return 1; } else { $Imager::ERRSTR = "Cannot open palette file $filename: $!"; return; } } sub _get_x_color { my %args = @_; my $filename; if ($args{palette}) { $filename = $args{palette}; } elsif (defined $default_x_rgb) { unless (length $default_x_rgb) { $Imager::ERRSTR = "No X rgb.txt palette found"; return (); } $filename = $default_x_rgb; } else { for my $attempt (@x_search) { if (-e $attempt) { $filename = $attempt; last; } } if (!$filename) { $Imager::ERRSTR = "No X rgb.txt palette found"; $default_x_rgb = ""; return (); } } if ((!$x_cache{$filename} || (stat $filename)[9] != $x_cache{$filename}{mod_time}) && !_load_x_rgb($filename)) { return (); } $default_x_rgb = $filename; if (!$x_cache{$filename}{colors}{lc $args{name}}) { $Imager::ERRSTR = "Color '$args{name}' isn't in $filename"; return (); } return @{$x_cache{$filename}{colors}{lc $args{name}}}; } # Parse color spec into an a set of 4 colors sub _pspec { return (@_,255) if @_ == 3 && !grep /[^\d.+eE-]/, @_; return (@_ ) if @_ == 4 && !grep /[^\d.+eE-]/, @_; if ($_[0] =~ /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) { return (hex($1),hex($2),hex($3),hex($4)); } if ($_[0] =~ /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) { return (hex($1),hex($2),hex($3),255); } if ($_[0] =~ /^\#([\da-f])([\da-f])([\da-f])$/i) { return (hex($1) * 17, hex($2) * 17, hex($3) * 17, 255); } my %args; if (@_ == 1) { # a named color %args = ( name => @_ ); } else { %args = @_; } my @result; if (exists $args{gray}) { @result = $args{gray}; } elsif (exists $args{grey}) { @result = $args{grey}; } elsif ((exists $args{red} || exists $args{r}) && (exists $args{green} || exists $args{g}) && (exists $args{blue} || exists $args{b})) { @result = ( exists $args{red} ? $args{red} : $args{r}, exists $args{green} ? $args{green} : $args{g}, exists $args{blue} ? $args{blue} : $args{b} ); } elsif ((exists $args{hue} || exists $args{h}) && (exists $args{saturation} || exists $args{'s'}) && (exists $args{value} || exists $args{v})) { my $hue = exists $args{hue} ? $args{hue} : $args{h}; my $sat = exists $args{saturation} ? $args{saturation} : $args{'s'}; my $val = exists $args{value} ? $args{value} : $args{v}; @result = _hsv_to_rgb($hue, $sat, $val); } elsif (exists $args{web}) { if ($args{web} =~ /^#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])$/i) { @result = (hex($1),hex($2),hex($3)); } elsif ($args{web} =~ /^#?([\da-f])([\da-f])([\da-f])$/i) { @result = (hex($1) * 17, hex($2) * 17, hex($3) * 17); } } elsif ($args{name}) { unless (@result = _get_gimp_color(%args)) { unless (@result = _get_x_color(%args)) { require Imager::Color::Table; unless (@result = Imager::Color::Table->get($args{name})) { $Imager::ERRSTR = "No color named $args{name} found"; return (); } } } } elsif ($args{gimp}) { @result = _get_gimp_color(name=>$args{gimp}, %args); } elsif ($args{xname}) { @result = _get_x_color(name=>$args{xname}, %args); } elsif ($args{builtin}) { require Imager::Color::Table; @result = Imager::Color::Table->get($args{builtin}); } elsif ($args{rgb}) { @result = @{$args{rgb}}; } elsif ($args{rgba}) { @result = @{$args{rgba}}; return @result if @result == 4; } elsif ($args{hsv}) { @result = _hsv_to_rgb(@{$args{hsv}}); } elsif ($args{channels}) { return @{$args{channels}}; } elsif (exists $args{channel0} || $args{c0}) { my $i = 0; while (exists $args{"channel$i"} || exists $args{"c$i"}) { push(@result, exists $args{"channel$i"} ? $args{"channel$i"} : $args{"c$i"}); ++$i; } } else { $Imager::ERRSTR = "No color specification found"; return (); } if (@result) { if (exists $args{alpha} || exists $args{a}) { push(@result, exists $args{alpha} ? $args{alpha} : $args{a}); } while (@result < 4) { push(@result, 255); } return @result; } return (); } sub new { shift; # get rid of class name. my @arg = _pspec(@_); return @arg ? new_internal($arg[0],$arg[1],$arg[2],$arg[3]) : (); } sub set { my $self = shift; my @arg = _pspec(@_); return @arg ? set_internal($self, $arg[0],$arg[1],$arg[2],$arg[3]) : (); } sub equals { my ($self, %opts) = @_; my $other = $opts{other} or return Imager->_set_error("'other' parameter required"); my $ignore_alpha = $opts{ignore_alpha} || 0; my @left = $self->rgba; my @right = $other->rgba; my $last_chan = $ignore_alpha ? 2 : 3; for my $ch (0 .. $last_chan) { $left[$ch] == $right[$ch] or return; } return 1; } sub CLONE_SKIP { 1 } # Lifted from Graphics::Color::RGB # Thank you very much sub hsv { my( $self ) = @_; my( $red, $green, $blue, $alpha ) = $self->rgba; my $max = $red; my $maxc = 'r'; my $min = $red; if($green > $max) { $max = $green; $maxc = 'g'; } if($blue > $max) { $max = $blue; $maxc = 'b'; } if($green < $min) { $min = $green; } if($blue < $min) { $min = $blue; } my ($h, $s, $v); if($max == $min) { $h = 0; } elsif($maxc eq 'r') { $h = 60 * (($green - $blue) / ($max - $min)) % 360; } elsif($maxc eq 'g') { $h = (60 * (($blue - $red) / ($max - $min)) + 120); } elsif($maxc eq 'b') { $h = (60 * (($red - $green) / ($max - $min)) + 240); } $v = $max/255; if($max == 0) { $s = 0; } else { $s = 1 - ($min / $max); } return int($h), $s, $v, $alpha; } 1; __END__ =head1 NAME Imager::Color - Color handling for Imager. =head1 SYNOPSIS use Imager; $color = Imager::Color->new($red, $green, $blue); $color = Imager::Color->new($red, $green, $blue, $alpha); $color = Imager::Color->new("#C0C0FF"); # html color specification $color->set($red, $green, $blue); $color->set($red, $green, $blue, $alpha); $color->set("#C0C0FF"); # html color specification ($red, $green, $blue, $alpha) = $color->rgba(); @hsv = $color->hsv(); $color->info(); if ($color->equals(other=>$other_color)) { ... } =head1 DESCRIPTION This module handles creating color objects used by Imager. The idea is that in the future this module will be able to handle color space calculations as well. An Imager color consists of up to four components, each in the range 0 to 255. Unfortunately the meaning of the components can change depending on the type of image you're dealing with: =over =item * for 3 or 4 channel images the color components are red, green, blue, alpha. =item * for 1 or 2 channel images the color components are gray, alpha, with the other two components ignored. =back An alpha value of zero is fully transparent, an alpha value of 255 is fully opaque. =head1 METHODS =over 4 =item new This creates a color object to pass to functions that need a color argument. =item set This changes an already defined color. Note that this does not affect any places where the color has been used previously. =item rgba() This returns the red, green, blue and alpha channels of the color the object contains. =item info Calling info merely dumps the relevant color to the log. =item equals(other=>$other_color) =item equals(other=>$other_color, ignore_alpha=>1) Compares $self and color $other_color returning true if the color components are the same. Compares all four channels unless C is set. If C is set only the first three channels are compared. =back You can specify colors in several different ways, you can just supply simple values: =over =item * simple numeric parameters - if you supply 3 or 4 numeric arguments, you get a color made up of those RGB (and possibly A) components. =item * a six hex digit web color, either C or C<#RRGGBB> =item * an eight hex digit web color, either C or C<#RRGGBBAA>. =item * a 3 hex digit web color, C<#RGB> - a value of F becomes 255. =item * a color name, from whichever of the gimp C file or X C is found first. The same as using the C keyword. =back You can supply named parameters: =over =item * 'red', 'green' and 'blue', optionally shortened to 'r', 'g' and 'b'. The color components in the range 0 to 255. # all of the following are equivalent my $c1 = Imager::Color->new(red=>100, blue=>255, green=>0); my $c2 = Imager::Color->new(r=>100, b=>255, g=>0); my $c3 = Imager::Color->new(r=>100, blue=>255, g=>0); =item * C, C and C, optionally shortened to C, C and C, to specify a HSV color. 0 <= hue < 360, 0 <= s <= 1 and 0 <= v <= 1. # the same as RGB(127,255,127) my $c1 = Imager::Color->new(hue=>120, v=>1, s=>0.5); my $c1 = Imager::Color->new(hue=>120, value=>1, saturation=>0.5); =item * C, which can specify a 6 or 3 hex digit web color, in any of the forms C<#RRGGBB>, C<#RGB>, C or C. my $c1 = Imager::Color->new(web=>'#FFC0C0'); # pale red =item * C or C which specifies a single channel, from 0 to 255. # exactly the same my $c1 = Imager::Color->new(gray=>128); my $c1 = Imager::Color->new(grey=>128); =item * C which takes a 3 member arrayref, containing each of the red, green and blue values. # the same my $c1 = Imager::Color->new(rgb=>[255, 100, 0]); my $c1 = Imager::Color->new(r=>255, g=>100, b=>0); =item * C which takes a 3 member arrayref, containing each of hue, saturation and value. # the same my $c1 = Imager::Color->new(hsv=>[120, 0.5, 1]); my $c1 = Imager::Color->new(hue=>120, v=>1, s=>0.5); =item * C which specifies a color from a GIMP palette file. You can specify the file name of the palette file with the 'palette' parameter, or let Imager::Color look in various places, typically C<$HOME/gimp-1.x/palettes/Named_Colors> with and without the version number, and in C. The palette file must have color names. my $c1 = Imager::Color->new(gimp=>'snow'); my $c1 = Imager::Color->new(gimp=>'snow', palette=>'testimg/test_gimp_pal); =item * C which specifies a color from an X11 C file. You can specify the file name of the C file with the C parameter, or let Imager::Color look in various places, typically C. my $c1 = Imager::Color->new(xname=>'blue') # usually RGB(0, 0, 255) =item * C which specifies a color from the built-in color table in Imager::Color::Table. The colors in this module are the same as the default X11 C file. my $c1 = Imager::Color->new(builtin=>'black') # always RGB(0, 0, 0) =item * C which specifies a name from either a GIMP palette, an X C file or the built-in color table, whichever is found first. =item * 'channel0', 'channel1', etc, each of which specifies a single channel. These can be abbreviated to 'c0', 'c1' etc. =item * 'channels' which takes an arrayref of the channel values. =back Optionally you can add an alpha channel to a color with the 'alpha' or 'a' parameter. These color specifications can be used for both constructing new colors with the new() method and modifying existing colors with the set() method. =head1 METHODS =over =item hsv() my($h, $s, $v, $alpha) = $color->hsv(); Returns the color as a Hue/Saturation/Value/Alpha tuple. =back =head1 AUTHOR Arnar M. Hrafnkelsson, addi@umich.edu And a great deal of help from others - see the C for a complete list. =head1 SEE ALSO Imager(3), Imager::Color http://imager.perl.org/ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/LargeSamples.pod0000644000175000017500000000623012263740601022620 0ustar gregoagregoa=head1 NAME Imager::LargeSamples - track/document large sample support =head1 SYNOPSIS # make a large sample image my $im = Imager->new(..., bits => 16); # call some method my $result = $im->$method(...); # was the image modified at its full sample size =head1 DESCRIPTION Imager has had in-memory support for large samples for years now, but many methods still don't work at the higher sample size when supplied with a large sample image. This document will track which methods support large samples and which don't, for future improvements. =head1 Support by method Method Support Notes ------ ------- ----- arc Partial [1] box Partial [2] circle Partial [1] convert Full copy Full crop Full difference Full filter Partial Depends on the filter. flip Full flood_fill Partial [1] getpixel Full getsamples Full getscanline Full map None masked Full matrix_transform Full paste Full polygon Partial [1] polyline None read Partial See L read_multi Partial See L rotate Full rubthrough Full scale Partial Some qtypes support large samples scaleX None scaleY None setpixel Full setscanline Full string Full Preserves large samples, but most font drivers generate 8 or fewer bits of levels of coverage. transform None transform2 None write Partial See L write_multi Partial See L [1] filling an area using the fill parameter works at the full depth of the image, using filled => 1 and color works at 8-bits/sample [2] box() will fill the area at the supplied color, but outline at 8-bits/sample. =head1 File format large sample support Format Format samples Imager support ------ -------------- -------------- BMP 8 8 GIF 8 8 ICO 8 8 JPEG 8, 12 8 PBM 1 1 PGM/PPM 1-16 read any, writes 8, 16 PNG 1, 2, 4, 8, 16 1, 2, 4, 8 paletted 1, 8, 16 gray (1 for is_monochrome() images) 8, 16 RGB RAW 8 SGI 8, 16 8, 16 TGA 8 8 TIFF (many) read/write 8, 16, 32 contig rgb/grey images read/write bi-level read/write 4/8 paletted images =head1 Filter larger sample support Filter Large sample support ------ -------------------- autolevels No bumpmap No bumpmap_complex No contrast No conv Yes fountain Yes gaussian Yes gradgen No hardinvert Yes mosaic No postlevels No radnoise No turbnoise No unsharpmask Yes watermark No =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Filters.pod0000644000175000017500000005177412322335073021665 0ustar gregoagregoa=head1 NAME Imager::Filters - Entire Image Filtering Operations =head1 SYNOPSIS use Imager; $img = ...; $img->filter(type=>'autolevels'); $img->filter(type=>'autolevels', lsat=>0.2); $img->filter(type=>'turbnoise') # and lots of others load_plugin("dynfilt/dyntest.so") or die "unable to load plugin\n"; $img->filter(type=>'lin_stretch', a=>35, b=>200); unload_plugin("dynfilt/dyntest.so") or die "unable to load plugin\n"; $out = $img->difference(other=>$other_img); =head1 DESCRIPTION Filters are operations that have similar calling interface. =over =item filter() Parameters: =over =item * type - the type of filter, see L. =item * many other possible parameters, see L below. =back Returns the invocant (C<$self>) on success, returns a false value on failure. You can call C<< $self->errstr >> to determine the cause of the failure. $self->filter(type => $type, ...) or die $self->errstr; =back =head2 Types of Filters Here is a list of the filters that are always available in Imager. This list can be obtained by running the C script that comes with the module source. Filter Arguments Default value autolevels lsat 0.1 usat 0.1 autolevels_skew lsat 0.1 usat 0.1 skew 0 bumpmap bump lightx lighty elevation 0 st 2 bumpmap_complex bump channel 0 tx 0 ty 0 Lx 0.2 Ly 0.4 Lz -1 cd 1.0 cs 40.0 n 1.3 Ia (0 0 0) Il (255 255 255) Is (255 255 255) contrast intensity conv coef fountain xa ya xb yb ftype linear repeat none combine none super_sample none ssample_param 4 segments(see below) gaussian stddev gradgen xo yo colors dist 0 hardinvert hardinvertall mosaic size 20 noise amount 3 subtype 0 postlevels levels 10 radnoise xo 100 yo 100 ascale 17.0 rscale 0.02 turbnoise xo 0.0 yo 0.0 scale 10.0 unsharpmask stddev 2.0 scale 1.0 watermark wmark pixdiff 10 tx 0 ty 0 All parameters must have some value but if a parameter has a default value it may be omitted when calling the filter function. Every one of these filters modifies the image in place. If none of the filters here do what you need, the L or L function may be useful. =for stopwords autolevels bumpmap bumpmap_complex conv gaussian hardinvert hardinvertall radnoise turbnoise unsharpmask gradgen postlevels A reference of the filters follows: =over =item autolevels Scales the luminosity of the image so that the luminosity will cover the possible range for the image. C and C truncate the range by the specified fraction at the top and bottom of the range respectively. # increase contrast, losing little detail $img->filter(type=>"autolevels") or die $img->errstr; The method used here is typically called L. =item autolevels_skew Scales the value of each channel so that the values in the image will cover the whole possible range for the channel. C and C truncate the range by the specified fraction at the top and bottom of the range respectively. # increase contrast per channel, losing little detail $img->filter(type=>"autolevels_skew") or die $img->errstr; # increase contrast, losing 20% of highlight at top and bottom range $img->filter(type=>"autolevels", lsat=>0.2, usat=>0.2) or die $img->errstr; This filter was the original C filter, but it's typically useless due to the significant color skew it can produce. =item bumpmap uses the channel C image C as a bump map on your image, with the light at (C, C), with a shadow length of C. $img->filter(type=>"bumpmap", bump=>$bumpmap_img, lightx=>10, lighty=>10, st=>5) or die $img->errstr; =item bumpmap_complex uses the channel C image C as a bump map on your image. If C<< Lz < 0 >> the three L parameters are considered to be the direction of the light. If C<< Lz > 0 >> the L parameters are considered to be the light position. C is the ambient color, C is the light color, C is the color of specular highlights. C is the diffuse coefficient and C is the specular coefficient. C is the shininess of the surface. $img->filter(type=>"bumpmap_complex", bump=>$bumpmap_img) or die $img->errstr; =item contrast scales each channel by C. Values of C < 1.0 will reduce the contrast. # higher contrast $img->filter(type=>"contrast", intensity=>1.3) or die $img->errstr; # lower contrast $img->filter(type=>"contrast", intensity=>0.8) or die $img->errstr; =item conv performs 2 1-dimensional convolutions on the image using the values from C. C should be have an odd length and the sum of the coefficients must be non-zero. # sharper $img->filter(type=>"conv", coef=>[-0.5, 2, -0.5 ]) or die $img->errstr; # blur $img->filter(type=>"conv", coef=>[ 1, 2, 1 ]) or die $img->errstr; # error $img->filter(type=>"conv", coef=>[ -0.5, 1, -0.5 ]) or die $img->errstr; =item fountain renders a fountain fill, similar to the gradient tool in most paint software. The default fill is a linear fill from opaque black to opaque white. The points C and C control the way the fill is performed, depending on the C parameter: =for stopwords ramping =over =item C the fill ramps from A through to B. =item C the fill ramps in both directions from A, where AB defines the length of the gradient. =item C A is the center of a circle, and B is a point on it's circumference. The fill ramps from the center out to the circumference. =item C A is the center of a square and B is the center of one of it's sides. This can be used to rotate the square. The fill ramps out to the edges of the square. =item C A is the center of a circle and B is a point on its circumference. B marks the 0 and 360 point on the circle, with the fill ramping clockwise. =item C A is the center of a circle and B is a point on it's circumference. B marks the 0 and point on the circle, with the fill ramping in both directions to meet opposite. =back The C option controls how the fill is repeated for some Cs after it leaves the AB range: =over =item C no repeats, points outside of each range are treated as if they were on the extreme end of that range. =item C the fill simply repeats in the positive direction =item C the fill repeats in reverse and then forward and so on, in the positive direction =item C the fill repeats in both the positive and negative directions (only meaningful for a linear fill). =item C as for triangle, but in the negative direction too (only meaningful for a linear fill). =back By default the fill simply overwrites the whole image (unless you have parts of the range 0 through 1 that aren't covered by a segment), if any segments of your fill have any transparency, you can set the I option to 'normal' to have the fill combined with the existing pixels. See the description of I in L. If your fill has sharp edges, for example between steps if you use repeat set to 'triangle', you may see some aliased or ragged edges. You can enable super-sampling which will take extra samples within the pixel in an attempt anti-alias the fill. The possible values for the super_sample option are: =over =item none no super-sampling is done =item grid a square grid of points are sampled. The number of points sampled is the square of ceil(0.5 + sqrt(ssample_param)). =item random a random set of points within the pixel are sampled. This looks pretty bad for low ssample_param values. =item circle the points on the radius of a circle within the pixel are sampled. This seems to produce the best results, but is fairly slow (for now). =back You can control the level of sampling by setting the ssample_param option. This is roughly the number of points sampled, but depends on the type of sampling. The segments option is an arrayref of segments. You really should use the L class to build your fountain fill. Each segment is an array ref containing: =over =item start a floating point number between 0 and 1, the start of the range of fill parameters covered by this segment. =item middle a floating point number between start and end which can be used to push the color range towards one end of the segment. =item end a floating point number between 0 and 1, the end of the range of fill parameters covered by this segment. This should be greater than start. =item c0 =item c1 The colors at each end of the segment. These can be either Imager::Color or Imager::Color::Float objects. =item segment type The type of segment, this controls the way the fill parameter varies over the segment. 0 for linear, 1 for curved (unimplemented), 2 for sine, 3 for sphere increasing, 4 for sphere decreasing. =item color type The way the color varies within the segment, 0 for simple RGB, 1 for hue increasing and 2 for hue decreasing. =back Don't forget to use Imager::Fountain instead of building your own. Really. It even loads GIMP gradient files. # build the gradient the hard way - linear from black to white, # then back again my @simple = ( [ 0, 0.25, 0.5, 'black', 'white', 0, 0 ], [ 0.5. 0.75, 1.0, 'white', 'black', 0, 0 ], ); # across my $linear = $img->copy; $linear->filter(type => "fountain", ftype => 'linear', repeat => 'sawtooth', segments => \@simple, xa => 0, ya => $linear->getheight / 2, xb => $linear->getwidth - 1, yb => $linear->getheight / 2) or die $linear->errstr; # around my $revolution = $img->copy; $revolution->filter(type => "fountain", ftype => 'revolution', segments => \@simple, xa => $revolution->getwidth / 2, ya => $revolution->getheight / 2, xb => $revolution->getwidth / 2, yb => 0) or die $revolution->errstr; # out from the middle my $radial = $img->copy; $radial->filter(type => "fountain", ftype => 'radial', segments => \@simple, xa => $im->getwidth / 2, ya => $im->getheight / 2, xb => $im->getwidth / 2, yb => 0) or die $radial->errstr; =for stopwords Gaussian =item gaussian performs a Gaussian blur of the image, using C as the standard deviation of the curve used to combine pixels, larger values give bigger blurs. For a definition of Gaussian Blur, see: http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node99.html Values of C around 0.5 provide a barely noticeable blur, values around 5 provide a very strong blur. # only slightly blurred $img->filter(type=>"gaussian", stddev=>0.5) or die $img->errstr; # more strongly blurred $img->filter(type=>"gaussian", stddev=>5) or die $img->errstr; =item gradgen renders a gradient, with the given I at the corresponding points (x,y) in C and C. You can specify the way distance is measured for color blending by setting C to 0 for Euclidean, 1 for Euclidean squared, and 2 for Manhattan distance. $img->filter(type="gradgen", xo=>[ 10, 50, 10 ], yo=>[ 10, 50, 50 ], colors=>[ qw(red blue green) ]); =item hardinvert XX inverts the image, black to white, white to black. All color channels are inverted, excluding the alpha channel if any. $img->filter(type=>"hardinvert") or die $img->errstr; =item hardinvertall XX inverts the image, black to white, white to black. All channels are inverted, including the alpha channel if any. $img->filter(type=>"hardinvertall") or die $img->errstr; =item mosaic produces averaged tiles of the given C. $img->filter(type=>"mosaic", size=>5) or die $img->errstr; =item noise adds noise of the given C to the image. If C is zero, the noise is even to each channel, otherwise noise is added to each channel independently. # monochrome noise $img->filter(type=>"noise", amount=>20, subtype=>0) or die $img->errstr; # color noise $img->filter(type=>"noise", amount=>20, subtype=>1) or die $img->errstr; =for stopwords Perlin =item radnoise renders radiant Perlin turbulent noise. The center of the noise is at (C, C), C controls the angular scale of the noise , and C the radial scale, higher numbers give more detail. $img->filter(type=>"radnoise", xo=>50, yo=>50, ascale=>1, rscale=>0.02) or die $img->errstr; =item postlevels alters the image to have only C distinct level in each channel. $img->filter(type=>"postlevels", levels=>10) or die $img->errstr; =item turbnoise renders Perlin turbulent noise. (C, C) controls the origin of the noise, and C the scale of the noise, with lower numbers giving more detail. $img->filter(type=>"turbnoise", xo=>10, yo=>10, scale=>10) or die $img->errstr; =for stopwords unsharp =item unsharpmask performs an unsharp mask on the image. This increases the contrast of edges in the image. This is the result of subtracting a Gaussian blurred version of the image from the original. C controls the C parameter of the Gaussian blur. Each output pixel is: in + scale * (in - blurred) eg. $img->filter(type=>"unsharpmask", stddev=>1, scale=>0.5) or die $img->errstr; C has the following parameters: =for stopwords GIMP GIMP's =over =item * C - this is equivalent to the C value in the GIMP's unsharp mask filter. This controls the size of the contrast increase around edges, larger values will remove fine detail. You should probably experiment on the types of images you plan to work with. Default: 2.0. =item * C - controls the strength of the edge enhancement, equivalent to I in the GIMP's unsharp mask filter. Default: 1.0. =back =item watermark applies C as a watermark on the image with strength C, with an origin at (C, C) $img->filter(type=>"watermark", tx=>10, ty=>50, wmark=>$wmark_image, pixdiff=>50) or die $img->errstr; =back A demonstration of most of the filters can be found at: http://www.develop-help.com/imager/filters.html =head2 External Filters As of Imager 0.48 you can create perl or XS based filters and hook them into Imager's filter() method: =over =item register_filter() Registers a filter so it is visible via Imager's filter() method. Imager->register_filter(type => 'your_filter', defaults => { parm1 => 'default1' }, callseq => [ qw/image parm1/ ], callsub => \&your_filter); $img->filter(type=>'your_filter', parm1 => 'something'); The following parameters are needed: =over =item * C - the type value that will be supplied to filter() to use your filter. =item * C - a hash of defaults for the filter's parameters =item * C - a reference to an array of required parameter names. =item * C - a code reference called to execute your filter. The parameters passed to filter() are supplied as a list of parameter name, value ... which can be assigned to a hash. The special parameters C and C are supplied as the low level image object from $self and $self itself respectively. The function you supply must modify the image in place. To indicate an error, die with an error message followed by a newline. C will store the error message as the C for the invocant and return false to indicate failure. sub my_filter { my %opts = @_; _is_valid($opts{myparam}) or die "myparam invalid!\n"; # actually do the filtering... } =back See L for an example. =back =for stopwords DSOs =head2 Plug-ins The plug in interface is deprecated. Please use the Imager API, see L and L for details It is possible to add filters to the module without recompiling Imager itself. This is done by using DSOs (Dynamic shared object) available on most systems. This way you can maintain your own filters and not have to have it added to Imager, or worse patch every new version of Imager. Modules can be loaded AND UNLOADED at run time. This means that you can have a server/daemon thingy that can do something like: load_plugin("dynfilt/dyntest.so") or die "unable to load plugin\n"; $img->filter(type=>'lin_stretch', a=>35, b=>200); unload_plugin("dynfilt/dyntest.so") or die "unable to load plugin\n"; Someone decides that the filter is not working as it should - F can be modified and recompiled, and then reloaded: load_plugin("dynfilt/dyntest.so") or die "unable to load plugin\n"; $img->filter(%hsh); =for stopwords Linux Solaris HPUX OpenBSD FreeBSD TRU64 OSF1 AIX Win32 OS X Note: This has been tested successfully on the following systems: Linux, Solaris, HPUX, OpenBSD, FreeBSD, TRU64/OSF1, AIX, Win32, OS X. =over =item load_plugin() This is a function, not a method, exported by default. You should import this function explicitly for future compatibility if you need it. Accepts a single parameter, the name of a shared library file to load. Returns true on success. Check Imager->errstr on failure. =item unload_plugin() This is a function, not a method, which is exported by default. You should import this function explicitly for future compatibility if you need it. Accepts a single parameter, the name of a shared library to unload. This library must have been previously loaded by load_plugin(). Returns true on success. Check Imager->errstr on failure. =back A few example plug-ins are included and built (but not installed): =over =item * F - provides the C (no action) filter, and C filters. C stretches sample values between C and C out to the full sample range. =item * F - provides the C filter that writes the image to the HTML fragment file supplied in C as a HTML table. =item * F - provides the C filter that dims alternate lines to emulate an old CRT display. L provides the same functionality. =item * F - provides the C filter that renders the Mandelbrot set within the given range of x [-2, 0.5) and y [-1.25, 1,25). L provides a more flexible Mandelbrot set renderer. =back =head2 Image Difference =over =item difference() You can create a new image that is the difference between 2 other images. my $diff = $img->difference(other=>$other_img); For each pixel in $img that is different to the pixel in $other_img, the pixel from $other_img is given, otherwise the pixel is transparent black. This can be used for debugging image differences ("Where are they different?"), and for optimizing animated GIFs. Note that $img and $other_img must have the same number of channels. The width and height of $diff will be the minimum of each of the width and height of $img and $other_img. Parameters: =over =item * C - the other image object to compare against =item * C - the difference between corresponding samples must be greater than C for the pixel to be considered different. So a value of zero returns all different pixels, not all pixels. Range: 0 to 255 inclusive. Default: 0. For large sample images this is scaled down to the range 0 .. 1. =back =back =head1 AUTHOR Arnar M. Hrafnkelsson, Tony Cook . =head1 SEE ALSO Imager, Imager::Filter::Flines, Imager::Filter::Mandelbrot =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/lib/Imager/ImageTypes.pod0000644000175000017500000010120212617611415022306 0ustar gregoagregoa=head1 NAME Imager::ImageTypes - image models for Imager =head1 SYNOPSIS use Imager; $img = Imager->new(); # Empty image (size is 0 by 0) $img->open(file=>'lena.png',type=>'png'); # Read image from file $img = Imager->new(xsize=>400, ysize=>300); # RGB data $img = Imager->new(xsize=>400, ysize=>300, # Grayscale channels=>1); # $img = Imager->new(xsize=>400, ysize=>300, # RGB with alpha channels=>4); # $img = Imager->new(xsize=>200, ysize=>200, type=>'paletted'); # paletted image $img = Imager->new(xsize=>200, ysize=>200, bits=>16); # 16 bits/channel rgb $img = Imager->new(xsize=>200, ysize=>200, bits=>'double'); # 'double' floating point # per channel $img->img_set(xsize=>500, ysize=>500, # reset the image object channels=>4); # Example getting information about an Imager object print "Image information:\n"; print "Width: ", $img->getwidth(), "\n"; print "Height: ", $img->getheight(), "\n"; print "Channels: ", $img->getchannels(), "\n"; print "Bits/Channel: ", $img->bits(), "\n"; print "Virtual: ", $img->virtual() ? "Yes" : "No", "\n"; my $colorcount = $img->getcolorcount(maxcolors=>512); print "Actual number of colors in image: "; print defined($colorcount) ? $colorcount : ">512", "\n"; print "Type: ", $img->type(), "\n"; if ($img->type() eq 'direct') { print "Modifiable Channels: "; print join " ", map { ($img->getmask() & 1<<$_) ? $_ : () } 0..$img->getchannels(); print "\n"; } else { # palette info my $count = $img->colorcount; @colors = $img->getcolors(); print "Palette size: $count\n"; my $mx = @colors > 4 ? 4 : 0+@colors; print "First $mx entries:\n"; for (@colors[0..$mx-1]) { my @res = $_->rgba(); print "(", join(", ", @res[0..$img->getchannels()-1]), ")\n"; } } my @tags = $img->tags(); if (@tags) { print "Tags:\n"; for(@tags) { print shift @$_, ": ", join " ", @$_, "\n"; } } else { print "No tags in image\n"; } =head1 DESCRIPTION Imager supports two basic models of image: =over =item * direct color - all samples are stored for every pixel. eg. for an 8-bit/sample RGB image, 24 bits are stored for each pixel. =item * paletted - an index into a table of colors is stored for each pixel. =back Direct color or paletted images can have 1 to 4 samples per color stored. Imager treats these as follows: =over =item * 1 sample per color - gray scale image. =item * 2 samples per color - gray scale image with alpha channel, allowing transparency. =item * 3 samples per color - RGB image. =item * 4 samples per color - RGB image with alpha channel, allowing transparency. =back Direct color images can have sample sizes of 8-bits per sample, 16-bits per sample or a double precision floating point number per sample (64-bits on many systems). Paletted images are always 8-bits/sample. To query an existing image about it's parameters see the C, C, C, C, C and C methods. The coordinate system in Imager has the origin in the upper left corner, see L for details. The alpha channel when one is present is considered unassociated - ie the color data has not been scaled by the alpha channel. Note that not all code follows this (recent) rule, but will over time. =head2 Creating Imager Objects =over =item new() X $img = Imager->new(); $img->read(file=>"alligator.ppm") or die $img->errstr; Here C creates an empty image with width and height of zero. It's only useful for creating an Imager object to call the read() method on later. %opts = (xsize=>300, ysize=>200); $img = Imager->new(%opts); # create direct mode RGBA image $img = Imager->new(%opts, channels=>4); # create direct mode RGBA image You can also read a file from new(): $img = Imager->new(file => "someimage.png"); The parameters for new are: =over =item * C, C - Defines the width and height in pixels of the image. These must be positive. If not supplied then only placeholder object is created, which can be supplied to the C or C methods. =item * C - The number of channels for the image. Default 3. Valid values are from 1 to 4. =item * C - this overrides the value, if any, supplied for C. This can be one of C, C, C or C. =item * C - The storage type for samples in the image. Default: 8. Valid values are: =over =item * C<8> - One byte per sample. 256 discrete values. =item * C<16> - 16-bits per sample, 65536 discrete values. =item * C - one C double per sample. =back Note: you can use any Imager function on any sample size image. Paletted images always use 8 bits/sample. =item * C - either C<'direct'> or C<'paletted'>. Default: C<'direct'>. Direct images store color values for each pixel. Paletted images keep a table of up to 256 colors called the palette, each pixel is represented as an index into that table. In most cases when working with Imager you will want to use the C image type. If you draw on a C image with a color not in the image's palette then Imager will transparently convert it to a C image. =item * C - the maximum number of colors in a paletted image. Default: 256. This must be in the range 1 through 256. =item * C, C, C, C, C, or C - specify a file name, filehandle, file descriptor or callback to read image data from. See L for details. The typical use is: my $im = Imager->new(file => $filename); =item * C - treated as the file format parameter, as for C with the read() method, eg: my $im = Imager->new(file => $filename, filetype => "gif"); In most cases Imager will detect the file's format itself. =back In the simplest case just supply the width and height of the image: # 8 bit/sample, RGB image my $img = Imager->new(xsize => $width, ysize => $height); or if you want an alpha channel: # 8 bits/sample, RGBA image my $img = Imager->new(xsize => $width, ysize => $height, channels=>4); Note that it I possible for image creation to fail, for example if channels is out of range, or if the image would take too much memory. To create paletted images, set the 'type' parameter to 'paletted': $img = Imager->new(xsize=>200, ysize=>200, type=>'paletted'); which creates an image with a maximum of 256 colors, which you can change by supplying the C parameter. For improved color precision you can use the bits parameter to specify 16 bit per channel: $img = Imager->new(xsize=>200, ysize=>200, channels=>3, bits=>16); or for even more precision: $img = Imager->new(xsize=>200, ysize=>200, channels=>3, bits=>'double'); to get an image that uses a double for each channel. Note that as of this writing all functions should work on images with more than 8-bits/channel, but many will only work at only 8-bit/channel precision. If you want an empty Imager object to call the read() method on, just call new() with no parameters: my $img = Imager->new; $img->read(file=>$filename) or die $img->errstr; Though it's much easier now to just call new() with a C parameter: my $img = Imager->new(file => $filename) or die Imager->errstr; If none of C, C, C, C, C, C, C, C, C is supplied, and other parameters I supplied C<< Imager->new >> will return failure rather than returning an empty image object. =item img_set() X img_set destroys the image data in the object and creates a new one with the given dimensions and channels. For a way to convert image data between formats see the C method. $img->img_set(xsize=>500, ysize=>500, channels=>4); This takes exactly the same parameters as the new() method, excluding those for reading from files. =back =head2 Image Attribute functions These return basic attributes of an image object. =over =item getwidth() print "Image width: ", $img->getwidth(), "\n"; The C method returns the width of the image. This value comes either from C with C, C parameters or from reading data from a file with C. If called on an image that has no valid data in it like Cnew()> returns, the return value of C is undef. =item getheight() print "Image height: ", $img->getheight(), "\n"; Same details apply as for L. =item getchannels() XX print "Image has ",$img->getchannels(), " channels\n"; Returns the number of channels in an image. Note: previously the number of channels in an image mapped directly to the color model of the image, ie a 4 channel image was always RGBA. This may change in a future release of Imager. Returns an empty list if the image object is not initialized. =item colorchannels() XX Returns the number of color channels. Currently this is always 1 or 3, but may be 0 for some rare images in a future version of Imager. Returns an empty list if the image object is not initialized. =item colormodel() XX Returns the color model of the image, including whether there is an alpha channel. By default this is returned as a string, one of C, C, C, C or C. If you call C with a true numeric parameter: my $model = $img->colormodel(numeric => 1); then the color model is returned as a number, mapped as follows: Numeric String ------- ------ 0 unknown 1 gray 2 graya 3 rgb 4 rgba =item alphachannel() XX Returns the channel index of the alpha channel of the image. This is 1 for grayscale images with alpha, 3 for RGB images with alpha and will return C for all other images. Returns an empty list if the image object is not initialized. =item bits() The bits() method retrieves the number of bits used to represent each channel in a pixel, 8 for a normal image, 16 for 16-bit image and 'double' for a double/channel image. if ($img->bits eq 8) { # fast but limited to 8-bits/sample } else { # slower but more precise } Returns an empty list if the image object is not initialized. =item type() The type() method returns either 'direct' for direct color images or 'paletted' for paletted images. if ($img->type eq 'paletted') { # print the palette for my $color ($img->getcolors) { print join(",", $color->rgba), "\n"; } } Returns an empty list if the image object is not initialized. =item virtual() The virtual() method returns non-zero if the image contains no actual pixels, for example masked images. =for stopwords SDL This may also be used for non-native Imager images in the future, for example, for an Imager object that draws on an SDL surface. =item is_bilevel() Tests if the image will be written as a monochrome or bi-level image for formats that support that image organization. In scalar context, returns true if the image is bi-level. In list context returns a list: ($is_bilevel, $zero_is_white) = $img->is_bilevel; An image is considered bi-level, if all of the following are true: =over =item * the image is a paletted image =item * the image has 1 or 3 channels =item * the image has only 2 colors in the palette =item * those 2 colors are black and white, in either order. =back If a real bi-level organization image is ever added to Imager, this function will return true for that too. Returns an empty list if the image object is not initialized. =back =head2 Direct Type Images Direct images store the color value directly for each pixel in the image. =over =item getmask() @rgbanames = qw( red green blue alpha ); my $mask = $img->getmask(); print "Modifiable channels:\n"; for (0..$img->getchannels()-1) { print $rgbanames[$_],"\n" if $mask & 1<<$_; } =for stopwords th C is used to fetch the current channel mask. The mask determines what channels are currently modifiable in the image. The channel mask is an integer value, if the C least significant bit is set the C channel is modifiable. eg. a channel mask of 0x5 means only channels 0 and 2 are writable. =item setmask() $mask = $img->getmask(); $img->setmask(mask=>8); # modify alpha only ... $img->setmask(mask=>$mask); # restore previous mask C is used to set the channel mask of the image. See L for details. =back =head2 Palette Type Images Paletted images keep an array of up to 256 colors, and each pixel is stored as an index into that array. In general you can work with paletted images in the same way as RGB images, except that if you attempt to draw to a paletted image with a color that is not in the image's palette, the image will be converted to an RGB image. This means that drawing on a paletted image with anti-aliasing enabled will almost certainly convert the image to RGB. Palette management takes place through C, C, C and C: =over =item addcolors() You can add colors to a paletted image with the addcolors() method: my @colors = ( Imager::Color->new(255, 0, 0), Imager::Color->new(0, 255, 0) ); my $index = $img->addcolors(colors=>\@colors); The return value is the index of the first color added, or undef if adding the colors would overflow the palette. The only parameter is C which must be a reference to an array of Imager::Color objects. =item setcolors() $img->setcolors(start=>$start, colors=>\@colors); Once you have colors in the palette you can overwrite them with the C method: C returns true on success. Parameters: =over =item * start - the first index to be set. Default: 0 =item * colors - reference to an array of Imager::Color objects. =back =item getcolors() To retrieve existing colors from the palette use the getcolors() method: # get the whole palette my @colors = $img->getcolors(); # get a single color my $color = $img->getcolors(start=>$index); # get a range of colors my @colors = $img->getcolors(start=>$index, count=>$count); =item findcolor() To quickly find a color in the palette use findcolor(): my $index = $img->findcolor(color=>$color); which returns undef on failure, or the index of the color. Parameter: =over =item * color - an Imager::Color object. =back =item colorcount() Returns the number of colors in the image's palette: my $count = $img->colorcount; =item maxcolors() Returns the maximum size of the image's palette. my $maxcount = $img->maxcolors; =back =head2 Color Distribution =over =item getcolorcount() Calculates the number of colors in an image. The amount of memory used by this is proportional to the number of colors present in the image, so to avoid using too much memory you can supply a maxcolors() parameter to limit the memory used. Note: getcolorcount() treats the image as an 8-bit per sample image. =over =item * XC - the maximum number of colors to return. Default: unlimited. =back if (defined($img->getcolorcount(maxcolors=>512)) { print "Less than 512 colors in image\n"; } =item getcolorusagehash() Calculates a histogram of colors used by the image. =over =item * XC - the maximum number of colors to return. Default: unlimited. =back Returns a reference to a hash where the keys are the raw color as bytes, and the values are the counts for that color. The alpha channel of the image is ignored. If the image is gray scale then the hash keys will each be a single character. my $colors = $img->getcolorusagehash; my $blue_count = $colors->{pack("CCC", 0, 0, 255)} || 0; print "#0000FF used $blue_count times\n"; =item getcolorusage() Calculates color usage counts and returns just the counts. =over =item * XC - the maximum number of colors to return. Default: unlimited. =back Returns a list of the color frequencies in ascending order. my @counts = $img->getcolorusage; print "The most common color is used $counts[0] times\n"; =back =head2 Conversion Between Image Types Warning: if you draw on a paletted image with colors that aren't in the palette, the image will be internally converted to a normal image. =over =item to_paletted() You can create a new paletted image from an existing image using the to_paletted() method: $palimg = $img->to_paletted(\%opts) where %opts contains the options specified under L. # convert to a paletted image using the web palette # use the closest color to each pixel my $webimg = $img->to_paletted({ make_colors => 'webmap' }); # convert to a paletted image using a fairly optimal palette # use an error diffusion dither to try to reduce the average error my $optimag = $img->to_paletted({ make_colors => 'mediancut', translate => 'errdiff' }); =item to_rgb8() You can convert a paletted image (or any image) to an 8-bit/channel RGB image with: $rgbimg = $img->to_rgb8; No parameters. =item to_rgb16() Convert a paletted image (or any image) to a 16-bit/channel RGB image. $rgbimg = $img->to_rgb16; No parameters. =item to_rgb_double() Convert a paletted image (or any image) to an double/channel direct color image. $rgbimg = $img->to_rgb_double; No parameters. =item masked() Creates a masked image. A masked image lets you create an image proxy object that protects parts of the underlying target image. In the discussion below there are 3 image objects involved: =over =item * the masked image - the return value of the masked() method. Any writes to this image are written to the target image, assuming the mask image allows it. =item * the mask image - the image that protects writes to the target image. Supplied as the C parameter to the masked() method. =item * the target image - the image you called the masked() method on. Any writes to the masked image end up on this image. =back Parameters: =over =item * mask - the mask image. If not supplied then all pixels in the target image are writable. On each write to the masked image, only pixels that have non-zero in channel 0 of the mask image will be written to the original image. Default: none, if not supplied then no masking is done, but the other parameters are still honored. =item * left, top - the offset of writes to the target image. eg. if you attempt to set pixel (x,y) in the masked image, then pixel (x+left, y+top) will be written to in the original image. =item * bottom, right - the bottom right of the area in the target available from the masked image. =back Masked images let you control which pixels are modified in an underlying image. Where the first channel is completely black in the mask image, writes to the underlying image are ignored. For example, given a base image called $img: my $mask = Imager->new(xsize=>$img->getwidth, ysize=>$img->getheight, channels=>1); # ... draw something on the mask my $maskedimg = $img->masked(mask=>$mask); # now draw on $maskedimg and it will only draw on areas of $img # where $mask is non-zero in channel 0. You can specify the region of the underlying image that is masked using the left, top, right and bottom options. If you just want a subset of the image, without masking, just specify the region without specifying a mask. For example: # just work with a 100x100 region of $img my $maskedimg = $img->masked(left => 100, top=>100, right=>200, bottom=>200); =item make_palette() This doesn't perform an image conversion, but it can be used to construct a common palette for use in several images: my @colors = Imager->make_palette(\%opts, @images); You must supply at least one image, even if the C parameter produces a fixed palette. On failure returns no colors and you can check C<< Imager->errstr >>. =back =head2 Tags Image tags contain meta-data about the image, ie. information not stored as pixels of the image. At the perl level each tag has a name or code and a value, which is an integer or an arbitrary string. An image can contain more than one tag with the same name or code, but having more than one tag with the same name is discouraged. You can retrieve tags from an image using the tags() method, you can get all of the tags in an image, as a list of array references, with the code or name of the tag followed by the value of the tag. Imager's support for fairly limited, for access to pretty much all image metadata you may want to try L. =over =item tags() Retrieve tags from the image. With no parameters, retrieves a list array references, each containing a name and value: all tags in the image: # get a list of ( [ name1 => value1 ], [ name2 => value2 ] ... ) my @alltags = $img->tags; print $_->[0], ":", $_->[1], "\n" for @all_tags; # or put it in a hash, but this will lose duplicates my %alltags = map @$_, $img->tags; in scalar context this returns the number of tags: my $num_tags = $img->tags; or you can get all tags values for the given name: my @namedtags = $img->tags(name => $name); in scalar context this returns the first tag of that name: my $firstnamed = $img->tags(name => $name); or a given code: my @tags = $img->tags(code=>$code); =item addtag() You can add tags using the addtag() method, either by name: my $index = $img->addtag(name=>$name, value=>$value); or by code: my $index = $img->addtag(code=>$code, value=>$value); =item deltag() You can remove tags with the deltag() method, either by index: $img->deltag(index=>$index); or by name: $img->deltag(name=>$name); or by code: $img->deltag(code=>$code); In each case deltag() returns the number of tags deleted. =item settag() settag() replaces any existing tags with a new tag. This is equivalent to calling deltag() then addtag(). =back =head2 Common Tags Many tags are only meaningful for one format. GIF looping information is pretty useless for JPEG for example. Thus, many tags are set by only a single reader or used by a single writer. For a complete list of format specific tags see L. Since tags are a relatively new addition their use is not wide spread but eventually we hope to have all the readers for various formats set some standard information. =over =item * XXXXC, C - The spatial resolution of the image in pixels per inch. If the image format uses a different scale, eg. pixels per meter, then this value is converted. A floating point number stored as a string. # our image was generated as a 300 dpi image $img->settag(name => 'i_xres', value => 300); $img->settag(name => 'i_yres', value => 300); # 100 pixel/cm for a TIFF image $img->settag(name => 'tiff_resolutionunit', value => 3); # RESUNIT_CENTIMETER # convert to pixels per inch, Imager will convert it back $img->settag(name => 'i_xres', value => 100 * 2.54); $img->settag(name => 'i_yres', value => 100 * 2.54); =item * XXC - If this is non-zero then the values in i_xres and i_yres are treated as a ratio only. If the image format does not support aspect ratios then this is scaled so the smaller value is 72 DPI. =item * XXC - If this tag is present then the whole image could not be read. This isn't implemented for all images yet, and may not be. =item * XXC - If C is set then this tag may be set to the number of scan lines successfully read from the file. This can be used to decide whether an image is worth processing. =item * XXi_format - The file format this file was read from. =item * XXi_background - used when writing an image with an alpha channel to a file format that doesn't support alpha channels. The C method will convert a normal color specification like "#FF0000" into a color object for you, but if you set this as a tag you will need to format it like CIC<,>IC<,>IC<)>, eg color(255,0,0). =item * XC - used when reading or writing several image formats. If the format has only one text field it will be read into the C tag or written to the file. =back =head2 Quantization options These options can be specified when calling L, write_multi() for GIF files, when writing a single image with the C option set to C, or for direct calls to i_writegif_gen() and i_writegif_callback(). =over =item * C - An arrayref of colors that are fixed. Note that some color generators will ignore this. If this is supplied it will be filled with the color table generated for the image. =item * C - The type of transparency processing to perform for images with an alpha channel where the output format does not have a proper alpha channel (eg. GIF). This can be any of: =over =item * C - No transparency processing is done. (default) =item * C - pixels more transparent than C are rendered as transparent. =item * C - An error diffusion dither is done on the alpha channel. Note that this is independent of the translation performed on the color channels, so some combinations may cause undesired artifacts. =item * C - the ordered dither specified by tr_orddith is performed on the alpha channel. =back This will only be used if the image has an alpha channel, and if there is space in the palette for a transparency color. =item * C - the highest alpha value at which a pixel will be made transparent when C is 'threshold'. (0-255, default 127) =item * C - The type of error diffusion to perform on the alpha channel when C is C. This can be any defined error diffusion type except for custom (see C below). =item * C - The type of ordered dither to perform on the alpha channel when C is 'ordered'. Possible values are: =over =item * C - A semi-random map is used. The map is the same each time. =item * C - 8x8 dot dither. =item * C - 4x4 dot dither =item * C - horizontal line dither. =item * C - vertical line dither. =item * C, C - diagonal line dither =item * C<\line>, C - diagonal line dither =item * C - dot matrix dither (currently the default). This is probably the best for displays (like web pages). =item * C - A custom dither matrix is used - see C. =back =item * C - When tr_orddith is custom this defines an 8 x 8 matrix of integers representing the transparency threshold for pixels corresponding to each position. This should be a 64 element array where the first 8 entries correspond to the first row of the matrix. Values should be between 0 and 255. =item * C - Defines how the quantization engine will build the palette(s). Currently this is ignored if C is C, but that may change. Possible values are: =over =item * C - only colors supplied in 'colors' are used. =item * C - the web color map is used (need URL here.) =item * C - The original code for generating the color map (Addi's code) is used. =item * C - Uses a median-cut algorithm, faster than C, but not as good a result. =item * C, C - a fixed black and white palette, suitable for producing bi-level images (eg. facsimile) =item * C, C, C - make fixed gray palette with 256, 4 or 16 entries respectively. =back Other methods may be added in the future. =item * C - an arrayref containing Imager::Color objects, which represents the starting set of colors to use in translating the images. C will ignore this. On return the final colors used are copied back into this array (which is expanded if necessary.) =item * C - the maximum number of colors to use in the image. =item * C - The method used to translate the RGB values in the source image into the colors selected by make_colors. Note that make_colors is ignored when C is C. Possible values are: =over =item * C - this is a historical equivalent for C that also forces C to C. =item * C - the closest color available is used. =item * C - the pixel color is modified by C, and the closest color is chosen. =item * C - an error diffusion dither is performed. If the supplied (or generated) palette contains only grays the source colors are converted to gray before error diffusion is performed. =back It's possible other C values will be added. =item * C - The type of error diffusion dither to perform. These values (except for custom) can also be used in tr_errdif. =for stopwords Floyd-Steinberg Jarvis Judice Ninke Stucki =over =item * C - Floyd-Steinberg dither =item * C - Jarvis, Judice and Ninke dither =item * C - Stucki dither =item * C - custom. If you use this you must also set C, C and C. =back =item * C, C, C, C - When C is C and C is C these define a custom error diffusion map. C and C define the size of the map in the arrayref in C. C is an integer which indicates the current pixel position in the top row of the map. =item * C - When translate is C this is the magnitude of the random bias applied to each channel of the pixel before it is looked up in the color table. =back =head1 INITIALIZATION This documents the Imager initialization function, which you will almost never need to call. =over =item init() This is a function, not a method. This function is a mess, it can take the following named parameters: =over =item * C - name of a log file to log Imager's actions to. Not all actions are logged, but the debugging memory allocator does log allocations here. Ignored if Imager has been built without logging support. Preferably use the open_log() method instead. =item * C - the maximum level of message to log. Default: 1. =item * C - if this is non-zero then Imager will warn when you attempt to use obsoleted parameters or functionality. This currently only includes the old GIF output options instead of tags. =item * C - if non-zero then T1lib will be configured to produce a log file. This will fail if there are any existing T1lib font objects. =back Example: Imager::init(log => 'trace.log', loglevel => 9); =back =head1 LOGGING METHODS Imager can open an internal log to send debugging information to. This log is extensively used in Imager's tests, but you're unlikely to use it otherwise. If Imager has been built with logging disabled, the methods fail quietly. =over =item open_log() Open the Imager debugging log file. =over =item * C - the file name to log to. If this is undef logging information is sent to the standard error stream. =item * C the level of logging to produce. Default: 1. =back Returns a true value if the log file was opened successfully. # send debug output to test.log Imager->open_log(log => "test.log"); # send debug output to stderr Imager->open_log(); =item close_log() Close the Imager debugging log file and disable debug logging. No parameters. Imager->close_log(); =item log() Imager->log($message) Imager->log($message, $level) This method does not use named parameters. The default for C<$level> is 1. Send a message to the debug log. Imager->log("My code got here!"); =item is_logging() Returns a true value if logging is enabled. =back =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =head1 SEE ALSO Imager(3), Imager::Files(3), Imager::Draw(3), Imager::Color(3), Imager::Fill(3), Imager::Font(3), Imager::Transformations(3), Imager::Engines(3), Imager::Filters(3), Imager::Expr(3), Imager::Matrix2d(3), Imager::Fountain(3) =cut libimager-perl-1.004+dfsg.orig/lib/Imager/APIRef.pod0000644000175000017500000014630012617611601021312 0ustar gregoagregoaDo not edit this file, it is generated automatically by apidocs.perl from Imager's source files. Each function description has a comment listing the source file where you can find the documentation. =head1 NAME Imager::APIRef - Imager's C API - reference. =head1 SYNOPSIS i_color color; color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255; double x[] = { ... }; double y[] = { ... }; i_polygon_t poly; poly.count = sizeof(x) / sizeof(*x); poly.x = x; poly.y = y; # Blit tools # Data Types i_img *img; i_color black; black.rgba.r = black.rgba.g = black.rgba.b = black.rgba.a = 0; i_fill_t *fill; i_img_dim x, y; i_img_dim_u limit; printf("left %" i_DF "\n", i_DFc(x)); printf("point (" i_DFp ")\n", i_DFcp(x, y)); # Drawing i_arc(im, 50, 50, 20, 45, 135, &color); i_arc_cfill(im, 50, 50, 35, 90, 135, fill); i_arc_aa(im, 50, 50, 35, 90, 135, &color); i_arc_aa_cfill(im, 50, 50, 35, 90, 135, fill); i_circle_aa(im, 50, 50, 45, &color); i_box(im, 0, 0, im->xsize-1, im->ysize-1, &color). i_box_filled(im, 0, 0, im->xsize-1, im->ysize-1, &color); i_box_cfill(im, 0, 0, im->xsize-1, im->ysize-1, fill); i_flood_fill(im, 50, 50, &color); i_flood_cfill(im, 50, 50, fill); i_flood_fill_border(im, 50, 50, &color, &border); i_flood_cfill_border(im, 50, 50, fill, border); i_poly_poly_aa(im, 1, &poly, mode, color); i_poly_aa_m(im, count, x, y, mode, color); i_poly_poly_aa_cfill(im, 1, &poly, mode, fill); i_poly_aa_cfill(im, count, x, y, mode, fill); # Error handling im_clear_error(aIMCTX); i_clear_error(); i_push_error(0, "Yep, it's broken"); i_push_error(errno, "Error writing"); im_push_error(aIMCTX, 0, "Something is wrong"); va_args args; va_start(args, lastarg); im_push_errorvf(ctx, code, format, args); i_push_errorf(errno, "Cannot open file %s: %d", filename, errno); im_push_errorf(aIMCTX, errno, "Cannot open file %s: %d", filename, errno); # Files im_set_image_file_limits(aIMCTX, 500, 500, 1000000); i_set_image_file_limits(500, 500, 1000000); im_get_image_file_limits(aIMCTX, &width, &height, &bytes) i_get_image_file_limits(&width, &height, &bytes) im_int_check_image_file_limits(aIMCTX, width, height, channels, sizeof(i_sample_t)) i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t)) # Fills i_fill_t *fill = i_new_fill_solidf(&fcolor, combine); i_fill_t *fill = i_new_fill_solid(&color, combine); i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy); i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy); i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine); fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear, i_fr_triangle, 0, i_fts_grid, 9, 1, segs); i_fill_destroy(fill); # I/O Layers ssize_t count = i_io_peekn(ig, buffer, sizeof(buffer)); ssize_t result = i_io_write(io, buffer, size) char buffer[BUFSIZ] ssize_t len = i_io_gets(buffer, sizeof(buffer), '\n'); io_glue_destroy(ig); # Image # Image creation/destruction i_img *img = i_sametype(src, width, height); i_img *img = i_sametype_chans(src, width, height, channels); i_img *img = im_img_16_new(aIMCTX, width, height, channels); i_img *img = i_img_16_new(width, height, channels); i_img *img = im_img_8_new(aIMCTX, width, height, channels); i_img *img = i_img_8_new(width, height, channels); i_img *img = im_img_double_new(aIMCTX, width, height, channels); i_img *img = i_img_double_new(width, height, channels); i_img *img = im_img_pal_new(aIMCTX, width, height, channels, max_palette_size) i_img *img = i_img_pal_new(width, height, channels, max_palette_size) i_img_destroy(img) # Image Implementation i_img *im = im_img_alloc(aIMCTX); i_img *im = i_img_alloc(); im_img_init(aIMCTX, im); i_img_init(im); # Image Information // only channel 0 writable i_img_setmask(img, 0x01); int mask = i_img_getmask(img); int channels = i_img_getchannels(img); i_img_dim width = i_img_get_width(im); i_img_dim height = i_img_get_height(im); i_color_model_t cm = i_img_color_model(im); int alpha_channel; int has_alpha = i_img_alpha_channel(im, &alpha_channel); int color_channels = i_img_color_channels(im); # Image quantization # Logging # mutex i_mutex_t mutex; # Mutex functions i_mutex_t m = i_mutex_new(); i_mutex_destroy(m); i_mutex_lock(m); i_mutex_unlock(m); # Paletted images # Tags i_tags_set(&img->tags, "i_comment", -1); i_tags_setn(&img->tags, "i_xres", 204); i_tags_setn(&img->tags, "i_yres", 196); =head1 DESCRIPTION =head2 Blit tools =over =item i_render_color(r, x, y, width, source, color) Render the given color with the coverage specified by C to C. Renders in normal combine mode. =for comment From: File render.im =item i_render_delete(r) Release an C object. =for comment From: File render.im =item i_render_fill(r, x, y, width, source, fill) Render the given fill with the coverage in C through C. =for comment From: File render.im =item i_render_line(r, x, y, width, source, fill) Render the given fill with the coverage in C through C. =for comment From: File render.im =item i_render_linef(r, x, y, width, source, fill) Render the given fill with the coverage in C through C. =for comment From: File render.im =item i_render_new(im, width) Allocate a new C object and initialize it. =for comment From: File render.im =back =head2 Data Types =over =item i_img i_img *img; This is Imager's image type. It contains the following members: =over =item * C - the number of channels in the image =item * C, C - the width and height of the image in pixels =item * C - the number of bytes used to store the image data. Undefined where virtual is non-zero. =item * C - a mask of writable channels. eg. if this is 6 then only channels 1 and 2 are writable. There may be bits set for which there are no channels in the image. =item * C - the number of bits stored per sample. Should be one of i_8_bits, i_16_bits, i_double_bits. =item * C - either i_direct_type for direct color images, or i_palette_type for paletted images. =item * C - if zero then this image is-self contained. If non-zero then this image could be an interface to some other implementation. =item * C - the image data. This should not be directly accessed. A new image implementation can use this to store its image data. i_img_destroy() will myfree() this pointer if it's non-null. =item * C - a structure storing the image's tags. This should only be accessed via the i_tags_*() functions. =item * C - a pointer for use internal to an image implementation. This should be freed by the image's destroy handler. =item * C - data internal to Imager. This is initialized by i_img_init(). =item * i_f_ppix, i_f_ppixf, i_f_plin, i_f_plinf, i_f_gpix, i_f_gpixf, i_f_glin, i_f_glinf, i_f_gsamp, i_f_gampf - implementations for each of the required image functions. An image implementation should initialize these between calling i_img_alloc() and i_img_init(). =item * i_f_gpal, i_f_ppal, i_f_addcolors, i_f_getcolors, i_f_colorcount, i_f_maxcolors, i_f_findcolor, i_f_setcolors - implementations for each paletted image function. =item * i_f_destroy - custom image destruction function. This should be used to release memory if necessary. =item * i_f_gsamp_bits - implements i_gsamp_bits() for this image. =item * i_f_psamp_bits - implements i_psamp_bits() for this image. =item * i_f_psamp - implements psamp() for this image. =item * i_f_psampf - implements psamp() for this image. =item * C - image specific data internal to Imager. =item * C - the Imager API context this image belongs to. =back =for comment From: File imdatatypes.h =item i_color i_color black; black.rgba.r = black.rgba.g = black.rgba.b = black.rgba.a = 0; Type for 8-bit/sample color. Samples as per; i_color c; i_color is a union of: =over =item * gray - contains a single element gray_color, eg. C =item * C - contains three elements C, C, C, eg. C =item * C - contains four elements C, C, C, C, eg. C =item * C - contains four elements C, C, C, C, eg. C. Note that Imager never uses CMYK colors except when reading/writing files. =item * channels - an array of four channels, eg C. =back =for comment From: File imdatatypes.h =item i_fcolor This is the double/sample color type. Its layout exactly corresponds to i_color. =for comment From: File imdatatypes.h =item i_fill_t i_fill_t *fill; This is the "abstract" base type for Imager's fill types. Unless you're implementing a new fill type you'll typically treat this as an opaque type. =for comment From: File imdatatypes.h =item i_poly_fill_mode_t Control how polygons are filled. Has the following values: =over =item * C - simple even-odd fills. =item * C - non-zero winding rule fills. =back =for comment From: File imdatatypes.h =item i_polygon_t Represents a polygon. Has the following members: =over =item * C, C - arrays of x and y locations of vertices. =item * C - the number of entries in the C and C arrays. =back =for comment From: File imdatatypes.h =item im_context_t Imager's per-thread context. =for comment From: File imdatatypes.h =item im_slot_t Represents a slot in the context object. =for comment From: File imdatatypes.h =item i_img_dim i_img_dim x, y; A signed integer type that represents an image dimension or ordinate. May be larger than int on some platforms. =for comment From: File imdatatypes.h =item i_img_dim_u i_img_dim_u limit; An unsigned variant of L. =for comment From: File imdatatypes.h =item i_color_model_t Returned by L to indicate the color model of the image. An enumerated type with the following possible values: =over =item * C - the image has no usable color data. In future versions of Imager this will be returned in a few limited cases, eg. when the source image is CMYK and the user has requested no color translation is done. =item * C - gray scale with no alpha channel. =item * C - gray scale with an alpha channel. =item * C - RGB =item * C - RGB with an alpha channel. =back =for comment From: File imdatatypes.h =item i_DF printf("left %" i_DF "\n", i_DFc(x)); This is a constant string that can be used with functions like printf() to format i_img_dim values after they're been cast with i_DFc(). Does not include the leading C<%>. =for comment From: File imdatatypes.h =item i_DFc Cast an C value to a type for use with the i_DF format string. =for comment From: File imdatatypes.h =item i_DFcp Casts two C values for use with the i_DF (or i_DFp) format. =for comment From: File imdatatypes.h =item i_DFp printf("point (" i_DFp ")\n", i_DFcp(x, y)); Format a pair of C values. This format string I include the leading C<%>. =for comment From: File imdatatypes.h =back =head2 Drawing =over =item i_arc(im, x, y, rad, d1, d2, color) i_arc(im, 50, 50, 20, 45, 135, &color); Fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the color. =for comment From: File draw.c =item i_arc_aa(im, x, y, rad, d1, d2, color) i_arc_aa(im, 50, 50, 35, 90, 135, &color); Anti-alias fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the color. =for comment From: File draw.c =item i_arc_aa_cfill(im, x, y, rad, d1, d2, fill) i_arc_aa_cfill(im, 50, 50, 35, 90, 135, fill); Anti-alias fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the fill object. =for comment From: File draw.c =item i_arc_cfill(im, x, y, rad, d1, d2, fill) i_arc_cfill(im, 50, 50, 35, 90, 135, fill); Fills an arc centered at (x,y) with radius I covering the range of angles in degrees from d1 to d2, with the fill object. =for comment From: File draw.c =item i_box(im, x1, y1, x2, y2, color) i_box(im, 0, 0, im->xsize-1, im->ysize-1, &color). Outlines the box from (x1,y1) to (x2,y2) inclusive with I. =for comment From: File draw.c =item i_box_cfill(im, x1, y1, x2, y2, fill) i_box_cfill(im, 0, 0, im->xsize-1, im->ysize-1, fill); Fills the box from (x1,y1) to (x2,y2) inclusive with fill. =for comment From: File draw.c =item i_box_filled(im, x1, y1, x2, y2, color) i_box_filled(im, 0, 0, im->xsize-1, im->ysize-1, &color); Fills the box from (x1,y1) to (x2,y2) inclusive with color. =for comment From: File draw.c =item i_circle_aa(im, x, y, rad, color) i_circle_aa(im, 50, 50, 45, &color); Anti-alias fills a circle centered at (x,y) for radius I with color. =for comment From: File draw.c =item i_flood_cfill(C, C, C, C) i_flood_cfill(im, 50, 50, fill); Flood fills the 4-connected region starting from the point (C, C) with C. Returns false if (C, C) are outside the image. =for comment From: File draw.c =item i_flood_cfill_border(C, C, C, C, C) i_flood_cfill_border(im, 50, 50, fill, border); Flood fills the 4-connected region starting from the point (C, C) with C, the fill stops when it reaches pixels of color C. Returns false if (C, C) are outside the image. =for comment From: File draw.c =item i_flood_fill(C, C, C, C) i_flood_fill(im, 50, 50, &color); Flood fills the 4-connected region starting from the point (C, C) with I. Returns false if (C, C) are outside the image. =for comment From: File draw.c =item i_flood_fill_border(C, C, C, C, C) i_flood_fill_border(im, 50, 50, &color, &border); Flood fills the 4-connected region starting from the point (C, C) with C, fill stops when the fill reaches a pixels with color C. Returns false if (C, C) are outside the image. =for comment From: File draw.c =item i_glin(im, l, r, y, colors) Retrieves (r-l) pixels starting from (l,y) into I. Returns the number of pixels retrieved. =for comment From: File imext.c =item i_glinf(im, l, r, y, colors) Retrieves (r-l) pixels starting from (l,y) into I as floating point colors. Returns the number of pixels retrieved. =for comment From: File imext.c =item i_gpal(im, left, right, y, indexes) Reads palette indexes for the horizontal line (left, y) to (right-1, y) into C. Returns the number of indexes read. Always returns 0 for direct color images. =for comment From: File imext.c =item i_gpix(im, C, C, C) Retrieves the C of the pixel (x,y). Returns 0 if the pixel was retrieved, or -1 if not. =for comment From: File imext.c =item i_gpixf(im, C, C, C) Retrieves the color of the pixel (x,y) as a floating point color into C. Returns 0 if the pixel was retrieved, or -1 if not. =for comment From: File imext.c =item i_gsamp(im, left, right, y, samples, channels, channel_count) Reads sample values from C for the horizontal line (left, y) to (right-1,y) for the channels specified by C, an array of int with C elements. If channels is NULL then the first channels_count channels are retrieved for each pixel. Returns the number of samples read (which should be (right-left) * channel_count) =for comment From: File imext.c =item i_gsamp_bg(im, l, r, y, samples, out_channels, background) Like C but applies the source image color over a supplied background color. This is intended for output to image formats that don't support alpha channels. =for comment From: File paste.im =item i_gsamp_bits(im, left, right, y, samples, channels, channel_count, bits) Reads integer samples scaled to C bits of precision into the C array C. Expect this to be slow unless C<< bits == im->bits >>. Returns the number of samples copied, or -1 on error. Not all image types implement this method. Pushes errors, but does not call C. =for comment From: File imext.c =item i_gsampf(im, left, right, y, samples, channels, channel_count) Reads floating point sample values from C for the horizontal line (left, y) to (right-1,y) for the channels specified by C, an array of int with channel_count elements. If C is NULL then the first C channels are retrieved for each pixel. Returns the number of samples read (which should be (C-C) * C) =for comment From: File imext.c =item i_gsampf_bg(im, l, r, y, samples, out_channels, background) Like C but applies the source image color over a supplied background color. This is intended for output to image formats that don't support alpha channels. =for comment From: File paste.im =item i_line(C, C, C, C, C, C, C) =for stopwords Bresenham's Draw a line to image using Bresenham's line drawing algorithm im - image to draw to x1 - starting x coordinate y1 - starting x coordinate x2 - starting x coordinate y2 - starting x coordinate color - color to write to image endp - endpoint flag (boolean) =for comment From: File draw.c =item i_line_aa(C, C, C, C, C, C, C) Anti-alias draws a line from (x1,y1) to (x2, y2) in color. The point (x2, y2) is drawn only if C is set. =for comment From: File draw.c =item i_plin(im, l, r, y, colors) Sets (r-l) pixels starting from (l,y) using (r-l) values from I. Returns the number of pixels set. =for comment From: File imext.c =item i_plinf(im, C, C, C) Sets (right-left) pixels starting from (left,y) using (right-left) floating point colors from C. Returns the number of pixels set. =for comment From: File imext.c =item i_poly_aa_cfill_m(im, count, x, y, mode, fill) i_poly_aa_cfill(im, count, x, y, mode, fill); Fill a polygon defined by the points specified by the x and y arrays with the fill specified by C. =for comment From: File polygon.c =item i_poly_aa_m(im, count, x, y, mode, color) i_poly_aa_m(im, count, x, y, mode, color); Fill a polygon defined by the points specified by the x and y arrays with the color specified by C. =for comment From: File polygon.c =item i_poly_poly_aa(im, count, polys, mode, color) i_poly_poly_aa(im, 1, &poly, mode, color); Fill the C polygons defined by C the color specified by C. At least one polygon must be supplied. All polygons must have at least 3 points. =for comment From: File polygon.c =item i_poly_poly_aa_cfill(im, count, polys, mode, fill) i_poly_poly_aa_cfill(im, 1, &poly, mode, fill); Fill the C polygons defined by C the fill specified by C. At least one polygon must be supplied. All polygons must have at least 3 points. =for comment From: File polygon.c =item i_ppal(im, left, right, y, indexes) Writes palette indexes for the horizontal line (left, y) to (right-1, y) from C. Returns the number of indexes written. Always returns 0 for direct color images. =for comment From: File imext.c =item i_ppix(im, x, y, color) Sets the pixel at (x,y) to I. Returns 0 if the pixel was drawn, or -1 if not. Does no alpha blending, just copies the channels from the supplied color to the image. =for comment From: File imext.c =item i_ppixf(im, C, C, C) Sets the pixel at (C,C) to the floating point color C. Returns 0 if the pixel was drawn, or -1 if not. Does no alpha blending, just copies the channels from the supplied color to the image. =for comment From: File imext.c =item i_psamp(im, left, right, y, samples, channels, channel_count) Writes sample values from C to C for the horizontal line (left, y) to (right-1, y) inclusive for the channels specified by C, an array of C with C elements. If C is C then the first C channels are written to for each pixel. Returns the number of samples written, which should be (right - left) * channel_count. If a channel not in the image is in channels, left is negative, left is outside the image or y is outside the image, returns -1 and pushes an error. =for comment From: File immacros.h =item i_psamp_bits(im, left, right, y, samples, channels, channel_count, bits) Writes integer samples scaled to C bits of precision from the C array C. Expect this to be slow unless C<< bits == im->bits >>. Returns the number of samples copied, or -1 on error. Not all image types implement this method. Pushes errors, but does not call C. =for comment From: File imext.c =item i_psampf(im, left, right, y, samples, channels, channel_count) Writes floating point sample values from C to C for the horizontal line (left, y) to (right-1, y) inclusive for the channels specified by C, an array of C with C elements. If C is C then the first C channels are written to for each pixel. Returns the number of samples written, which should be (right - left) * channel_count. If a channel not in the image is in channels, left is negative, left is outside the image or y is outside the image, returns -1 and pushes an error. =for comment From: File immacros.h =back =head2 Error handling =over =item i_push_errorf(int code, char const *fmt, ...) i_push_errorf(errno, "Cannot open file %s: %d", filename, errno); A version of i_push_error() that does printf() like formatting. Does not support perl specific format codes. =for comment From: File error.c =item im_clear_error(ctx) XX im_clear_error(aIMCTX); i_clear_error(); Clears the error stack. Called by any Imager function before doing any other processing. Also callable as C. =for comment From: File error.c =item im_push_error(ctx, code, message) XX i_push_error(0, "Yep, it's broken"); i_push_error(errno, "Error writing"); im_push_error(aIMCTX, 0, "Something is wrong"); Called by an Imager function to push an error message onto the stack. No message is pushed if the stack is full (since this means someone forgot to call i_clear_error(), or that a function that doesn't do error handling is calling function that does.). =for comment From: File error.c =item im_push_errorf(ctx, code, char const *fmt, ...) im_push_errorf(aIMCTX, errno, "Cannot open file %s: %d", filename, errno); A version of im_push_error() that does printf() like formatting. Does not support perl specific format codes. =for comment From: File error.c =item im_push_errorvf(ctx, code, format, args) XX va_args args; va_start(args, lastarg); im_push_errorvf(ctx, code, format, args); Intended for use by higher level functions, takes a varargs pointer and a format to produce the finally pushed error message. Does not support perl specific format codes. Also callable as C =for comment From: File error.c =back =head2 Files =over =item i_get_file_background(im, &bg) Retrieve the file write background color tag from the image. If not present, C is set to black. Returns 1 if the C tag was found and valid. =for comment From: File image.c =item i_get_file_backgroundf(im, &bg) Retrieve the file write background color tag from the image as a floating point color. Implemented in terms of i_get_file_background(). If not present, C is set to black. Returns 1 if the C tag was found and valid. =for comment From: File image.c =item im_get_image_file_limits(ctx, &width, &height, &bytes) XX im_get_image_file_limits(aIMCTX, &width, &height, &bytes) i_get_image_file_limits(&width, &height, &bytes) Retrieves the file limits set by i_set_image_file_limits(). =over =item * i_img_dim *width, *height - the maximum width and height of the image. =item * size_t *bytes - size in memory of the image in bytes. =back Also callable as C. =for comment From: File limits.c =item im_int_check_image_file_limits(width, height, channels, sample_size) XX im_int_check_image_file_limits(aIMCTX, width, height, channels, sizeof(i_sample_t)) i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t)) Checks the size of a file in memory against the configured image file limits. This also range checks the values to those permitted by Imager and checks for overflows in calculating the size. Returns non-zero if the file is within limits. This function is intended to be called by image file read functions. Also callable as C. =for comment From: File limits.c =item im_set_image_file_limits(ctx, width, height, bytes) XX im_set_image_file_limits(aIMCTX, 500, 500, 1000000); i_set_image_file_limits(500, 500, 1000000); Set limits on the sizes of images read by Imager. Setting a limit to 0 means that limit is ignored. Negative limits result in failure. Parameters: =over =item * i_img_dim width, height - maximum width and height. =item * size_t bytes - maximum size in memory in bytes. A value of zero sets this limit to one gigabyte. =back Returns non-zero on success. Also callable as C. =for comment From: File limits.c =back =head2 Fills =over =item i_new_fill_fount(C, C, C, C, C, C, C, C, C, C, C) fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear, i_fr_triangle, 0, i_fts_grid, 9, 1, segs); Creates a new general fill which fills with a fountain fill. =for comment From: File filters.im =item i_new_fill_hatch(C, C, C, C, C, C, C) i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy); Creates a new hatched fill with the C color used for the 1 bits in the hatch and C for the 0 bits. If C is non-zero alpha values will be combined. If C is non-NULL it should be a pointer to 8 bytes of the hash definition, with the high-bits to the left. If C is NULL then one of the standard hatches is used. (C, C) are an offset into the hatch which can be used to hatch adjoining areas out of alignment, or to align the origin of a hatch with the side of a filled area. =for comment From: File fills.c =item i_new_fill_hatchf(C, C, C, C, C, C, C) i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy); Creates a new hatched fill with the C color used for the 1 bits in the hatch and C for the 0 bits. If C is non-zero alpha values will be combined. If C is non-NULL it should be a pointer to 8 bytes of the hash definition, with the high-bits to the left. If C is NULL then one of the standard hatches is used. (C, C) are an offset into the hatch which can be used to hatch adjoining areas out of alignment, or to align the origin of a hatch with the side of a filled area. =for comment From: File fills.c =item i_new_fill_image(C, C, C, C, C) i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine); Create an image based fill. matrix is an array of 9 doubles representing a transformation matrix. C and C are the offset into the image to start filling from. =for comment From: File fills.c =item i_new_fill_solid(color, combine) i_fill_t *fill = i_new_fill_solid(&color, combine); Create a solid fill based on an 8-bit color. If combine is non-zero then alpha values will be combined. =for comment From: File fills.c =item i_new_fill_solidf(color, combine) i_fill_t *fill = i_new_fill_solidf(&fcolor, combine); Create a solid fill based on a float color. If combine is non-zero then alpha values will be combined. =for comment From: File fills.c =item i_fill_destroy(fill) i_fill_destroy(fill); Call to destroy any fill object. =for comment From: File fills.c =back =head2 I/O Layers =over =item im_io_new_bufchain(ctx) XX Returns a new io_glue object that has the 'empty' source and but can be written to and read from later (like a pseudo file). Also callable as C. =for comment From: File iolayer.c =item im_io_new_buffer(ctx, data, length) XX Returns a new io_glue object that has the source defined as reading from specified buffer. Note that the buffer is not copied. ctx - an Imager context object data - buffer to read from length - length of buffer Also callable as C. =for comment From: File iolayer.c =item im_io_new_cb(ctx, p, read_cb, write_cb, seek_cb, close_cb, destroy_cb) XX Create a new I/O layer object that calls your supplied callbacks. In general the callbacks should behave like the corresponding POSIX primitives. =over =item * C(p, buffer, length) should read up to C bytes into C and return the number of bytes read. At end of file, return 0. On error, return -1. =item * C(p, buffer, length) should write up to C bytes from C and return the number of bytes written. A return value <= 0 will be treated as an error. =item * C(p, offset, whence) should seek and return the new offset. =item * C(p) should return 0 on success, -1 on failure. =item * C(p) should release any memory specific to your callback handlers. =back Also callable as C. =for comment From: File iolayer.c =item im_io_new_fd(ctx, file) XX Returns a new io_glue object that has the source defined as reading from specified file descriptor. Note that the interface to receiving data from the io_glue callbacks hasn't been done yet. ctx - and Imager context object file - file descriptor to read/write from Also callable as C. =for comment From: File iolayer.c =item i_io_close(io) Flush any pending output and perform the close action for the stream. Returns 0 on success. =for comment From: File iolayer.c =item i_io_flush(io) Flush any buffered output. Returns true on success, =for comment From: File iolayer.c =item i_io_getc(ig) A macro to read a single byte from a buffered I/O glue object. Returns EOF on failure, or a byte. =for comment From: File iolayer.c =item i_io_gets(ig, buffer, size, end_of_line) char buffer[BUFSIZ] ssize_t len = i_io_gets(buffer, sizeof(buffer), '\n'); Read up to C-1 bytes from the stream C into C. If the byte C is seen then no further bytes will be read. Returns the number of bytes read. Always C terminates the buffer. =for comment From: File iolayer.c =item i_io_peekc(ig) Read the next character from the stream without advancing the stream. On error or end of file, return EOF. For unbuffered streams a single character buffer will be setup. =for comment From: File iolayer.c =item i_io_peekn(ig, buffer, size) ssize_t count = i_io_peekn(ig, buffer, sizeof(buffer)); Buffer at least C (at most C<< ig->buf_size >> bytes of data from the stream and return C bytes of it to the caller in C. This ignores the buffered state of the stream, and will always setup buffering if needed. If no C parameter is provided to Imager::read() or Imager::read_multi(), Imager will call C when probing for the file format. Returns -1 on error, 0 if there is no data before EOF, or the number of bytes read into C. =for comment From: File iolayer.c =item i_io_putc(ig, c) Write a single character to the stream. On success return c, on error returns EOF =for comment From: File iolayer.c =item i_io_read(io, buffer, size) Read up to C bytes from the stream C into C. Returns the number of bytes read. Returns 0 on end of file. Returns -1 on error. =for comment From: File iolayer.c =item i_io_seek(io, offset, whence) Seek within the stream. Acts like perl's seek. =for comment From: File iolayer.c =item i_io_set_buffered(io, buffered) Set the buffering mode of the stream. If you switch buffering off on a stream with buffering on: =over =item * any buffered output will be flushed. =item * any existing buffered input will be consumed before reads become unbuffered. =back Returns true on success. This may fail if any buffered output cannot be flushed. =for comment From: File iolayer.c =item i_io_write(io, buffer, size) ssize_t result = i_io_write(io, buffer, size) Write to the given I/O stream. Returns the number of bytes written. =for comment From: File iolayer.c =item io_slurp(ig, c) X Takes the source that the io_glue is bound to and allocates space for a return buffer and returns the entire content in a single buffer. Note: This only works for io_glue objects created by io_new_bufchain(). It is useful for saving to scalars and such. ig - io_glue object c - pointer to a pointer to where data should be copied to char *data; size_t size = io_slurp(ig, &data); ... do something with the data ... myfree(data); io_slurp() will abort the program if the supplied I/O layer is not from io_new_bufchain(). =for comment From: File iolayer.c =item io_glue_destroy(ig) X io_glue_destroy(ig); Destroy an io_glue objects. Should clean up all related buffers. ig - io_glue object to destroy. =for comment From: File iolayer.c =back =head2 Image =over =item i_copy(source) Creates a new image that is a copy of the image C. Tags are not copied, only the image data. Returns: i_img * =for comment From: File image.c =item i_copyto(C, C, C, C, C, C, C, C) Copies image data from the area (C,C)-[C,C] in the source image to a rectangle the same size with it's top-left corner at (C,C) in the destination image. If C > C or C > C then the corresponding co-ordinates are swapped. =for comment From: File paste.im =item i_copyto_trans(C, C, C, C, C, C, C, C, C) (C,C) (C,C) specifies the region to copy (in the source coordinates) (C,C) specifies the upper left corner for the target image. pass NULL in C for non transparent i_colors. =for comment From: File image.c =item i_img_info(im, info) Return image information im - Image pointer info - pointer to array to return data info is an array of 4 integers with the following values: info[0] - width info[1] - height info[2] - channels info[3] - channel mask =for comment From: File image.c =item i_rubthru(C, C, C, C, C, C, C, C) Takes the sub image C[C, C)[C, C)> and overlays it at (C,C) on the image object. The alpha channel of each pixel in C is used to control how much the existing color in C is replaced, if it is 255 then the color is completely replaced, if it is 0 then the original color is left unmodified. =for comment From: File rubthru.im =back =head2 Image creation/destruction =over =item i_sametype(C, C, C) i_img *img = i_sametype(src, width, height); Returns an image of the same type (sample size, channels, paletted/direct). For paletted images the palette is copied from the source. =for comment From: File image.c =item i_sametype_chans(C, C, C, C) i_img *img = i_sametype_chans(src, width, height, channels); Returns an image of the same type (sample size). For paletted images the equivalent direct type is returned. =for comment From: File image.c =item im_img_16_new(ctx, x, y, ch) XX i_img *img = im_img_16_new(aIMCTX, width, height, channels); i_img *img = i_img_16_new(width, height, channels); Create a new 16-bit/sample image. Returns the image on success, or NULL on failure. Also callable as C =for comment From: File img16.c =item im_img_8_new(ctx, x, y, ch) XX i_img *img = im_img_8_new(aIMCTX, width, height, channels); i_img *img = i_img_8_new(width, height, channels); Creates a new image object I pixels wide, and I pixels high with I channels. =for comment From: File img8.c =item im_img_double_new(ctx, x, y, ch) XX i_img *img = im_img_double_new(aIMCTX, width, height, channels); i_img *img = i_img_double_new(width, height, channels); Creates a new double per sample image. Also callable as C. =for comment From: File imgdouble.c =item im_img_pal_new(ctx, C, C, C, C) XX i_img *img = im_img_pal_new(aIMCTX, width, height, channels, max_palette_size) i_img *img = i_img_pal_new(width, height, channels, max_palette_size) Creates a new paletted image of the supplied dimensions. C is the maximum palette size and should normally be 256. Returns a new image or NULL on failure. Also callable as C. =for comment From: File palimg.c =item i_img_destroy(C) i_img_destroy(img) Destroy an image object =for comment From: File image.c =back =head2 Image Implementation =over =item im_img_alloc(aIMCTX) XX i_img *im = im_img_alloc(aIMCTX); i_img *im = i_img_alloc(); Allocates a new i_img structure. When implementing a new image type perform the following steps in your image object creation function: =over =item 1. allocate the image with i_img_alloc(). =item 2. initialize any function pointers or other data as needed, you can overwrite the whole block if you need to. =item 3. initialize Imager's internal data by calling i_img_init() on the image object. =back =for comment From: File image.c =item im_img_init(aIMCTX, image) XX im_img_init(aIMCTX, im); i_img_init(im); Imager internal initialization of images. See L for more information. =for comment From: File image.c =back =head2 Image Information =over =item i_img_alpha_channel(im, &channel) int alpha_channel; 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 may be C. =for comment From: File image.c =item i_img_color_channels(im) 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. =for comment From: File image.c =item i_img_color_model(im) 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. =for comment From: File image.c =item i_img_get_height(C) i_img_dim height = i_img_get_height(im); Returns the height in pixels of the image. =for comment From: File image.c =item i_img_get_width(C) i_img_dim width = i_img_get_width(im); Returns the width in pixels of the image. =for comment From: File image.c =item i_img_getchannels(C) int channels = i_img_getchannels(img); Get the number of channels in C. =for comment From: File image.c =item i_img_getmask(C) int mask = i_img_getmask(img); Get the image channel mask for C. =for comment From: File image.c =item i_img_has_alpha(C) Return true if the image has an alpha channel. =for comment From: File immacros.h =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. C for C. For performance of encoders we require monochrome images: =over =item * be paletted =item * have a palette of two colors, containing only C<(0,0,0)> and C<(255,255,255)> in either order. =back C is set to non-zero if the first palette entry is white. =for comment From: File image.c =item i_img_setmask(C, C) // only channel 0 writable i_img_setmask(img, 0x01); Set the image channel mask for C to C. The image channel mask gives some control over which channels can be written to in the image. =for comment From: File image.c =back =head2 Image quantization =over =item i_quant_makemap(C, C, C) Analyzes the C images in C according to the rules in C to build a color map (optimal or not depending on C<< quant->make_colors >>). =for comment From: File quant.c =item i_quant_translate(C, C) Quantize the image given the palette in C. On success returns a pointer to a memory block of C<< img->xsize * img->ysize >> C entries. On failure returns NULL. You should call myfree() on the returned block when you're done with it. This function will fail if the supplied palette contains no colors. =for comment From: File quant.c =item i_quant_transparent(C, C, C, C) Dither the alpha channel on C into the palette indexes in C. Pixels to be transparent are replaced with C. The method used depends on the tr_* members of C. =for comment From: File quant.c =back =head2 Logging =over =item i_lhead(file, line) This is an internal function called by the mm_log() macro. =for comment From: File log.c =item i_loog(level, format, ...) This is an internal function called by the mm_log() macro. =for comment From: File log.c =back =head2 mutex =over =item i_mutex_t X i_mutex_t mutex; Opaque type for Imager's mutex API. =for comment From: File imdatatypes.h =back =head2 Mutex functions =over =item i_mutex_new() i_mutex_t m = i_mutex_new(); Create a mutex. If a critical section cannot be created for whatever reason, Imager will abort. =for comment From: File mutexwin.c =item i_mutex_destroy(m) i_mutex_destroy(m); Destroy a mutex. =for comment From: File mutexwin.c =item i_mutex_lock(m) i_mutex_lock(m); Lock the mutex, waiting if another thread has the mutex locked. =for comment From: File mutexwin.c =item i_mutex_unlock(m) i_mutex_unlock(m); Release the mutex. The behavior of releasing a mutex you don't hold is unspecified. =for comment From: File mutexwin.c =back =head2 Paletted images =over =item i_addcolors(im, colors, count) Adds colors to the image's palette. On success returns the index of the lowest color added. On failure returns -1. Always fails for direct color images. =for comment From: File imext.c =item i_colorcount(im) Returns the number of colors in the image's palette. Returns -1 for direct images. =for comment From: File imext.c =item i_findcolor(im, color, &entry) Searches the images palette for the given color. On success sets *I to the index of the color, and returns true. On failure returns false. Always fails on direct color images. =for comment From: File imext.c =item i_getcolors(im, index, colors, count) Retrieves I colors starting from I in the image's palette. On success stores the colors into I and returns true. On failure returns false. Always fails for direct color images. Fails if there are less than I+I colors in the image's palette. =for comment From: File imext.c =item i_maxcolors(im) Returns the maximum number of colors the palette can hold for the image. Returns -1 for direct color images. =for comment From: File imext.c =item i_setcolors(im, index, colors, count) Sets I colors starting from I in the image's palette. On success returns true. On failure returns false. The image must have at least I+I colors in it's palette for this to succeed. Always fails on direct color images. =for comment From: File imext.c =back =head2 Tags =over =item i_tags_delbycode(tags, code) Delete any tags with the given code. Returns the number of tags deleted. =for comment From: File tags.c =item i_tags_delbyname(tags, name) Delete any tags with the given name. Returns the number of tags deleted. =for comment From: File tags.c =item i_tags_delete(tags, index) Delete a tag by index. Returns true on success. =for comment From: File tags.c =item i_tags_destroy(tags) Destroys the given tags structure. Called by i_img_destroy(). =for comment From: File tags.c =item i_tags_find(tags, name, start, &entry) Searches for a tag of the given I starting from index I. On success returns true and sets *I. On failure returns false. =for comment From: File tags.c =item i_tags_findn(tags, code, start, &entry) Searches for a tag of the given I starting from index I. On success returns true and sets *I. On failure returns false. =for comment From: File tags.c =item i_tags_get_color(tags, name, code, &value) Retrieve a tag specified by name or code as color. On success sets the i_color *I to the color and returns true. On failure returns false. =for comment From: File tags.c =item i_tags_get_float(tags, name, code, value) Retrieves a tag as a floating point value. If the tag has a string value then that is parsed as a floating point number, otherwise the integer value of the tag is used. On success sets *I and returns true. On failure returns false. =for comment From: File tags.c =item i_tags_get_int(tags, name, code, &value) Retrieve a tag specified by name or code as an integer. On success sets the int *I to the integer and returns true. On failure returns false. =for comment From: File tags.c =item i_tags_get_string(tags, name, code, value, value_size) Retrieves a tag by name or code as a string. On success copies the string to value for a max of value_size and returns true. On failure returns false. value_size must be at least large enough for a string representation of an integer. The copied value is always C terminated. =for comment From: File tags.c =item i_tags_new(i_img_tags *tags) Initialize a tags structure. Should not be used if the tags structure has been previously used. This should be called tags member of an i_img object on creation (in i_img_*_new() functions). To destroy the contents use i_tags_destroy() =for comment From: File tags.c =item i_tags_set(tags, name, data, size) i_tags_set(&img->tags, "i_comment", -1); Sets the given tag to the string I If size is -1 then the strlen(I) bytes are stored. Even on failure, if an existing tag I exists, it will be removed. =for comment From: File tags.c =item i_tags_set_color(tags, name, code, &value) Stores the given color as a tag with the given name and code. =for comment From: File tags.c =item i_tags_set_float(tags, name, code, value) Equivalent to i_tags_set_float2(tags, name, code, value, 30). =for comment From: File tags.c =item i_tags_set_float2(tags, name, code, value, places) Sets the tag with the given name and code to the given floating point value. Since tags are strings or ints, we convert the value to a string before storage at the precision specified by C. =for comment From: File tags.c =item i_tags_setn(C, C, C) i_tags_setn(&img->tags, "i_xres", 204); i_tags_setn(&img->tags, "i_yres", 196); Sets the given tag to the integer C Even on failure, if an existing tag C exists, it will be removed. =for comment From: File tags.c =back =head2 Uncategorized functions =over =item i_utf8_advance(char **p, size_t *len) Retrieve a C character from the stream. Modifies *p and *len to indicate the consumed characters. This doesn't support the extended C encoding used by later versions of Perl. Since this is typically used to implement text output by font drivers, the strings supplied shouldn't have such out of range characters. This doesn't check that the C character is using the shortest possible representation. Returns ~0UL on failure. =for comment From: File io.c =item im_context_refdec(ctx, where) X =section Context objects im_context_refdec(aIMCTX, "a description"); Remove a reference to the context, releasing it if all references have been removed. =for comment From: File context.c =item im_context_refinc(ctx, where) X =section Context objects im_context_refinc(aIMCTX, "a description"); Add a new reference to the context. =for comment From: File context.c =item im_context_slot_get(ctx, slot) Retrieve the value previously stored in the given slot of the context object. =for comment From: File context.c =item im_context_slot_new(destructor) Allocate a new context-local-storage slot. C will be called when the context is destroyed if the corresponding slot is non-NULL. =for comment From: File context.c =item im_context_slot_set(slot, value) Set the value of a slot. Returns true on success. Aborts if the slot supplied is invalid. If reallocation of slot storage fails, returns false. =for comment From: File context.c =item im_errors(ctx) i_errmsg *errors = im_errors(aIMCTX); i_errmsg *errors = i_errors(); Returns a pointer to the first element of an array of error messages, terminated by a NULL pointer. The highest level message is first. Also callable as C. =for comment From: File error.c =item im_get_context() Retrieve the context object for the current thread. Inside Imager itself this is just a function pointer, which the F BOOT handler initializes for use within perl. If you're taking the Imager code and embedding it elsewhere you need to initialize the C pointer at some point. =for comment From: File imext.c =back =head1 UNDOCUMENTED The following API functions are undocumented so far, hopefully this will change: =over =item * B =item * B =item * B =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::API, Imager::ExtUtils, Imager::Inline =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Install.pod0000644000175000017500000002467712263740601021666 0ustar gregoagregoa=for stopwords freetype MinGW dfont Redhat SDK IFD GDI TTF preprocessor Redhat-like =head1 NAME Imager::Install - installation notes for Imager =head1 SYNOPSIS perl Makefile.PL make make test make install =head1 DESCRIPTION Assuming you have all of your required libraries in the places Imager looks, you should be able to use the standard mantra: perl Makefile.PL make make test make install to install Imager. If you've installed libraries in places Imager doesn't look, you can supply extra locations either with command-line options: perl Makefile.PL --libpath=/home/tony/local/lib --incpath=/home/tony/local/include or with environment variables: export IM_LIBPATH=/home/tony/local/lib IM_INCPATH=/home/tony/local/include perl Makefile.PL Imager's F produces an epilogue indicating which libraries have and haven't been found, for example: Libraries found: FT2 GIF JPEG PNG T1 TIFF Libraries *not* found: Win32 If a library you expect to be found isn't on this list, use the C<--verbose> or C<-v> option to produce way too much information from Imager's search for the libraries: perl Makefile.PL -v If you can't resolve this, then run perl errep.perl and include the (large) generated F in your email to: bug-Imager@rt.cpan.org There are other options used to configure how Imager is built: =over =item C<--nolog> build Imager without logging support. This will speed up Imager a little. You can also remove logging by setting the C environment variable to a true value. =item C<--coverage> used to build Imager for C coverage testing. This is intended for development and also requires options supplied to C. =item C<--assert> build Imager with assertions enabled. =item C<--tracecontext> build Imager to trace context object management to C for debugging. =back =head2 Build time environment variables X =over =item * X<< C >>C - build Imager with logging disabled. =item * X<< C >>C - build Imager with it's debug malloc wrappers. This is I compatible with threaded code. =item * X<< C >>C - equivalent to C<--incpath>. =item * X<< C >>C - equivalent to C<--libpath>. =item * X<< C >>C - equivalent to C<--verbose> =item * X<< C >>C - extra C compiler flags. =item * X<< C >>C - extra linker flags. =item * X<< C >>C - extra preprocessor flags. =back =head1 EXTERNAL LIBRARIES Some of the file format and font modules included with Imager use external libraries, which should be installed before you try to install Imager itself. If you don't have the libraries installed then Imager itself will install successfully, but the file format or font support module won't be. Preferably the latest version of each library should be used, simple because it has the latest security fixes. =head2 PNG - C X<< C >>L uses L<< C |http://www.libpng.org/pub/png/libpng.html >> for PNG image file support. Debian package: C Redhat package: C =head2 TIFF - C X<< C >>L uses L<< C |http://www.remotesensing.org/libtiff/ >> for GIF image file support. Version 3.6.0 or later is required to avoid an exploit with infinite IFD loops, though it's possible some distributions have applied the fix to older versions as a security fix. Version 3.9.0 is rejected during the probe process due to a serious bug, fixed in 3.9.1. Debian package: C Redhat package: C =head2 GIF - C X<< C >>L uses L<< C |http://sourceforge.net/projects/giflib/ >> for GIF image file support. C releases 4.2.0 and 5.0.0 are specifically not supported, due to bugs in those versions. Release 4.1.4 or later should be used. C 3 is no longer supported. C is no longer supported as an alternative. Debian package: C Redhat package: C =head2 JPEG - C L uses L<< C |http://www.ijg.org/ >> for JPEG image file support. You may also use L<< C |http://sourceforge.net/projects/libjpeg-turbo/ >>. To install older releases of C from source, you'll need to run: make install-lib to install the libraries. C only installs the program binaries. Redhat package: C Debian package: C =head2 Freetype 2.x - C L uses L<< Freetype 2 (C)|http://www.freetype.org/ >> for font support, supporting too many font formats to mention here. This is the recommended library to use for font support. Debian package: C Redhat package: C =head2 Win32 GDI fonts L uses L to render text using installed Windows fonts. This requires Win32 SDK headers and libraries, and is only expected to work on native Win32 or Cygwin. For this to work under Cygwin, install the C and C packages. =head2 C L uses L<< C |http://www.t1lib.org/ >> for font support, supporting Postscript Type 1 fonts only. Debian package: C Redhat package: C =head2 Freetype 1.x - C Imager uses L<< Freetype 1 (C)|http://www.freetype.org/ >> if available for font support, supporting TTF fonts only. Freetype 1.x is essentially unsupported and shouldn't be used for new code. =head1 PLATFORM SPECIFICS =head2 Linux Several distributions include an Imager package, but they are typically several releases behind due to the nature of release cycles. Imager typically supports the external libraries as packaged with any supported release of Linux. =head3 Debian To install the libraries used by Imager under Debian (or Ubuntu), run as root (or with sudo): apt-get install libgif-dev libjpeg8-dev libtiff4-dev libpng12-dev libfreetype6-dev You may also need to install development tools: apt-get install build-essential =head3 Redhat To install the libraries used by Imager under Redhat and related Linux distributions, run as root (or sudo): yum install giflib-devel libjpeg-devel libtiff-devel libpng-devel freetype-devel To install the development tools needed: yum install gcc (which appears to be enough on a base Redhat-like install) or the more commonly recommended recipe: yum groupinstall "Development Tools" which is massive overkill. =head2 Mac OS X =head3 Building libraries The default perl build in Snow Leopard and Lion is a fat binary, and default builds of C, C and C (and maybe other libraries) will produce link failures. To avoid this you need to supply a C parameter to the library's configure script, but since the C<-arch> flag conflicts with the options used to build the dependency files, you need to supply another flag to disable dependency tracking. Snow Leopard fat binaries include C, C and C objects, hence you would run configure like: ./configure --disable-dependency-tracking CFLAGS='-arch x86_64 -arch i386 -arch ppc' Lion doesn't support C, so there you run configure like: ./configure --disable-dependency-tracking CFLAGS='-arch x86_64 -arch i386' For C you might also want to supply the C<--without-x> option: ./configure --disable-dependency-tracking --without-x CFLAGS='-arch x86_64 -arch i386' If you copy library files into place manually, you may need to run C on them in their new location: ranlib /usr/local/lib/libgif.a =head3 Macintosh C and suitcase font support Through Freetype 2.1, Imager can use Macintosh C (C<.dfont>) fonts and suitcase font files. If you want to be able to use more than just the first face in the font file though, you will need to configure C with the --with-old-mac-fonts option: ./configure --with-old-mac-fonts You can use the index option to get to the other font faces in the file: # get the second face from $file my $font = Imager::Font->new(file=>$file, index=>1) or die Imager->errstr; If you're using a suitcase font, you will also need to force the use of Freetype 2 with the type argument: my $font = Imager::Font->new(file=>$suitcase, type=>'ft2', index=>$index) or die Imager->errstr; =head2 Microsoft Windows The simplest way to install the libraries used by Imager is to install L. You can then use either the bundled Imager, or install from CPAN. If you get errors from your make tool, make sure you're using the same make that was used to build your perl - C for Visual C/C++ and C for MinGW, run: perl -V:make to see which make was used to build your perl. =head2 Cygwin To build Imager with as much library support as possible on Cygwin, install the following packages: libjpeg-devel libpng-devel libgif-devel libtiff-devel libfreetype-devel t1lib-devel w32api-headers w32api-runtime If you see an error under cygwin during testing along the lines of: C:\cygwin\bin\perl.exe: *** unable to remap C:\cygwin\...some dll to the same address as parent (0x...) != 0x.... you will need to install the cygwin C package and run: $ rebaseall -v or possibly, just: $ perlrebase will fix the problem. =head1 Other issues =head2 Freetype 1.x vs Freetype 2.x Freetype 1.x is no longer recommended, is no longer supported upstream, and receives only limited updates in Imager. These two libraries have some conflicting include file names, but as long as you don't put the Freetype 2.x F directory in the include path it should all work. Put the directory containing F in the include path, but not the directory containing the freetype 2.x F. If you see compilation errors from font.c you've probably made the mistake of putting the Freetype 2.x F directory into the include path. To see which directories should be in the include path, try: freetype-config --cflags Ideally, C should be in the PATH when building Imager with freetype 2.x support, in which case L can configure itself. =head1 AUTHOR Tony Cook , Arnar M. Hrafnkelsson =cut libimager-perl-1.004+dfsg.orig/lib/Imager/Regops.pm0000644000175000017500000002257012370406475021346 0ustar gregoagregoa# AUTOMATICALLY GENERATED BY regops.perl package Imager::Regops; use strict; require Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK %Attr $MaxOperands $PackCode); @ISA = qw(Exporter); @EXPORT_OK = qw(%Attr $MaxOperands $PackCode); use constant RBC_ADD => 0; use constant RBC_SUBTRACT => 1; use constant RBC_MULT => 2; use constant RBC_DIV => 3; use constant RBC_MOD => 4; use constant RBC_POW => 5; use constant RBC_UMINUS => 6; use constant RBC_MULTP => 7; use constant RBC_ADDP => 8; use constant RBC_SUBTRACTP => 9; use constant RBC_SIN => 10; use constant RBC_COS => 11; use constant RBC_ATAN2 => 12; use constant RBC_SQRT => 13; use constant RBC_DISTANCE => 14; use constant RBC_GETP1 => 15; use constant RBC_GETP2 => 16; use constant RBC_GETP3 => 17; use constant RBC_VALUE => 18; use constant RBC_HUE => 19; use constant RBC_SAT => 20; use constant RBC_HSV => 21; use constant RBC_RED => 22; use constant RBC_GREEN => 23; use constant RBC_BLUE => 24; use constant RBC_RGB => 25; use constant RBC_INT => 26; use constant RBC_IF => 27; use constant RBC_IFP => 28; use constant RBC_LE => 29; use constant RBC_LT => 30; use constant RBC_GE => 31; use constant RBC_GT => 32; use constant RBC_EQ => 33; use constant RBC_NE => 34; use constant RBC_AND => 35; use constant RBC_OR => 36; use constant RBC_NOT => 37; use constant RBC_ABS => 38; use constant RBC_RET => 39; use constant RBC_JUMP => 40; use constant RBC_JUMPZ => 41; use constant RBC_JUMPNZ => 42; use constant RBC_SET => 43; use constant RBC_SETP => 44; use constant RBC_PRINT => 45; use constant RBC_RGBA => 46; use constant RBC_HSVA => 47; use constant RBC_ALPHA => 48; use constant RBC_LOG => 49; use constant RBC_EXP => 50; use constant RBC_DET => 51; use constant RBC_OP_COUNT => 52; @EXPORT = qw(RBC_ADD RBC_SUBTRACT RBC_MULT RBC_DIV RBC_MOD RBC_POW RBC_UMINUS RBC_MULTP RBC_ADDP RBC_SUBTRACTP RBC_SIN RBC_COS RBC_ATAN2 RBC_SQRT RBC_DISTANCE RBC_GETP1 RBC_GETP2 RBC_GETP3 RBC_VALUE RBC_HUE RBC_SAT RBC_HSV RBC_RED RBC_GREEN RBC_BLUE RBC_RGB RBC_INT RBC_IF RBC_IFP RBC_LE RBC_LT RBC_GE RBC_GT RBC_EQ RBC_NE RBC_AND RBC_OR RBC_NOT RBC_ABS RBC_RET RBC_JUMP RBC_JUMPZ RBC_JUMPNZ RBC_SET RBC_SETP RBC_PRINT RBC_RGBA RBC_HSVA RBC_ALPHA RBC_LOG RBC_EXP RBC_DET RBC_OP_COUNT); %Attr = ( 'abs' => { 'func' => 1, 'opcode' => 38, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'add' => { 'func' => 0, 'opcode' => 0, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'addp' => { 'func' => 0, 'opcode' => 8, 'parms' => 2, 'result' => 'p', 'types' => 'pp', }, 'alpha' => { 'func' => 1, 'opcode' => 48, 'parms' => 1, 'result' => 'r', 'types' => 'p', }, 'and' => { 'func' => 0, 'opcode' => 35, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'atan2' => { 'func' => 1, 'opcode' => 12, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'blue' => { 'func' => 1, 'opcode' => 24, 'parms' => 1, 'result' => 'r', 'types' => 'p', }, 'cos' => { 'func' => 1, 'opcode' => 11, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'det' => { 'func' => 1, 'opcode' => 51, 'parms' => 4, 'result' => 'r', 'types' => 'rrrr', }, 'distance' => { 'func' => 1, 'opcode' => 14, 'parms' => 4, 'result' => 'r', 'types' => 'rrrr', }, 'div' => { 'func' => 0, 'opcode' => 3, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'eq' => { 'func' => 0, 'opcode' => 33, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'exp' => { 'func' => 1, 'opcode' => 50, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'ge' => { 'func' => 0, 'opcode' => 31, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'getp1' => { 'func' => 1, 'opcode' => 15, 'parms' => 2, 'result' => 'p', 'types' => 'rr', }, 'getp2' => { 'func' => 1, 'opcode' => 16, 'parms' => 2, 'result' => 'p', 'types' => 'rr', }, 'getp3' => { 'func' => 1, 'opcode' => 17, 'parms' => 2, 'result' => 'p', 'types' => 'rr', }, 'green' => { 'func' => 1, 'opcode' => 23, 'parms' => 1, 'result' => 'r', 'types' => 'p', }, 'gt' => { 'func' => 0, 'opcode' => 32, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'hsv' => { 'func' => 1, 'opcode' => 21, 'parms' => 3, 'result' => 'p', 'types' => 'rrr', }, 'hsva' => { 'func' => 1, 'opcode' => 47, 'parms' => 4, 'result' => 'p', 'types' => 'rrrr', }, 'hue' => { 'func' => 1, 'opcode' => 19, 'parms' => 1, 'result' => 'r', 'types' => 'p', }, 'if' => { 'func' => 1, 'opcode' => 27, 'parms' => 3, 'result' => 'r', 'types' => 'rrr', }, 'ifp' => { 'func' => 1, 'opcode' => 28, 'parms' => 3, 'result' => 'p', 'types' => 'rpp', }, 'int' => { 'func' => 1, 'opcode' => 26, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'jump' => { 'func' => 0, 'opcode' => 40, 'parms' => 0, 'result' => undef, 'types' => '', }, 'jumpnz' => { 'func' => 0, 'opcode' => 42, 'parms' => 1, 'result' => undef, 'types' => 'r', }, 'jumpz' => { 'func' => 0, 'opcode' => 41, 'parms' => 1, 'result' => undef, 'types' => 'r', }, 'le' => { 'func' => 0, 'opcode' => 29, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'log' => { 'func' => 1, 'opcode' => 49, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'lt' => { 'func' => 0, 'opcode' => 30, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'mod' => { 'func' => 0, 'opcode' => 4, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'mult' => { 'func' => 0, 'opcode' => 2, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'multp' => { 'func' => 0, 'opcode' => 7, 'parms' => 2, 'result' => 'p', 'types' => 'pr', }, 'ne' => { 'func' => 0, 'opcode' => 34, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'not' => { 'func' => 0, 'opcode' => 37, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'op_count' => { 'func' => 0, 'opcode' => 52, 'parms' => 0, 'result' => undef, 'types' => '', }, 'or' => { 'func' => 0, 'opcode' => 36, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'pow' => { 'func' => 0, 'opcode' => 5, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'print' => { 'func' => 1, 'opcode' => 45, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'red' => { 'func' => 1, 'opcode' => 22, 'parms' => 1, 'result' => 'r', 'types' => 'p', }, 'ret' => { 'func' => 0, 'opcode' => 39, 'parms' => 1, 'result' => undef, 'types' => 'p', }, 'rgb' => { 'func' => 1, 'opcode' => 25, 'parms' => 3, 'result' => 'p', 'types' => 'rrr', }, 'rgba' => { 'func' => 1, 'opcode' => 46, 'parms' => 4, 'result' => 'p', 'types' => 'rrrr', }, 'sat' => { 'func' => 1, 'opcode' => 20, 'parms' => 1, 'result' => 'r', 'types' => 'p', }, 'set' => { 'func' => 0, 'opcode' => 43, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'setp' => { 'func' => 0, 'opcode' => 44, 'parms' => 1, 'result' => 'p', 'types' => 'p', }, 'sin' => { 'func' => 1, 'opcode' => 10, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'sqrt' => { 'func' => 1, 'opcode' => 13, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'subtract' => { 'func' => 0, 'opcode' => 1, 'parms' => 2, 'result' => 'r', 'types' => 'rr', }, 'subtractp' => { 'func' => 0, 'opcode' => 9, 'parms' => 2, 'result' => 'p', 'types' => 'pp', }, 'uminus' => { 'func' => 0, 'opcode' => 6, 'parms' => 1, 'result' => 'r', 'types' => 'r', }, 'value' => { 'func' => 1, 'opcode' => 18, 'parms' => 1, 'result' => 'r', 'types' => 'p', }, ); $MaxOperands = 4; $PackCode = "i"; 1; __END__ =head1 NAME Imager::Regops - generated information about the register based virtual machine =head1 SYNOPSIS use Imager::Regops; $Imager::Regops::Attr{$opname}->{opcode} # opcode for given operator $Imager::Regops::Attr{$opname}->{parms} # number of parameters $Imager::Regops::Attr{$opname}->{types} # types of parameters $Imager::Regops::Attr{$opname}->{func} # operator is a function $Imager::Regops::Attr{$opname}->{result} # r for numeric, p for pixel result $Imager::Regops::MaxOperands; # maximum number of operands =head1 DESCRIPTION This module is generated automatically from F so we don't need to maintain the same information in at least one extra place. At least that's the idea. =head1 AUTHOR Tony Cook, tony@develop-help.com =head1 SEE ALSO perl(1), Imager(3), http://imager.perl.org/ =cut libimager-perl-1.004+dfsg.orig/iolayer.c0000644000175000017500000013065512263740601017404 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "iolayer.h" #include "imerror.h" #include "log.h" #include #include #ifdef _MSC_VER #include #endif #include #include #include "imageri.h" #define IOL_DEB(x) #define IOL_DEBs stderr #define IO_BUF_SIZE 8192 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" }; typedef struct io_blink { char buf[BBSIZ]; /* size_t cnt; */ size_t len; /* How large is this buffer = BBZIS for now */ struct io_blink *next; struct io_blink *prev; } io_blink; typedef struct { i_io_glue_t base; int fd; } io_fdseek; typedef struct { i_io_glue_t base; const char *data; size_t len; i_io_closebufp_t closecb; /* free memory mapped segment or decrement refcount */ void *closedata; off_t cpos; } io_buffer; typedef struct { i_io_glue_t base; void *p; /* Callback data */ i_io_readl_t readcb; i_io_writel_t writecb; i_io_seekl_t seekcb; i_io_closel_t closecb; i_io_destroyl_t destroycb; } io_cb; typedef struct { off_t offset; /* Offset of the source - not used */ off_t length; /* Total length of chain in bytes */ io_blink *head; /* Start of chain */ io_blink *tail; /* End of chain */ off_t tfill; /* End of stream in last link */ io_blink *cp; /* Current element of list */ off_t cpos; /* Offset within the current */ off_t gpos; /* Global position in stream */ } io_ex_bchain; /* turn current offset, file length, whence and offset into a new offset */ #define calc_seek_offset(curr_off, length, offset, whence) \ (((whence) == SEEK_SET) ? (offset) : \ ((whence) == SEEK_CUR) ? (curr_off) + (offset) : \ ((whence) == SEEK_END) ? (length) + (offset) : -1) /* =head1 NAME iolayer.c - encapsulates different source of data into a single framework. =head1 SYNOPSIS io_glue *ig = io_new_fd( fileno(stdin) ); method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet switch (method) { case IOL_NOSEEK: code that uses ig->readcb() to read data goes here. break; case IOL_MMAP: code that uses ig->readcb() to read data goes here. break; } io_glue_destroy(ig); // and much more =head1 DESCRIPTION iolayer.c implements the basic functions to create and destroy io_glue objects for Imager. The typical usage pattern for data sources is: 1. Create the source (io_new_fd) 2. Define how you want to get data from it (io_reqmeth) 3. read from it using the interface requested (ig->readdb, ig->mmapcb) 4. Close the source, which shouldn't really close the underlying source. (io_glue DESTROY) =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ static void i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb, i_io_seekp_t seekcb); static ssize_t fd_read(io_glue *ig, void *buf, size_t count); static ssize_t fd_write(io_glue *ig, const void *buf, size_t count); static off_t fd_seek(io_glue *ig, off_t offset, int whence); static int fd_close(io_glue *ig); static ssize_t fd_size(io_glue *ig); static const char *my_strerror(int err); static void i_io_setup_buffer(io_glue *ig); static void i_io_start_write(io_glue *ig); static int i_io_read_fill(io_glue *ig, ssize_t needed); static void dump_data(unsigned char *start, unsigned char *end, int bias); static ssize_t realseek_read(io_glue *igo, void *buf, size_t count); static ssize_t realseek_write(io_glue *igo, const void *buf, size_t count); static int realseek_close(io_glue *igo); static off_t realseek_seek(io_glue *igo, off_t offset, int whence); static void realseek_destroy(io_glue *igo); static ssize_t buffer_read(io_glue *igo, void *buf, size_t count); static ssize_t buffer_write(io_glue *ig, const void *buf, size_t count); static int buffer_close(io_glue *ig); static off_t buffer_seek(io_glue *igo, off_t offset, int whence); static void buffer_destroy(io_glue *igo); static io_blink*io_blink_new(void); static void io_bchain_advance(io_ex_bchain *ieb); static void io_destroy_bufchain(io_ex_bchain *ieb); static ssize_t bufchain_read(io_glue *ig, void *buf, size_t count); static ssize_t bufchain_write(io_glue *ig, const void *buf, size_t count); static int bufchain_close(io_glue *ig); static off_t bufchain_seek(io_glue *ig, off_t offset, int whence); static void bufchain_destroy(io_glue *ig); /* * Methods for setting up data source */ /* =item im_io_new_bufchain(ctx) XX =order 10 =category I/O Layers Returns a new io_glue object that has the 'empty' source and but can be written to and read from later (like a pseudo file). Also callable as C. =cut */ io_glue * im_io_new_bufchain(pIMCTX) { io_glue *ig; io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain)); im_log((aIMCTX, 1, "io_new_bufchain()\n")); ig = mymalloc(sizeof(io_glue)); memset(ig, 0, sizeof(*ig)); i_io_init(aIMCTX, ig, BUFCHAIN, bufchain_read, bufchain_write, bufchain_seek); ieb->offset = 0; ieb->length = 0; ieb->cpos = 0; ieb->gpos = 0; ieb->tfill = 0; ieb->head = io_blink_new(); ieb->cp = ieb->head; ieb->tail = ieb->head; ig->exdata = ieb; ig->closecb = bufchain_close; ig->destroycb = bufchain_destroy; im_context_refinc(aIMCTX, "im_io_new_bufchain"); return ig; } /* =item im_io_new_buffer(ctx, data, length) XX =order 10 =category I/O Layers Returns a new io_glue object that has the source defined as reading from specified buffer. Note that the buffer is not copied. ctx - an Imager context object data - buffer to read from length - length of buffer Also callable as C. =cut */ io_glue * im_io_new_buffer(pIMCTX, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata) { io_buffer *ig; im_log((aIMCTX, 1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata)); ig = mymalloc(sizeof(io_buffer)); memset(ig, 0, sizeof(*ig)); i_io_init(aIMCTX, &ig->base, BUFFER, buffer_read, buffer_write, buffer_seek); ig->data = data; ig->len = len; ig->closecb = closecb; ig->closedata = closedata; ig->cpos = 0; ig->base.closecb = buffer_close; ig->base.destroycb = buffer_destroy; im_context_refinc(aIMCTX, "im_io_new_bufchain"); return (io_glue *)ig; } /* =item im_io_new_fd(ctx, file) XX =order 10 =category I/O Layers Returns a new io_glue object that has the source defined as reading from specified file descriptor. Note that the interface to receiving data from the io_glue callbacks hasn't been done yet. ctx - and Imager context object file - file descriptor to read/write from Also callable as C. =cut */ io_glue * im_io_new_fd(pIMCTX, int fd) { io_fdseek *ig; im_log((aIMCTX, 1, "io_new_fd(fd %d)\n", fd)); ig = mymalloc(sizeof(io_fdseek)); memset(ig, 0, sizeof(*ig)); i_io_init(aIMCTX, &ig->base, FDSEEK, fd_read, fd_write, fd_seek); ig->fd = fd; ig->base.closecb = fd_close; ig->base.sizecb = fd_size; ig->base.destroycb = NULL; im_context_refinc(aIMCTX, "im_io_new_bufchain"); im_log((aIMCTX, 1, "(%p) <- io_new_fd\n", ig)); return (io_glue *)ig; } /* =item im_io_new_cb(ctx, p, read_cb, write_cb, seek_cb, close_cb, destroy_cb) XX =category I/O Layers =order 10 Create a new I/O layer object that calls your supplied callbacks. In general the callbacks should behave like the corresponding POSIX primitives. =over =item * C(p, buffer, length) should read up to C bytes into C and return the number of bytes read. At end of file, return 0. On error, return -1. =item * C(p, buffer, length) should write up to C bytes from C and return the number of bytes written. A return value <= 0 will be treated as an error. =item * C(p, offset, whence) should seek and return the new offset. =item * C(p) should return 0 on success, -1 on failure. =item * C(p) should release any memory specific to your callback handlers. =back Also callable as C. =cut */ io_glue * im_io_new_cb(pIMCTX, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb) { io_cb *ig; im_log((aIMCTX, 1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, " "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb)); ig = mymalloc(sizeof(io_cb)); memset(ig, 0, sizeof(*ig)); i_io_init(aIMCTX, &ig->base, CBSEEK, realseek_read, realseek_write, realseek_seek); im_log((aIMCTX, 1, "(%p) <- io_new_cb\n", ig)); ig->base.closecb = realseek_close; ig->base.destroycb = realseek_destroy; ig->p = p; ig->readcb = readcb; ig->writecb = writecb; ig->seekcb = seekcb; ig->closecb = closecb; ig->destroycb = destroycb; im_context_refinc(aIMCTX, "im_io_new_bufchain"); return (io_glue *)ig; } /* =item io_slurp(ig, c) X =category I/O Layers Takes the source that the io_glue is bound to and allocates space for a return buffer and returns the entire content in a single buffer. Note: This only works for io_glue objects created by io_new_bufchain(). It is useful for saving to scalars and such. ig - io_glue object c - pointer to a pointer to where data should be copied to char *data; size_t size = io_slurp(ig, &data); ... do something with the data ... myfree(data); io_slurp() will abort the program if the supplied I/O layer is not from io_new_bufchain(). =cut */ size_t io_slurp(io_glue *ig, unsigned char **c) { ssize_t rc; io_ex_bchain *ieb; unsigned char *cc; io_type inn = ig->type; if ( inn != BUFCHAIN ) { dIMCTXio(ig); im_fatal(aIMCTX, 0, "io_slurp: called on a source that is not from a bufchain\n"); } ieb = ig->exdata; cc = *c = mymalloc( ieb->length ); bufchain_seek(ig, 0, SEEK_SET); rc = bufchain_read(ig, cc, ieb->length); if (rc != ieb->length) { dIMCTXio(ig); im_fatal(aIMCTX,1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length); } return rc; } /* =item io_glue_destroy(ig) X =category I/O Layers =order 90 =synopsis io_glue_destroy(ig); Destroy an io_glue objects. Should clean up all related buffers. ig - io_glue object to destroy. =cut */ void io_glue_destroy(io_glue *ig) { dIMCTXio(ig); im_log((aIMCTX, 1, "io_glue_DESTROY(ig %p)\n", ig)); if (ig->destroycb) ig->destroycb(ig); if (ig->buffer) myfree(ig->buffer); myfree(ig); im_context_refdec(aIMCTX, "io_glue_destroy"); } /* =item i_io_getc(ig) =category I/O Layers A macro to read a single byte from a buffered I/O glue object. Returns EOF on failure, or a byte. =cut */ int i_io_getc_imp(io_glue *ig) { if (ig->write_ptr) return EOF; if (ig->error || ig->buf_eof) return EOF; if (!ig->buffered) { unsigned char buf; ssize_t rc = i_io_raw_read(ig, &buf, 1); if (rc > 0) { return buf; } else if (rc == 0) { ig->buf_eof = 1; return EOF; } else { ig->error = 1; return EOF; } } if (!ig->buffer) i_io_setup_buffer(ig); if (!ig->read_ptr || ig->read_ptr == ig->read_end) { if (!i_io_read_fill(ig, 1)) return EOF; } return *(ig->read_ptr++); } /* =item i_io_peekc(ig) =category I/O Layers Read the next character from the stream without advancing the stream. On error or end of file, return EOF. For unbuffered streams a single character buffer will be setup. =cut */ int i_io_peekc_imp(io_glue *ig) { if (ig->write_ptr) return EOF; if (!ig->buffer) i_io_setup_buffer(ig); if (!ig->buffered) { ssize_t rc = i_io_raw_read(ig, ig->buffer, 1); if (rc > 0) { ig->read_ptr = ig->buffer; ig->read_end = ig->buffer + 1; return *(ig->buffer); } else if (rc == 0) { ig->buf_eof = 1; return EOF; } else { ig->error = 1; return EOF; } } if (!ig->read_ptr || ig->read_ptr == ig->read_end) { if (ig->error || ig->buf_eof) return EOF; if (!i_io_read_fill(ig, 1)) return EOF; } return *(ig->read_ptr); } /* =item i_io_peekn(ig, buffer, size) =category I/O Layers =synopsis ssize_t count = i_io_peekn(ig, buffer, sizeof(buffer)); Buffer at least C (at most C<< ig->buf_size >> bytes of data from the stream and return C bytes of it to the caller in C. This ignores the buffered state of the stream, and will always setup buffering if needed. If no C parameter is provided to Imager::read() or Imager::read_multi(), Imager will call C when probing for the file format. Returns -1 on error, 0 if there is no data before EOF, or the number of bytes read into C. =cut */ ssize_t i_io_peekn(io_glue *ig, void *buf, size_t size) { IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn(%p, %p, %d)\n", ig, buf, (int)size)); if (size == 0) { dIMCTXio(ig); i_push_error(0, "peekn size must be positive"); IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (zero size)\n")); return -1; } if (ig->write_ptr) { IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (write_ptr set)\n")); return -1; } if (!ig->buffer) i_io_setup_buffer(ig); if ((!ig->read_ptr || size > ig->read_end - ig->read_ptr) && !(ig->buf_eof || ig->error)) { i_io_read_fill(ig, size); } if (size > ig->read_end - ig->read_ptr) size = ig->read_end - ig->read_ptr; if (size) memcpy(buf, ig->read_ptr, size); else if (ig->buf_eof) { IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => 0 (eof)\n")); return 0; } else if (ig->error) { IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (error)\n")); return -1; } else { IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() - size 0 but not eof or error!\n")); return -1; } IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => %d\n", (int)size)); return size; } /* =item i_io_putc(ig, c) =category I/O Layers Write a single character to the stream. On success return c, on error returns EOF =cut */ int i_io_putc_imp(io_glue *ig, int c) { IOL_DEB(fprintf(IOL_DEBs, "i_io_putc_imp(%p, %d)\n", ig, c)); if (!ig->buffered) { char buf = c; ssize_t write_result; int result = c; if (ig->error) return EOF; write_result = i_io_raw_write(ig, &buf, 1); if (write_result != 1) { ig->error = 1; result = EOF; IOL_DEB(fprintf(IOL_DEBs, " unbuffered putc() failed, setting error mode\n")); } IOL_DEB(fprintf(IOL_DEBs, " unbuffered: result %d\n", result)); return result; } if (ig->read_ptr) return EOF; if (ig->error) return EOF; if (!ig->buffer) i_io_setup_buffer(ig); if (ig->write_ptr && ig->write_ptr == ig->write_end) { if (!i_io_flush(ig)) return EOF; } i_io_start_write(ig); *(ig->write_ptr)++ = c; return (unsigned char)c; } /* =item i_io_read(io, buffer, size) =category I/O Layers Read up to C bytes from the stream C into C. Returns the number of bytes read. Returns 0 on end of file. Returns -1 on error. =cut */ ssize_t i_io_read(io_glue *ig, void *buf, size_t size) { unsigned char *pbuf = buf; ssize_t read_total = 0; IOL_DEB(fprintf(IOL_DEBs, "i_io_read(%p, %p, %u)\n", ig, buf, (unsigned)size)); if (ig->write_ptr) { IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => -1 (write_ptr set)\n")); return -1; } if (!ig->buffer && ig->buffered) i_io_setup_buffer(ig); if (ig->read_ptr && ig->read_ptr < ig->read_end) { size_t alloc = ig->read_end - ig->read_ptr; if (alloc > size) alloc = size; memcpy(pbuf, ig->read_ptr, alloc); ig->read_ptr += alloc; pbuf += alloc; size -= alloc; read_total += alloc; } if (size > 0 && !(ig->error || ig->buf_eof)) { if (!ig->buffered || size > ig->buf_size) { ssize_t rc; while (size > 0 && (rc = i_io_raw_read(ig, pbuf, size)) > 0) { size -= rc; pbuf += rc; read_total += rc; } IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => %d (raw read)\n", (int)read_total)); if (rc < 0) ig->error = 1; else if (rc == 0) ig->buf_eof = 1; if (!read_total) return rc; } else { if (i_io_read_fill(ig, size)) { size_t alloc = ig->read_end - ig->read_ptr; if (alloc > size) alloc = size; memcpy(pbuf, ig->read_ptr, alloc); ig->read_ptr += alloc; pbuf += alloc; size -= alloc; read_total += alloc; } else { if (!read_total && ig->error) { IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => -1 (fill failure)\n")); return -1; } } } } if (!read_total && ig->error) read_total = -1; IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => %d\n", (int)read_total)); return read_total; } /* =item i_io_write(io, buffer, size) =category I/O Layers =synopsis ssize_t result = i_io_write(io, buffer, size) Write to the given I/O stream. Returns the number of bytes written. =cut */ ssize_t i_io_write(io_glue *ig, const void *buf, size_t size) { const unsigned char *pbuf = buf; size_t write_count = 0; IOL_DEB(fprintf(IOL_DEBs, "i_io_write(%p, %p, %u)\n", ig, buf, (unsigned)size)); if (!ig->buffered) { ssize_t result; if (ig->error) { IOL_DEB(fprintf(IOL_DEBs, " unbuffered, error state\n")); return -1; } result = i_io_raw_write(ig, buf, size); if (result != size) { ig->error = 1; IOL_DEB(fprintf(IOL_DEBs, " unbuffered, setting error flag\n")); } IOL_DEB(fprintf(IOL_DEBs, " unbuffered, result: %d\n", (int)result)); return result; } if (ig->read_ptr) { IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (read_ptr set)\n")); return -1; } if (ig->error) { IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (error)\n")); return -1; } if (!ig->buffer) i_io_setup_buffer(ig); if (!ig->write_ptr) i_io_start_write(ig); if (ig->write_ptr && ig->write_ptr + size <= ig->write_end) { size_t alloc = ig->write_end - ig->write_ptr; if (alloc > size) alloc = size; memcpy(ig->write_ptr, pbuf, alloc); write_count += alloc; size -= alloc; pbuf += alloc; ig->write_ptr += alloc; } if (size) { if (!i_io_flush(ig)) { IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => %d (i_io_flush failure)\n", (int)write_count)); return write_count ? write_count : -1; } i_io_start_write(ig); if (size > ig->buf_size) { ssize_t rc; while (size > 0 && (rc = i_io_raw_write(ig, pbuf, size)) > 0) { write_count += rc; pbuf += rc; size -= rc; } if (rc <= 0) { ig->error = 1; if (!write_count) { IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (direct write failure)\n")); return -1; } } } else { memcpy(ig->write_ptr, pbuf, size); write_count += size; ig->write_ptr += size; } } IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => %d\n", (int)write_count)); return write_count; } /* =item i_io_seek(io, offset, whence) =category I/O Layers Seek within the stream. Acts like perl's seek. =cut */ off_t i_io_seek(io_glue *ig, off_t offset, int whence) { off_t new_off; IOL_DEB(fprintf(IOL_DEBs, "i_io_seek(%p, %ld, %d)\n", ig, (long)offset, whence)); if (ig->write_ptr && ig->write_ptr != ig->write_end) { if (!i_io_flush(ig)) return (off_t)(-1); } if (whence == SEEK_CUR && ig->read_ptr && ig->read_ptr != ig->read_end) offset -= ig->read_end - ig->read_ptr; ig->read_ptr = ig->read_end = NULL; ig->write_ptr = ig->write_end = NULL; ig->error = 0; ig->buf_eof = 0; new_off = i_io_raw_seek(ig, offset, whence); if (new_off < 0) ig->error = 1; IOL_DEB(fprintf(IOL_DEBs, "i_io_seek() => %ld\n", (long)new_off)); return new_off; } /* =item i_io_flush(io) =category I/O Layers Flush any buffered output. Returns true on success, =cut */ int i_io_flush(io_glue *ig) { unsigned char *bufp; IOL_DEB(fprintf(IOL_DEBs, "i_io_flush(%p)\n", ig)); if (ig->error) { IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 0 (error set)\n", ig)); return 0; } /* nothing to do */ if (!ig->write_ptr) return 1; bufp = ig->buffer; while (bufp < ig->write_ptr) { ssize_t rc = i_io_raw_write(ig, bufp, ig->write_ptr - bufp); if (rc <= 0) { IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 0 (write error)\n", ig)); ig->error = 1; return 0; } bufp += rc; } ig->write_ptr = ig->write_end = NULL; IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 1\n", ig)); return 1; } /* =item i_io_close(io) =category I/O Layers Flush any pending output and perform the close action for the stream. Returns 0 on success. =cut */ int i_io_close(io_glue *ig) { int result = 0; IOL_DEB(fprintf(IOL_DEBs, "i_io_close(%p)\n", ig)); if (ig->error) result = -1; if (ig->write_ptr && !i_io_flush(ig)) result = -1; if (i_io_raw_close(ig)) result = -1; IOL_DEB(fprintf(IOL_DEBs, "i_io_close() => %d\n", result)); return result; } /* =item i_io_gets(ig, buffer, size, end_of_line) =category I/O Layers =synopsis char buffer[BUFSIZ] =synopsis ssize_t len = i_io_gets(buffer, sizeof(buffer), '\n'); Read up to C-1 bytes from the stream C into C. If the byte C is seen then no further bytes will be read. Returns the number of bytes read. Always C terminates the buffer. =cut */ ssize_t i_io_gets(io_glue *ig, char *buffer, size_t size, int eol) { ssize_t read_count = 0; if (size < 2) return 0; --size; /* room for nul */ while (size > 0) { int byte = i_io_getc(ig); if (byte == EOF) break; *buffer++ = byte; ++read_count; if (byte == eol) break; --size; } *buffer++ = '\0'; return read_count; } /* =item i_io_init(ig, readcb, writecb, seekcb) Do common initialization for io_glue objects. =cut */ static void i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb, i_io_seekp_t seekcb) { ig->type = type; ig->exdata = NULL; ig->readcb = readcb; ig->writecb = writecb; ig->seekcb = seekcb; ig->closecb = NULL; ig->sizecb = NULL; ig->destroycb = NULL; ig->context = aIMCTX; ig->buffer = NULL; ig->read_ptr = NULL; ig->read_end = NULL; ig->write_ptr = NULL; ig->write_end = NULL; ig->buf_size = IO_BUF_SIZE; ig->buf_eof = 0; ig->error = 0; ig->buffered = 1; } /* =item i_io_set_buffered(io, buffered) =category I/O Layers Set the buffering mode of the stream. If you switch buffering off on a stream with buffering on: =over =item * any buffered output will be flushed. =item * any existing buffered input will be consumed before reads become unbuffered. =back Returns true on success. This may fail if any buffered output cannot be flushed. =cut */ int i_io_set_buffered(io_glue *ig, int buffered) { if (!buffered && ig->write_ptr) { if (!i_io_flush(ig)) { ig->error = 1; return 0; } } ig->buffered = buffered; return 1; } /* =item i_io_dump(ig) Dump the base fields of an io_glue object to stdout. =cut */ void i_io_dump(io_glue *ig, int flags) { fprintf(IOL_DEBs, "ig %p:\n", ig); fprintf(IOL_DEBs, " type: %d\n", ig->type); fprintf(IOL_DEBs, " exdata: %p\n", ig->exdata); if (flags & I_IO_DUMP_CALLBACKS) { fprintf(IOL_DEBs, " readcb: %p\n", ig->readcb); fprintf(IOL_DEBs, " writecb: %p\n", ig->writecb); fprintf(IOL_DEBs, " seekcb: %p\n", ig->seekcb); fprintf(IOL_DEBs, " closecb: %p\n", ig->closecb); fprintf(IOL_DEBs, " sizecb: %p\n", ig->sizecb); } if (flags & I_IO_DUMP_BUFFER) { fprintf(IOL_DEBs, " buffer: %p\n", ig->buffer); fprintf(IOL_DEBs, " read_ptr: %p\n", ig->read_ptr); if (ig->read_ptr) { fprintf(IOL_DEBs, " "); dump_data(ig->read_ptr, ig->read_end, 0); putc('\n', IOL_DEBs); } fprintf(IOL_DEBs, " read_end: %p\n", ig->read_end); fprintf(IOL_DEBs, " write_ptr: %p\n", ig->write_ptr); if (ig->write_ptr) { fprintf(IOL_DEBs, " "); dump_data(ig->buffer, ig->write_ptr, 1); putc('\n', IOL_DEBs); } fprintf(IOL_DEBs, " write_end: %p\n", ig->write_end); fprintf(IOL_DEBs, " buf_size: %u\n", (unsigned)(ig->buf_size)); } if (flags & I_IO_DUMP_STATUS) { fprintf(IOL_DEBs, " buf_eof: %d\n", ig->buf_eof); fprintf(IOL_DEBs, " error: %d\n", ig->error); fprintf(IOL_DEBs, " buffered: %d\n", ig->buffered); } } /* =back =head1 INTERNAL FUNCTIONS =over =item my_strerror Calls strerror() and ensures we don't return NULL. On some platforms it's possible for strerror() to return NULL, this wrapper ensures we only get non-NULL values. =cut */ static const char *my_strerror(int err) { const char *result = strerror(err); if (!result) result = "Unknown error"; return result; } static void i_io_setup_buffer(io_glue *ig) { ig->buffer = mymalloc(ig->buf_size); } static void i_io_start_write(io_glue *ig) { ig->write_ptr = ig->buffer; ig->write_end = ig->buffer + ig->buf_size; } static int i_io_read_fill(io_glue *ig, ssize_t needed) { unsigned char *buf_end = ig->buffer + ig->buf_size; unsigned char *buf_start = ig->buffer; unsigned char *work = ig->buffer; ssize_t rc; int good = 0; IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill(%p, %d)\n", ig, (int)needed)); /* these conditions may be unused, callers should also be checking them */ if (ig->error || ig->buf_eof) return 0; if (needed > ig->buf_size) needed = ig->buf_size; if (ig->read_ptr && ig->read_ptr < ig->read_end) { size_t kept = ig->read_end - ig->read_ptr; if (needed < kept) { IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill(%u) -> 1 (already have enough)\n", (unsigned)needed)); return 1; } if (ig->read_ptr != ig->buffer) memmove(ig->buffer, ig->read_ptr, kept); good = 1; /* we have *something* available to read */ work = buf_start + kept; needed -= kept; } else { work = ig->buffer; } /* there should always be buffer space the first time around, but avoid a compiler warning here */ rc = -1; while (work < buf_end && (rc = i_io_raw_read(ig, work, buf_end - work)) > 0) { work += rc; good = 1; if (needed < rc) break; needed -= rc; } if (rc < 0) { ig->error = 1; IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc %d, setting error\n", (int)rc)); } else if (rc == 0) { ig->buf_eof = 1; IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc 0, setting eof\n")); } if (good) { ig->read_ptr = buf_start; ig->read_end = work; } IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill => %d, %u buffered\n", good, (unsigned)(ig->read_end - ig->read_ptr))); return good; } /* =item dump_data(start, end, bias) Hex dump the data between C and C. If there is more than a pleasing amount of data, either dump the beginning (C) or dump the end C() of the range. =cut */ static void dump_data(unsigned char *start, unsigned char *end, int bias) { unsigned char *p; size_t count = end - start; if (start == end) { fprintf(IOL_DEBs, "(empty)"); return; } if (count > 15) { if (bias) { fprintf(IOL_DEBs, "... "); start = end - 14; } else { end = start + 14; } for (p = start; p < end; ++p) { fprintf(IOL_DEBs, " %02x", *p); } putc(' ', IOL_DEBs); putc('<', IOL_DEBs); for (p = start; p < end; ++p) { if (*p < ' ' || *p > '~') putc('.', IOL_DEBs); else putc(*p, IOL_DEBs); } putc('>', IOL_DEBs); if (!bias) fprintf(IOL_DEBs, " ..."); } else { for (p = start; p < end; ++p) { fprintf(IOL_DEBs, " %02x", *p); } putc(' ', IOL_DEBs); for (p = start; p < end; ++p) { if (*p < ' ' || *p > '~') putc('.', IOL_DEBs); else putc(*p, IOL_DEBs); } } } /* * Callbacks for sources that cannot seek */ /* * Callbacks for sources that can seek */ /* =item realseek_read(ig, buf, count) Does the reading from a source that can be seeked on ig - io_glue object buf - buffer to return data in count - number of bytes to read into buffer max =cut */ static ssize_t realseek_read(io_glue *igo, void *buf, size_t count) { io_cb *ig = (io_cb *)igo; void *p = ig->p; ssize_t rc = 0; IOL_DEB( fprintf(IOL_DEBs, "realseek_read: buf = %p, count = %u\n", buf, (unsigned)count) ); rc = ig->readcb(p,buf,count); IOL_DEB( fprintf(IOL_DEBs, "realseek_read: rc = %d\n", (int)rc) ); return rc; } /* =item realseek_write(ig, buf, count) Does the writing to a 'source' that can be seeked on ig - io_glue object buf - buffer that contains data count - number of bytes to write =cut */ static ssize_t realseek_write(io_glue *igo, const void *buf, size_t count) { io_cb *ig = (io_cb *)igo; void *p = ig->p; ssize_t rc = 0; size_t bc = 0; char *cbuf = (char*)buf; IOL_DEB( fprintf(IOL_DEBs, "realseek_write: ig = %p, buf = %p, " "count = %u\n", ig, buf, (unsigned)count) ); /* Is this a good idea? Would it be better to handle differently? skip handling? */ while( count!=bc && (rc = ig->writecb(p,cbuf+bc,count-bc))>0 ) { bc+=rc; } IOL_DEB( fprintf(IOL_DEBs, "realseek_write: rc = %d, bc = %u\n", (int)rc, (unsigned)bc) ); return rc < 0 ? rc : bc; } /* =item realseek_close(ig) Closes a source that can be seeked on. Not sure if this should be an actual close or not. Does nothing for now. Should be fixed. ig - data source =cut */ static int realseek_close(io_glue *igo) { io_cb *ig = (io_cb *)igo; dIMCTXio(igo); IOL_DEB(fprintf(IOL_DEBs, "realseek_close(%p)\n", ig)); im_log((aIMCTX,1, "realseek_close(ig %p)\n", ig)); if (ig->closecb) return ig->closecb(ig->p); else return 0; } /* =item realseek_seek(ig, offset, whence) Implements seeking for a source that is seekable, the purpose of having this is to be able to have an offset into a file that is different from what the underlying library thinks. ig - data source offset - offset into stream whence - whence argument a la lseek =cut */ static off_t realseek_seek(io_glue *igo, off_t offset, int whence) { io_cb *ig = (io_cb *)igo; void *p = ig->p; off_t rc; IOL_DEB( fprintf(IOL_DEBs, "realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) ); rc = ig->seekcb(p, offset, whence); IOL_DEB( fprintf(IOL_DEBs, "realseek_seek: rc %ld\n", (long) rc) ); return rc; /* FIXME: How about implementing this offset handling stuff? */ } static void realseek_destroy(io_glue *igo) { io_cb *ig = (io_cb *)igo; if (ig->destroycb) ig->destroycb(ig->p); } /* * Callbacks for sources that are a fixed size buffer */ /* =item buffer_read(ig, buf, count) Does the reading from a buffer source ig - io_glue object buf - buffer to return data in count - number of bytes to read into buffer max =cut */ static ssize_t buffer_read(io_glue *igo, void *buf, size_t count) { io_buffer *ig = (io_buffer *)igo; IOL_DEB( fprintf(IOL_DEBs, "buffer_read: ig->cpos = %ld, buf = %p, count = %u\n", (long) ig->cpos, buf, (unsigned)count) ); if ( ig->cpos+count > ig->len ) { dIMCTXio(igo); im_log((aIMCTX, 1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ig->cpos, (long)ig->len, (long)count)); count = ig->len - ig->cpos; } memcpy(buf, ig->data+ig->cpos, count); ig->cpos += count; IOL_DEB( fprintf(IOL_DEBs, "buffer_read: count = %ld\n", (long)count) ); return count; } /* =item buffer_write(ig, buf, count) Does nothing, returns -1 ig - io_glue object buf - buffer that contains data count - number of bytes to write =cut */ static ssize_t buffer_write(io_glue *ig, const void *buf, size_t count) { dIMCTXio(ig); im_log((aIMCTX, 1, "buffer_write called, this method should never be called.\n")); return -1; } /* =item buffer_close(ig) Closes a source that can be seeked on. Not sure if this should be an actual close or not. Does nothing for now. Should be fixed. ig - data source =cut */ static int buffer_close(io_glue *ig) { dIMCTXio(ig); im_log((aIMCTX, 1, "buffer_close(ig %p)\n", ig)); return 0; } /* =item buffer_seek(ig, offset, whence) Implements seeking for a buffer source. ig - data source offset - offset into stream whence - whence argument a la lseek =cut */ static off_t buffer_seek(io_glue *igo, off_t offset, int whence) { io_buffer *ig = (io_buffer *)igo; off_t reqpos = calc_seek_offset(ig->cpos, ig->len, offset, whence); if (reqpos > ig->len) { dIMCTXio(igo); im_log((aIMCTX, 1, "seeking out of readable range\n")); return (off_t)-1; } if (reqpos < 0) { dIMCTXio(igo); i_push_error(0, "seek before beginning of file"); return (off_t)-1; } ig->cpos = reqpos; IOL_DEB( fprintf(IOL_DEBs, "buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) ); return reqpos; /* FIXME: How about implementing this offset handling stuff? */ } static void buffer_destroy(io_glue *igo) { io_buffer *ig = (io_buffer *)igo; if (ig->closecb) { dIMCTXio(igo); im_log((aIMCTX, 1,"calling close callback %p for io_buffer\n", ig->closecb)); ig->closecb(ig->closedata); } } /* * Callbacks for sources that are a chain of variable sized buffers */ /* Helper functions for buffer chains */ static io_blink* io_blink_new(void) { io_blink *ib; #if 0 im_log((aIMCTX, 1, "io_blink_new()\n")); #endif ib = mymalloc(sizeof(io_blink)); ib->next = NULL; ib->prev = NULL; ib->len = BBSIZ; memset(&ib->buf, 0, ib->len); return ib; } /* =item io_bchain_advance(ieb) Advances the buffer chain to the next link - extending if necessary. Also adjusts the cpos and tfill counters as needed. ieb - buffer chain object =cut */ static void io_bchain_advance(io_ex_bchain *ieb) { if (ieb->cp->next == NULL) { ieb->tail = io_blink_new(); ieb->tail->prev = ieb->cp; ieb->cp->next = ieb->tail; ieb->tfill = 0; /* Only set this if we added a new slice */ } ieb->cp = ieb->cp->next; ieb->cpos = 0; } /* =item io_bchain_destroy() frees all resources used by a buffer chain. =cut */ static void io_destroy_bufchain(io_ex_bchain *ieb) { io_blink *cp; #if 0 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb)); #endif cp = ieb->head; while(cp) { io_blink *t = cp->next; myfree(cp); cp = t; } } /* static void bufchain_dump(io_ex_bchain *ieb) { mm_log((1, " buf_chain_dump(ieb %p)\n")); mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset)); mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length)); mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head )); mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail )); mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill )); mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp )); mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos )); mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos )); } */ /* * TRUE if lengths are NOT equal */ /* static void chainlencert( io_glue *ig ) { int clen; int cfl = 0; size_t csize = 0; size_t cpos = 0; io_ex_bchain *ieb = ig->exdata; io_blink *cp = ieb->head; if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length)); while(cp) { clen = (cp == ieb->tail) ? ieb->tfill : cp->len; if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n")); if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n")); if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n")); if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n")); if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next)); if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev)); if (cp == ieb->cp) { cfl = 1; cpos += ieb->cpos; } if (!cfl) cpos += clen; csize += clen; cp = cp->next; } if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length)); if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos )); } static void chaincert( io_glue *ig) { size_t csize = 0; io_ex_bchain *ieb = ig->exdata; io_blink *cp = ieb->head; mm_log((1, "Chain verification.\n")); mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset)); mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length)); mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head )); mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail )); mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill )); mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp )); mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos )); mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos )); while(cp) { int clen = cp == ieb->tail ? ieb->tfill : cp->len; mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next)); if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n")); if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n")); if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n")); if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n")); if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next)); if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev)); csize += clen; cp = cp->next; } mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length)); } */ /* =item bufchain_read(ig, buf, count) Does the reading from a source that can be seeked on ig - io_glue object buf - buffer to return data in count - number of bytes to read into buffer max =cut */ static ssize_t bufchain_read(io_glue *ig, void *buf, size_t count) { io_ex_bchain *ieb = ig->exdata; size_t scount = count; char *cbuf = buf; size_t sk; dIMCTXio(ig); im_log((aIMCTX, 1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count)); while( scount ) { int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; if (clen == ieb->cpos) { if (ieb->cp == ieb->tail) break; /* EOF */ ieb->cp = ieb->cp->next; ieb->cpos = 0; clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; } sk = clen - ieb->cpos; sk = sk > scount ? scount : sk; memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk); scount -= sk; ieb->cpos += sk; ieb->gpos += sk; } im_log((aIMCTX, 1, "bufchain_read: returning %ld\n", (long)(count-scount))); return count-scount; } /* =item bufchain_write(ig, buf, count) Does the writing to a 'source' that can be seeked on ig - io_glue object buf - buffer that contains data count - number of bytes to write =cut */ static ssize_t bufchain_write(io_glue *ig, const void *buf, size_t count) { char *cbuf = (char *)buf; io_ex_bchain *ieb = ig->exdata; size_t ocount = count; size_t sk; dIMCTXio(ig); im_log((aIMCTX, 1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count)); IOL_DEB( fprintf(IOL_DEBs, "bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %ld\n", ig, (long) ieb->cpos, buf, (long)count) ); while(count) { im_log((aIMCTX, 2, "bufchain_write: - looping - count = %ld\n", (long)count)); if (ieb->cp->len == ieb->cpos) { im_log((aIMCTX, 1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos)); io_bchain_advance(ieb); } sk = ieb->cp->len - ieb->cpos; sk = sk > count ? count : sk; memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk); if (ieb->cp == ieb->tail) { int extend = ieb->cpos + sk - ieb->tfill; im_log((aIMCTX, 2, "bufchain_write: extending tail by %d\n", extend)); if (extend > 0) { ieb->length += extend; ieb->tfill += extend; } } ieb->cpos += sk; ieb->gpos += sk; count -= sk; } return ocount; } /* =item bufchain_close(ig) Closes a source that can be seeked on. Not sure if this should be an actual close or not. Does nothing for now. Should be fixed. ig - data source =cut */ static int bufchain_close(io_glue *ig) { dIMCTXio(ig); im_log((aIMCTX, 1, "bufchain_close(ig %p)\n",ig)); IOL_DEB( fprintf(IOL_DEBs, "bufchain_close(ig %p)\n", ig) ); return 0; } /* =item bufchain_seek(ig, offset, whence) Implements seeking for a source that is seekable, the purpose of having this is to be able to have an offset into a file that is different from what the underlying library thinks. ig - data source offset - offset into stream whence - whence argument a la lseek =cut */ static off_t bufchain_seek(io_glue *ig, off_t offset, int whence) { io_ex_bchain *ieb = ig->exdata; int wrlen; off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence); off_t sk; dIMCTXio(ig); im_log((aIMCTX, 1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence)); if (scount < 0) { i_push_error(0, "invalid whence supplied or seek before start of file"); return (off_t)-1; } ieb->cp = ieb->head; ieb->cpos = 0; ieb->gpos = 0; while( scount ) { int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; if (clen == ieb->cpos) { if (ieb->cp == ieb->tail) break; /* EOF */ ieb->cp = ieb->cp->next; ieb->cpos = 0; clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; } sk = clen - ieb->cpos; sk = sk > scount ? scount : sk; scount -= sk; ieb->cpos += sk; ieb->gpos += sk; } wrlen = scount; if (wrlen > 0) { /* * extending file - get ieb into consistent state and then * call write which will get it to the correct position */ char TB[BBSIZ]; memset(TB, 0, BBSIZ); ieb->gpos = ieb->length; ieb->cpos = ieb->tfill; while(wrlen > 0) { ssize_t rc, wl = i_min(wrlen, BBSIZ); im_log((aIMCTX, 1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl)); rc = bufchain_write( ig, TB, wl ); if (rc != wl) im_fatal(aIMCTX, 0, "bufchain_seek: Unable to extend file\n"); wrlen -= rc; } } im_log((aIMCTX, 2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos)); return ieb->gpos; } static void bufchain_destroy(io_glue *ig) { io_ex_bchain *ieb = ig->exdata; io_destroy_bufchain(ieb); myfree(ieb); } /* =item fd_read(ig, buf, count) Read callback for file descriptor IO objects. =cut */ static ssize_t fd_read(io_glue *igo, void *buf, size_t count) { io_fdseek *ig = (io_fdseek *)igo; ssize_t result; #ifdef _MSC_VER result = _read(ig->fd, buf, count); #else result = read(ig->fd, buf, count); #endif IOL_DEB(fprintf(IOL_DEBs, "fd_read(%p, %p, %u) => %d\n", ig, buf, (unsigned)count, (int)result)); /* 0 is valid - means EOF */ if (result < 0) { dIMCTXio(igo); im_push_errorf(aIMCTX, 0, "read() failure: %s (%d)", my_strerror(errno), errno); } return result; } static ssize_t fd_write(io_glue *igo, const void *buf, size_t count) { io_fdseek *ig = (io_fdseek *)igo; ssize_t result; #ifdef _MSC_VER result = _write(ig->fd, buf, count); #else result = write(ig->fd, buf, count); #endif IOL_DEB(fprintf(IOL_DEBs, "fd_write(%p, %p, %u) => %d\n", ig, buf, (unsigned)count, (int)result)); if (result <= 0) { dIMCTXio(igo); im_push_errorf(aIMCTX, errno, "write() failure: %s (%d)", my_strerror(errno), errno); } return result; } static off_t fd_seek(io_glue *igo, off_t offset, int whence) { io_fdseek *ig = (io_fdseek *)igo; off_t result; #ifdef _MSC_VER result = _lseek(ig->fd, offset, whence); #else result = lseek(ig->fd, offset, whence); #endif if (result == (off_t)-1) { dIMCTXio(igo); im_push_errorf(aIMCTX, errno, "lseek() failure: %s (%d)", my_strerror(errno), errno); } return result; } static int fd_close(io_glue *ig) { /* no, we don't close it */ return 0; } static ssize_t fd_size(io_glue *ig) { dIMCTXio(ig); im_log((aIMCTX, 1, "fd_size(ig %p) unimplemented\n", ig)); return -1; } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/Makefile.PL0000644000175000017500000004321512614520110017530 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Cwd; use Config; use File::Spec; use Getopt::Long; use ExtUtils::Manifest qw(maniread); use ExtUtils::Liblist; use vars qw(%formats $VERBOSE $INCPATH $LIBPATH $NOLOG $DEBUG_MALLOC $MANUAL $CFLAGS $LFLAGS $DFLAGS); use lib 'inc', 'lib'; use Imager::Probe; # EU::MM runs Makefile.PL all in the same process, so sub-modules will # see this our $BUILDING_IMAGER = 1; # used to display a summary after we've probed the world our %IMAGER_LIBS; # # IM_INCPATH colon seperated list of paths to extra include paths # IM_LIBPATH colon seperated list of paths to extra library paths # # IM_VERBOSE turns on verbose mode for the library finding and such # IM_MANUAL to manually select which libraries are used and which not # IM_ENABLE to programmatically select which libraries are used # and which are not # IM_NOLOG if true logging will not be compiled into the module # IM_DEBUG_MALLOC if true malloc debbuging will be compiled into the module # do not use IM_DEBUG_MALLOC in production - this slows # everything down by alot # IM_CFLAGS Extra flags to pass to the compiler # IM_LFLAGS Extra flags to pass to the linker # IM_DFLAGS Extra flags to pass to the preprocessor my $KEEP_FILES = $ENV{IMAGER_KEEP_FILES}; # make sure --verbose will dump environment settings if (grep $_ =~ /^--?v(?:erbose)?$/, @ARGV) { $VERBOSE = 1; } # modules/features bundled with Imager that can be enabled/disabled # withs --enable/--disable my @bundled = qw(FT1 FT2 GIF JPEG PNG T1 TIFF W32); # extra modules bundled with Imager not available on CPAN my @extras = qw(CountColor DynTest ICO SGI Mandelbrot Flines); # alternate names for modules my %bundled_names = qw(win32 w32 tt ft1); getenv(); # get environment variables my $lext=$Config{'so'}; # Get extensions of libraries my $aext=$Config{'_a'}; my $help; # display help if set my @enable; # list of drivers to enable my @disable; # or list of drivers to disable my @incpaths; # places to look for headers my @libpaths; # places to look for libraries my $coverage; # build for coverage testing my $assert; # build with assertions my $trace_context; # trace context management to stderr GetOptions("help" => \$help, "enable=s" => \@enable, "disable=s" => \@disable, "incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$VERBOSE, "nolog" => \$NOLOG, 'coverage' => \$coverage, "assert|a" => \$assert, "tracecontext" => \$trace_context); setenv(); if ($ENV{AUTOMATED_TESTING}) { $assert = 1; } if ($VERBOSE) { print "Verbose mode\n"; require Data::Dumper; import Data::Dumper qw(Dumper); } if ($help) { usage(); } my @defines; if ($NOLOG) { print "Logging not compiled into module\n"; } else { push @defines, [ IMAGER_LOG => 1, "Logging system" ]; } if ($assert) { push @defines, [ IM_ASSERT => 1, "im_assert() are effective" ]; } if ($DEBUG_MALLOC) { push @defines, [ IMAGER_DEBUG_MALLOC => 1, "Use Imager's DEBUG malloc()" ]; print "Malloc debugging enabled\n"; } if (@enable && @disable) { print STDERR "Only --enable or --disable can be used, not both, try --help\n"; exit 1; } my %definc; my %deflib; my @incs; # all the places to look for headers my @libs; # all the places to look for libraries init(); # initialize global data pathcheck(); # Check if directories exist my @enabled_bundled; if (exists $ENV{IM_ENABLE}) { push @enable, split ' ', $ENV{IM_ENABLE}; } if (@enable) { my %en = map { lc $_ => 1 } map_bundled(@enable); @enabled_bundled = grep $en{lc $_}, @bundled; } elsif (@disable) { my %dis = map { lc $_ => 1 } map_bundled(@disable); @enabled_bundled = grep !$dis{lc $_}, @bundled; } else { @enabled_bundled = @bundled; } # Pick what libraries are used if ($MANUAL) { manual(); } else { automatic(); } my @objs = qw(Imager.o context.o draw.o polygon.o image.o io.o iolayer.o log.o gaussian.o conv.o pnm.o raw.o feat.o combine.o filters.o dynaload.o stackmach.o datatypes.o regmach.o trans2.o quant.o error.o convert.o map.o tags.o palimg.o maskimg.o img8.o img16.o rotate.o bmp.o tga.o color.o fills.o imgdouble.o limits.o hlines.o imext.o scale.o rubthru.o render.o paste.o compose.o flip.o perlio.o); my $lib_define = ''; my $lib_inc = ''; my $lib_libs = ''; for my $frmkey (sort { $formats{$a}{order} <=> $formats{$b}{order} } keys %formats) { my $frm = $formats{$frmkey}; if ($frm->{enabled}) { push @defines, [ $frm->{def}, 1, "$frmkey available" ]; push @objs, $frm->{objfiles}; $lib_define .= " $frm->{DEFINE}" if $frm->{DEFINE}; $lib_inc .= " $frm->{INC}" if $frm->{INC}; $lib_libs .= " $frm->{LIBS}" if $frm->{LIBS}; } } my $OSLIBS = ''; my $OSDEF = "-DOS_$^O"; if ($^O eq 'hpux') { $OSLIBS .= ' -ldld'; } if (defined $Config{'d_dlsymun'}) { $OSDEF .= ' -DDLSYMUN'; } if ($Config{useithreads}) { if ($Config{i_pthread}) { print "POSIX threads\n"; push @objs, "mutexpthr.o"; } elsif ($^O eq 'MSWin32') { print "Win32 threads\n"; push @objs, "mutexwin.o"; } else { print "Unsupported threading model\n"; push @objs, "mutexnull.o"; if ($ENV{AUTOMATED_TESTING}) { die "OS unsupported: no threading support code for this platform\n"; } } } else { print "No threads\n"; push @objs, "mutexnull.o"; } my @typemaps = qw(typemap.local typemap); if ($] < 5.008) { unshift @typemaps, "typemap.oldperl"; } if ($trace_context) { $CFLAGS .= " -DIMAGER_TRACE_CONTEXT"; } my $tests = 't/*.t t/*/*.t'; if (-d "xt" && scalar(() = glob("xt/*.t"))) { $tests .= " xt/*.t"; } my %opts= ( NAME => 'Imager', VERSION_FROM => 'Imager.pm', LIBS => "$LFLAGS -lm $lib_libs $OSLIBS", DEFINE => "$OSDEF $lib_define $CFLAGS", INC => "$lib_inc $DFLAGS", OBJECT => join(' ', @objs), DIR => [ sort grep -d, @enabled_bundled, @extras ], clean => { FILES=>'testout rubthru.c scale.c conv.c filters.c gaussian.c render.c rubthru.c' }, PM => gen_PM(), PREREQ_PM => { 'Test::More' => 0.47, 'Scalar::Util' => 1.00, 'XSLoader' => 0, }, TYPEMAPS => \@typemaps, test => { TESTS => $tests }, ); if ($coverage) { if ($Config{gccversion}) { push @ARGV, 'OPTIMIZE=-ftest-coverage -fprofile-arcs -g'; $opts{dynamic_lib} = { OTHERLDFLAGS => '-ftest-coverage -fprofile-arcs' }; } else { die "Don't know the coverage C flags for your compiler\n"; } } # eval to prevent warnings about versions with _ in them my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook , Arnar M. Hrafnkelsson'; $opts{ABSTRACT} = 'Perl extension for Generating 24 bit Images'; } if ($MM_ver >= 6.46) { $opts{META_MERGE} = { recommends => { "Parse::RecDescent" => 0 }, license => "perl", dynamic_config => 1, no_index => { directory => [ "PNG", "GIF", "TIFF", "JPEG", "W32", "FT2", "T1", ], }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; } make_imconfig(\@defines); if ($VERBOSE) { print Dumper(\%opts); } mkdir('testout',0777); # since we cannot include it in the archive. -d "probe" and rmdir "probe"; WriteMakefile(%opts); my @good; my @bad; for my $name (sort { lc $a cmp lc $b } keys %IMAGER_LIBS) { if ($IMAGER_LIBS{$name}) { push @good, $name; } else { push @bad, $name; } } print "\n"; print "Libraries found:\n" if @good; print " $_\n" for @good; print "Libraries *not* found:\n" if @bad; print " $_\n" for @bad; exit; sub MY::postamble { my $self = shift; my $perl = $self->{PERLRUN} ? '$(PERLRUN)' : '$(PERL)'; my $mani = maniread; my @ims = grep /\.im$/, keys %$mani; ' dyntest.$(MYEXTLIB) : dynfilt/Makefile cd dynfilt && $(MAKE) $(PASTHRU) lib/Imager/Regops.pm : regmach.h regops.perl $(PERL) regops.perl regmach.h lib/Imager/Regops.pm imconfig.h : Makefile.PL $(ECHO) "imconfig.h out-of-date with respect to $?" $(PERLRUN) Makefile.PL $(ECHO) "==> Your Makefile has been rebuilt - re-run your make command <==" '.qq! lib/Imager/APIRef.pod : \$(C_FILES) \$(H_FILES) apidocs.perl $perl apidocs.perl lib/Imager/APIRef.pod !.join('', map _im_rule($perl, $_), @ims) } sub _im_rule { my ($perl, $im) = @_; (my $c = $im) =~ s/\.im$/.c/; return < to continue EOF ; # eat one return for my $frm(sort { $formats{$b}{order} <=> $formats{$a}{order} } keys %formats) { SWX: if ($formats{$frm}{docs}) { print "\n",$formats{$frm}{docs},"\n\n"; } print "Enable $frm support: "; my $gz = ; chomp($gz); if ($gz =~ m/^(y|yes|n|no)/i) { if ($gz =~ /y/i) { $formats{$frm}{enabled} = 1; $IMAGER_LIBS{$frm} = 1; } } else { goto SWX; } } } # automatic configuration of helper libraries sub automatic { print "Automatic probing:\n" if $VERBOSE; if (grep $_ eq "FT1", @enabled_bundled) { my %probe = ( name => "FT1", inccheck => sub { -e File::Spec->catfile($_[0], "ftnameid.h") }, libbase => "ttf", testcode => _ft1_test_code(), testcodeheaders => [ "freetype.h", "stdio.h" ], incpaths => \@incpaths, libpaths => \@libpaths, alternatives => [ { incsuffix => "freetype", } ], verbose => $VERBOSE, ); my $probe_res = Imager::Probe->probe(\%probe); $IMAGER_LIBS{FT1} = defined $probe_res; if ($probe_res) { $formats{FT1}{enabled} = 1; @{$formats{FT1}}{qw/DEFINE INC LIBS/} = @$probe_res{qw/DEFINE INC LIBS/}; } } } sub pathcheck { if ($VERBOSE) { print "pathcheck\n"; print " Include paths:\n"; for (@incs) { print $_,"\n"; } } @incs=grep { -d $_ && -r _ && -x _ or ( print(" $_ doesnt exist or is unaccessible - removed.\n"),0) } @incs; if ($VERBOSE) { print "\nLibrary paths:\n"; for (@libs) { print $_,"\n"; } } @libs=grep { -d $_ && -r _ && -x _ or ( print(" $_ doesnt exist or is unaccessible - removed.\n"),0) } @libs; print "\ndone.\n"; } # Format data initialization # format definition is: # defines needed # default include path # files needed for include (boolean perl code) # default lib path # libs needed # files needed for link (boolean perl code) # object files needed for the format sub init { my @definc = qw(/usr/include); @definc{@definc}=(1) x @definc; @incs= ( split(/\Q$Config{path_sep}/, $INCPATH), map _tilde_expand($_), map { split /\Q$Config{path_sep}/ } @incpaths ); if ($Config{locincpth}) { push @incs, grep -d, split ' ', $Config{locincpth}; } if ($^O =~ /win32/i && $Config{cc} =~ /\bcl\b/i) { push(@incs, split /;/, $ENV{INCLUDE}) if exists $ENV{INCLUDE}; } if ($Config{incpath}) { push @incs, grep -d, split /\Q$Config{path_sep}/, $Config{incpath}; } push @incs, grep -d, qw(/sw/include /usr/include/freetype2 /usr/local/include/freetype2 /usr/local/include/freetype1/freetype /usr/include /usr/local/include /usr/include/freetype /usr/local/include/freetype); if ($Config{ccflags}) { my @hidden = map { /^-I(.*)$/ ? ($1) : () } split ' ', $Config{ccflags}; push @incs, @hidden; @definc{@hidden} = (1) x @hidden; } @libs= ( split(/\Q$Config{path_sep}/,$LIBPATH), map _tilde_expand($_), map { split /\Q$Config{path_sep}/} @libpaths ); if ($Config{loclibpth}) { push @libs, grep -d, split ' ', $Config{loclibpth}; } push @libs, grep -d, qw(/sw/lib), split(/ /, $Config{'libpth'}); push @libs, grep -d, split / /, $Config{libspath} if $Config{libspath}; if ($^O =~ /win32/i && $Config{cc} =~ /\bcl\b/i) { push(@libs, split /;/, $ENV{LIB}) if exists $ENV{LIB}; } if ($^O eq 'cygwin') { push(@libs, '/usr/lib/w32api') if -d '/usr/lib/w32api'; push(@incs, '/usr/include/w32api') if -d '/usr/include/w32api'; } if ($Config{ldflags}) { # some builds of perl put -Ldir into ldflags without putting it in # loclibpth, let's extract them my @hidden = grep -d, map { /^-L(.*)$/ ? ($1) : () } split ' ', $Config{ldflags}; push @libs, @hidden; # don't mark them as seen - EU::MM will remove any libraries # it can't find and it doesn't look for -L in ldflags #@deflib{@hidden} = @hidden; } push @libs, grep -d, qw(/usr/local/lib); $formats{FT1}= { order=>'31', def=>'HAVE_LIBTT', objfiles=>'fontft1.o', LIBS => "-lttf", docs=>q{ Freetype 1.x supports Truetype fonts and is obsoleted by Freetype 2.x. It's probably insecure. } }; # Make fix indent for (keys %formats) { $formats{$_}->{docs} =~ s/^\s+/ /mg; } } sub gen { my $V = $ENV{$_[0]}; print " $_[0]: '$V'\n" if $VERBOSE && defined $V; defined($V) ? $V : ""; } # Get information from environment variables sub getenv { $VERBOSE ||= gen("IM_VERBOSE"); print "Environment config:\n" if $VERBOSE; ($INCPATH, $LIBPATH, $NOLOG, $DEBUG_MALLOC, $MANUAL, $CFLAGS, $LFLAGS, $DFLAGS) = map { gen $_ } qw(IM_INCPATH IM_LIBPATH IM_NOLOG IM_DEBUG_MALLOC IM_MANUAL IM_CFLAGS IM_LFLAGS IM_DFLAGS); } # populate the environment so that sub-modules get the same info sub setenv { $ENV{IM_VERBOSE} = 1 if $VERBOSE; $ENV{IM_INCPATH} = join $Config{path_sep}, @incpaths if @incpaths; $ENV{IM_LIBPATH} = join $Config{path_sep}, @libpaths if @libpaths; } sub make_imconfig { my ($defines) = @_; open CONFIG, "> imconfig.h" or die "Cannot create imconfig.h: $!\n"; print CONFIG <[2]) { print CONFIG "\n/*\n $define->[2]\n*/\n\n"; } print CONFIG "#define $define->[0] $define->[1]\n"; } if ($Config{gccversion} && $Config{gccversion} =~ /^([0-9]+)/ && $1 > 3) { print CONFIG <catdir($home, $path); } $path; } sub _ft1_test_code { return <<'CODE'; TT_Engine engine; TT_Error error; error = TT_Init_FreeType(&engine); if (error) { printf("FT1: Could not initialize engine\n"); exit(1); } return 0; CODE } sub map_bundled { my (@names) = @_; @names = map { split /,/ } @names; my @outnames; for my $name (@names) { push @outnames, $name; push @outnames, $bundled_names{$name} if $bundled_names{$name}; } @outnames; } 1; libimager-perl-1.004+dfsg.orig/TIFF/0000755000175000017500000000000012617614576016330 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/TIFF/TIFF.xs0000644000175000017500000000653112263740600017422 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "imext.h" #include "imperl.h" #include "imtiff.h" DEFINE_IMAGER_CALLBACKS; #ifdef IEEEFP_TYPES #define i_tiff_ieeefp() &PL_sv_yes #else #define i_tiff_ieeefp() &PL_sv_no #endif MODULE = Imager::File::TIFF PACKAGE = Imager::File::TIFF Imager::ImgRaw i_readtiff_wiol(ig, allow_incomplete=0, page=0) Imager::IO ig int allow_incomplete int page void i_readtiff_multi_wiol(ig) Imager::IO ig PREINIT: i_img **imgs; int count; int i; PPCODE: imgs = i_readtiff_multi_wiol(ig, &count); if (imgs) { EXTEND(SP, count); for (i = 0; i < count; ++i) { SV *sv = sv_newmortal(); sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]); PUSHs(sv); } myfree(imgs); } undef_int i_writetiff_wiol(im, ig) Imager::ImgRaw im Imager::IO ig undef_int i_writetiff_multi_wiol(ig, ...) Imager::IO ig PREINIT: int i; int img_count; i_img **imgs; CODE: if (items < 2) croak("Usage: i_writetiff_multi_wiol(ig, images...)"); img_count = items - 1; RETVAL = 1; if (img_count < 1) { RETVAL = 0; i_clear_error(); i_push_error(0, "You need to specify images to save"); } else { imgs = mymalloc(sizeof(i_img *) * img_count); for (i = 0; i < img_count; ++i) { SV *sv = ST(1+i); imgs[i] = NULL; if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) { imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv))); } else { i_clear_error(); i_push_error(0, "Only images can be saved"); myfree(imgs); RETVAL = 0; break; } } if (RETVAL) { RETVAL = i_writetiff_multi_wiol(ig, imgs, img_count); } myfree(imgs); } OUTPUT: RETVAL undef_int i_writetiff_wiol_faxable(im, ig, fine) Imager::ImgRaw im Imager::IO ig int fine undef_int i_writetiff_multi_wiol_faxable(ig, fine, ...) Imager::IO ig int fine PREINIT: int i; int img_count; i_img **imgs; CODE: if (items < 3) croak("Usage: i_writetiff_multi_wiol_faxable(ig, fine, images...)"); img_count = items - 2; RETVAL = 1; if (img_count < 1) { RETVAL = 0; i_clear_error(); i_push_error(0, "You need to specify images to save"); } else { imgs = mymalloc(sizeof(i_img *) * img_count); for (i = 0; i < img_count; ++i) { SV *sv = ST(2+i); imgs[i] = NULL; if (SvROK(sv) && sv_derived_from(sv, "Imager::ImgRaw")) { imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(sv))); } else { i_clear_error(); i_push_error(0, "Only images can be saved"); myfree(imgs); RETVAL = 0; break; } } if (RETVAL) { RETVAL = i_writetiff_multi_wiol_faxable(ig, imgs, img_count, fine); } myfree(imgs); } OUTPUT: RETVAL const char * i_tiff_libversion() bool i_tiff_has_compression(name) const char *name SV * i_tiff_ieeefp() BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; i_tiff_init();libimager-perl-1.004+dfsg.orig/TIFF/TIFF.pm0000644000175000017500000000516512460670607017416 0ustar gregoagregoapackage Imager::File::TIFF; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.89"; require XSLoader; XSLoader::load('Imager::File::TIFF', $VERSION); } Imager->register_reader ( type=>'tiff', single => sub { my ($im, $io, %hsh) = @_; my $allow_incomplete = $hsh{allow_incomplete}; defined $allow_incomplete or $allow_incomplete = 0; my $page = $hsh{page}; defined $page or $page = 0; $im->{IMG} = i_readtiff_wiol($io, $allow_incomplete, $page); unless ($im->{IMG}) { $im->_set_error(Imager->_error_as_msg); return; } return $im; }, multiple => sub { my ($io, %hsh) = @_; my @imgs = i_readtiff_multi_wiol($io); unless (@imgs) { Imager->_set_error(Imager->_error_as_msg); return; } return map bless({ IMG => $_, ERRSTR => undef }, "Imager"), @imgs; }, ); Imager->register_writer ( type=>'tiff', single => sub { my ($im, $io, %hsh) = @_; $im->_set_opts(\%hsh, "i_", $im); $im->_set_opts(\%hsh, "tiff_", $im); $im->_set_opts(\%hsh, "exif_", $im); if (defined $hsh{class} && $hsh{class} eq "fax") { my $fax_fine = $hsh{fax_fine}; defined $fax_fine or $fax_fine = 1; if (!i_writetiff_wiol_faxable($im->{IMG}, $io, $fax_fine)) { $im->{ERRSTR} = Imager->_error_as_msg(); return undef; } } else { unless (i_writetiff_wiol($im->{IMG}, $io)) { $im->_set_error(Imager->_error_as_msg); return; } } return $im; }, multiple => sub { my ($class, $io, $opts, @ims) = @_; Imager->_set_opts($opts, "tiff_", @ims); Imager->_set_opts($opts, "exif_", @ims); my @work = map $_->{IMG}, @ims; my $tiff_class = $opts->{class}; defined $tiff_class or $tiff_class = ""; my $result; if ($tiff_class eq "fax") { my $fax_fine = $opts->{fax_fine}; defined $fax_fine or $fax_fine = 1; $result = i_writetiff_multi_wiol_faxable($io, $fax_fine, @work); } else { $result = i_writetiff_multi_wiol($io, @work); } unless ($result) { $class->_set_error($class->_error_as_msg); return; } return 1; }, ); __END__ =head1 NAME Imager::File::TIFF - read and write TIFF files =head1 SYNOPSIS use Imager; my $img = Imager->new; $img->read(file=>"foo.tiff") or die $img->errstr; $img->write(file => "foo.tif") or die $img->errstr; =head1 DESCRIPTION Imager's TIFF support is documented in L. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Files. =cut libimager-perl-1.004+dfsg.orig/TIFF/testimg/0000755000175000017500000000000012617614576020004 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/TIFF/testimg/slab.tif0000644000175000017500000000065612031434614021417 0ustar gregoagregoaII*ôCreated with The GIMPÖ@+ †Ö@+ †çÎòMIŽš_Ãùñ`à²SŠRKÿçÎòMIŽš_Ãùñ`à²SŠRKÿçÎòMIŽš_Ãùñ`à²SŠRKÿçÎòMIŽš_Ãùñ`à²SŠRKÿçÎòMIŽš_Ãùñ`à²SŠRKÿçÎòMIŽš_Ãùñ`à²SŠRKÿçÎòMIŽš_Ãùñ`à²SŠRKÿçÎòMIŽš_Ãùñ`à²SŠRKÿþ4À$,(libimager-perl-1.004+dfsg.orig/TIFF/testimg/penguin-base.ppm0000644000175000017500000025505412031434614023071 0ustar gregoagregoaP6 # CREATOR: The GIMP's PNM Filter Version 1.0 164 180 255 þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþúýþùýþùýþûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýýûüüúþþüþþüþþüþþüþþüýýûýýûýýûýýûþþüýýûþþüýýûüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýýýýþþþýýýššš€€€€€€€€€€€€%%%€€€   þþþýýýýýýýýýþþýþþüþþüþÿûþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþýýþ××ÙZZ\aabÝÝÞýýýþþýþþüþÿûþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþüýýûþþüþþüýýüþþþ˜˜˜!!"žžžþþüýýûýþúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûýýûýýûþþý×××YYY!!!žžœþþüýýûýýûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüýýüÖÖÖÛÛÚüüúþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþünnnzzyýýüþþýþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû¬¬¬]]`ÜÜÝþþÿþþÿýýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÔÔÒ 333CCC???---"ÚÚÜýýþüüüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý... %%%BBB___cccPPP222xxyýýþýýûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü««ª '''MMMoooyyydddCCC(((wwwýýüýþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýû---+++OOOqqqtttbbbGGG333!!ÙÙØþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüüüúªª¨---OOOggg]]]LLL888///%%%777ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû--,(((AAAFFF<<<---!!! ´´´þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÔÔÒ ***%%%668ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýýªª«  ³³´ýýûþþüýýûþþüþþüþþýþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûûû--.667ýýüüüúüüúþþüþþüþþýþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýý++-ØØØýýüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýý,,.³³³ýýüþþûþþüþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©556üüûýýûþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©    "! 555ýýûýýûþþúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©© ...++- >>@FFH556ýýýüüûþþúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©© !!"224335EEE;;; 444889²²²þþýþÿûþÿúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§224PPP<<<&&&224 RRQttr……„•••™™™”””\\\...±±²ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§ggh———³³³­­­yyy)))000iigƒƒ’’ŸŸŸªªª²²²¾¾¾¿¿¿qqq ²²³þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©§ \\\“““´´´ÇÇÆÃÃÁ­­«~~},,, (()lll““‘¦¦¤³³±¸¸·¿¿¿ÄÄÄÑÑÑÁÁÁ¢¢¢RRR ²²²ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©'''¥¥£ÁÁ¿ÒÒÐÑÑÏÊÊÈ­­¬yyy ]]]™™—ÇÇÅââàìììòòòôôôóóóíííØØØ®®®{{{%%%sstýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©©OOO¬¬¬ÞÞÜôôòûûùüüúüüúûûûãããDDD((*§§¨ææäýýûþþýþþþíííÎÎÎçççýýýúúúñññ···YYY444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ©©© |||èèèõõõ¢¢¢qqo  žððîýýüüüü“““JJJÉÉÉööôýýûûûú¨¨¨$$& '''ŠŠŠôôôýýýùùù­­­444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ©©ª¯¯±÷÷ù ***===kkkññïýýûÉÉÈ VVWÓÓÓûûùüüúººº888zzzGGGzzzõõõýýýååå777444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«ÄÄÆìëí436:::xxw443›œšýýûÝÝÝ))) ``aÔÕÕûûúóóòIII SSS}}}///ÄÄÄþþþ÷ø÷_`^444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû¨¨¨ÄÇÇÄÃÇ YYUKLHTWVóöõààÝ331 ";;;HDC0,*`^bÒÔ×øüüÈÉË"!YWW/.0ŒŒŽúýýøýùˆ€444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÓÓÓ!ÆÃź¹µ+,*HDF.-.ääáÖÑË(#  '+,³³¶ôôô¶¶º    qnqûøüüøü–’—444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüü,,.À½¼ÉËÅ)+-"%)ØÙ׎ˆ{ &$wrðëæ¸·´   qslüû÷úùö”’444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýý**,«¬¬áäå.//#"²¨†€m%¥ŠáɢȜÍÖ—vrc#¾ÏÌ  –š˜ûýõ÷ùð‚ƒ444þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-†ˆŒðñõ‹Š‡  eF ®‚Ëšêµì¸ æ¶ à´ ×¬ÅžÛÖ®#ɦ2йuQF./0/âåâýÿüëëëXVZ444ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-SSTåàäïîïSTV6!‰e±ƒ°|Ú£î¸î» é¼ á¹ Ó­´“ xÆœ è½ä» mV"%'#ÀÅÂúÿþøüýÅÈÊ"!%××Öþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,-"!ÃÂÄøöùëæÚzg7šr¿‰ ÖŸç¯ ðµ ñ· ï¹ë½èÁåÀ äÀá¾çÈîÑêÊçÃã¿Í©xo^ Цþùõýûúëíç|z±±°ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ,,- twxâÝÐϹ‡¬ƒ½ˆÓ™ã­éµì¸ ë¹é¼ç¿ ëÇîÍîÒñÓ+ôÔ/÷Ö0öÕ.øÕ%öÑóÉ î¿ß°È¡*À¡KŰv¦—r*!±±°þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûýýý//02(£‡Vª}!¿† Жܤ ç° ëµ í¹ ì¼ ê¾ êÁ ìÇïÎðÓ ò×/ôØ>÷ÚDöÚ4õØöÕ öÐ ôÍòÇðÆë¿Ú°Á™{W±±±þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûüüü++- YC›xµ„ÊØ›â« ê´ ê´ ë· ì¼ ëÀ ìÆîÌðÑóÕ*õØ>÷ÚA÷Û=ôØ,öÙ÷Øù×øÛù×öÖ÷ÕöÑòÅ+Ö§)bL ±±²ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý,,. L2  u²€¿ˆÔ• â¡ä¯êµì¶ íºë¾ëÄ ìË ìÎïÒôÖ9øÙGùÚBöÙ*õÚõØõ×õ×õØøÙô×ëÎãÂôÇ+î»"“s rrsþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþýªª«…`¶x¿€ÉÛœ ç¦ç± ì¸ ë· í¼ìÂêÇêÍ íÐòÔ/÷ÚAøÙ@öØ-öØöÙ÷ÚôØôØ÷×öÏằ‡­‚Ùª à¯~_445ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«, ”o¸włіޡ è« é´ ë· íºê½ ëÄ êËìÏðÓ'òÓ<õØ7õØ%ó×öØ÷×ö×ôÖóÖìËÇ› µ„ÂŽ Ñ Ø¡ ÏœfL ØØØþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþüþþüþþüþþüþþýªªª( s´} ÈŒ Óœ ߦ ç®î¹ í¹ ì» ë¿ êÅìÌ îÑòÕ+÷Ø=õÖ*õØô×ö×÷Ø õÕôÑܵª„·Šʘӛܠ؛ќdK qqqþþýþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþþþüþþüþþüþþýªªª T>†_ ½ؤà¬ë´ ï·îº í½ ìà íÉíÍïÒóÖ#ô×&öÖ÷Öô×ñÓñÏêÄÄ— «yÁ‘К Õ› Ùœ Ú՚ĒL7 333þþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþþþüþþüþþüþþýªªªZ>S·…Ý®ë·ò·ï¼ îÁ îÅñÍïÏñÓóÖó×öÕõÔíÏ ãÄ¿˜Ÿo±| É’ Õ— ܘ Ýš Ú Î˜Ãc  SSUhhj'')±±°ýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« C)vM€U§ Û®ñ·ï¿îÇñÍóÐ'ôÔ%ñÔïÔïÑèÈÕ´¬‹Œe›m¼‡ Δ Õ™ ×› ÙŸÕÉ”¶ˆ­‰?yfC;;;yyyyyyQQQ**) qqqþþüýþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«("gƒh%~W‹\©{ Ç  Ô±Ù¸Û¼Ò±έœ¨|¡oi«v º‚ÉŒ Ò‘ Ò“ Ñ—З Å »Ž!Ä \ʱ”Ǻ°¸³®QQLccc€€€zzy442××Öýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«³µ«³¨ƒl&•h“i ˜o ¦~ ¥£}¢y§z°º…ÉćÊ Î’ΔÍ’ ÊŒȇ¸„»”M˵—Ê»ÄÃÀ¾½º¿¿¿”–™777}}}€€aa` !pppþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« \ZS¾¾¹¾·³®™ul˜i¢pÀ’Û²Û´׫ÒŸЖÒ•Ï– Ì“ Ê ÈŽÉÁ‹µƒ±…0¾¦~ƼªÅ¹ÊÌÉÈÍÊÂÇÀ½¾¹©§§! "]]]€€€~~}mmm445ÖÖÕþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþþjjl[XZ½¹º½»¾Áº³°—p–išd¬w ȓҞÔÒ˜ Ò”ÏÊŽÃŒ¿‡½~¾| ·´–Q½´™º»¶»½¸¹½¶ÃÆÁÐÑÏÒÑÑÈÆÅ¼º¹TSS;;;oopqqqBBB 000ýýüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýýýü,,. U[W¸º·»½¸»¼ºÂ·®¶šv‘g'“e ¥u¶¾„ À… Á… ½‚ ·y°p°o°w ²„/¼žmÆ»¦»½±¾¹·Á¼¾ÆÉÉÖÛØèèêõï÷õó÷ÛßÛŸ¡ž ,,.®®­þþüýýûüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüújjj OTK¹½¶Âÿ¿¿¸¿½´Áº³º¨Œ“{@ƒd‘hšhžih›i ˜e ˜e šn¬ŽK¿±‹Â½³»º»¿»¹Ã¿ÀÐÌÏçäç÷õûûüýûþøúý÷÷øø×ÖØOOO333þþüýýûüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÓÓÑ b[_ØÔÖÖÔÖÈÅÄÀ½º¼½¼¾¼ºÃ»¬µ¢ƒ ‚V”n4•l%“l"™t0¦„K±™m¼³˜À¿´¾»µ¾º±¾¼µÁÂÁÎÓÌâçáò÷÷ýþýÿýùÿüöþýùýþýö÷÷²²² ®®­þþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúüýøiig%$%ÏÎÏîííáááÌËÌ¿¾¾¼¼¼½¼½À½½Á½¹Â¼´¿¸­¾¶§½µ¤¾¶§Ã»²Ã½¶À¼¹½¼º¼»¹ÁÀ¾ÆÅÄÓÓÓãäáôõòþÿýýþüÿþüþþûþþüþþüýþûôôô[[[""#ÔÔÕýýüýþúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúüüú¨¨¦ŒŒŒúúúöööëëëÖÖÖÁÁÁ¾¾¾¿½¾¿¾¼¾½»¾½º½¼¸À¾¹Á¾ºÁ¾¸À¼¹¿»º¼º¹¿¾¼ÆÅÃÎÎÎÜÜÜçççòòðýýûýýûÿÿýþþüþþüþþüþþüþþüüüüÃÃÃrrsýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÒÒÐ DDEßßßýýýýýýùùùìììÑÑѽ½½¾½¼¾½»¾½»À¿»¿¾º¾½¹¾¼¸¾½¹À½»¿½»ÁÀ¾ÌËÉ××Õääâïïï÷÷÷üüûýýûþþüýýûþþüþþüþþüþþüþþüþþüõõônnnÔÔÒþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýþþþ+++ µµ´÷÷õýýûþþüýýûúúøååãÄľ½º¾½¹¾½»¾¾»¾½¼¾¾»¾¾»¾½»¾½»ÃÂÀÐÏÍàßÝìëéööôûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûûúÎÎÎ&&&---þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüýýýggg nnnïïíýýûþþüþþüþþüýýûóóñÖÖÔÀ¿½¾½»¾½»¿¾¼¾½»¾½»¾¼¼¾¼½ÈÆÅÛÚØèçåóóñúúøûûùüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûøøøkkkªªªþþþýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûýýû¥¥¦))'ÑÑÏýýûýýûþþüþþüþþüþþüûûùììê×ÖÔÆÅÃÂÁ¿½¼º¾½½½½½ÂÂÂÐÐÐâââñññùùøûûùþþüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýýÁÁÁÓÓÔýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûÐÐÎ ŒŒŠö÷óþþüÿÿýþþüþþüþþüþþüÿÿýüüúù÷÷íëìÝÛÜÕÕÕ×××ÜÜÜççåòòðùùøþþþýýýýýûþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüôôóJJJkklþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÑÑÏ888ääãýýùþþûþþüþþüþþüþþüþþüþþüþþüÿýþýüýòðñëêëðððøøøûûùûýúýþýþþþýýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüýýýŒŒŒkkjþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýþùüüúýýýeefœœ›ûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúúøööôýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþÿüþþüþþüýýü¼¼¼jjjýýüüüúþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûþþüddd>>>ÛÛÚøøöüüúýýûþþüþþüþþüþþüþþüþþüþþüýýûýýûúúøüüúþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüûûúâââ++-ÓÓÒþþüýýûÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúþþüþþüýýû¢¢¡ ‰‰‰ççåøøöüüúþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüüüúûûùþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýþþüüüúùùùîîîMMMÑÑÐüüúýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýýûÏÏÏ---²²²æææõõóýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüùù÷ûûùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúùù÷÷÷õñññóó󇇇ÒÒÒüüüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûÏÏÏ???´´´ßßßôôôûûûþþýþþüþþüþþüýýûýýûýýûýýûþþüýýûûûùôôòööôûûùýýûþþüþþüýýûþþüþþüþþüþþüýýûýýûþþüþþüþþüþþüüüúýýûüüúúúøøøöððîêêèììëìììììì°°°ÒÒÒþþþýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû###XXX©©©ÍÍÍìììøøøùùùüüüþþþþþþþþþýýýüüüúúú÷÷÷òòòñññêêêèèèðððöööùùùúúùüüúýýûûûùüüúúúøýýûýýûûûûûûûúúúùùùøøøøøøòòòïïïééçããâÛÛÛÛÛÛÞÞÞää䯯Æ (((üüüþþýþþüþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüaa_ ttt¢¢¢¶¶¶ÐÐÐçççðððñññöööúúúùùùùùùøøøòòòéééâââßßßäääàààßßßåååïïïööõùù÷øøö÷÷õùù÷ùù÷øøöóóñéééåååáááÝÝÝÛÛÛØØØÖÖÖÓÓÓÑÑÑÐÐÐÈÈÈÈÈÈÊÊÊØØØÜÜÜNNN fffüüûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÎÎÌ………žžž¨¨¨ºººÌÌÌÜÜÜäääîîî÷÷÷úúúùùùúúúùùù÷÷÷íííßßßÞÞÞåååïïïñññøøøýýûýýûüüúýýûýýûúúøøøöóóñææåÚÚÚÒÒÒÉÉÉÅÅÅÄÄÄÂÂÂÂÂÂÀÀÀÁÁÁÀÀÀÂÂÂÂÂÂÉÉÉÝÝÛÊÊÉ001££¢þþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüþþþýýýaab&&&ŽŽŽ¡¡¡¯¯¯ÃÃÃÒÒÒààßééçóóñûûùýýûþþüýýûþþüýýýöööåååæææ÷÷÷ýýýþþþþþþþþüýýûþþüþþüýýûþþüþþüýýûööõíííæææÛÛÛÒÒÒÌÌÌÉÉÉÅÅÅÄÄÄÂÂÂÀÀÀÁÁÁÀÀÀÀÀÀÊÊÊåååÇÇÆ""!$$&556%%%ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúýýûþþüýýýÎÎÎ---˜˜˜¶¶¶ÉÉÉßßßííí÷÷öýýûýýûüüúýýûüüúþþüýýûþþþöööèèèôôôýýýþþþþþþþþþÿÿýýýûüüúýýûþþüþþüüüúýýûûûúüüüüüü÷÷÷ôôôìììäääÚÚÚÒÒÒÊÊÊÅÅÅÁÁÁÀÀÀÀÀÀÃÃÃÕÕÕðð¡  ::;@@@""" ££¢üüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüþþþ___aaa¸¸¸ÓÓÓæææööôüüúþþüþþüýýûýýûüüúýýûûûùýýûýýý÷÷÷ëëëõõõüüüýýýûûûûûûüüúûûùýýûûûùüüúüüúþþüýýûþþýþþþþþþúúúýýýýýýüüüúúúñññçççÜÜÜÐÐÐÇÇÇÃÃÃÁÁÁÉÉÉààÞððïlll 222444$$$üüüýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüýýûýýý"""  222¬¬¬ÔÔÔëëëøøöüüúûûùûûùýýûûûùýýûþþüüüúýýûýýûýýûúúøõõóøøöýýûþþüþþüþþüþþüþþüýýûüüúþþüýýûýýûüüúüüúûûùûûùþþüüüúýýûüüúýýûþþýýýý÷÷÷ìììÝÝÝÑÑÑÆÆÆÃÃÃÍÍÍëëëÝÝÝ)))%%%@@@ÏÏÏþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþþüÍÍÍ668†††ØØØíííúúøþþüýýûþþüûûùþþüýýûúúøýýûþþüýýûýýûüüúüüúûûùýýûûûùúúøýýûýýûûûùüüúüüúýýûüüúûûùýýûüüúûûùýýûüüúýýûþþüþþüýýûûûùþþýýýýþþþüüü÷÷÷èèèÙÙÙÈÈÈÃÃÃÔÔÔôôô”””@@@ccdüüûýýûýýûþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüüüúžžž ??A:::ÑÑÑòòòúúùýýûûûùüüúýýûþþüûûùýýûýýûüüúüüúþþüþþüþþüüüúüüúþþüþþüþþüþþüýýûÿÿýþþüýýûþþüþþüýýûþþüþþüþþüûûùüüúýýûûûùüüúþþüýýûýýûýýûüüúýýûüüúúúøííëÛÛÙÊÊÉÇÇÇáááããã000444ÏÏÎýýûþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüýýû]]] "99;””•ùùùüüûýýûþþüýýûýýûûûùýýûüüúýýûûûùýýûýýûýýûúúøýýûþþüýýûüüúûûùüüúüüúûûùüüúüüúüüúüüúüüúüüúüüúüüúþþüýýûþþüýýûþþüýýûüüúýýûüüúûûùýýûüüúþþüþþüýýûððîÜÜÝÉÉÉÍÍÍïïî ***(((¡¡ üüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúýþûüüú 668668ãããüüüþþüýýûûûùüüúýýûýýûþþüýýûüüúýýûýýûýýûþþüþþüýýûýýûûûùþþüýýûþþüüüúþþüþþüýýûýýûþþüýýûþþüþþüýýûüüúüüúüüúûûùýýûüüúþþüüüúýýûþþüþþüýýûýýûûûùþþüýýûðððÙÙÚËËËÚÚØááá*** !! 888$$$þþüüüúüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûžž777«««ýýüþþüüüúýýûýýûûûùýýûýýûüüúþþüþþüüüúüüúüüúýýûüüúýýûþþüýýûûûùýýûýýûþþüýýûýýûýýûýýûüüúýýûüüúûûùþþüþþüþþüþþüþþüþþüýýûýýûþþüþþüýýûüüúþþüþþüþþüüüúýýûýýûóóñââàÞÞÛññîqqo...<<<000777ÏÏÏýýüüüúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû]]] FFFDDDëëéþþüþþüüüúýýûþþüþþüþþüüüúþþüûûùüüúüüúÿÿýþþüþþüüüúýýûûûùýýûýýûüüúüüúýýûúúøþþüþþüýýûþþüüüúýýûýýûüüúýýûýýûûûùüüúüüúûûùþþüúúøýýûþþüüüúüüúýýûüüúýýûûûùüüúþþüûûùúúöýýû»»¹ 777FFF;;;### 111$$$bbbüüûýýûýýùþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü ==<¨¨¨ûûúýýûýýûüüúýýûûûùýýûüüúüüúþþüýýûþþüýýûûûùüüúüüúýýûûûùüüúûûùýýûüüúþþüþþüþþüúúøýýûûûùþþüþþüþþüþþüüüúþþüüüúýýûúúøþþüüüúýýûýýûýýûþþüüüúüüúüüúþþüþþüþþüüüúýýûýýûþÿûþþûççå000"""999@@@000@@@ ""#þþýüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüœ;;;HHHîîìýýûûûùþþüûûùþþüýýûýýûýýûýýûüüúüüúýýûúúøþþüþþüýýûüüúùù÷øøöýýûûûùýýûüüúüüúþþüþþüþþüþþüûûùýýûüüúþþüýýûýýûþþüýýûþþüüüúþþüýýûüüúüüúýýûþþüüüúüüúûûùüüúüüúýýûüüúûûùýýùüüùùù÷__^%%%### ???(((   ýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúþþûþþüýýý^^^<<<¢¢¢ýýûýýûüüúýýûþþüûûùüüúýýûþþüýýûýýûÿÿýýýûþþüüüúüüúûûùööôëëéùù÷ýýûþþüûûùüüúûûùýýûýýûûûùþþüþþüþþüüüúýýûûûùüüúýýûüüúýýûþþüüüúýýûþþüûûùüüúþþüýýûþþüýýûþþüüüúüüúþþüþþüýþúüýúüüú––•  BBBaabþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþùýýûþþüÍÍÌ666###000äääûûùýþúþþüüüúýýûþþüûûùýýûýýûþþüüüúýýûüüúüüúýýûýýûüüúòòðççåóóñýýûýýûýýûüüúÿÿýþþüýýûýýûûûùýýûýýûþþüþþüþþüýýûþþüþþüüüúþþüýýûýýûüüúþþüýýûýýûûûùüüúüüúüüúýýûþþüûûùýýûþþûýýúþþüÇÇÆ  === ""$ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüýøþÿúýýûœœ› AAA „„„úúúþþüýýùþþüþþüüüúþþüýýûýýûýýûüüúüüúüüúýýûüüúýýûýýûüüúïïíååãùù÷þþüüüúþþüýýûýýûýýûþþüüüúýýûûûùýýûýýûýýûýýûûûùýýûüüúþþüûûùýýûýýûýýûûûùýýûûûùþþüýýûþþüýýûüüúûûùþþüýýûýýùüýúýýûååä)));;;žžŸýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúýýúþþü"""000'')ÓÓÓüüüüüúúûöýýûûûùþþüûûùýýûýýûýýûþþüýýûûûùýýûþþüüüúýýûúúøììêééçùù÷þþüýýûüüúýýûüüúüüúüüúþþüþþüýýûûûùþþüýýûÿÿýþþüþþüýýûûûùþþüþþüûûùþþüþþüþþüþþüûûùýýûüüúþþüþþüþþüýýûþþüýýúüýúüüúòòòDDD666***ŸŸ þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýüýýý›››AAC ``_ööôþþüþþüþþüüüúþþüûûùþþüüüúüüúýýûüüúüüúýýûýýûüüúþþüýýûûûùééçííìúúúûûûýýüþþüþþüþþüþþüüüúüüúüüúýýûþþüüüúýýûûûùýýûûûùýýûýýûüüúþþüýýûüüúýýûüüúþþüþþüþþüüüúúúøýýûýýûüüúüüúüüúþþüýýýüüü^^^333)))!!"ýýýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþþþþ CCE ®®­üüúûûùüüúýýûýýûýýûþþüþþüþþüüüúýýûþþüüüúþþüþþüýýûýýûúúøøøöääâçççúúúýýýýýûýýûüüúûûùüüúýýûþþüýýûûûùüüúýýûþþüüüúýýûýýûüüúþþüýýûûûùÿÿýþþüþþüýýûûûùýýûýýûÿÿýýýûþþüüüúüüúþþüýýûûûùûûûüüü~~~445$$$ !þþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýý™™™--/../ÞÞÜýýûþþüþþüüüúýýûüüúüüúûûùþþüþþüüüúþþüýýûûûùýýûüüúþþüþþüööôââàèèçúúúüüüýýûüüúüüúýýûüüúþþüûûùýýûþþüþþüýýûüüúýýûüüúþþüûûùüüúüüúýýûûûùüüúüüúÿÿýþþüýýûüüúüüúüüúüüúþþüýýûüüúûûùýýûþþþùùù———223ÎÎÎþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ444ZZ[ôôóûûùýýûüüúþþüüüúýýûþþüþþüüüúûûùýýûüüúüüúüüúýýûüüúûûùþþüôôòààÞæææøøøþþþýýüþþüþþüýýûþþüûûùýýûüüúüüúýýûþþüþþüþþüüüúþþüýýûþþüýýûþþüþþüýýûýýûýýûüüúþþüþþüýýûüüúýýûüüúþþüÿÿýþþüûûùýýüýýý¥¥¥--.ŸŸŸþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýþþüýýûýýûZZ[888ˆˆ‰ýýûþþüýýûüüúýýûýýûýýûüüúþþüþþüþþüýýûüüúþþüüüúýýûüüúüüúþþüööôßßÝééé÷÷÷ýýýüüûüüúüüúüüúýýûûûùüüúýýûþþüýýûüüúüüúþþüýýûýýûûûùýýûýýûýýûýýûþþüýýûüüúýýûþþüüüúýýûþþüþþüüüúüüúûûùýýûüüúýýüþþþ¸¸¸223žžžÿÿýýýûüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüüúýýûËËÉ>>>ÀÀÀûûùýýûýýûþþüþþüýýûþþüþþüûûùüüúýýûýýûýýûýýûþþüüüúýýûûûùýýûòòðßßÝçççøøøýýýýýûþþüþþüýýûüüúþþüþþüüüúýýûúúøþþüüüúýýûýýûþþüþþüýýûûûùýýûüüúûûùþþüýýûþþüþþüþþüûûùýýûýýûüüúüüúýýûþþüþþüüüûýýýÅÅÅ  777___ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüYYW BBB((*ÚÚÚþþüüüúþþüüüúüüúýýûûûùüüúýýûþþüýýûýýûþþüüüúýýûûûùþþüþþüüüúîîìÝÝÛççæ÷÷÷üüüûûúüüúûûùýýûýýûýýûýýûüüúþþüþþüûûùýýûüüúýýûüüúûûùþþüûûùûûùýýûüüúüüúýýûýýûýýûüüúþþüüüúþþüýýûÿÿýýýûúúøýýûüüüýýýÌÌÌ  667 þþüþþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýû——• GGG556ßßßþþüþþüûûùþþüÿÿýûûùþþüþþüüüúýýûþþüýýûýýûþþüýýûþþüýýûþþüþþüððîÝÝÛçççùùùüüüýýûýýûýýûûûùüüúýýûýýûýýûüüúþþüþþüþþüýýûýýûýýûýýûþþüýýûþþüþþüþþüýýûýýûûûùþþüþþüþþüýýûüüúýýûüüúýýûýýûÿÿýþþýþþþÏÏÏ445!!!ýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþFFFFFFèèçúúøýþúÿÿüúúøþþüþþüüüúýýûûûùüüúýýûúúøüüúûûùýýûüüúüüúúúøýýûîîìÝÝÛççæúúúüüüýýûûûùþþüþþüþþüûûùýýûüüúþþüûûùýýûüüúüüúþþüýýûûûùüüúýýûýýûüüúýýûüüúýýûþþüüüúýýûúúøýýûþþüýýûýýûüüúýýûüüúüüûþþþÔÔÔ##%##% þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû———KKK WWWïïíýýûüüøüüúýýûüüúüüúýýûþþüþþüüüúýýûþþüþþüþþüþþüþþüþþüþþüûûùííëÞÞÜëëêúúúþþþþþüþþüûûùüüúýýûþþüüüúýýûûûùþþüýýûýýûýýûüüúûûùþþüýýûûûùüüúýýûýýûþþüûûùýýûýýûþþüýýûûûùüüúþþüþþüþþüýýûýýûýýüýýýÕÕÕ--/  þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû–––,,.PPP888cccññïþþüþþúýýúýýûüüúüüúýýûýýûþþüþþüûûùýýûüüúýýûúúøýýûüüúýýûýýûììêßßÝíííûûûüüüüüúüüúýýûÿÿýúúøþþüýýûýýûûûùýýûüüúüüúýýûýýûþþüûûùþþüþþüýýûüüúýýûûûùýýûýýûýýûüüúýýûþþüýýûýýûüüúýýûýýûüüúþþýüüüÕÕÕ 668 þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüVVV;;=___NNN òòñûûùüüøþþûüüúýýûýýûþþüþþüûûùüüúþþüýýûýýûþþüþþüþþüýýûýýûûûùèèæßßÝíííüüüþþþýýüþþüýýûüüúþþüùù÷ýýûûûùþþüþþüýýûýýûüüúþþüüüúýýûüüúýýûüüúþþüþþüûûùþþüþþüýýûûûùýýûýýûýýûþþüþþüûûùþþüýýûûûûþþþ×××%%% þþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüCCCXXX ‚‚‚ôôòýýûþþúþþûþþüüüúýýûûûùþþüþþüûûùüüúýýûýýûüüúýýûûûùüüúýýûüüúêêèÝÝÛìììúúúüüüúúøýýûýýûýýûþþüýýûýýûÿÿýüüúüüúýýûþþüþþüûûùþþüþþüþþüýýûüüúúúøþþüýýûûûùüüúþþüþþüýýûýýûýýûüüúýýûýýûûûùýýûüüüýýýÐÐÐ,,,!!!ýýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü JJJ ŠŠŠööôüüúüýùýýúþþüþþüüüúýýûûûùüüúýýûüüúýýûýýûþþüþþüþþüýýûýýûüüúêêèááßïïîúúúþþþþþüýýûýýûûûùüüúþþüüüúüüúüüúýýûüüúýýûûûùþþüüüúüüúûûùýýûýýûýýûûûùýýûýýûüüúûûùýýûüüúüüúýýûüüúüüúýýûþþüþþüúúúþþþÁÁÁ /// þþüþþüüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü*** ………øøöþþüþÿûþþûüüúüüúýýûûûùþþüýýûýýûýýûüüúüüúýýûúúøýýûýýûüüúýýûêêèââàòòñúúúýýýýýüþþüÿÿýþþüþþüýýûþþüþþüýýûüüúýýûþþüýýûüüúüüúýýûüüúýýûýýûþþüýýûûûùþþüÿÿýýýûþþüþþüþþüþþüþþüþþüûûùýýûþþüþþþýýý¯¯¯///###  ___ýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþûþþüþþý  /./212xxxööôûüûüýùýþúþþüþþýýýûþþüüüúüüúûûùüüúýýûþþüþþüþþüüüúüüúüüúýýûëëéààÞññðýýýþþþûûúýýûüüúüüúýýûûûùýýûýýûþþüýýûýýûûûùýýûüüúýýûýýûýýûúúøýýûüüúúúøþþüýýûûûùüüúýýûûûùüüúýýûûûúýüûýýúüýùûüøýýüüüüŒŒ333''' """***&&&žžÿÿþýýûýüùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿýÿþÿùûÿþüþÿ”––#eGžw·Ž¡€YG  96;yywíîíúþþúýùüý÷ýûýþýÿúúùýýûþþüýýûþþüþþüüüúúúøýýûýýûüüúýýûþþüüüüéééàààòòñûûùüüúþþüþþüýýûþþüýýûüüúüüúüüúûûùýýûüüúþþüþþüþþüýýûýýûýýûýýûüüúýýûþþüüüúþþüþþüüüúþþüþþüþþüüýûúýýýýýÿýùýÿ÷ùÿøüþúùúùbdd! ,,-EEEKKK  ›þýþÿýûþÿøýÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúÿôüÿûÿþúýü÷ÿýôcO$«…×¥ï¼ñ¾ñ½æ· šx!HIKÍÊÐúûûûýùþþüþýþýþûüýúýýûüüúüüúýýûþþüþþüýýûüüúýýûþþüýýûýýûüüüëëëàààòòñüüúüüúýýûûûùýýûüüúþþüüüúýýûýýûþþüüüúþþüüüúýýûýýûýýûýýûüüúþþüýýûüüúþþüþþüüüúþþüþþüûûùýýûüüúþþüûþøüûùýùùûúôúýóüýôèâß4.. ZZZbb\ $!"þüþÿüÿÿýúüÿüüÿþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûúÿùýþüÿûÿÿûùë⻵Œ Ú¤ òµô½ õ¿ ú»þ·ðµ¥…  ROSËÊÊùûõýýýúûøùý÷üýúüüúýýûýýûüüúýýûüüúþþüþþüýýûýýûýýûüüúûûûêêêßßßóóñûûùýýûþþüýýûüüúýýûýýûþþüþþüûûùýýûýýûþþüýýûýýûýýûýýûýýûýýûüüúýýûýýûûûùþþüýýûûûùýýûüüúûûùýýûüüúýüôýöÙïÞ®îÛ£íÛ¢îڟθ„5" % 888GG?32. ""&ýþùûÿôþþøýþùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿÿøÿüÿÿüÿýÿøÿýîͱ]Иå®î·ñ¾ ð¾ õ¼ú¼ø¿ê»©‚) :>3¿¿¼úøûýþüýþüþþüýýûüüúýýûþþüþþüýýûüüúþþüýýûüüúýýûþþüýýüêêêàààóóñýýûýýûüüúþþüýýûþþüüüúüüúûûùýýûúúøýýûûûùýýûüüúþþüþþüûûùþþüýýûþþüüüúüüúûûùþþüþþüþþüþþüýýûýýûýüøûíÉÙ³QÞ³ ë¾íÀíÀ廯¢$PB7770,- e`aüþûøÿúûÿýÿýüÿþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüÿüúüþûûþïØË’¼ŠØœ æ¯ ð¸ò¾ ñÀ ñÀ òÂó¿ö½ò¹¬‚% 855´²´õöøþýýüûùþþüýýûüüúýýûüüúýýûþþüûûùüüúýýûûûùýýûûûúèèèßßß÷÷õüüúüüúýýûüüúýýûüüúýýûþþüýýûþþüþþüýýûüüúýýûüüúüüúûûùþþüüüúýýûüüúþþüþþüþþüûûùýýûüüúúúøýýûüüúýûóëÌ|â³ôÉ ÷Ö ôÙöÖõÏå¾#RB """%%%€l×Åyÿýâýýðùÿùûüþÿüþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûÿþüþüúþ÷þûç·.̑ݣï®ö²ø¹÷½ ô½ ö¼÷½ õ¾ ô¾ê´r -.*¢£Ÿöòôýüüúúøýýûþþüþþüþþüüüúüüúüüúüüúýýûüüúþþüûûûëëëàààññïýýûþþüþþüüüúýýûýýûüüúýýûûûùüüúýýûþþüýýûüüúþþüýýûþþüýýûüüúþþüýýûþþüüüúýýûýýûýýûýýûþþüýýûýýûþüôä½k⥠ò· òÂóÍõÐ ÷Ïد?.  <-ƧðÍ"æÊ=õð¹ûþûúÿúüþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûûÿöýýøÿûë˪gÁ‰Ôš à§ ï®÷µ ùº ø¼÷¼÷¼÷¾ ô¿óÁõÀÞµuW "$ƒƒ…íííýýûûûùüüúûûùýýûýýûþþüüüúüüúýýûûûùýýûüüüêêêÜÜÜëëéøøöûûùþþüýýûýýûýýûþþüÿÿýýýûýýûüüúýýûüüúýýûüüúûûùýýûüüúýýûüüúýýûþþüüüúýýûüüúýýûüüúüüúýýûûûùþýõãÃrÜ¥ñ²õ»ò óÈìÅ»˜2$‘qêÆôÍúÓéØkÿýéúýýüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþýþþýþþüþþûþþüþþüþþüþþøþþóþþïþþíþþìþþíþþïÿýéìå¿Ç¥[¿†Ï•Ú£æ¬ î¶ò½ôÀ ó¾ ó¿ò¿ò¿ö¾ ø¾ òÀó½Ñ¡M6 UVUÔÔÒúúøüüúýýûþþüýýûýýûýýûýýûþþüýýûûûùüüüöööêêêííëúúøþþüûûùýýûüüúýýûýýûüüúþþüýýûþþüþþüþþüûûùýýûýýûþþüýýûüüúýýûýýûþþüýýûýýûüüúýýûýýûþþüýýûüüúýüôãÄpÚ£ î±ö¾ ñÂí¿ã¶®…1 `E ݵîÅ îÈ îËäÄ<íè¾üüúÿþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþùýÿøþþÿûÿþÿüýþý÷øÿþÿûöÿüêÏ¿˜ÕÁy°ˆ%¶†¶…±ƒ­€ °€¶‚ËЖ Úž ãª ê± òºó½ ô¾ õ¾ õ¾ ô¾ ô¾ õ¾ õ¾ òÀ ó½ð»´(  ??>ÃÃÁüûùüüøýþùýþúûýúýýûúúøüüúüüúýýûþþþýýýùùùøø÷úúøýýûýýûûûùþþüüüúþþüþþüûûùýýûüüúûûùüüúýýûüüúýýûýýûûûùþþüûûùüüúüüúþþüþþüþþüþþüýýûúúøüüüýýýüúôæÇwÙ¢î²ô¼ ñ¿ î¹ á­µ„B+ 1 º”îÀíÂî ðÀ äµ!ÛÏ—ýþÿÿýþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿøýÿùþÿùýÿûþûÿÿýúýþøçÝ·¯„!¾ŒÍ—ל Úœ ך Ó–Ë É Ï•ÖœÜ  ã¨ ê° òºô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò¾õ½ò¾ß¹ˆj###—–•ñðîýýûüýûýÿüþþüýýûþþüþþüüüúúúùûûûýýýýýüüüúýýûýýûÿÿýþþüýýûüüúýýûþþüþþüüüúþþüüüúýýûýýûþþüýýûþþüýýûþþüýýûýýûýýûüüúýýûýýûþþüýýûøøøîîîãàÚÛºi򣓡 ô»ï» ç±ݦ À‹eC   $šqÝ­ê¼ é» íº ô½ êµÞЖýþüÿýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþþýýÿÿüþþÿùýþöþüúÿùî­‰*Î Ú˜ Ý  á¨á¨ৠݣߤÞ¤ à¦å«é¯î³ó¹ô½ ô½ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ ÷¿÷½ ñÀðÇѨXC }{|éèçûûùþþüûûùüüúûûùüüúþþüýýûþþþýýýüüûüüúýýûüüúüüúûûùþþüýýûüüúýýûýýûüüúýýûþþüþþüýýûüüúûûùýýûûûùýýûýýûûûùýýûþþüýýûüüúþþüûûùáááÉÉÉÇľԳaØ ï²ñ·ì· å®Û¢Á‹ ˜m?'   +ŽcÏ™ ä± æ· ê·îµ ô· å¬ÝÍŽþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûÿÿýýÿÿüýÿþøüýúþýõÒÀ»ˆÓ™ Ü£ ã®ç´è´ê²ê°æ«æ«ì± ñ¶ñ· óº õ½ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ó½òÀ öÇè¿®‹$ ][\ÔÒÒüûùþþüýýûüüúýýûûûùüüúýýûûûùýýûüüúþþüþþüþþüýýûýýûüüúþþüýýûüüúüüúüüúüüúüüúûûùþþüþþüþþüýýûûûùþþüýýûûûùýýûýýûýýûüüúèèæËËÊÅÅůĽӰ_Ù¡ê¬ ï´é³ ä« Ú ÇŽ¯| Že;"   [: Ÿoȑء â¯é· ì· ó¸ ö¹ç°ßΔýþÿýÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûüÿõþÿüÿþûÿþøüþÿþþö¾¢^ÈŠÙ  æ¯ì´ ð¶ ó· óµ ô·ò¶ñ· ôº õ»ö¼õ½õ½õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ¼ò½ ôÀïÇرu]  423µ´³ùù÷ûûùýýûýýûþþüüüúýýûþþüûûùþþüúúøýýûûûùûûùýýûýýûýýûüüúýýûüüúýýûûûùþþüýýûûûùýýûüüúþþüþþüûûùþþüýýûýýûýýûýýûûûùÚÚØÄÄÃÄÄÄÇľѯaÚ¡é¬ ë° è±äª Ý¢Ε»…®{ŸrtP K18%.+5"N3wVœr°|Š Ö Þ©ä°í¶ ó» õ¹ô» ë¹êÙ—ýüúüþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿôþÿúþþÿÿýùüÿûþýòÅ¥VÌÝ¡è­ð² ö¶ øº÷» ó½ ñ¾ ô¼ ö½ õ¾ õ¾ õ½õ½õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ó¾ó» ó¾òÄ éľ™:(‘‘‘òòòûûúüüúýýûýýûüüúýýûÿÿýþþüþþüþþüþþüþþüüüúüüúûûùüüúýýûþþüýýûþþüûûùÿÿýþþüýýûýýûýýûþþüûûùüüúüüúþþüüüúüüúùù÷××ÕÄÄÃÄÄÄÈſЮdÓšã§ è¯ é³å¬ á¥ÔšÅŽ ¾„ »} µz ªx  vŸv¢w¥x ©z¬| ·‚ÆŒ Ô˜ âªè³ ï¹ õº ôº õ»ó¼ð¾Õ¶AÿüÙÿüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþýþÿûÿûÿýûüþÿÿÿì«…(Ê’Þ¤ê° ñ· ôº õ½ ô¾ ò¿ òÀõ¾ õ¾ ô½ ó¾ ó¾ õ¾ õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ õ½ô» ó»ô¾ ðÈ์j|||ïïïýýüüüúýýûýýûüüúýýûûûùýýûýýûýýûýýûýýûþþüþþüþþüýýûüüúûûùþþüûûùýýûþþüüüúýýûýýûûûùþþüþþüýýûüüúüüúüüú÷÷õ××ÕÅÅÅÄÄÄÆÃ¾Ë¨bјá¥ ç¯ ç³ç® ä©ÙŸ Ï—ÉŽƆ Å… Á„ ¼€¼ ¾ Á‚ Æ Ä襅 â¦í±ñ¸óº ÷º ô¼ó½ô¾ó¸æ¶ØÁbÿýåþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýýýþþúÿùÿþüüþúýüñÀ [đݣ ç­ìµ ò» õ½ö¼ø½ø¼ö¾ õ¾ ò½ ó¾ ó¿ õ¾ ö½ ö½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ ö½ õ½ ÷» ô¼ôÄëÈ΢L7 †††ôôóþþüýýûýýûþþüÿÿýþþüýýüýýûýýûûûùýýûüüúüüúüüúþþüþþüþþüûûùþþüýýûþþüýýûüüúþþüþþüüüúûûùúúøýýûýýûýýûööõ××ÕÅÅÅÃÃÃÅýƤ`ÈÜ å­ ç³ è¯ æ«ݤ Ø› Ò• Í“ÇÈ‘ÉÇŒ ÆŒ É Ë‘ Ô• Üžá©é´ ó½ø½ø½ø»ô¾ó¿ ô¾ö¶ ô´Ü®åÚ•þþõþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþüÿþüÿýÿýüýýüþþøÕÁ‰ÂŒÙŸ æ¬ í´ ñ¹ õ½õ½õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ õ¼ ó¼ ñ¿ òÆç»§$°°°úúøþþüûûùüüúüüúýýûûûùüüúýýûüüúýýüýýûüüúüüúýýûûûùþþüþþüüüúýýûûûùýýûüüúûûùüüúýýûþþüþþüþÿûþþûýûüùøúÜÛÜÆÆÅÅÅÃÅüÀ¡]‹Õš á¨ ç° ê° ì¯ â¨Þ¤ ØÔšÓš Ñ—Ï–Ï— ЗÓ˜ØœÜ¡ã¨ ç® ï¸ õ½ ô½ õ½ õ½ô¾ õ¾ õ¾ ô» ò¸ìµÑ®-ðê±ýþ÷úýþþýþÿüÿüÿýûÿûüÿúþÿúþþûûÿýúÿýÿýýÿûüýþûüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýüüÿüýÿüÿþúþýûýý÷ÖÃŽÁŒÙž ã¨ ë² ñ¹ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ô½ ñ¾ ñ òÅÖ­uU [[[ííëúúøþþüþþüþþüýýûüüúüüúþþüýýûüüúþþüüüúûûùýýûüüúüüúýýûýýûýýûýýûÿÿýþþüýýûþþüýýûûûùýýûüýùûüùýýüûûûåååÊÊÉÄÄÂÆÃ¾½Ÿ[»…Ó˜ à¦ å® ì± î² è¯ ä« á¦ Þ£ Û¡ Ú¡ ÙŸ Ú  Ù  Ü¢ ߤåª ç® íµ ó»õ½ ô½ õ¾ õ½õ¾ õ¾ õ¾ ó¼ ñ¹ ñ¹ï³Í¡.ëã±ûþøúÿúÿýüÿúÿþþúûÿùÿýÿÿýýýÿøûÿøþþþÿýüüÿùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýúüÿúýÿúÿÿ÷þþúþýöÖÆ–¼ˆÕš ᦠë±ñ¸ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò½ ô½ õ¾ ö½ õ½ ò½ ð¿ óÄé¿Ú>-***ááßýýûüüúüüúýýûþþüýýûþþüüüúûûùýýûûûùþþüþþüýýûþþüýýûýýûüüúþþüýýûýýûûûùýýûýýûýýûýýûþþüýýûþþüüýúûûùììêÒÑÏÄÃÃÈÿº›W»…ДÞ£å­ î´ ñµ í´ ê² ç® ã©⨠㨠à¦à¦ã¨ ã© å« ç­ ì³ ï¶ ó»ô½ õ¾ õ¾õ½õ¾ õ¾ õ¾ õ¾ ô¼ òº ñ¶î®Ï+ñè·øÿïüÿöÿüýþþûüÿøþþüÿûÿÿýúþÿ÷ýþÿþþüýÿúýÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýúýÿúþÿüþÿøþþúÿþùèß¹¾‹Õ™ Þ¢ è® ð· ô¼ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ó¾ õ¾ õ¾ õ¾ ó½ ò½ ôÀõÇÞ¶˜v !!!××Öüüúýýûþþüüüúüüúûûùþþüþþüÿÿýþþüþþüüüúüüúüüúùù÷ýýûþþüüüúüüúþþüýýûüüúûûùýýûþþüýýûýýûüüûýýûýþùýýøîïêÖÖÓÆÅÄŸš”‡f#¸‚Ò– Þ£å® í³ ò· ð¸ ð· î´ ë° è­æ«å«å¬äªè¯é°ì´ î¶ òº ô¼õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô¾ ï¹í¹ë¸Ù¬,òè³üþóùÿúüÿüûÿøüÿôÿüýÿûÿþþýüþÿýÿüþþýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿýÿùþþþÿýüÿý⼋Ñ• Þ¢é¯î¶ ó»õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ò½ õ¾ õ¾ õ¾ õ¾ ô½ ô¾ ïÁîÅÑ¥bI )))ßßÝþþüýýûýýûþþüýýûþþüûûùýýûýýûüüúýýûþþüþþüýýûþþüüüúýýûþþüüüúüüúþþüýýûþþüûûùüüúýýûüüúüüüþþüýþøüü÷íîêÖÔÔ¹¶´IB:sS·Д Þ£ä¬ ïµ õº òº òºò¸ð¶ ïµ í³ í³ í³ í³ íµ ï· ï· òº òº ô¼ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ î¼ î¾ î¹ä°"ؼkþþßýý÷üüÿúÿúúýúýýÿüþþüÿýýÿûÿýûÿýýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿûÿúÿþÿÿýÿÿýíºŠ!Д Ü ç¬ñ¸ó» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¼ õ¾ ô½ õ¾ ô¿ ëÁ óÅ íÀ¿˜8, ƒƒƒ÷÷õýýûýýûüüúýýûüüúüüúýýûýýûüüúüüúüüúýýûûûùûûùüüúþþüüüúüüúûûùýýûýýûüüúýýûýýûýýûüüúüüúýýýüýûûý÷üþùðñðÂÀÁLHDyYº„Ò– Þ¤ å® î´ ô¸ òº ó¼ô¼ó»òºó¹ó¹ó¹ó¹ò¹ ô¼ ó¼ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ô½ õ¾÷¼ öºñºÔ«,ÚÉŒÿüïýüýúþúøþ÷ýÿúýÿúþÿùÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþúýÿýÿýÿúÿ÷þþýÿýþÿþñº‹#Î’ Ûž è®ï¶ ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ö½ ó¼ õ¾ õ¾ ó¼ õ¿ îÂò òÇáµ Žq  ˆˆˆóóóþþüüüúüüúüüúýýûüüúýýûýýûýýûýýûýýûüüúýýûýýûþþüýýûýýûúúøþþüýýûþþüþþüþþüþþüüüúüüúýýûýýûýýüýýûýÿùúüúÈÈÌD@D xX ¸‚ Ò– Ý¢ ä­ ðµ ô¹ òº ô½õ½õ½ õ½ õ½ ö½ ö½ ö½ õ½ ö¿ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½õ¾ ø½÷½ ÷¼ú¼õº ð½æµ ǤCÿûâüýûûÿöþþûÿýüþÿúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿþùþÿûÿýÿúÿ÷þþýÿüûþþò½$Î’ Úž å« ð· ô¼ ô¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ õ¼ ö½ ö½ õ¾ ö¿ ö¿ ô½ ò¿ î¾ôÄðÉϤgH 4,VWR›œ›çççþþþûûüüýûûûùýýüýþûþþüýýûüüúüüúüüúüüúüüúýýûûûùüüúüüúûûùýýûýýûüüúüüúýýûüüúüüúýýûûûùüüúýýûüüúüüúúúøüýùÊËÊ337#~\¶ Ó— Þ¤ ç¯ ð¶ ô¹ ô¼ó¾ ó¿ ó¿ ô¾ õ¾ ö¾ ö¾ ö¾ ö¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½õ½ò¾ôÀ ö¾õ½ òÀ óÀ ÷½õ¸â²æÖ–þüýûþúÿýýÿüÿþþþûþÿýþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþûÿýþûÿýýÿûÿûþÿû÷ýý弌Α Ú æª ò¸óº õ¼ ô¼ô¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ò»ë½êÉ å¿ ¿Ž¬‹Wöôéùýùûýùûûýþüÿþýùþþúúúûûý÷üþùþþüþþüþþüþþüýýûþþüþþüþþüþþüÿÿýþþüûûùþþüþþüûûùýýùüýøýþùþþúýýûýýûýýûýýûýþûø÷ø¯¯­###0†] ¶‚ Ñ™ ߥè® îµ ó» ô» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ð¿ñ¿ ù½ú»õ½ñ¿ ñ¼õ·ê¬ìÕ”üýúüþøþþûþýýÿýýûÿüüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúÿþüüÿüþÿûÿüþþýùçâ¹¾‹Α Úž è­ ó¹ô» ô» õ½ó»õ½ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ¼ ï½ èÁ èÀÚ© yƹ˜üüøûüûüüúüüùüü÷þýúþþþýþûüüùüüúûûùüüúüüúúúøýýûüüúüüúýýûýýûýýûþþüüüúýýûÿÿýþþúýþùýþùüüúüüúûûùüüúüüúóôòƒ„:&‰_ ¶‚ Ñš à¦é® ï¶ ó¼ õ¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ ö½÷½ ö¾ô½ õºó¸ó¹è³ܪç×”üüúþýÿýýþþþýÿþýýþþýþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþÿúþþþûþøÕ„¾‡Ï‘ÛŸ è­ ñ· ô» ô» õ½õ½õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó»ö» õ½ê½ìÂç¹ Èž•w/èÞÒüùûüý÷ýÿôýþùýüýýýýûüüúûùüüúýýûûûùþþüþþüýýûýýûýýûþþüýýûüüúýýûüüúüüúüüúüüúüüúýýûÿÿýüüúýýûýýûáááXYY  D/‰^ ³ Й â§ ê¯ ï¶ ô¼ õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ½õ½õ¾ õ¾ õ¾ ø½÷¾ó¿ ó½ô¹íµ è² ä§ Ò¥-ïê»ýÿýþüÿþþýüÿýþþýþþýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþýÿùÿýüÿþýúýüýþòŤPÀ… ÍÜ¡ é® ó¹ ô» õ¼ ó¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ½ö» ÷» î¼è¾ íà ٬­ƒ˜ƒY÷òîýüûùýóûýøýüþûûûýÿýýýûýýûþþüûûùüüúüüúüüúþþüüüúüüúüüúýýûþþüþþüýýûþþüþþüýýûüüúþþüþþýöööŸŸŸ$$$ J3‡\°|Ϙã¨ ë° ï¶ ó» ô¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ õ¾ó¾îºìµåª Ý¡ Õ—äËŽþýóüÿüþûüþþøûÿûýÿüÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýþÿýÿúÿýþþþÿýþùÿý߸„ Æ Ó–å«ñ¶óº õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ ö¿ õ¾ ó½ ñÀ ó¼ ÷»ï¼æ½è¿ á±Ä‘ ƒe¬›ƒýøùûþûüþúþýþýýþûüøüüùýýûýýûýýûþþüüüúýýûûûùüüúýýûþþüýýûüüúúúøüüúüüúüüúýýûýýüööö¹¹¹BBBQ9‰\±}Ϙã© ë° ð· ó» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ õ¾ ó»öºó·íµâ¦Û™Í” É«mÿúòþýÿýÿüÿýýþþøúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýþÿþþûÿýþþýÿþýïÑÁ„¼ ÉŒ Û  ì²ó¹óº ô» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ ñ¿ ó¾ ô¼ ðºä¶å¹߯ Ë–  xZ>£—’óôõûþûûúûýýýûý÷ýþúüüúýýûüüúýýûýýûüüúþþüþþüýýûýýûþþüüüúüüúüüúýýûýýüûûûËËËSSS W<ˆ[±| Ζâ§ ê¯ ñ¸ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó» óºñ·ïµé®㢠֖Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿüÿþúÿþûýþÿÿý毄(Ɖ Ò— ⨠ñ¸ó¹ óº õ¼ ö¼ö¾õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ô½ õ¼ óºè´â±ܪ Ó›°} wR.\ZWÎÏÎüûøúúùùüøúüùþþüüüúüüúüüúýýûüüúüüúüüúýýûýýûüüúüüúýýûüüúééç­­­SSS Y=Š\²} Ï– á¦ ê¯ ð· ó¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ô¼ð·ì³è­Û¢ ҞŒʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûýÿùÿþùþÿùüÿýäÞ»»†Ç‹Øž â¨ ë² ôº óº ô» õ»ô¼ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¼ ö¼õº÷»ð· â¬Ü¥ Ò™ ¹ bN: SRO¡¡ ÒÔÔìíìøøöûûùýýûûûùûûùüüúüüúùù÷ùù÷ññïßßݼ¼º‰‰‡PPN#\=Ž`´ Ζá¦ é¯ ð· ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ó» óº ô¼ ô½ò¼ ï¸ é± Þ¥ÙŸ љȒ³‡,îâ¿ýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþþúþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúÿúÿþýÿþûÿýúÏÂŒ¼ˆÍŠÕšâ¤ è¬ ïµ ò¹ òº óºôºô¹öº÷¼ ö½ ó¼ ô¼ ö½ ÷½ ÷½ ô½ ó¿ ó¿ õ¾ õ¾ õ¾ õ¾ ö½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ö¿ ô½ õ½ ö½óº ð¸ æ®Ý¥ Óš ¼ƒ˜f iG ' *))GGGaaawww‚‚‚wwwfffXXXPPPEEE$$$ 2!eB–e·€ Ì• ݤ è° ñ· ô» ô¼ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ö½ ø½ ø½ ö½õ¼ôºóµõ¶ó¸î¸è´ á¬ÕžË”¾‰¿¦_èä½ÿüçÿýùýýþþÿûþþûÿýþþþÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿûÿÿþóÿþñÓÄ·…ʆÏ“ ןߨç° é° îµï¶ñ¸ ò¸ ò¶ ò¸ ó» ô¼ô¼ó»ö½ö½ õ½õ½õ¾ õ¾ õ¾ ö½ õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½ö¾ö¾ õ½ö½ôºï¶ è® Û¢ ј »i rL <&  ;( kH™g·€ Ê’ Û£ ç­î´ ö¼õ½ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ö½ õ½ ó½ ï¹ î¶î³ï²ê¯㬠ڢ Д»‚º˜QçÞºÿüçÿýïþýùüüþþÿþþÿúþÿúÿýýþþþþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿúÿüÿÿüþÿýöÑ“³džÊ‹Ñ•כݡ ã¦ ã¨ ä« ã®å±è¯ ê¯ ë³ îµ î¸î¸ò¹òºôºôºôºô»õ¼ö½÷½ö¼õ¾ õ¾ õ¾ õ¾ õ¾ ö¾õ½õ½ö½ ÷¾ö½ó¹í³ äª Ú  Ε ¶}šfuLM4   ?) oJ™g¶ ÇŽ ÙŸ åª ï´ óºõ¼ö½ö½ö½ö½ö½ö½ö½ö½ö½ô½ ô»ñ¸ëµ ç±ä¬㩠ঠÙÑ’ À†œs'æÛ¼þýøþþûþý÷ÿüúþýÿüüþüþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûúÿõûþÿýÿøþÿõçÞ½§}&¹}¾‚ ¾† Ä‹ Ì Õ• Ú™ Ûœ ÛŸ ܡޡ à¤ â¦ ã© åª è®ê°î´ñ¶ó¶ô·ó¸ôºò¸ óº ö½õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô½ ô¼ õ½ õ¼ ôºó¹é° ߦ Óš Æ‹ ¯w–bzPY< %B, nH–c²{ ‰ Ô™ ߤë® ò·ó¹ ô» õ¼ ö½ö½ õ¼ ô» óº ò¹ ò¹ ñ·îµé¯ä© ⥠ܟ ך ΔŠ ©{!˸‰þüîüýùúýùûÿüüýýýýþýýÿûüýýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüþþýþÿüÿùþÿùÿûöèÚ¶y% x «z °z·~¹~¿ Â… ĉ ÉŽ Í Ó• Õ—Õ˜ךÜŸ Ý¡ à¥ ä© æ« è­ ê¯ î´ ñ¸òºòº ó» ö¾ó¼ ô½ ô½ õ¾ ô½ ô½ óº õ¼ ó¹ ïµ㪠؞ ɹ€¦p’_zP[> ' @* iD^¬t ¼ƒ Γ Ü  å© î³ñ·ò¹ óº ô» ô» ô» ò¹ ôºó¹ñ¶ë±æ¬ á¥ÞžØ” Ó‘Ç µ‚¶›Tãܺýýôþýúÿþ÷ýÿöúÿùüÿüýÿýýÿüýÿúýÿøþÿùþÿûÿýþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýÿüÿÿüþÿÿóþÿöþýýÿûôÿûéáٸQi—oŸr¦t®w ´z ¸} ½ À„ÈćÆŠ ÈÌ‘ јÕ› ÙŸ Ý£ ߥ ã¨ ç­ ì²ñ·ò·ó¹óº ôº óº ò¹ ôºóº ò¸ï´ç­ Û¢ Δ¾…¬t›e‹[sKV:%=( b@ˆW¥n ³{ ÄŠ Ô™ Ý  æª ë° ïµ ñ· ò¸ óº ó¹ ò¸ ñ¶ë± è­ ã¨Þ¤Ùš Ðƈ·ƒ ©(ɹŒÿüèÿÿòøþøùÿýþýþÿüýÿýüþÿúþÿúþÿùþÿøþÿùþÿúþþýþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýüÿýûÿüÿÿýÿûüùüþýüþûýüúýýöþþòþþëâÙ¼Á¯‚ªŽKe šk¢n ¨s®w ®v³y ³y ¶{ ¸~ º½„Áˆ Æ Ë‘ Ò— Øž Ü£⦠è«ë¯ï´ó¹ñ¶ó¸ò¸ï´ì±ç¬Ý£ј Ä‹ ³{ ¡i’\QiEM7  8& [:€R›e«tºÊ Ö› ߤ äª è® ì³ ì³ ì³ î´ê°ç¬㨠ݡ ՚ϕ È‹º} ¨w–w$èß¼ÿû÷ýüûúþúùþýüþÿþþÿÿýþÿýþÿýýþþûþÿûþÿúþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûûÿøûÿ÷ýþþÿýÿýþøûþúüýþþüüÿýúýýúýýúþþüþýùÿüñÿýå¿´Žª‹I‡]Œ` —g ›h h¡k£l§o©q­t²y·}½‚ĉÌ’ Ò– Ùœ ÚžÞ¢â§ ç« è¬ é®åª ॠٜ Í’ˆ·~¦n”]†SuI^=B- ggg€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€$$& 3# V7|N–a¥o´{À…Ë‘ÖœÝ¢á§ á¨ ãª ä« ãª ß¥ ÛŸ Ö™Д È‹¼ ±yœj †`&äÚÆûýùùþüýýüýûüÿüýþýûþÿúýÿúûÿûýþþÿýÿÿýþÿýþÿýþþþÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþûþþüþþýþþüþþüþþüþþüþþýþþýþþüþþûþþùÿýôþýïÿý庮‰š…SvS„X ‹[ [‘]—bžg¢l§p«v²~º„ ¾ˆ Œȑ Í•Ó˜Ú Û› Õ— Ð’ ÈŠ ¾‚ ±x¢l‘]„TwJfAO5 + ghhåææýûüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþþýþþýþþýþþýþþýýþýþþýþüüãâ ‚‚|QD+N3qG\ h¬t¶|¾† ÇŒΓј Ò™ Óš њљ͔Ȇº³{ ¨q’e¨“hÿýðüþüýþÿþþýþþüþþüþþüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþûýûýþúýüöþþòÿýìÜÕÀ­ž…{PcGoP{W „Y ‹Z—ae¥lªq®u²y ¶} ¹€ ½ƒ ¿†½…¹±y§ošdZ€PvHiBW9?*  ,*(åæåüýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüýûýþûþýûýüýýýÿþþù¥‡G0e@S”a¤l­u³{ ¶~»‚Á…ćň Ĉ Á‡ »„ ³} ®x¨q™hƒ] ¦’hÿûïýüùüýûýþùþÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýüøþþúýþûüþüúþüüýúýþùþý÷þüôÿýñÛÕÀ« xQa@ pG€Q‹X[˜b œe  i £l £o ¡ožlj”aŽ\†V{NpEe=V9 F3…zgêçßýþüüþþþÿýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþýþýüýüùýýüüþþüýøÕÑÁ>,U7pI‡X˜d£l©r ªt ­v²yµz·{ ¶y ´w ®u¥p l“c wS Žfþþñýþûüûüýûþþÿùýÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüÿþüþýüýþýþýüúÿýùÿþùÿþùþýøÿÿúþüøÿüõÿû‰‡uQ`ApKzR ƒV‡WŠY‹ZŠYŠXˆU…S~NwKnH`?W9@/«¥‘ÿýôýýüûýþýþþýþúÿþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýýüûÿþûýþûúýüüýúÿýõ¥ŽA. V9mG…V“`œfŸj¢l£p¢o§q¦m¥lŸi “a‡YoJ šˆlþûõøþùúþúýüþþûþýýüýþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûýÿüýÿýýÿþþþþþþþþþþÿýþÿüýÿýûþÿúüÿûüÿýýÿþþþüÿþ÷ÚÖÁ¦š|]H^A hEoFuIzK|KyHtDrG hCY<N6A- ª¤’ÿýöýýüüþÿûÿÿýÿýþÿúÿýúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþÿûýÿúýÿûþþüÿþúÿýö¢‰?/P4d?wL…WŽ^•b˜g –f”d”cŽ_‚X oK `A —ˆmÿüõþüýýþüýþýþþþÿþûþþþþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿùþþøþÿøýÿùüÿùûÿùûÿùûÿúþýþÿýþýÿýüÿýüÿþüÿýýÿúþÿ÷þþ÷þýôÿýï­¢„rVP5Z: a> c>a<_;X8 P5 F2\N6ºµ¥þüõüüûþþÿüýÿýþþýÿûþÿúÿþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþþöìêÛXK2G0 R6^>iEoHwLxMuKmHbCS;ƒv[ߨÌýüøûýùÿýýÿûÿÿýýþþüþþþÿþùþÿùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüþÿýþÿýýÿþûþþûþþûýÿúýÿøýÿøýÿùþþýþýÿþýÿÿþýÿþúþþüýýýýüûþþüýü÷ÿý𭣡–|M=>- >,^O6”ïìÜÿûõþýüýüüýüüýüýûûüþÿûþÿùþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûýÿýþþþÿþýÿþüþþüþþýýÿüþþúÿýöëèÛ›“}\N1?- F0I0 I0 E/ …vVž•}ÞÚÌþüøýýþúþýûþúüúúþüþÿþüüÿúüÿýÿþúþþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüÿýüÿýüÿýýÿþþþþÿýþÿýþÿýÿþþÿþþþÿþúÿþøÿþùÿþüþþþþþþÿüüýûúýþûúþúùÿúùþùûþùýþùþþ÷þý÷ÿýöÿüõÿþöþþ÷üþüûýþþýûÿýûþüüþýýÿþúþÿùþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþüýþþþþÿÿþýÿýûþþûýÿýúþûüýüüüüüüüþþûýü÷ÿþöÿüöÿýôþýóþþ÷ýýøþþûýýúþþûýþúüþüüþûýþùüþúüþýüÿ÷ýÿôÿýýþýÿþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþýþþýþþýþþýþþüþþûþþûþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþüþþüþþüþþüþþüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþüþþûþþûþþüþþüþþüþþüþþüþþûþþüþþüþþûþþüþþüþþûþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþülibimager-perl-1.004+dfsg.orig/TIFF/testimg/grey16.tif0000755000175000017500000006136012031434614021615 0ustar gregoagregoaII*âaÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÝ:Íò„ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ²Ñ e1 »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ö  -ßÝ̈́Ȳ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²è À!eß(É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,(;ö ßÝò0O_________________________________________________________Tl-#Oe;`ähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähI^I; ßÝ„ÈO“555555555555555555555555555555555555555555555555555555555Š$b:feé{ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†dyI^(ö ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////////////////////p^9 '!¶!¶!¶!¶!¶!¶!¶!é,3DÇreŠE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////////////////p^9 '!¤"$e(A*/+/+/+/+/+/+/+–4’H[peX„Qè“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////////////////p^9 ø!$e(A* -¤0A8E< > > > > > > >:DlQhkeçx' „ŠHè“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////p^ ! $e(,¤0A8E<?é@ÐD«F™G™G™G™G™G™G™GáI%O÷Ye;_e–jqvB~ „±ŠºŽ¨“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////////////p^ ! $A*¶/A82=é@ÐD«F(HIñJßKŠLŠLŠLŠLŠLŠLŠLÒLDN(QešRêTÎWá]©c–jãw'±ŠºŽ¨“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////////pL2#•)¶//9?ÐDíFIñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLÒLDN(Q¿SÎWÅ`$iãwn#Œ6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////////////p^ !û%Ú-A8?/EÛGñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLÒLDNMR:WÅ`–jÇz͇ºŽ¨“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////////pL2#•)¤0 ;SCÛGñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLÒLDNMRZ@fqvn#Œ6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////pL%L-A8P?FJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLÒL¶OÈUš_–j¥{?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////pL%:.:SCÛGñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLDNMRZ²g3z?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////////pL%:.«:ADJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶O¬XÔf3z?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////pL%:.«:ADJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶O¬XÔf3z?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////^å"L-:ADJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶O¬X²g¥{Ö‹¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////p !•)A8SCJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶OZ–jnºŽ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////pLû%¤0P?ÛGßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLMRš_qv͇6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////^å"Ú- ;ÿEñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDN1U@fÇzÖ‹¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////p !•)A8SCJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶OZ–jnºŽ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////^Ó#¶/ñ>ÛGßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLMR.`ãwdЍ“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////p !ô)/9EñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDN£V$iÚ€ºŽ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////^Ó#¶/ñ>ÛGßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLMR.`ãwdЍ“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////// (A8ƒDñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDNW–j¾ƒ-E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////pø!ÿ+æ<íFßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¿S\c¬}H•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////^b$¤0Ì@ÉHŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÛPJ]qv†‰¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////// (A8ƒDñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDNW–j¾ƒ-E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////// !ô)ø;^FßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLTÎdÚ€ºŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////p†"í,ñ>ÛGŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLMR.`9|jŒ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////^b$¤0Ì@ÉHŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÛPJ]qv†‰¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////// (A8ƒDñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDNW–j¾ƒ-E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////// !ô)ø;^FßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLTÎdÚ€ºŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////¶!/+ >™GŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLxS7b´sŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////¶!/+ >™GŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLxS7b´sŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////¶!/+ >™GŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLxS7b´sŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////¶!/+ >™GŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLxS7b´sŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////¶!/+ >™GŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLxS7b´sŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////¶!/+ >™GŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLxS7b´sŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////¶!/+ >™GŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLxS7b´sŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////// !ô)ø;^FßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLTÎdÚ€ºŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////// (A8ƒDñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDNW–j¾ƒ-E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////^b$¤0Ì@ÉHŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÛPJ]qv†‰¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////p†"í,ñ>ÛGŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLMR.`9|jŒ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////// !ô)ø;^FßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLTÎdÚ€ºŽE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////// (A8ƒDñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDNW–j¾ƒ-E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////^b$¤0Ì@ÉHŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÛPJ]qv†‰¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////pø!ÿ+æ<íFßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¿S\c¬}H•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////// (A8ƒDñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDNW–j¾ƒ-E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////^Ó#¶/ñ>ÛGßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLMR.`ãwdЍ“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////p !ô)/9EñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDN£V$iÚ€ºŽ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////^Ó#¶/ñ>ÛGßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLMR.`ãwdЍ“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////p !•)A8SCJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶OZ–jnºŽ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////^å"Ú- ;ÿEñJŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLDN1U@fÇzÖ‹¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////pLû%¤0P?ÛGßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLMRš_qv͇6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////p !•)A8SCJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶OZ–jnºŽ•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////^å"L-:ADJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶O¬X²g¥{Ö‹¨“E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////pL%:.«:ADJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶O¬XÔf3z?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////////pL%:.«:ADJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLÒL¶O¬XÔf3z?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////pL%:.:SCÛGñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLŠLÒLDNMRZ²g3z?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////pL%L-A8P?FJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLŠLŠLÒL¶OÈUš_–j¥{?‰6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////////pL2#•)¤0 ;SCÛGñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLŠLŠLÒLDNMRZ@fqvn#Œ6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5////////////////////////////////p^ !û%Ú-A8?/EÛGñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLŠLŠLŠLÒLDNMR:WÅ`–jÇz͇ºŽ¨“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////////pL2#•)¶//9?ÐDíFIñJßKŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLŠLeŠLÒLDN(Q¿SÎWÅ`$iãwn#Œ6’•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////////////p^ ! $A*¶/A82=é@ÐD«F(HIñJßKŠLŠLŠLŠLŠLŠLŠLÒLDN(QešRêTÎWá]©c–jãw'±ŠºŽ¨“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////p^ ! $e(,¤0A8E<?é@ÐD«F™G™G™G™G™G™G™GáI%O÷Ye;_e–jqvB~ „±ŠºŽ¨“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5///////////////////////////////////////p^9 ø!$e(A* -¤0A8E< > > > > > > >:DlQhkeçx' „ŠHè“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////////////////p^9 '!¤"$e(A*/+/+/+/+/+/+/+–4’H[peX„Qè“•E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5//////////////////////////////////////////////p^9 '!¶!¶!¶!¶!¶!¶!¶!é,3DÇreŠE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝܲ_5/////////////////////////////////////////////////////////ð((A—qeωE–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–E–ò†ähÉ,»ßÝ„ÈO“555555555555555555555555555555555555555555555555555555555Š$b:feé{ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†ò†dyI^(ö ßÝò0O_________________________________________________________Tl-#Oe;`ähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähähI^I; ßÝ̈́Ȳ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²è À!eß(É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,É,(;ö ßÝ:Íò„ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ²Ñ e1 »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ö  -ßÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ––€  œb¬bÀbØb(Standard Inputconverted PNM fileB& 6îNˆa:äääšZlibimager-perl-1.004+dfsg.orig/TIFF/testimg/gralpha.tif0000644000175000017500000000054012031434614022104 0ustar gregoagregoaII*(ÿÿÿ4ÿrÿ¿ÿ¿4¿p¿ÿ4p?ÿ?3?o?þ 3:@ PX(R/home/tony/dev/imager/svn/tiff/testimg/gralpha.tifCreated with The GIMPHHlibimager-perl-1.004+dfsg.orig/TIFF/testimg/pengtile.tif0000644000175000017500000033030012031434614022275 0ustar gregoagregoaII*¯ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþZüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþÿþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþþüúþþüýýûþþüþþüýýüþþþ˜ÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûýýûýýûþþýþ×þYþÿþQüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüýýüþÖþÿÿþNüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþnùÿþKüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþ¬ùÿþKüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÔÔÒþü ÿþEüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþýþ.þü ÿþHüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü««ªù ÿþEüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûþ-ÿÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÿþþüúªª¨ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýû--,ÿþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÔÔÒþÿÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþúýþùýþùýþûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿý]ûþþüýýûüüúþþüþþüþþüþþüþþüýýûýýûýýûýýûþþüýýûþþüýýûüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûýþþþýþšõ€þþ%þþþ€þ þþøýÿþ$ýþþüþþüþÿûþÿúþþûþþüþþüþþüþþüþþüþþüþþüÿýþ××ÙZZ\ÿþaabÝÝÞþýÿþ!ýþþüþÿûþÿúþþûþþüþþüþþüþþüþþüþþüþþüÿ9!!"þžÿþüýýûýþúþþûþþüþþüþþüþþüþþüþþüþþüÿ9þþ!ÿžœþþüýýûýýûýýûýýûþþüþþüþþüþþüÿ0ÿþþþþÿÛÚüüúþþüýýûýýûþþüþþüþþüÿ0þþÿ ÿýÿzyýýüþþýþþýþþýþþüþþüÿ0þûþþþüÿ ]]`ÜÜÝþþÿþþÿþýÿþüÿ!ÿþþ þþ3þCþ?þ-þþÿ"ÚÚÜýýþþüÿýûÿ0 þ%þBþ_þcþPþ2þþÿxxyýýþýýûýýûÿ0 þ'þMþoþyþdþCþ(þþþÿþþwÿýüýþúÿ-þþ+þOþqþtþbþGþ3ÿ!þþûþÿÙØþþüÿ0þ-þOþgþ]þLþ8þ/þ%þþÿþþ7ÿýüÿ0þ(þAþFþ<þ-þ!þþþ ÿ þþ´ÿ$ÿþþþ þ*þ%þþþþþÿ668ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿý]ûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]ýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿý]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþýÿª«ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþûÿ-.ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþýÿ+-ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþýÿ,.ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþ©ÿÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþ©ÿûþþûþ þÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþ©ÿþþþ þþþþ.ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþ©ÿþþþøþþ ÿþ?üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§ù 224þPþ<þÿþ?üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþü©©§ù gghþ—þ³þ­þyÿþ?üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü©©§üþþ þ\þ“þ´ÿÇÆÃÃÁ­­«ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþ©ÿþþ'þÿ¥ £ÁÁ¿ÒÒÐÑÑÏÊÊÈÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþ©ÿþOþ¬ÿÞ Üôôòûûùüüúüüúÿþ9üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþ©ÿ þ|þèþõþ¢ÿqo  žððîÿþ9üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþÿ©ª¯¯±÷÷ùþþ þ*þ=þkÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«ÄÄÆìëí436þ:ÿxw443ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþ¨ÿÄÇÇÄÃÇ YYUKLHÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþÓÿ!ÆÃź¹µ+,*HDFÿþ9üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþýüÿ,.À½¼ÉËÅ)+-ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþýÿ*,«¬¬áäå.//ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþÿ,-†ˆŒðñõ‹Š‡  ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþÿ,-SSTåàäïîïSTV6!‰eÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþÿ,-"!ÃÂÄøöùëæÚzg7šr¿‰ ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþÿ,-ÿÿ twxâÝÐϹ‡¬ƒ½ˆÓ™ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûþýÿ/02(£‡Vª}!¿† Жܤ ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþþüýýûþüÿ+- YC›xµ„ÊØ›â« ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþýÿ,. L2  u²€¿ˆÔ• â¡ä¯ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþþýªª«…`¶x¿€ÉÛœ ç¦ç± ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«, ”o¸włіޡ è« é´ ÿþ-üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüþ üþþüþþüþþüþþýþª( s´} ÈŒ Óœ ߦ ç®î¹ ÿþ-üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüùþ üþþüþþüþþýþªÿ T>†_ ½ؤà¬ë´ ï·ÿþ-üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüùþ üþþüþþüþþýþªÿZ>S·…Ý®ë·ò·ÿ0 þþþ þüÿ-þþûÿ!ÿ]ÿ]ÿ-ÿþ*ÿ]   "! ÿ+-- ûþþÿ>!@FFHÿ!!"224ÿþ335þEþ;þþþ þ4ÿ89þþ&ÿ24 ÿýÿ RRQttr……„þ•þ™þ”þ\þþþ.þÿþ)þÿþþ0ÿigƒƒ’’þŸþªþ²þ¾þ¿þqþþþÿ  ÿ~}þ,þÿ ÿÿ(()þlÿ“ ‘¦¦¤³³±¸¸·þ¿þÄþÑþÁþ¢þRþþÿ  ÿ­¬þyþü þ]ÿ™—ÇÇÅââàþìþòþôþóþíþØþ®þ{þ%þÿþûþãþDù((*§§¨ææäýýûþþýþþþíþÎþçþýþúþñþ·þYþÿÿýýüþ“þûÿþJþÉÿöôÿýþûúþ¨ÿ$& þ'þŠþôþýþùþ­þÿÿñïýýûÉÉÈþþþþ þÿVVWþÓÿûùüüúþºþÿþ8þzþGþzþõþýþåþ7ÿ›œšýýûþÝþ)þÿ þÿÿ`aÔÿÕÿûúóóòþIÿþþ þSþ}þ/þÄþþ÷ø÷_`^TWVóöõààÝ331 "þ;JHDC0,*`^bÒÔ×øüüÈÉË"!YWW/.0ŒŒŽúýýøýùˆ€ .-.ääáÖÑË(#  '+,³³¶þôÿ¶9º    qnqûøüüøü–’—H"%)ØÙ׎ˆ{ &$wrðëæ¸·´   qslüû÷úùö”’ÿÿ,#"²¨†€m%¥ŠáɢȜÍÖ—vrc#¾ÏÌÂþÿþ*  –š˜ûýõ÷ùð‚ƒAeF ®‚Ëšêµì¸ æ¶ à´ ×¬ÅžÛÖ®#ɦ2йuQF./0/âåâýÿüþëXVZ0±ƒ°|Ú£î¸î» é¼ á¹ Ó­´“ xÆœ è½ä» mV"ÿÿ*%'#ÀÅÂúÿþøüýÅÈÊ"!%_ÖŸç¯ ðµ ñ· ï¹ë½èÁåÀ äÀá¾çÈîÑêÊçÃã¿Í©xo^ Цþùõýûúëíç|z_ã­éµì¸ ë¹é¼ç¿ ëÇîÍîÒñÓ+ôÔ/÷Ö0öÕ.øÕ%öÑóÉ î¿ß°È¡*À¡KŰv¦—r*!_ç° ëµ í¹ ì¼ ê¾ êÁ ìÇïÎðÓ ò×/ôØ>÷ÚDöÚ4õØöÕ öÐ ôÍòÇðÆë¿Ú°Á™{W_ê´ ê´ ë· ì¼ ëÀ ìÆîÌðÑóÕ*õØ>÷ÚA÷Û=ôØ,öÙ÷Øù×øÛù×öÖ÷ÕöÑòÅ+Ö§)bL _êµì¶ íºë¾ëÄ ìË ìÎïÒôÖ9øÙGùÚBöÙ*õÚõØõ×õ×õØøÙô×ëÎãÂôÇ+î»"“s _ì¸ ë· í¼ìÂêÇêÍ íÐòÔ/÷ÚAøÙ@öØ-öØöÙ÷ÚôØôØ÷×öÏằ‡­‚Ùª à¯~_Ië· íºê½ ëÄ êËìÏðÓ'òÓ<õØ7õØ%ó×öØ÷×ö×ôÖóÖìËÇ› µ„ÂŽ Ñ Ø¡ ÏœfL þYí¹ ì» ë¿ êÅìÌ îÑòÕ+÷Ø=õÖ*õØô×ö×÷Ø õÕôÑܵª„·Šʘӛܠ؛ќdK ÿþ_îº í½ ìà íÉíÍïÒóÖ#ô×&öÖ÷Öô×ñÓñÏêÄÄ— «yÁ‘К Õ› Ùœ Ú՚ĒL7 Gï¼ îÁ îÅñÍïÏñÓóÖó×öÕõÔíÏ ãÄ¿˜Ÿo±| É’ Õ— ܘ Ýš Ú Î˜Ãc ü SSUhhj'')ÿ³´ýýûþþüýýûþþüþþüþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ67ÿýþü úüüúþþüþþüþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþØÿýWüþþüþþüþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþ³ÿýWüþþûþþüþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]556üüûýýûþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ5ÿýWûýýûþþúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ556þýÿüTûþþúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþþ²ÿþTýþÿûþÿúþÿúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]±±²ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþZ²²³þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ²ÿýTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]sstýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿþTýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ4ÿýTûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]××Öþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþÿ±T°ýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþÿ±T°þþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ±üþNýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ ±±²þýÿþNýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ rrsüþNýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ 445þýÿþNýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿþþØÿþNüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ þqÿþNýþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿþþþ3ÿþNüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþþÿ±N°ýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« C)vM€U§ Û®ñ·ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«("gƒh%~W‹\©{ ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª«³µ«³¨ƒl&•h“i ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýªª« \ZS¾¾¹¾·³®™ul˜iÿþ6üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþþüúþþÿjlÿÿÿ[XZ½¹º½»¾Áº³°—p–iÿþ9üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿþýü,,. U[W¸º·»½¸»¼ºÂ·®¶švÿþ6üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþþüúþjÿ OTK¹½¶ÂÃþ¿¸¿½´Áº³ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÓÓÑ b[_ØÔÖÖÔÖÈÅÄÀ½º¼½¼ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþúüýøiigþÿ %$%ÏÎÏîÿíþáÌËÌ¿ÿ¾þ¼ÿþ<üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúüüú¨¨¦þÿÿýþŒþúþöþëþÖþÁþ¾ÿþ?üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÒÒÐ ÿþDDEþßûýþùþìþÑþ½ÿþ-üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþýþþþ+þþþ þþÿµ´÷÷õýýûþþüýýûúúøååãÄÄÂÿþ-üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüþýþgþþþ ûþnÿïíýýûþþüþþüþþüýýûóóñÖÖÔÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûýýû¥¥¦))'ÑÑÏýýûýýûþþüþþüþþüþþüûûùììêÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûÐÐÎ ŒŒŠö÷óþþüÿÿýþþüþþüþþüþþüÿÿýüüúÿþ0üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûÑÑÏÿÿþ8ÿäãýýùþþûþþüþþüþþüþþüþþüþþüþþüÿþ$üþþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýþùüüúþýÿe fþþÿœ›ûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüÿþ$üþþüþþüþþüþþüþþüþþüþþüþþüýýûüüúýýûþþüþdÿ þþ>ÿÛÚøøöüüúýýûþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþþüþþüþþüÿþþü úþþüþþüýýû¢¢¡þÿ þ þ‰ÿçåøøöüüúþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþþüþþüþþüþþüýýûþþüýýûþÏþþÿ þþ-þ²þæÿõóýýûþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþÏþüûþþ?þ´þßþôþûÿþýþþüþþüþþüýýûýýûýýûýýûÿþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþ#ÿ þþþþXþ©þÍþìþøþùþüøþþýþüþúÿþüþþüþþüþþüþþüþþüþþüþþüþþüaa_þÿ þþþ þtþ¢þ¶þÐþçþðþñþöþúûùþøþòÿþüþþüþþüþþüþþüþþüþþüþþüÎÎÌþü þþþþ…þžþ¨þºþÌþÜþäþîþ÷þúþùþúþùÿþüþþüþþüþÿúþþüþþüþþþýÿabþ&þŽþ¡þ¯þÃþÒÿàßééçóóñûûùýýûþþüýýûþþüÿþüþþüþþüþÿúýýûþþüþýþÎÿÿþÿþ þ-þ˜þ¶þÉþßþíÿ÷öýýûýýûüüúýýûüüúþþüýýûÿþüþþüþþüþÿúþþüþþüþþþ_ÿÿþþþaþ¸þÓþæÿöôüüúþþüþþüýýûýýûüüúÿýþûùýýûÿþüþþüþþüþÿúþþüýýûþýþ"ÿ þ þ2þ¬þÔþëÿø öüüúûûùûûùÿýþûùýýûÿþþüúýýûýýûÿþüþþüþþüþÿúþþüþþüþÍþÿ668þþ†þØþíÿú!øþþüýýûþþüûûùþþüýýûúúøýýûþþüýýûýýûÿþ üþþüþþüþÿúÿþþüúþžü ??Aþ:þÑþòÿúùÿýþûùüüúýýûþþüûûùýýûýýûüüúüüúþþüþþüÿþüþþüþþüþÿúþþüýýûþ]ü "99;””•þùÿü ûýýûþþüýýûÿýþûùýýûüüúÿýþû ùýýûýýûýýûúúøÿþüþþüþþüþÿúýþûüüúþü  668ÿþ668þãþüÿþüÿýþû!ùüüúýýûýýûþþüýýûüüúýýûýýûýýûþþüþþüSï¿îÇñÍóÐ'ôÔ%ñÔïÔïÑèÈÕ´¬‹Œe›m¼‡ Δ Õ™ ×› ÙŸÕÉ”¶ˆ­‰?yfCþ;ûyþQSÇ  Ô±Ù¸Û¼Ò±έœ¨|¡oi«v º‚ÉŒ Ò‘ Ò“ Ñ—З Å »Ž!Ä \ʱ”Ǻ°¸³®QQLþþcþ€þA˜o ¦~ ¥£}¢y§z°º…ÉćÊ Î’ΔÍ’ ÊŒȇ¸„»”M˵—Ê»ÄÃÀ¾½ºþ¿ ”–™þþþ7þ}þM¢pÀ’Û²Û´׫ÒŸЖÒ•Ï– Ì“ Ê ÈŽÉÁ‹µƒ±…0¾¦~ƼªÅ¹ÊÌÉÈÍÊÂÇÀ½¾¹©§§! "þûþþ]þ€Hšd¬w ȓҞÔÒ˜ Ò”ÏÊŽÃŒ¿‡½~¾| ·´–Q½´™º»¶»½¸¹½¶ÃÆÁÐÑÏÒÑÑÈÆÅ¼º¹TÿSþþþþþþ;ÿopJ‘g'“e ¥u¶¾„ À… Á… ½‚ ·y°p°o°w ²„/¼žmÆ»¦»½±¾¹·Á¼¾ÆÉÉÖÛØèèêõï÷õó÷ÛßÛŸ¡žþþù Cº¨Œ“{@ƒd‘hšhžih›i ˜e ˜e šn¬ŽK¿±‹Â½³»º»¿»¹Ã¿ÀÐÌÏçäç÷õûûüýûþøúýÿ÷ÿø×ÖØþOþùþH¾¼ºÃ»¬µ¢ƒ ‚V”n4•l%“l"™t0¦„K±™m¼³˜À¿´¾»µ¾º±¾¼µÁÂÁÎÓÌâçáò÷÷ýþýÿýùÿüöþýùýþýöÿ÷þ²þüÿþ,½¼½À½½Á½¹Â¼´¿¸­¾¶§½µ¤¾¶§Ã»²Ã½¶À¼¹½¼º¼»¹ÁÀ¾ÆÅÄþÓãäáôõòþÿýýþüÿþüþþûþþüþþüýþûþôþ[þÿ &¿½¾¿¾¼¾½»¾½º½¼¸À¾¹Á¾ºÁ¾¸À¼¹¿»º¼º¹¿¾¼ÆÅÃþÎþÜþçÿòðýýûýýûÿÿýþþüþþüþþüþþüÿþýüþÃþÿ )¾½¼¾½»¾½»À¿»¿¾º¾½¹¾¼¸¾½¹À½»¿½»ÁÀ¾ÌËÉ××Õääâþïþ÷ÿüûýýûþþüýýûþþüþþüþþüþþüþþüþþüõõôþnþÿP¾½º¾½¹¾½»¾¾»¾½¼¾¾»¾¾»¾½»¾½»ÃÂÀÐÏÍàßÝìëéööôûûùýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûûúþÎþ&ÿPÀ¿½¾½»¾½»¿¾¼¾½»¾½»¾¼¼¾¼½ÈÆÅÛÚØèçåóóñúúøûûùüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþøþkþÿ ×ÖÔÆÅÃÂÁ¿½¼º¾ü½þÂþÐþâþñÿù0øûûùþþüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþýþÁþÿþù÷÷íëìÝÛÜþÕþ×þÜÿçåòòðùùøþþüý3ûþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüôôóþJü ÿýþýüýòðñëêëþðþøÿûùûýúýþýþþþýÿþ0üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüþýþŒþÿÿþTüþþüúúøööôýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþÿüþþüþþüýýüþ¼ÿÿýTûýýûúúøüüúþþüþþüþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûþþüþþüûûúþâÿ+-ÿýûÿþþüEúûûùþþüÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýÿþþüúþùþîþMÿÿþEüþþüþþüùù÷ûûùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþþüúÿùþ÷õþñþóþ‡þÿþüÿýþû0ùôôòööôûûùýýûþþüþþüýýûþþüþþüþþüþþüýýûýýûþþüþþüþþüÿþþüúýýûÿüþúþø öððîêêèììëûìþ°þþ÷þòþñþêþèþðþöþùÿúùüüúÿýþûùÿüþúøýýûÿýúûþúþùûøþòþïÿéçããâûÛþÞþäþÆþþéþâþßþäþàþßþåþïÿöõùù÷øøö÷÷õùù÷ùù÷øøöóóñþéþåþáþÝþÛþØþÖþÓþÑþÐûÈþÊþØþÜþNþ÷þíþßþÞþåþïþñþøÿý ûýýûüüúýýûýýûÿúþøöóóñææåþÚþÒþÉþÅþÄûÂþÀþÁþÀûÂþÉÿÝÛÊÊÉþýþöþåþæþ÷þýùþüýýûþþüþþüýýûþþüþþüýýûööõþíþæþÛþÒþÌþÉþÅþÄþÂþÀþÁûÀþÊþåþþþöþèþôþýøþÿÿþý ûüüúýýûþþüÿþþüúÿýþûúûüþ÷þôþìþäþÚþÒþÊþÅþÁûÀþÃþÕþýþ÷þëþõþüþýûûÿüúûûùÿýþûùüüúüüúþþüýýûþþýûþþúûýþüþúþñþçþÜþÐþÇþÃþÁþÉÿý6ûúúøõõóøøöýýûþþüþþüþþüþþüþþüýýûüüúþþüýýûýýûüüúüüúûûùûûùÿþþü úýýûüüúýýûÿþýýþ÷þìþÝþÑþÆþÃÿüúüüúûûùÿýþûùúúøýýûÿýþû'ùüüúüüúýýûüüúûûùýýûüüúûûùýýûüüúýýûþþüþþüÿýþûùÿþýýþþþüþ÷þèþÙþÈÿþþü3úüüúþþüþþüþþüþþüýýûÿÿýþþüýýûþþüþþüýýûþþüþþüþþüûûùüüúÿýþûùüüúþþüýýûýýûýýûüüúýýûÿüþúøííëÛÛÙÿý]ûþþüýýûüüúûûùüüúüüúûûùüüúüüúüüúüüúüüúüüúüüúüüúþþüýýûþþüýýûþþüýýûüüúýýûüüúûûùýýûüüúþþüþþüýýûððîÿýûÿýþûùþþüýýûÿþþü-úþþüþþüýýûýýûþþüýýûþþüþþüýýûüüúüüúüüúûûùýýûüüúÿþþü úýýûþþüþþüýýûÿýþûùþþüýýûÿ*) þÿþqÿþKüýþúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿz]y442××Öýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ€aa` !þpÿþHüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ~}þmÿ4 5þÿÖHÕþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþqþBÿ  ÿþþ0ÿýEüþþüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ,].®®­þþüýýûüüúýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿþþ3ÿþBüýýûüüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ ÿ®B­þþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]""#ÔÔÕýýüýþúþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]rrsýýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]ÔÔÒþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ-üþ6ýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ!þªþþÿý3üýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]ÓÓÔýýüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]kklþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ$þÿk3jþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ*þjÿýþü*úþþüýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]ÓÓÒþþüýýûÿÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ]ÑÑÐüüúýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ$ÿþþþÒþüÿþ!ýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿ-ÿýþþÒþþÿýüýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüÿ 0 ÿýþ(þüÿþýþþüþþüýýûþþüþþüþþüþþüþþüþþüþþüÿ 6 þþfÿüûýýûýýûþþüþþüþþüþþüþþüþþüþþüþþüÿ061þþÿ£¢ÿþþüúþþüþþüþþüþþüþþüþþüþþüþþüÿÇÆ""!ü $$&556þþüþþ%ÿýüýýûþþüþþüþþüþþüþþüþþüþþüþþüÿð¡þ ÿ  ::;þ@þ"þ ÿûÿ£¢üüúþþüþþüþþüþþüþþüþþüþþüþþüÿàÞððïþlÿ  þ2þ4þÿþþ$þüÿýüþþüþþüþþüþþüþþüþþüþþüþÍþëþÝþ)ÿþþþ%þ@þÿÿýþþÏÿþýþþüþþüþþüþþüþþüþþüþþüþÃþÔþôþ”þÿ þþþ@þÿ6ccdüüûýýûýýûþþüýýûþþüþþüþþüÿÊÉþÇþáþãþ0þÿþþþþ4þÿ3ÏÏÎýýûþþüýýûþþüþþüþþüþþüÿÜÝþÉþÍÿïîþü  þ þþ*þ(þþÿ-¡¡ üüúýýûþþüþþüþþüþþüþþüþðÿÙÚþËÿÚØþáþ*ÿ  !! þþþ8þþÿ ÿþþ$ÿþþüúüüúýýûþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýþþüýýûýýûÿþQüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþþüúýýûËËÉÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýûþþüYYWÿþZüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûýýû——•þÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþþÿÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþ—ÿÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýýûþ–ÿÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþVÿÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿÿþTüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþûþþüþþýÿþEüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþÿýÿþÿùûÿþüþÿ”––#ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüúÿôüÿûÿþúýü÷ÿýôcO$«…ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûúÿùýþüÿûÿÿûùë⻵Œ Ú¤ ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿÿøÿüÿÿüÿýÿøÿýîͱ]Иå®ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüÿüúüþûûþïØË’¼ŠØœ æ¯ ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüûÿþüþüúþ÷þûç·.̑ݣï®ÿþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþÿûÿöýýøÿûë˪gÁ‰Ôš à§ ï®ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþûþþýþþýþþüþþûþþüþþüþþüþþøþþóþþïþþíþþìþþíþþïÿýéìå¿Ç¥[¿†Ï•Ú£æ¬ î¶ÿþüþþüþþüþþüýýûžžÿÿþþþ7ÿþþþ«ÿýüÿþþüúýýûÿýþû ùýýûýýûüüúþþüÿþþü úüüúüüúýýûüüúÿþ üþþüþþüþþüýýûþ]ÿ þFþÿþþþDÿëéþþüÿþþü úýýûþþüþþüÿþþüúþþüûûùüüúüüúÿÿýþþüÿþþüúÿþ üþþüþþüþþüþþüþ ÿ ==<þÿþþ¨ÿû úýýûýýûüüúÿýþûùýýûüüúüüúþþüýýûþþüÿýþû ùüüúüüúýýûÿþ üþþüþþüþþüœüþþ;þüþþHÿîìÿýþû-ùþþüûûùþþüýýûýýûýýûýýûüüúüüúýýûúúøþþüþþüýýûüüúýþúþþûþþüþýþ^þþÿþ<þÿþ¢ÿýûýýûüüúýýûþþüûûùüüúýýûþþüýýûýýûÿÿþýûÿþþü úüüúûûùööô ýþùýýûþþüÍÍÌþþþþ6þ#ÿþ0þäÿûùýþúÿþþüúýýûþþüûûùýýûýýûÿþþüúýýûüüúüüúýýûýýûüüúòòðüýøþÿúýýûœœ›þ þAþ ÿþ„þúÿþüýýùþþüÿþþü'úþþüýýûýýûýýûüüúüüúüüúýýûüüúýýûýýûüüúïïíýþúýýúþþüþÿþþ"þ0ÿ '')þÓüüÿúûöÿýþûùþþüûûùýýûýýûýýûþþüÿýþûùýýûÿþþü úýýûúúøììêÿýüþýþ›üAAC ``_ööôþþüþþüÿþþüúþþüûûùÿþþüúüüúýýûüüúüüúýýûýýûüüúþþüÿýþûùééçûþþþþÿ CCE þÿ®­üüúûûùüüúýýûýýûýýûþþüþþüÿþþüúýýûÿþþü úþþüþþüýýûýýûÿúþøöääâþýþ™ûþÿ--/../ÞÞÜýýûþþüÿþþüúýýûüüúüüúûûùþþüÿþþüúþþüÿýþûùýýûüüúþþüþþüööôââàþþþþþþþ4þÿZZ[ôôóûûùýýûüüúÿþþüúýýûþþüÿþþü!úûûùýýûüüúüüúüüúýýûüüúûûùþþüôôòààÞÿZ[þûþþ8þþÿþ*ˆˆ‰ýýûþþüýýûüüúýýûýýûýýûüüúþþüþþüþþüýýûüüúÿþþüúýýûüüúüüúþþüööôßßÝÿÿýþþ>þþÿþÀÿû'ùýýûýýûþþüþþüýýûþþüþþüûûùüüúýýûýýûýýûýýûÿþþüúÿýþû ùýýûòòðßßÝÿ þ þBþü((*þÚÿþþüúÿþþüúüüúÿýþûùüüúýýûþþüýýûýýûÿþþüúÿýþûùþþüÿþþüúîîìÝÝÛÿ þ þGþü556þßÿþüþþüûûùþþüÿÿýûûùþþüÿþþü$úýýûþþüýýûýýûþþüýýûþþüýýûþþüþþüððîÝÝÛÿ þFþþþþFÿèçúúøýþúÿÿüúúøþþüÿþþüúÿýþûùüüúýýûúúøüüúûûùýýûüüúÿüþú øýýûîîìÝÝÛÿÿþþKþ ûþWÿïíýýûüüøüüúýýûüüúüüúýýûþþüÿþþü!úýýûþþüþþüþþüþþüþþüþþüþþüûûùííëÞÞÜÿ ,,.þPþ8ûþcÿñ?ïþþüþþúýýúýýûüüúüüúýýûýýûþþüþþüûûùýýûüüúýýûúúøýýûüüúýýûýýûììêßßÝÿÿþ;;=þ_þNþþ þÿò3ñûûùüüøþþûüüúýýûýýûþþüþþüûûùüüúþþüýýûýýûþþüþþüþþüýýûÿýþûùèèæßßÝÿ þCþXþþ þ‚ÿô òýýûþþúþþûÿþþüúÿýþûùþþüþþüûûùüüúýýûýýûüüúÿýþûùüüúýýûüüúêêèÝÝÛÿ  þþJû þŠÿö ôüüúüýùýýúþþüÿþþüúÿýþû'ùüüúýýûüüúýýûýýûþþüþþüþþüýýûýýûüüúêêèááßÿ þþ*þþ þ…ÿøöþþüþÿûþþûüüúüüúÿýþû*ùþþüýýûýýûýýûüüúüüúýýûúúøýýûýýûüüúýýûêêèââà  /./212þxÿö ôûüûüýùýþúþþüÿþþýûÿþþüúüüúûûùüüúýýûþþüþþüÿþþüúüüúüüúýýûëëéààÞ>eGžw·Ž¡€YG  96;yywíîíúþþúýùüý÷ýûýþýÿúúùýýûþþüýýûþþüÿþþüþú øýýûýýûüüúýýûÿþýüþéþà!×¥ï¼ñ¾ñ½æ· šx!HIKÍÊÐúþû1ýùþþüþýþýþûüýúýýûüüúüüúýýûþþüþþüýýûüüúýýûþþüýýûýýûþüþëþà&òµô½ õ¿ ú»þ·ðµ¥…  ROSËÊÊùûõþý,úûøùý÷üýúüüúýýûýýûüüúýýûüüúþþüþþüýýûýýûýýûüüúþûþêþßYî·ñ¾ ð¾ õ¼ú¼ø¿ê»©‚) :>3¿¿¼úøûýþüýþüþþüýýûüüúýýûþþüþþüýýûüüúþþüýýûüüúýýûþþüýýüþêþàMð¸ò¾ ñÀ ñÀ òÂó¿ö½ò¹¬‚% 855´²´õöøþýýüûùþþüýýûüüúýýûüüúýýûþþüûûùüüúÿýþûùÿýþûúþèþß0ö²ø¹÷½ ô½ ö¼÷½ õ¾ ô¾ê´r -.*¢£Ÿöòôýÿüÿú øýýûþþüþþüÿþþüúüüúüüúüüúýýûüüúþþüþûþëþà"÷µ ùº ø¼÷¼÷¼÷¾ ô¿óÁõÀÞµuW þÿ"$ƒƒ…þíÿýþû ùüüúûûùýýûýýûÿþþüúüüúÿýþûùýýûþüþêþÜPò½ôÀ ó¾ ó¿ò¿ò¿ö¾ ø¾ òÀó½Ñ¡M6 UVUÔÔÒúúøüüúýýûþþüýýûýýûýýûýýûþþüÿýþûùþüþöþêÿýûþþüÿýþûKùýýûýýûþþüýýûýýûýýûýýûüüúýýûüüúûûùþþüþþüþþüþþüþþüþþüýýûýýûþþüþþüýýûüüúþþüþþüÿþþüúýýûÿýþûùýýûýýûüüúüüúýýûúúøþþüþþüýýûÿþþü úýýûýýûüüúýýûÿýþûùüüúüüúûûùþþüúúøýýûÿþþü úüüúýýûüüúÿýþûùÿûùüüúûûùýýûüüúþþüþþüþþüúúøÿýþû ùþþüþþüþþüÿþþüúÿþþüúýýûúúøÿþþü úýýûýýûýýûÿþþüúüüúüüúþþüþþüþþüÿù÷øøöÿýþû-ùýýûüüúüüúþþüþþüþþüþþüûûùýýûüüúþþüýýûýýûþþüýýûÿþþüúþþüýýûüüúüüúýýûÿþþü úüüúûûùüüúüüúÿëéùù÷ýýûþþüûûùüüúûûùýýûÿýþûùþþüþþüÿþþüúÿýþû ùüüúýýûüüúýýûÿþþüúýýûþþüûûùüüúþþüýýûþþüýýûÿþþüúÿçåóóñýýûýýûýýûüüúÿÿýþþüýýûÿýþûùýýûýýûþþüþþüþþüýýûþþüÿþþüúþþüýýûýýûüüúþþüýýûÿýþû ùüüúüüúüüúýýûÿåãùù÷ÿþþü úþþüýýûýýûýýûÿþþüúÿýþû ùýýûýýûýýûÿýþûùýýûüüúþþüûûùýýûýýûÿýþûùÿýþûùþþüýýûþþüýýûüüúÿéçùù÷þþüýýûüüúýýûüüúüüúüüúþþüþþüÿýþûùþþüýýûÿÿýþþüþþüÿýþû$ùþþüþþüûûùþþüþþüþþüþþüûûùýýûüüúþþüþþüÿíìþúþûÿý üþþüþþüþþüÿþþü úüüúüüúýýûÿþþüúÿýþûùÿýþûùýýûýýûüüúþþüýýûüüúýýûüüúþþüþþüÿþþüþúøýýûþçþúüýûýýûüüúûûùüüúýýûþþüÿýþûùüüúýýûÿþþü úýýûýýûüüúþþüÿýþû ùÿÿýþþüþþüÿýþûùýýûýýûÿÿþýûþþüÿèçþúþüÿý3ûüüúüüúýýûüüúþþüûûùýýûþþüþþüýýûüüúýýûüüúþþüûûùüüúüüúÿýþûùüüúüüúÿÿýþþüýýûüüúüüúüüúüüúþæþøþþÿý!üþþüþþüýýûþþüûûùýýûüüúüüúýýûþþüþþüÿþþü-úþþüýýûþþüýýûþþüþþüýýûýýûýýûüüúþþüþþüýýûüüúýýûþéþ÷þýÿü ûüüúüüúüüúÿýþûùüüúýýûþþüýýûüüúüüúþþüýýûÿýþûùýýûýýûýýûýýûþþüýýûüüúýýûÿþþü úýýûþþüþþüþçþøüýûþþüþþüýýûüüúþþüÿþþüúýýûúúøÿþþü úýýûýýûþþüþþüÿýþû!ùýýûüüúûûùþþüýýûþþüþþüþþüûûùýýûýýûÿçæþ÷þüÿûKúüüúûûùýýûýýûýýûýýûüüúþþüþþüûûùýýûüüúýýûüüúûûùþþüûûùûûùýýûüüúüüúýýûýýûýýûüüúÿþþüúþþüþçþùþüÿýûýýûÿýþû6ùüüúýýûýýûýýûüüúþþüþþüþþüýýûýýûýýûýýûþþüýýûþþüþþüþþüýýûÿýþûùþþüþþüþþüýýûüüúÿçæþúþüÿýþû$ùþþüþþüþþüûûùýýûüüúþþüûûùýýûüüúüüúþþüÿýþûùüüúýýûýýûüüúýýûüüúýýûÿþþü úýýûúúøýýûþþüÿëêþúüþ üþþüûûùüüúýýûÿþþüúÿýþûùþþüýýûýýûýýûüüúûûùþþüÿýþûùüüúýýûýýûþþüûûùýýûýýûþþüÿýþûùüüúþíþûüüúüüúýýûÿÿýúúøþþüýýûÿýþû!ùýýûüüúüüúýýûýýûþþüûûùþþüþþüýýûüüúÿýþûùýýûýýûýýûüüúýýûþþüýýûþíþüþþÿýüþþüýýûüüúþþüùù÷ÿýþûùþþüþþüýýûýýûüüúÿþþüúýýûüüúýýûüüúþþüþþüûûùþþüþþüÿýþû ùýýûýýûýýûþìþúþüÿú3øýýûýýûýýûþþüýýûýýûÿÿýüüúüüúýýûþþüþþüûûùþþüþþüþþüýýûÿüþúøþþüÿýþûùüüúþþüþþüýýûýýûýýûÿïîþúüþüýýûÿýþûùüüúÿþþü úüüúüüúýýûüüúÿýþûùÿþþü úüüúûûùýýûýýûÿýþûùýýûýýûüüúûûùýýûüüúüüúýýûÿòñþúüý9üþþüÿÿýþþüþþüýýûþþüþþüýýûüüúýýûþþüýýûüüúüüúýýûüüúýýûýýûþþüÿýþûùþþüÿÿþý ûþþüþþüþþüþþüÿñðþýþþÿû úýýûüüúüüúÿýþû ùýýûýýûþþüýýûÿýþûùýýûüüúýýûýýûýýûúúøýýûÿüþúøþþüÿýþûùüüúÿýþûùüüúýýûÿòBñûûùüüúþþüþþüýýûþþüýýûüüúüüúüüúûûùýýûüüúþþüþþüþþüýýûýýûýýûýýûüüúýýûÿþþüúþþüÿþþüúþþüþþüÿþÿüýûÿòñüüúüüúÿýþûùýýûüüúÿþþüúýýûýýûÿþþüúÿþþüúýýûýýûýýûýýûüüúþþüýýûüüúþþüÿþþüúþþüþþüûûùýýûüüúþþüÿó?ñûûùýýûþþüýýûüüúýýûýýûþþüþþüûûùýýûýýûþþüýýûýýûýýûýýûýýûýýûüüúýýûÿýþûùþþüÿýþûùýýûüüúûûùýýûüüúÿóñýýûýýûüüúþþüýýûÿþþü úüüúûûùýýûúúøÿýþûùýýûüüúþþüþþüûûùþþüýýûÿþþüúüüúûûùþþüþþüþþüþþüýýûýýûýüøÿ÷3õüüúüüúýýûüüúýýûüüúýýûþþüýýûþþüþþüýýûüüúýýûüüúüüúûûùÿþþüúýýûüüúþþüþþüþþüûûùýýûÿüþú øýýûüüúýûóÿñïýýûþþüÿþþü úýýûýýûüüúÿýþû$ùüüúýýûþþüýýûüüúþþüýýûþþüýýûüüúþþüýýûÿþþüúýýûýýûýýûýýûþþüýýûýýûþüôÿëéøøöûûùþþüýýûýýûýýûþþüÿÿþý$ûýýûüüúýýûüüúýýûüüúûûùýýûüüúýýûüüúýýûÿþþüúýýûüüúýýûüüúüüúÿýþûùþýõÿí]ëúúøþþüûûùýýûüüúýýûýýûüüúþþüýýûþþüþþüþþüûûùýýûýýûþþüýýûüüúýýûýýûþþüýýûýýûüüúýýûýýûþþüýýûüüúýüôÿýûóóñââàÞÞÛññîqqoþþþ.þ<þ0þþþ7þþþüþÏÿýþü úþÿûþþûþþüþþüÿüúþþüûûùúúöýýû»»¹ þþþ7þFþ;þ#þ þ1þ$ûüþbÿüûýýûýýùþþûþþüþþüÿüúýýûýýûþÿûþþûççåþ0þþ"þ9þ@þ0þþþþ@þ þþÿ$""#þþýüüúþþüþþüþþüþþüÿý ûüüúûûùýýùÿüþù÷__^þþþ%þ#þþ þþþ?þ(ûÿþ ÿý üþþüþþüþþüþþüÿüúþþüþþüýþúüýúüüú––•þ þþ þþûþþþBþü$aabþþýþþüþþüþþüþþüÿþüûûùýýûþþûýýúþþüÇÇÆþ ÿ þ=þ üþ""$þýÿþ ýþþüþþüþþüÿûùþþüýýûýýùüýúýýûååäþ)ÿþ;þüþ!žžŸýýüþþüþþüþþüÿþüýýûþþüýýúüýúüüúþòþDÿþ6þ*þÿ$ŸŸ þþýþþüþþüþþüÿý ûüüúüüúüüúþþüþýþüþ^ÿþ3þ)þÿ!!"þýÿþýþþüþþüÿüúüüúþþüÿýþûùþûþüþ~ÿ445þ$þÿ !üþýþþüþþüÿþ üýýûüüúûûùýýûþþþùþ—ÿ223þþÿþþÎÿþýþþüþþüÿüúþþüÿÿýþþüûûùýýüþýþ¥ÿÿþ--.þþÿþŸÿþýþþüþþüÿüúüüúûûùýýûüüúýýüþþþ¸ÿ223þüþžÿÿþýûüüúÿü úüüúýýûþþüÿþþüûþýþÅÿ  þ7þüþ_ÿýüýýûþþüÿýûÿÿþýûúúøýýûþüþýþÌÿ ÿþ 667þþÿþ ÿþüÿþþüúÿýûüüúýýûýýûÿÿýþþýþþþÏÿ445þþÿþþ!ÿýüýýûýýûÿýûýýûüüúýýûüüúüüûþþþÔ;##%##%þ ÿþýþþüþþüÿþüþþüþþüýýûýýûýýüþýþÕ;--/ þ ÿþýþþüþþüÿýûüüúýýûýýûüüúþþýþüþÕÿ9 668þ ÿþýþþüþþüÿþ üþþüûûùþþüÿýýûþþþ×ÿþ%ÿ!þ ÿþýþþüþþüÿüúýýûÿýþûùýýûþüþýþÐÿ þþ,þÿ!þ!ÿýüýýûýýûÿü úüüúýýûþþüþþüþúþþþÁÿ þþþ/þûþûûþÿ þ ÿþüÿþþüúÿþ üþþüûûùýýûþþüþþþýþ¯ÿ þþ/þ#þ þþþþ þþþü þ_ÿýüýýûþþüÿû úýüûýýúüýùûüøÿýýüŒŒýþ3þ'þþ þþþþ"þ*þ&þþþÿþÿž ÿÿþýýûýüùúüýÿýùýÿ÷ùÿøüþúùúùbdd!ÿÿ ,,-þEþK ÿÿ  ›þýþÿýûþÿøûþøüûùýùùûúôúýóüýôèâß4.. ÿÿþþZÿb\ $!"þüþÿüÿÿýúüÿüýüôýöÙïÞ®îÛ£íÛ¢îڟθ„5" % þþþ8ÿG?32. ""&ýþùûÿôþþøýþùûíÉÙ³QÞ³ ë¾íÀíÀ廯¢$PBÿÿÿþþþ70,- e`aüþûøÿúûÿýÿýüëÌ|â³ôÉ ÷Ö ôÙöÖõÏå¾#RB ÿÿþþ"þ%€l×ÅyÿýâýýðùÿùûüþAä½k⥠ò· òÂóÍõÐ ÷Ïد?.þ þ <-ƧðÍ"æÊ=õð¹ûþûúÿúãÃrÜ¥ñ²õ»ò óÈìÅ»˜2$þÿýÿ‘qêÆôÍúÓéØkÿýéúÿý<ãÄpÚ£ î±ö¾ ñÂí¿ã¶®…1 ýÿ`E ݵîÅ îÈ îËäÄ<íè¾üüúÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ýÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüÿþþZüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_üÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ÿþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿüþþZüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_üþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_üÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ÿþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüÿþùýÿøþþÿûÿþÿüýþý÷øÿþÿûöÿüêÏ¿˜ÕÁy°ˆ%¶†¶…±ƒ­€ °€¶‚ËЖ Úž ãª ê± òºÿþ]üþþüþþüþþüþþüþþüþþüþþûþÿøýÿùþÿùýÿûþûÿÿýúýþøçÝ·¯„!¾ŒÍ—ל Úœ ך Ó–Ë É Ï•ÖœÜ  ã¨ ê° òºô¼ÿþüþþüþþüþþüþþüþþüþþüþþüýÿþÿýÿÿ@üþþÿùýþöþüúÿùî­‰*Î Ú˜ Ý  á¨á¨ৠݣߤÞ¤ à¦å«é¯î³ó¹ô½ ô½ ÿþüþþüþþüþþüþþüþþüþþüþþüûÿÿÿýÿÿ@üýÿþøüýúþýõÒÀ»ˆÓ™ Ü£ ã®ç´è´ê²ê°æ«æ«ì± ñ¶ñ· óº õ½ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþûüÿõþÿüÿþûÿþøüþÿþþö¾¢^ÈŠÙ  æ¯ì´ ð¶ ó· óµ ô·ò¶ñ· ôº õ»ö¼õ½õ½õ½õ½ÿþüþþüþþüþþüþþüþþüþþüþþûþÿôþÿúÿþÿÿ=ýùüÿûþýòÅ¥VÌÝ¡è­ð² ö¶ øº÷» ó½ ñ¾ ô¼ ö½ õ¾ õ¾ õ½õ½õ¼ õ¼ ÿþ#üþþüþþüþþüþþüþþüþþüþþüÿýþýþÿûÿûÿýûüþþÿ6ì«…(Ê’Þ¤ê° ñ· ôº õ½ ô¾ ò¿ òÀõ¾ õ¾ ô½ ó¾ ó¾ õ¾ õ¼ õ¼ ÿþüþþüþþüþþüþþüþþüþþüþþüÿþýÿþAúÿùÿþüüþúýüñÀ [đݣ ç­ìµ ò» õ½ö¼ø½ø¼ö¾ õ¾ ò½ ó¾ ó¿ õ¾ ö½ ö½ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿýþüÿþüÿýÿýüýýüþþøÕÁ‰ÂŒÙŸ æ¬ í´ ñ¹ õ½õ½õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿýüüÿüýÿüÿþúþýûýý÷ÖÃŽÁŒÙž ã¨ ë² ñ¹ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿýúüÿúýÿúÿÿ÷þþúþýöÖÆ–¼ˆÕš ᦠë±ñ¸ ô¼ õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿýúýÿúþÿüþÿøþþúÿþùèß¹¾‹Õ™ Þ¢ è® ð· ô¼ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ!üþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿýÿùþþ8ÿýüÿý⼋Ñ• Þ¢é¯î¶ ó»õ½õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿþüýÿþÿýÿûÿúÿþÿÿýÿÿýíºŠ!Д Ü ç¬ñ¸ó» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿþúýÿýÿýÿúÿ÷þþýÿýþÿþñº‹#Î’ Ûž è®ï¶ ô¼õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþûÿþùþÿûÿýÿúÿ÷þþýÿüûþþò½$Î’ Úž å« ð· ô¼ ô¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿþûÿýþûÿýýÿûÿûþÿû÷ýý弌Α Ú æª ò¸óº õ¼ ô¼ô¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüþÿúÿþüüÿüþÿûÿüþþýùçâ¹¾‹Α Úž è­ ó¹ô» ô» õ½ó»õ½ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ ÿþ!üþþüþþüþþüþþüþþüþþüþþüþþüþÿúþþüþÿúþþ8ûþøÕ„¾‡Ï‘ÛŸ è­ ñ· ô» ô» õ½õ½õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüýÿþýÿùÿýüÿþýúýüýþòŤPÀ… ÍÜ¡ é® ó¹ ô» õ¼ ó¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþüþþüþþüþþüþþüþþüþþüÿþÿýþÿýÿúÿýþþ<ÿýþùÿý߸„ Æ Ó–å«ñ¶óº õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþüþþüþþüþþüþþüþþüþþüÿþÿýFþÿþþûÿýþþýÿþýïÑÁ„¼ ÉŒ Û  ì²ó¹óº ô» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüýÿüÿþúÿþûýþÿÿý毄(Ɖ Ò— ⨠ñ¸ó¹ óº õ¼ ö¼ö¾õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþûýÿùÿþùþÿùüÿýäÞ»»†Ç‹Øž â¨ ë² ôº óº ô» õ»ô¼ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ÿþ]üþþüþþüþþüþþüþþüþþüþþüúÿúÿþýÿþûÿýúÏÂŒ¼ˆÍŠÕšâ¤ è¬ ïµ ò¹ òº óºôºô¹öº÷¼ ö½ ó¼ ô¼ ö½ ÷½ ÷½ ÿþüþþüþþüþþüþþüþþüþþüþþüþþDÿûÿÿþóÿþñÓÄ·…ʆÏ“ ןߨç° é° îµï¶ñ¸ ò¸ ò¶ ò¸ ó» ô¼ô¼ó»ö½ö½ ÿþ]üþþüþþüþþüþþüþþüþþüþþüýÿúÿüÿÿüþÿýöÑ“³džÊ‹Ñ•כݡ ã¦ ã¨ ä« ã®å±è¯ ê¯ ë³ îµ î¸î¸ò¹òºÿþ]üþþüþþüþþüþþüþþüþþüþþûúÿõûþÿýÿøþÿõçÞ½§}&¹}¾‚ ¾† Ä‹ Ì Õ• Ú™ Ûœ ÛŸ ܡޡ à¤ â¦ ã© åª è®ê°î´ÿþüþþüþþüþþüþþüþþüþþüÿþÿüÿþDýþÿüÿùþÿùÿûöèÚ¶y% x «z °z·~¹~¿ Â… ĉ ÉŽ Í Ó• Õ—Õ˜ךÜŸ Ý¡ ॠÿþ]üþþüþþüþþüþþüþþüþþüþþýÿüÿÿüþÿÿóþÿöþýýÿûôÿûéáٸQi—oŸr¦t®w ´z ¸} ½ À„ÈćÆŠ ÈÌ‘ ÿþ]üþþüþþüþþüþþüþþüþþüþþüÿýüÿýûÿüÿÿýÿûüùüþýüþûýüúýýöþþòþþëâÙ¼Á¯‚ªŽKe šk¢n ¨s®w ®v³y ³y ¶{ ¸~ ÿþüþþüþþüþþüþþüþþüþþüÿþÿûÿøûÿ÷ýþþÿýÿýþøûþúüýÿþÿü/ÿýúýýúýýúþþüþýùÿüñÿýå¿´Žª‹I‡]Œ` —g ›h h¡k£l(ó½ ô¾ õ¾ õ¾ ô¾ ô¾ õ¾ õ¾ òÀ ó½ð»´( ÿÿ) ??>ÃÃÁüûùüüøýþùýþúûýúýýûúúøüüúüüúýýûþþþýþù*õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò¾õ½ò¾ß¹ˆjýÿþþ#—–•ñðîýýûüýûýÿüþþüýýûþþüÿþþüþúùþûþý/õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ ÷¿÷½ ñÀðÇѨXC ÿþ$}{|éèçûûùþþüûûùüüúûûùüüúþþüýýûþþþýPõ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ó½òÀ öÇè¿®‹$ ][\ÔÒÒüûùþþüýýûüüúÿýþûùüüúÿýþûùSõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ¼ò½ ôÀïÇرu]  423µ´³ùù÷ûûùýýûýýûÿþþüúýýûþþü>õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ó¾ó» ó¾òÄ éľ™:(ÿþþ‘þòÿûúüüúýýûýýûüüúýýû6õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ õ½ô» ó»ô¾ ðÈ์jÿÿ þþ|þïÿýþü úýýûýýûüüú6õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ ö½ õ½ ÷» ô¼ôÄëÈ΢L7 ÿÿ þþþ†ÿô óþþüýýûýýûþþüGõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ õ¼ ó¼ ñ¿ òÆç»§$ÿþþ°ÿú øþþüûûùüüúMõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ô½ ñ¾ ñ òÅÖ­uU þþ[ÿí ëúúøþþüþþüMõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ò½ ô½ õ¾ ö½ õ½ ò½ ð¿ óÄé¿Ú>-þþ*ÿá ßýýûüüúüüúPõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ó¾ õ¾ õ¾ õ¾ ó½ ò½ ôÀõÇÞ¶˜v þ!ÿ× ÖüüúýýûþþüGõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¾ ò½ õ¾ õ¾ õ¾ õ¾ ô½ ô¾ ïÁîÅÑ¥bI þÿþþ)ÿß ÝþþüýýûýýûFõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó¼ õ¾ ô½ õ¾ ô¿ ëÁ óÅ íÀ¿˜8,þþ þƒÿ÷ õýýûýýûüüúDõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ ö½ ö½ ó¼ õ¾ õ¾ ó¼ õ¿ îÂò òÇáµ Žq  ûÿþˆþóÿþþüúüüúüüúJõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö½ õ¼ ö½ ö½ õ¾ ö¿ ö¿ ô½ ò¿ î¾ôÄðÉϤgH 4,VWR›œ›þçþþÿûÿüýþûùýýüýþûVõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ò»ë½êÉ å¿ ¿Ž¬‹Wöôéùýùûýùûûýþüÿþýùÿþþúÿûý÷Yõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ¼ ï½ èÁ èÀÚ© yƹ˜üüøûüûüüúüüùüü÷þýúþþýþûXõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó»ö» õ½ê½ìÂç¹ Èž•w/èÞÒüùûüý÷ýÿôýþùýüýýûÿüYõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¾ ñ½ö» ÷» î¼è¾ íà ٬­ƒ˜ƒY÷òîýüûùýóûýøýüþþûýÿý_õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ ö¿ õ¾ ó½ ñÀ ó¼ ÷»ï¼æ½è¿ á±Ä‘ ƒe¬›ƒýøùûþûüþúþýþýýþûüøYõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ ó½ ñ¿ ó¾ ô¼ ðºä¶å¹߯ Ë–  xZ>£—’óôõûþûûúûþýûý÷Yõ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ô½ õ¼ óºè´â±ܪ Ó›°} wR.\ZWÎÏÎüûøÿúÿùüø]õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¼ ö¼õº÷»ð· â¬Ü¥ Ò™ ¹ bN: SRO¡¡ ÒÿÔ_ô½ ó¿ ó¿ õ¾ õ¾ õ¾ õ¾ ö½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô½ ö¿ ô½ õ½ ö½óº ð¸ æ®Ý¥ Óš ¼ƒ˜f iG ' _õ½õ½õ¾ õ¾ õ¾ ö½ õ¼ õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½ö¾ö¾ õ½ö½ôºï¶ è® Û¢ ј »i rL <& Zôºôºôºô»õ¼ö½÷½ö¼õ¾ õ¾ õ¾ õ¾ õ¾ ö¾õ½õ½ö½ ÷¾ö½ó¹í³ äª Ú  Ε ¶}šfuLM4  ÿÿ_ñ¶ó¶ô·ó¸ôºò¸ óº ö½õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô½ ô¼ õ½ õ¼ ôºó¹é° ߦ Óš Æ‹ ¯w–bzPY< %Xä© æ« è­ ê¯ î´ ñ¸òºòº ó» ö¾ó¼ ô½ ô½ õ¾ ô½ ô½ óº õ¼ ó¹ ïµ㪠؞ ɹ€¦p’_zP[> 'ü_јÕ› ÙŸ Ý£ ߥ ã¨ ç­ ì²ñ·ò·ó¹óº ôº óº ò¹ ôºóº ò¸ï´ç­ Û¢ Δ¾…¬t›e‹[sKV:%_º½„Áˆ Æ Ë‘ Ò— Øž Ü£⦠è«ë¯ï´ó¹ñ¶ó¸ò¸ï´ì±ç¬Ý£ј Ä‹ ³{ ¡i’\QiEM7 _§o©q­t²y·}½‚ĉÌ’ Ò– Ùœ ÚžÞ¢â§ ç« è¬ é®åª ॠٜ Í’ˆ·~¦n”]†SuI^=B- ÿø÷úúøýýûÿýþûùÿþþüúþþüþþüûûùýýûüüúûûùüüúýýûüüúýýûÿýþûùþþüûûùüüúüüúþþüþþüþþüþþüýýûúúøþüþýüúôÿýþüúýýûýýûÿÿýþþüýýûüüúýýûþþüÿþþüúÿþþü-úýýûýýûþþüýýûþþüýýûþþüýýûýýûýýûüüúýýûýýûþþüýýûþøþîãàÚÿü3ûüüúýýûüüúüüúûûùþþüýýûüüúýýûýýûüüúýýûþþüþþüýýûüüúûûùÿýþûùýýûÿýþûùýýûþþüýýûüüúþþüûûùþáþÉÇľÿý6ûüüúþþüþþüþþüýýûýýûüüúþþüýýûüüúüüúüüúüüúüüúûûùþþüþþüþþüÿýþûùþþüÿýþûùýýûýýûýýûüüúèèæËËÊþůĽÿûùþþüúúøÿýþûùûûùýýûýýûýýûüüúýýûüüúÿýþûùþþüÿýþûùýýûüüúþþüþþüûûùþþüýýûýýûýýûÿýþûùÚÚØÄÄÃþÄÇľÿÿ ýþþüþþüþþüþþüÿþþü3úüüúûûùüüúýýûþþüýýûþþüûûùÿÿýþþüýýûýýûýýûþþüûûùüüúüüúÿþþü úüüúùù÷××ÕÄÄÃþÄÈÅ¿ÿýþû*ùýýûýýûýýûýýûýýûþþüþþüþþüýýûüüúûûùþþüûûùýýûÿþþüúýýûÿýþûùþþüþþüýýûüüúüüúüüú÷÷õ××ÕþÅþÄÆÃ¾ÿÿ ýþþüýýüýýûÿýþû*ùýýûüüúüüúüüúþþüþþüþþüûûùþþüýýûþþüýýûüüúþþüÿþþüúûûùúúøýýûýýûýýûööõ××ÕþÅþÃÅýÿüúÿýþûùüüúýýûüüúýýüýýûüüúüüúÿýþûùþþüÿþþüúÿýþû$ùýýûüüúûûùüüúýýûþþüþþüþÿûþþûýûüùøúÜÛÜÿÆþÅÃÅüÿþüýýûüüúüüúþþüýýûüüúÿþþü$úûûùýýûüüúüüúýýûýýûýýûýýûÿÿýþþüýýûþþüÿýþû ùýýûüýùûüùýýüþûþåÿÊÉÄÄÂÆÃ¾ÿýûþþüýýûÿþþüúûûùÿýþûùþþüþþüýýûþþüýýûýýûüüúþþüýýûÿýþûùýýûýýûýýûýýûþþüýýûÿþÿüýúûûùììêÒÑÏÄÃÃÈÿÿüúüüúûûùþþüþþüÿÿýþþüÿþþü úüüúüüúùù÷ýýûÿþþü3úüüúþþüýýûüüúûûùýýûþþüýýûýýûüüûýýûýþùýýøîïêÖÖÓÆÅÄŸš”ÿþüýýûþþüûûùýýûýýûüüúýýûþþüþþüýýûÿþþüúýýûÿþþüúüüúþþüýýûþþüûûùüüúýýûüüúþüÿþüýþøüü÷íîêÖÔÔ¹¶´IB:ÿýûüüúüüúýýûýýûüüúüüúüüúÿýþûùûûùüüúÿþþüúüüúûûùýýûýýûüüúýýûýýûýýûüüúüüúþýüýûûý÷üþùðñðÂÀÁLHDÿý6ûüüúýýûýýûýýûýýûýýûüüúýýûýýûþþüýýûýýûúúøþþüýýûþþüþþüþþüÿþþü!úüüúýýûýýûýýüýýûýÿùúüúÈÈÌD@D ÿþüýýûüüúüüúüüúüüúüüúÿýþûùüüúüüúûûùýýûýýûüüúüüúýýûüüúüüúÿýþû ùüüúýýûüüúÿüþúøüýùÊËÊ337#Püþùþþüþþüþþüþþüýýûþþüþþüþþüþþüÿÿýþþüûûùþþüþþüûûùýýùüýøýþùþþúýýûýýûýýûýýûýþûø÷ø¯¯­þ# 0ÿü ùüüúûûùüüúÿüþúøýýûüüúüüúýýûýýûýýûÿþþü%úýýûÿÿýþþúýþùýþùüüúüüúûûùüüúüüúóôòƒ„ÿÿ :&úûùüüúÿýþû9ùþþüþþüýýûýýûýýûþþüýýûüüúýýûüüúüüúüüúüüúüüúýýûÿÿýüüúýýûýýûþáXYY ÿÿ  D/ÿýûýýûþþüûûùüüúüüúüüúÿþþü$úüüúüüúýýûþþüþþüýýûþþüþþüýýûüüúþþüþþýþöþŸþ$ J3ÿü ùýýûýýûýýûÿþþüúÿýþû ùüüúýýûþþüýýûÿüþúøüüúüüúüüúýýûýýüþöþ¹þBþýÿ ÿÿQ9 ýþúüüúýýûüüúýýûýýûüüúþþüþþüýýûýýûÿþþü úüüúüüúýýûýýüþûþËþSþ ÿþW<úüùÿþþü'úüüúüüúýýûüüúüüúüüúýýûýýûüüúüüúýýûüüúééçþ­þSþ þÿ þY=ìíìøøöûûùÿýþû!ùûûùüüúüüúùù÷ùù÷ññïßßݼ¼º‰‰‡PPNþþþÿ$#\=*ÿ)þGþaþwþ‚þwþfþXþPþEþ$þ þþù-2!eBÿéþõþü- ;( kHÿGþ ?) oJÿGþB, nHÿ?ÿþþÿ @* iDÿ]=( b@þþûÛ- 8& [:ûþgÛ€€€€€ÿ€þ‚€€€€$$&þ  3# V7_æÇwÙ¢î²ô¼ ñ¿ î¹ á­µ„B+ 1 º”îÀíÂî ðÀ äµ!ÛÏ—ýþÿ6Ûºi򣓡 ô»ï» ç±ݦ À‹eC   þÿþ$šqÝ­ê¼ é» íº ô½ êµÞЖýþü_Ô³aØ ï²ñ·ì· å®Û¢Á‹ ˜m?'   +ŽcÏ™ ä± æ· ê·îµ ô· å¬ÝÍŽþþü_Ó°_Ù¡ê¬ ï´é³ ä« Ú ÇŽ¯| Že;"   [: Ÿoȑء â¯é· ì· ó¸ ö¹ç°ßΔýþÿ_ѯaÚ¡é¬ ë° è±äª Ý¢Ε»…®{ŸrtP K18%.+5"N3wVœr°|Š Ö Þ©ä°í¶ ó» õ¹ô» ë¹êÙ—ýüú_ЮdÓšã§ è¯ é³å¬ á¥ÔšÅŽ ¾„ »} µz ªx  vŸv¢w¥x ©z¬| ·‚ÆŒ Ô˜ âªè³ ï¹ õº ôº õ»ó¼ð¾Õ¶AÿüÙ_˨bјá¥ ç¯ ç³ç® ä©ÙŸ Ï—ÉŽƆ Å… Á„ ¼€¼ ¾ Á‚ Æ Ä襅 â¦í±ñ¸óº ÷º ô¼ó½ô¾ó¸æ¶ØÁb_Ƥ`ÈÜ å­ ç³ è¯ æ«ݤ Ø› Ò• Í“ÇÈ‘ÉÇŒ ÆŒ É Ë‘ Ô• Üžá©é´ ó½ø½ø½ø»ô¾ó¿ ô¾ö¶ ô´Ü®_À¡]‹Õš á¨ ç° ê° ì¯ â¨Þ¤ ØÔšÓš Ñ—Ï–Ï— ЗÓ˜ØœÜ¡ã¨ ç® ï¸ õ½ ô½ õ½ õ½ô¾ õ¾ õ¾ ô» ò¸ìµ_½Ÿ[»…Ó˜ à¦ å® ì± î² è¯ ä« á¦ Þ£ Û¡ Ú¡ ÙŸ Ú  Ù  Ü¢ ߤåª ç® íµ ó»õ½ ô½ õ¾ õ½õ¾ õ¾ õ¾ ó¼ ñ¹ ñ¹_º›W»…ДÞ£å­ î´ ñµ í´ ê² ç® ã©⨠㨠à¦à¦ã¨ ã© å« ç­ ì³ ï¶ ó»ô½ õ¾ õ¾õ½õ¾ õ¾ õ¾ õ¾ ô¼ òº _‡f#¸‚Ò– Þ£å® í³ ò· ð¸ ð· î´ ë° è­æ«å«å¬äªè¯é°ì´ î¶ òº ô¼õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ ô½ õ¾ ô¾ _sS·Д Þ£ä¬ ïµ õº òº òºò¸ð¶ ïµ í³ í³ í³ í³ íµ ï· ï· òº òº ô¼ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ _yYº„Ò– Þ¤ å® î´ ô¸ òº ó¼ô¼ó»òºó¹ó¹ó¹ó¹ò¹ ô¼ ó¼ ô½ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ _xX ¸‚ Ò– Ý¢ ä­ ðµ ô¹ òº ô½õ½õ½ õ½ õ½ ö½ ö½ ö½ õ½ ö¿ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½_~\¶ Ó— Þ¤ ç¯ ð¶ ô¹ ô¼ó¾ ó¿ ó¿ ô¾ õ¾ ö¾ ö¾ ö¾ ö¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ½õ½õ½õ½_†] ¶‚ Ñ™ ߥè® îµ ó» ô» ô¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ _‰_ ¶‚ Ñš à¦é® ï¶ ó¼ õ¼õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ õ¾ õ¾ õ¾ õ¾ _‰^ ³ Й â§ ê¯ ï¶ ô¼ õ½õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ½õ½õ¾ õ¾ õ¾ _‡\°|Ϙã¨ ë° ï¶ ó» ô¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½õ½õ½õ¾ õ¾ õ¾ õ¾ õ¾ _‰\±}Ϙã© ë° ð· ó» õ¼ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ö¾ õ¾ _ˆ[±| Ζâ§ ê¯ ñ¸ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ó» óº_Š\²} Ï– á¦ ê¯ ð· ó¼ õ½ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ô¼ð·ì³_Ž`´ Ζá¦ é¯ ð· ó¼ õ½ ö¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ õ¾ ô¼ ó» óº ô¼ ô½ò¼ ï¸ é± Þ¥ÙŸ _–e·€ Ì• ݤ è° ñ· ô» ô¼ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ö½ ø½ ø½ ö½õ¼ôºóµõ¶ó¸î¸è´ á¬ÕžË”¾‰_™g·€ Ê’ Û£ ç­î´ ö¼õ½ õ¾ õ¾ õ¾ ô½ õ¾ õ¾ õ¾ õ¾ õ¾ õ½ ö½ õ½ ó½ ï¹ î¶î³ï²ê¯㬠ڢ Д»‚º˜QçÞº_™g¶ ÇŽ ÙŸ åª ï´ óºõ¼ö½ö½ö½ö½ö½ö½ö½ö½ö½ô½ ô»ñ¸ëµ ç±ä¬㩠ঠÙÑ’ À†œs'æÛ¼þýøþþû_–c²{ ‰ Ô™ ߤë® ò·ó¹ ô» õ¼ ö½ö½ õ¼ ô» óº ò¹ ò¹ ñ·îµé¯ä© ⥠ܟ ך ΔŠ ©{!˸‰þüîüýùúýùûÿü_^¬t ¼ƒ Γ Ü  å© î³ñ·ò¹ óº ô» ô» ô» ò¹ ôºó¹ñ¶ë±æ¬ á¥ÞžØ” Ó‘Ç µ‚¶›Tãܺýýôþýúÿþ÷ýÿöúÿù_ˆW¥n ³{ ÄŠ Ô™ Ý  æª ë° ïµ ñ· ò¸ óº ó¹ ò¸ ñ¶ë± è­ ã¨Þ¤Ùš Ðƈ·ƒ ©(ɹŒÿüèÿÿòøþøùÿýþýþÿüýÿýüV€R›e«tºÊ Ö› ߤ äª è® ì³ ì³ ì³ î´ê°ç¬㨠ݡ ՚ϕ È‹º} ¨w–w$èß¼ÿû÷ýüûúþúùþýüþÿÿþÿÿýþÿýþ_|N–a¥o´{À…Ë‘ÖœÝ¢á§ á¨ ãª ä« ãª ß¥ ÛŸ Ö™Д È‹¼ ±yœj †`&äÚÆûýùùþüýýüýûüÿüýþýûþÿúýÿúûÿûÿýþþZüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ÿýüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]ýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ýÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_üþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ÿüúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ÿýåþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_åÚ•þþõþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÑ®-ðê±ýþ÷úýþþýþÿüÿüÿýûÿûüÿúþÿúÿþÿû=ÿýúÿýÿýýÿûüýþûüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüï³Í¡.ëã±ûþøúÿúÿýüÿúÿþþúûÿùÿýÿÿþýÿøûÿøþþ5ÿýüüÿùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ñ¶î®Ï+ñè·øÿïüÿöÿüýþþûüÿøþþüÿûÿÿýúþÿ÷ýþÿþþüýÿúýÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü/ï¹í¹ë¸Ù¬,òè³üþóùÿúüÿüûÿøüÿôÿüýÿûÿþþýüþÿýÿüþþýüþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü0ó¾ î¼ î¾ î¹ä°"ؼkþþßýý÷üüÿúÿúúýúýýÿüþþüÿýýÿûÿýûÿÿýÿþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ö¾ô½ õ¾÷¼ öºñºÔ«,ÚÉŒÿüïýüýúþúøþ÷ýÿúýÿúþÿùÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_õ¾ ø½÷½ ÷¼ú¼õº ð½æµ ǤCÿûâüýûûÿöþþûÿýüþÿúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü)ò¾ôÀ ö¾õ½ òÀ óÀ ÷½õ¸â²æÖ–þüýûþúÿýýÿüÿþþûþÿýýþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ð¿ñ¿ ù½ú»õ½ñ¿ ñ¼õ·ê¬ìÕ”üýúüþøþþûþýýÿýýûÿüüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü#ö½÷½ ö¾ô½ õºó¸ó¹è³ܪç×”üüúþýÿÿýþþýÿþÿýÿþýýþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü/ø½÷¾ó¿ ó½ô¹íµ è² ä§ Ò¥-ïê»ýÿýþüÿþþýüÿýþþýþþýüþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ö¾ õ¾ó¾îºìµåª Ý¡ Õ—äËŽþýóüÿüþûüþþøûÿûýÿüÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü!ó»öºó·íµâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_ñ·ïµé®㢠֖Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_è­Û¢ ҞŒʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü+љȒ³‡,îâ¿ýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü ¿¦_èä½ÿüçÿýùÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿüçÿýïþýùÿüÿþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_þý÷ÿüúþýÿüüþüþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüýýZþýýÿûüýýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüüÿüýÿýýÿüýÿúýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿúþÿúþÿùþÿøþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿÿýÿþZûþÿûþÿúþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü ýþþÿýÿÿýþÿýþÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþýþÿüÿüÿýûÿûüÿúþÿúÿþÿû=ÿýúÿýÿýýÿûüýþûüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüúÿúÿýüÿúÿþþúûÿùÿýÿÿþýÿøûÿøþþ5ÿýüüÿùüÿûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüøÿïüÿöÿüýþþûüÿøþþüÿûÿÿýúþÿ÷ýþÿþþüýÿúýÿýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ-üþþüþþüþþüòè³üþóùÿúüÿüûÿøüÿôÿüýÿûÿþþýüþÿýÿüþþýüþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ.üþþüþþüþþüä°"ؼkþþßýý÷üüÿúÿúúýúýýÿüþþüÿýýÿûÿýûÿÿýÿþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüöºñºÔ«,ÚÉŒÿüïýüýúþúøþ÷ýÿúýÿúþÿùÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüú¼õº ð½æµ ǤCÿûâüýûûÿöþþûÿýüþÿúþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ'üþþüþþüþþüòÀ óÀ ÷½õ¸â²æÖ–þüýûþúÿýýÿüÿþþûþÿýýþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüõ½ñ¿ ñ¼õ·ê¬ìÕ”üýúüþøþþûþýýÿýýûÿüüÿüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ!üþþüþþüþþüõºó¸ó¹è³ܪç×”üüúþýÿÿýþþýÿþÿýÿþýýþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ-üþþüþþüþþüô¹íµ è² ä§ Ò¥-ïê»ýÿýþüÿþþýüÿýþþýþþýüþ*üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüìµåª Ý¡ Õ—äËŽþýóüÿüþûüþþøûÿûýÿüÿþ÷ÿþùþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüÖ–Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ)üþþüþþüþþüýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüÿþÿüRþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþûþþüþþýþþüþþüþþüþþüþþýþþýþþüþþûþþùÿýôþýïÿý庮‰š…SvS„X ‹[ ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýÿþûýûýþúýüöþþòÿýìÜÕÀ­ž…ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýüøþþúýþûüþüúþüüýúýþùþý÷ÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüÿþüþýüýþýþýüúÿýùÿþùÿþPüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûýÿüýÿýýÿ÷þÿýþÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûþÿùþþøþÿøýÿùüÿùûÿùûÿùûÿúÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿýþÿüþÿýþÿýýÿþûþþûþþûýÿúÿþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþÿü ÿýüÿýüÿýýÿýþÿýþÿýþÿýÿÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþýþþýÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüÖ–Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ)üþþüþþüþþüýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüÿþÿüRþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_[‘]—bžg¢l§p«v²~º„ ¾ˆ Œȑ Í•Ó˜Ú Û› Õ— Ð’ ÈŠ ¾‚ ±x¢l‘]„TwJfAO5 + ghhåææýûü_{PcGoP{W „Y ‹Z—ae¥lªq®u²y ¶} ¹€ ½ƒ ¿†½…¹±y§ošdZ€PvHiBW9?*  ,*(åæåüýüþþüUþüôÿýñÛÕÀ« xQa@ pG€Q‹X[˜b œe  i £l £o ¡ožlj”aŽ\†V{NpEe=V9 F3…zgêçßýþÿüþþÿýþþû_ÿþùþýøÿÿúþüøÿüõÿû‰‡uQ`ApKzR ƒV‡WŠY‹ZŠYŠXˆU…S~NwKnH`?W9@/«¥‘ÿýôýýüûýþýþþýþúÿþúÿüýÿýûþÿúüÿûüÿýýÿþþ9üÿþ÷ÚÖÁ¦š|]H^A hEoFuIzK|KyHtDrG hCY<N6A- ª¤’ÿýöÿýÿü þÿûÿÿýÿýþÿúÿýú_þýþÿýþýÿýüÿýüÿþüÿýýÿúþÿ÷þþ÷þýôÿýï­¢„rVP5Z: a> c>a<_;X8 P5 F2\N6ºµ¥þüõüüûþþÿüýÿýþþýÿûþÿúÿþúýÿøýÿøýÿùþþýþýÿþýÿÿþýÿþúþþüýý@üûþþüýü÷ÿý𭣡–|M=>- >,^O6”ïìÜÿûõþýüýüüýüüýüýûûüþÿûþÿùþÿúþþüÿþÿþþ ÿþúÿþøÿþùÿþüûþGÿüüýûúýþûúþúùÿúùþùûþùýþùþþ÷þý÷ÿýöÿüõÿþöþþ÷üþüûýþþýûÿýûþüüþýýÿþúþÿùþÿúþþüÿþ]ýþþýþþüþþûþþûþþüþþüþþüþþüþþüþþüþþüýþüþþüþþüþþüþþüþþüþþüþþüþþûþþûþþüþþýþþüþþüþþüþþüþþüþþûþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüÖ–Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ)üþþüþþüþþüýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüÿþÿüRþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþþýþþýþþýþþýÿþÿý þýþþýþüüãâãÿ€ÿ‚|QD+N3ÿþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþÿü ýûýþûþýûýüþý ÿþþù¥‡G0ÿþNüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüýþýþýüýüùÿýÿüÿþüýøÕÑÁ>,ÿþEüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþÿýüûÿþûýþûúýüüýúÿýõ¥Žÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþýþÿûýÿúýÿûþþüÿþúÿýöÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþûÿþNüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþûýÿýþþ ÿþýÿþüþþüþþýÿþLüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþÿûþþüýýþÿÿ þýÿýûþþûýÿýÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþýþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüÖ–Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ)üþþüþþüþþüýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüÿþÿüRþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü_qG\ h¬t¶|¾† ÇŒΓј Ò™ Óš њљ͔Ȇº³{ ¨q’e¨“hÿýðüþüýþÿþþýþþüþþüþþüþþüþþüþþüþþü_e@S”a¤l­u³{ ¶~»‚Á…ćň Ĉ Á‡ »„ ³} ®x¨q™hƒ] ¦’hÿûïýüùüýûýþùþÿûþþüþþüþþüþþüþþüþþüþþü_U7pI‡X˜d£l©r ªt ­v²yµz·{ ¶y ´w ®u¥p l“c wS Žfþþñýþûüûüýûþþÿùýÿøþþüþþüþþüþþüþþüþþüþþü_A. V9mG…V“`œfŸj¢l£p¢o§q¦m¥lŸi “a‡YoJ šˆlþûõøþùúþúýüþþûþýýüýþûþþüþþüþþüþþüþþüþþüþþü>¢‰?/P4d?wL…WŽ^•b˜g –f”d”cŽ_‚X oK `A —ˆmÿüõþüýýþüýþýþþÿþûüþýþþüþþüþþüþþüþþüþþüþþüÿþ8öìêÛXK2G0 R6^>iEoHwLxMuKmHbCS;ƒv[ߨÌýüøûýùÿýýÿûÿÿÿýÿþüþþÿþùþÿùþþüþþüþþüþþüþþüþþüþþü_ýÿüþþúÿýöëèÛ›“}\N1?- F0I0 I0 E/ …vVž•}ÞÚÌþüøýýþúþýûþúüúúþüþÿþüüÿúüÿýÿþúþþúþþüþþüþþüþþüþþüþþüþþüúþûüýúüÿþQûýü÷ÿþöÿüöÿýôþýóþþ÷ýýøþþûýýúþþûýþúüþüüþûýþùüþúüþýüÿ÷ýÿôÿýýþýÿþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþýþþýþþüþþüþþüþþüþþûþþûþþüþþüþþüþþüþþüþþûþþüþþüþþûþþüþþüþþûþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüÖ–Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ)üþþüþþüþþüýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüÿþÿüRþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]ýþþýþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüÖ–Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ)üþþüþþüþþüýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüÿþÿüRþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüâ¦Û™Í” É«mÿúòþýÿýÿüÿÿýÿþ9øúÿûüÿýÿþ÷ÿÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüÖ–Á•+Óĉÿþìýÿüþÿúþþüþüÿÿýþûÿýýþÿÿýüþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüʧXìã½úÿîüÿöüþ÷þþøþþûýþþÿýþüÿýþþÿþýýþÿúþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ)üþþüþþüþþüýýôûü÷ÿýûþûþþüÿÿûÿþþûüÿ÷ÿþùþÿúþýþþ0úþÿøþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýÿþÿûþþûÿýþþEÿþþýþþûþþûþþüþþüþþýþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿþþÿúþÿúÿÿýüþBüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüÿþÿüRþýþÿùþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüýÿûþÿøþÿùÿþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüýÿøþÿùþÿûÿýþþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþüþþüþþüþþüþÿùþÿúþþýüþEýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ]üþþüþþüþþüþþûþþýþþýþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüÿþ üþþüþþüþþüÿýþþNÿþþýþÿûþþûþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþüþþü ¤´š¯€B C D$ ¯E$0°( (Ù#ù/<9HYT+`Ùkêw „*JœÕ§à²³¾ÓÊóÖã¦î˜ú'Go*w6üAN9ZUfmr‰~¬ŠÆ–å¢ ± Ò ®  ‹ Ó  ” ò o (  … !     #    libimager-perl-1.004+dfsg.orig/TIFF/testimg/srgba32f.tif0000644000175000017500000000316412263740600022106 0ustar gregoagregoaII*~€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?   òú(1:4RÿÿÿÿÒö ÿÿÿÿÒö testimg/srgba32.tifCreated with The GIMPImageMagick 6.2.4 02/10/07 Q16 http://www.imagemagick.org n   òú(1:4RSvlibimager-perl-1.004+dfsg.orig/TIFF/testimg/srgbaa.tif0000644000175000017500000000107612031434614021732 0ustar gregoagregoaII*xCreated with The GIMPÖ@+ †Ö@+ †ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ8@(0(Rlibimager-perl-1.004+dfsg.orig/TIFF/testimg/comp4t.tif0000644000175000017500000000765212031434614021707 0ustar gregoagregoaII*  ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»÷»ûª÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üwñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñªñwñwñwñwñwñwñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ù»¸úˆùª¨úfùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñˆñfñ3ñ3ñ3ñ3ñ3ñ3ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ˆ‹ø»üˆfˆø»üf3hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üwñwñwñwñwñwñwñwñwñwñwñwñwñwñwòwuówuTôwuTDôwTD™õwUDÿ™öwuDIÿ™öwTIþ™÷wuDý™÷wTIý™øwuDü™øwTIü™øwTû™ùwuDû™ùwTIû™ùwTú™úwuDú™úwuIú™úwTIú™ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3þwüU&cû3wÿUüDfcü3UDDIþ™”Dcý3DIù™cþ3ö™‘cÿ3õ™‘c3ô™A3ó™fó™”ò™‘ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3cò3fò3có3‘có3”ó3™cô3™‘cô3™”ô3ÿ™ô3ÿ™‘cõ3ÿ™‘cõ3þ™õ33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üwúwTù™úwTù™ûwuDù™ûwuDù™ûwuIù™ûwuIù™ûwTIù™ûwTIù™ûwTø™ûwTø™ûwTø™ûwTø™ûwTø™ûwTø™ûwTø™ûwTIù™ûwTIù™ûwuIù™ûwuIù™ûwuDù™ûwuDù™úwTù™úwTù™úwTIú™úwuIú™úwuDú™ùwTú™ùwTIû™ùwuDû™øwTû™øwTIü™øwuDü™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™ñ™þ™õ3þ™cö3þ™‘cö3þ™‘cö3þ™‘cö3þ™‘ö3ý™ö3ý™ö3ý™ö3ý™ö3ý™ö3ý™ö3ý™ö3ý™ö3ý™ö3ý™ö3ý™ö3þ™‘ö3þ™‘cö3þ™‘cö3þ™‘cö3þ™cö3þ™õ3þ™õ3ÿ™‘cõ3ÿ™‘cõ3ÿ™ô3™”ô3™‘cô3™cô3”ó3‘có33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»§üw÷»ûªñ»ñ»÷wTIý™÷wuDý™öwTIþ™öwuDIÿ™õwUDÿ™ôwTD™ôwuTDówuTòwuñwñwñwñwñwñwñwñwñwñwñwñwñwñwñwñwñwñwñwñwñªñ»ñ»ñ™ò™‘ó™”ó™fô™A3õ™‘c3ö™‘cÿ3DIù™cþ3UDDIþ™”Dcý3wÿUüDfcü3þwüU&cû3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùw&ú3ùª¨úfù»¸úˆñ»có3fò3cò3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñ3ñfñˆñ»3hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3fˆø»üfˆ‹ø»üˆñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»3hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3fˆø»üfˆ‹ø»üˆñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»3hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3fˆø»üfˆ‹ø»üˆñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»3hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3fˆø»üfˆ‹ø»üˆñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»3hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3fˆø»üfˆ‹ø»üˆñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»ñ»3hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü33hø»ü3fˆø»üfˆ‹ø»üˆñ»þ––€rz(@0‚B C DâEF``––¿¿^^..ýýXXffHHøø ­­KKDD²²33žžøø••b¢BªjüªõµˆÈ’r( ] ¤  ì Y Æ 3 Z@`@hÀ’®kàÀÓ@Êà¶gÎGÛmmmmmlibimager-perl-1.004+dfsg.orig/TIFF/testimg/imager.tif0000644000175000017500000000055512031434614021740 0ustar gregoagregoaII*?ÿÿÿÿÿÿü?ÿÿÿÿÿÿü?ÿÿÿÿÿÿü9?„øOÀ8àÀ8ÃŽxçŒyÄ9çÌüÏÌøÌ9çÌüÏÌÌ9çÌüÏÌÌ9çÌüÏÌÿÌ9çÎxçŒyÌ9çÎàÌ9çÏ„øO‡ÌÿÿÿÿÿÏÿüÿÿÿÿçŸÿüÿÿÿÿàÿüÿÿÿÿøÿü>  JZˆ(Standard Inputconverted PNM filelibimager-perl-1.004+dfsg.orig/TIFF/testimg/comp8.bmp0000644000175000017500000001240212031434614021510 0ustar gregoagregoaBM6(––Ì  3f™Ìÿ333f3™3Ì3ÿ3f3fff™fÌfÿf™3™f™™™Ì™ÿ™Ì3ÌfÌ™ÌÌÌÿÌÿ3ÿfÿ™ÿÌÿÿÿ333f3™3Ì3ÿ333333f33™33Ì33ÿ33f33f3ff3™f3Ìf3ÿf3™33™3f™3™™3Ì™3ÿ™3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌ3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿ3f3fff™fÌfÿf3f33ff3f™3fÌ3fÿ3fff3fffff™ffÌffÿff™f3™ff™f™™fÌ™fÿ™fÌf3ÌffÌf™ÌfÌÌfÿÌfÿf3ÿffÿf™ÿfÌÿfÿÿf™3™f™™™Ì™ÿ™3™33™f3™™3™Ì3™ÿ3™f™3f™ff™™f™Ìf™ÿf™™™3™™f™™™™™Ì™™ÿ™™Ì™3Ì™fÌ™™Ì™ÌÌ™ÿÌ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿ™Ì3ÌfÌ™ÌÌÌÿÌ3Ì33Ìf3Ì™3ÌÌ3Ìÿ3ÌfÌ3fÌffÌ™fÌÌfÌÿfÌ™Ì3™Ìf™Ì™™ÌÌ™Ìÿ™ÌÌÌ3ÌÌfÌÌ™ÌÌÌÌÌÿÌÌÿÌ3ÿÌfÿÌ™ÿÌÌÿÌÿÿÌÿ3ÿfÿ™ÿÌÿÿÿ3ÿ33ÿf3ÿ™3ÿÌ3ÿÿ3ÿfÿ3fÿffÿ™fÿÌfÿÿfÿ™ÿ3™ÿf™ÿ™™ÿÌ™ÿÿ™ÿÌÿ3ÌÿfÌÿ™ÌÿÌÌÿÿÌÿÿÿ3ÿÿfÿÿ™ÿÿÌÿÿÿÿÿ––––––––––––––––––––––nm                       q  s ;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .;0 9 .1 ))))(/ -( L'L'L'L'--=.+(((K(Knm’m’m’m’nPU<<<B+ '((KKnn‘n‘‘´‘´‘´‘‘—–rxZZ<Ð+èè?äý-Íc‹@0Œ ÀЫ=Á\4Ÿ?Є<ÙBp´E ,M{ ÅÊmÂ0ûcÄ‘dCLlõE‘tZÌFœ}¢±¬U¿‘Ìw.‘ìÆR‰!ºÒ4‘#ªrT™%Â’t¡'¸”©)¡ˆröæK¼›:rÜÕ"ÁÎÔ¿7É372΋ðàN‹ÄðrPå m?Pý@%`fbç K“[×6½³…%0ªí¬Í:¢³¼ó=Ï¥!D?”ƒ)P •AyWSU=USÅ¡$d g€° y†˜4 ѵì9H?ó&ÌÎTµ1SSÑ@|5EREiHX%ÀŠ^õ³mÛVí²ƒa¢4g9ð€ XB@[×5Ý}FËÖu+XíÕ’!BT…e§jÚàq~t˜ˆU˜Äɇb~%‡&HJgžæÈvoƒg),u'°„]Eˆ]×yG^–íaÀv,ÉK¼7ÝúRT…±_j†Eî…aA ™'‰”o™dQ™¥iš^¥F`ˆg‰4iF¡œkœ&éRqãçïtdÙFUyÅW®a7ߢ¿;‰„ødQ’¥Nt—86v˜Ú&¤i¼ŸÁð\£©ê¥ù§­˜§HtìCp°%ye’†Õ—Âmò®fÇÙJm¶® ˜¦Ù¿é<']ÂõýŽ›Ã™Âi¤ün>cŸFh³WY^Ñ.åÛ]…ÏmÉá¹n…M¦b™‡Õu‡­Ù{¾¡©v¦×’ü(:Àp]='¨þàÿ„P…Ã=Çl÷Åçcê@çÐ[T;YcÁˆ4*ÅÐAéÀB8} !ûN€C«ø$¤QÑ€($ „AáP–â dˆ/¥©¡zv+‹Fc¸Ôv9GN Òb|¥+•k¢ Êo²ÑLÉœÖi7›Ng¹Ôöy?ŸPY&bÙž¬l5Ã7Ðü6 ‚¤PµR­U¬UëUšån½]®<€ÎGC%X»GBmP»e®Ým¸[á°øŒNAwÞ/W”éy<åQ¡Édºa2 bhX¼V7:¢Q© ':•öÖªuüåƒ;ŸÏ¬VK5¢ß§¸êu¸5Î!Š_/{=”†F P¥U$ÁM‡/˜ãñÜ>‰C¢³Ãͤ³¨Ü]ªZ¦‡«WÑÙlöWwYßï 5×]ŽÓ͵H䯵*‘`P_¶Øü?íõüM¨„Ö’i¾8žÆh¨:n´ ëÀíÆí4Ï ÁÁÈSÆØ<ð«ÐޝÌ´VEÙþbž&Sï¿1+Œ"Á‰ª Æ9ôÌ3PDe»[JîBÌ"ÖBk´/ <í»rÝ·­ûI4”Ÿ2.S˜ç:’§J‘›³ÇRÌvÔǯ,/¼ëñ¦Q–Åyâ_>O¤“5ÉsjfýšAqÀqžã ʳ˫+»rÔý-¡ˆs_Hù!…H^\‚QE7RdÙf°Ht›@£ÆtêÁ>A³ýE-Ë´-M ÓË3Í,E%HÖ¼á9N“´ñOW ÅAPíGRÐÕ:8ÉPÞf$CWÙ•Œ•&»š_ah!\ÛSI>×Öìÿ`XV :‘Ÿ þUœÅáÚcMVu›w¸j!~i‹‡X~‰m9=_‘­·PÛØ !p\U:ü1q˜`&Eá‡ÝÎ9¶h FìC5½û×u=à— ÏbXÖE•GâN"ŸZ‘ÕjZÖÍ=ŽàY«Áà·qDŸؽvUÙ^…•?Fa:jÇ%2èæWæiêåòdT2FCGiYVú&‡¯§Oä䟃P}é­Ÿ›m‹–§ g4.„–^¯o™‰â¸¾2Íãyœmnj<*Ùœj«ÆIc—M—½o9V[iÚ¶¿§px ͼ[} ¸ÐÙÙSžç÷o#ÈYÊ&¤é`vÓ*m|ç Ät ÙlP…åX@_:ïQÓåCÁ¦œE¡þ9õܼ­Ì×–Ûή›‡ öýÏwÞøþ…áxž7‘×Ï~gÎvžš9ê÷]ç}ìý•‡¹âøþOÁv>ÉÏKß2ùôzÿ_´ûU{ï{ÏÉå;Äý A|®Õý»‡ÒöüY° ø¿6ÕßÏo芿ÇÕ ’‚~ ‡ëUûøƒ†ÖAA Ñ,#€YOÁˆ Ü #މÒ4a׋Fi )MC8Jý!´(f°åý8¶LãâQ'îM—¹Xhga;5 €($ „AáP–â dˆ/¥©¡zv+‹Fc¸Ôv9/'ŒJE"Á˜Àd²LÉ\¶Y/—Lf9”Öi7›Ng¹Ôé¶Ð%7N/d0%P"…©4ºU6™O§TjÈèd«hèMv_¯Xl;6‰ÇãÖ»U¶:pN¡”NÕcÅ|ÛcÏg—»Õöù¿_‰­!s€rü5AZKÈTjµzÍnÅ—²fs¸5š!Š[4Ví$t¡z*_ ²ó¾ËÀà6[¦ÎþÒf'ZŒç#hºdxXþ%R­X­W3\¼ç7˜€ÏZ4:^¦ŽÖPU ˆñem|[o–öDg ZégRø-pþ\^&O‘–çó¿_˜WG@êÀ²0¤i*N”¼ÐKÉÁIú‚¡¨ª;ç ¾ŠcìʹOÜ4þ3òÓD *¸ þUœÅáÚ×6d]F Ûp_šbáÆV¢@Å‘ëé ¹0Ü…30ó§É«°í;ŽóÁÊ|¤—=SØ÷>ô´ú¸ðć/ȈbÏÃñ’ë$&™F[ë²ð×Ê3Œ¦Û7  qžã  B³ì· ?"HÓ5 Ñ. ;R— ‘‹'Îs•$ó™Å¬-óOÔì)@C3 EAг=·M3\Ú»˜ó…#WÒi´êÂÄõ>KuË%.È5}0Tµ=LµÑ% *T»‚™†™UucXUíÁlgƒÆÓØ74ÛO[AAÜåƒaØI}”©( _ÍñmåxÁu™4o¨fhTåu©¸ Ñȳ¥ƒeA:ÓØöM—fâX¦&½ZV¥¬u[ÖAä5åèîLÿàùMÍt …h8]&%™gfZŠuš•†Áds”§Ý÷~ç™E ì .‡2è»*9„“àqJÅ^™§fž¤—ê†Á¨sgÐ~ã˜õÿ¿àõC’pîÇ#èÛ1;´m[fݦéùŽå(ó½ï¶Þ»ÀWl¥{Âô ïÄôœY;…q¥v—e/¡Éâ¦cÐÁÚº¿/¾c¼×9ÍÂÜCߺÒ£aK¤»˜x:cr=ƒkš™®.ök<ÇsÞwlv¿àd˜/‡ïø½9>v:Kvu†?]ÉnzŸdgv†Õî¡ÛÌûÈ-íì?ê ÷ž#ß.„Ó°ÅÔwp¿ãÖ·ÚLÍó@èkŒQÀ{Ë8¿?§6ÿã@€‚>ù:lQ$h DVFKëNPDg¢t aÐ+èè?äý-Íc‹@0Œ ÀЫ=Á\4Ÿ?Є<ÙBp´E ,M{ ÅÊmÂ0ûcÄ‘dCLlõE‘tZÌFœ}¢±¬U¿‘Ìw.‘ìÆR‰!ºÒ4‘#ªrT™%Â’t¡'¸”©)¡ˆröæK¼›:rÜÕ"ÁÎÔ¿7®„!dây$I’èœôMOsìù?ÏÔ AÐT- CÐÔMEÏdQH1@‰ÌtŸj-,RôÍ1MÓTí9OÓÕ AQÔUÈ|‰&ð$TÄdÁ8)ç‘Á;"5É)]W•Ý}^Øý…`Ø–bÙ=•] „àØV„fxvp(ö©Ñk[½µlۖݽnÜýÅpÜ5H$d‡døEU÷if•i:!÷©{_½õ|ß—Ýý~àþ€à˜ {XI˜ ¾T)8‰Y‰b˜ž-Šã¾5Œã˜Þ=Žãµ]ÓV„%ÝW‡WyYNHn\AeùŽa™æY®i›æÙÎqçYîyŸåå‘ Ɖ‘ª^”Gizn™§éÚŽ¡©êZ®©«êÚµ[uä¡i“ÖŰì›Ͳí>Õ´í›^ݶî~å¸î›žíºï¾õ¼ï›Þý¾ðÿÀðœ Âñ?ÄñœZ €€€($ „AáP˜d. ˆCâQ¤N-ŒEãQ˜än=GäR$ŽM%”IåR™d®]-˜KæS¤Îm5œMçS™äî}= OèT%E¤QéTše.M¨SêU¥N­U¬UëUšån½]°WìV%ŽÍe´YíV›e®Ým¸[îW¥Îíu¼]ïW›åîý}À_ðX&-––  êúÒº(Så*™íþ F[Standard Inputconverted PNM filelibimager-perl-1.004+dfsg.orig/TIFF/testimg/scmyk.tif0000644000175000017500000000076012031434614021620 0ustar gregoagregoaII*6Created with The GIMPÖ@+ †Ö@+ †ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ6&.(libimager-perl-1.004+dfsg.orig/TIFF/testimg/comp4bad.tif0000755000175000017500000000460212031434614022165 0ustar gregoagregoaII*Ô``––¿¿^^..ýýXXffHHøø ­­KKDD²²33žžøø••0PpÚJÙ~µFá~&¬|1œ¼ jp¥œ›‘›¨†p` ¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»Ù»¸éˆ‹ø»÷»ãª¨éfˆø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§éwüU&cê3hø»÷»§ëwÿUüDfcë3hø»÷»§íwuUÿDIþ™”Dcì3hø»÷»§îwuTDIù™cí3hø»÷»§ïwuTDö™‘cî3hø»÷»§ïwTDô™‘cï3hø»÷»§ðwUDò™Aï3hø»÷»§ñwuDIñ™fð3hø»÷»§ñwTIð™”cñ3hø»÷»§òwuDfñ3hø»÷»§òwTIí™cò3hø»÷»§ówuD왑cò3hø»÷»§ówTIì™”ò3hø»÷»§ówTê™có3hø»÷»§ôwuDꙑcó3hø»÷»§ôwTIê™”ó3hø»÷»§ôwTè™ó3hø»÷»§õwuD虑cô3hø»÷»§õwuI虑cô3hø»÷»§õwTIç™ô3hø»÷»§õwTæ™ô3hø»÷»§õwTæ™cõ3hø»÷»§öwuD晑cõ3hø»÷»§öwuD晑cõ3hø»÷»§öwuI晑cõ3hø»÷»§öwuI晑õ3hø»÷»§öwTIå™õ3hø»÷»§öwTIå™õ3hø»÷»§öwTä™õ3hø»÷»§öwTä™õ3hø»÷»§öwTä™õ3hø»÷»§öwTä™õ3hø»÷»§öwTä™õ3hø»÷»§öwTä™õ3hø»÷»§öwTä™õ3hø»÷»§öwTIå™õ3hø»÷»§öwTIå™õ3hø»÷»§öwuI晑õ3hø»÷»§öwuI晑cõ3hø»÷»§öwuD晑cõ3hø»÷»§öwuD晑cõ3hø»÷»§õwTæ™cõ3hø»÷»§õwTæ™ô3hø»÷»§õwTIç™ô3hø»÷»§õwuI虑cô3hø»÷»§õwuD虑cô3hø»÷»§ôwTè™ó3hø»÷»§ôwTIê™”ó3hø»÷»§ôwuDꙑcó3hø»÷»§ówTê™có3hø»÷»§ówTIì™”ò3hø»÷»§ówuD왑cò3hø»÷»§òwTIí™cò3hø»÷»§òwuDfñ3hø»÷»§ñwTIð™”cñ3hø»÷»§ñwuDIñ™fð3hø»÷»§ðwUDò™Aï3hø»÷»§ïwTDô™‘cï3hø»÷»§ïwuTDö™‘cî3hø»÷»§îwuTDIù™cí3hø»÷»§íwuUÿDIþ™”Dcì3hø»÷»§ëwÿUüDfcë3hø»÷»§éwüU&cê3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»§äw&é3hø»÷»ãª¨éfˆø»Ù»¸éˆ‹ø»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»¸»ÿ»þ––€xÄhp(@0libimager-perl-1.004+dfsg.orig/TIFF/testimg/srgba16.tif0000644000175000017500000000155612031434614021743 0ustar gregoagregoaII*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿò  ú€$,(1:4Rtestimg/srgba16.tifCreated with The GIMP ±X ±XImageMagick 6.2.4 02/10/07 Q16 http://www.imagemagick.orglibimager-perl-1.004+dfsg.orig/TIFF/testimg/scmykaa.tif0000644000175000017500000000120012031434614022110 0ustar gregoagregoaII*ºCreated with The GIMPÖ@+ †Ö@+ †ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ:€*2(Rlibimager-perl-1.004+dfsg.orig/TIFF/testimg/grey32.tif0000644000175000017500000036677612263740600021635 0ustar gregoagregoaII*tíýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿëVÏýÿÀnýÿk`« ýÿAJýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿ,eýÿAJýÿk`« ýÿÀnýÿëVÏýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿÀnýÿAJýÿB!&ýÿÃ*Þ0ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿƒ/L6ýÿÃ*Þ0ýÿB!&ýÿAJýÿÀnýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿÓ‡.ýÿx—‹ýÿöEýÿiÆ¢ýÿèÙ¤ýÿ9´È®ýÿ6À³ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿèÙ¤ýÿ9´È®ýÿ6À³ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿèÙ¤ýÿ7gD±ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿèÙ¤ýÿ7gD±ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿèÙ¤ýÿ7gD±ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿèÙ¤ýÿ7gD±ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿèÙ¤ýÿ9´È®ýÿ6À³ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿèÙ¤ýÿ9´È®ýÿ6À³ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿ¶óý´ýÿŠŽä¢ýÿ2ı~ýÿƒ/L6ýÿ,eýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿýýÿ 247; use Imager qw(:all); use Imager::Test qw(is_image is_image_similar test_image test_image_16 test_image_double test_image_raw); BEGIN { use_ok("Imager::File::TIFF"); } -d "testout" or mkdir "testout"; $|=1; # give us some progress in the test harness init_log("testout/t106tiff.log",1); my $green=i_color_new(0,255,0,255); my $blue=i_color_new(0,0,255,255); my $red=i_color_new(255,0,0,255); my $img=test_image_raw(); my $ver_string = Imager::File::TIFF::i_tiff_libversion(); ok(my ($full, $major, $minor, $point) = $ver_string =~ /Version +((\d+)\.(\d+).(\d+))/, "extract library version") or diag("Could not extract from:\n$ver_string"); diag("libtiff release $full") if $full; # make something we can compare my $cmp_ver = sprintf("%03d%03d%03d", $major, $minor, $point); if ($cmp_ver lt '003007000') { diag("You have an old version of libtiff - $full, some tests will be skipped"); } Imager::i_tags_add($img, "i_xres", 0, "300", 0); Imager::i_tags_add($img, "i_yres", 0, undef, 250); # resolutionunit is centimeters Imager::i_tags_add($img, "tiff_resolutionunit", 0, undef, 3); Imager::i_tags_add($img, "tiff_software", 0, "t106tiff.t", 0); open(FH,">testout/t106.tiff") || die "cannot open testout/t106.tiff for writing\n"; binmode(FH); my $IO = Imager::io_new_fd(fileno(FH)); ok(Imager::File::TIFF::i_writetiff_wiol($img, $IO), "write low level") or print "# ", Imager->_error_as_msg, "\n"; close(FH); open(FH,"testout/t106.tiff") or die "cannot open testout/t106.tiff\n"; binmode(FH); $IO = Imager::io_new_fd(fileno(FH)); my $cmpimg = Imager::File::TIFF::i_readtiff_wiol($IO); ok($cmpimg, "read low-level"); close(FH); print "# tiff average mean square pixel difference: ",sqrt(i_img_diff($img,$cmpimg))/150*150,"\n"; ok(!i_img_diff($img, $cmpimg), "compare written and read image"); # check the tags are ok my %tags = map { Imager::i_tags_get($cmpimg, $_) } 0 .. Imager::i_tags_count($cmpimg) - 1; ok(abs($tags{i_xres} - 300) < 0.5, "i_xres in range"); ok(abs($tags{i_yres} - 250) < 0.5, "i_yres in range"); is($tags{tiff_resolutionunit}, 3, "tiff_resolutionunit"); is($tags{tiff_software}, 't106tiff.t', "tiff_software"); is($tags{tiff_photometric}, 2, "tiff_photometric"); # PHOTOMETRIC_RGB is 2 is($tags{tiff_bitspersample}, 8, "tiff_bitspersample"); $IO = Imager::io_new_bufchain(); ok(Imager::File::TIFF::i_writetiff_wiol($img, $IO), "write to buffer chain"); my $tiffdata = Imager::io_slurp($IO); open(FH,"testout/t106.tiff"); binmode FH; my $odata; { local $/; $odata = ; } is($odata, $tiffdata, "same data in file as in memory"); # test Micksa's tiff writer # a shortish fax page my $faximg = Imager::ImgRaw::new(1728, 2000, 1); my $black = i_color_new(0,0,0,255); my $white = i_color_new(255,255,255,255); # vaguely test-patterny i_box_filled($faximg, 0, 0, 1728, 2000, $white); i_box_filled($faximg, 100,100,1628, 200, $black); my $width = 1; my $pos = 100; while ($width+$pos < 1628) { i_box_filled($faximg, $pos, 300, $pos+$width-1, 400, $black); $pos += $width + 20; $width += 2; } open FH, "> testout/t106tiff_fax.tiff" or die "Cannot create testout/t106tiff_fax.tiff: $!"; binmode FH; $IO = Imager::io_new_fd(fileno(FH)); ok(Imager::File::TIFF::i_writetiff_wiol_faxable($faximg, $IO, 1), "write faxable, low level"); close FH; # test the OO interface my $ooim = Imager->new; ok($ooim->read(file=>'testout/t106.tiff'), "read OO"); ok($ooim->write(file=>'testout/t106_oo.tiff'), "write OO"); # OO with the fax image my $oofim = Imager->new; ok($oofim->read(file=>'testout/t106tiff_fax.tiff'), "read fax OO"); # this should have tags set for the resolution %tags = map @$_, $oofim->tags; is($tags{i_xres}, 204, "fax i_xres"); is($tags{i_yres}, 196, "fax i_yres"); ok(!$tags{i_aspect_only}, "i_aspect_only"); # resunit_inches is($tags{tiff_resolutionunit}, 2, "tiff_resolutionunit"); is($tags{tiff_bitspersample}, 1, "tiff_bitspersample"); is($tags{tiff_photometric}, 0, "tiff_photometric"); ok($oofim->write(file=>'testout/t106_oo_fax.tiff', class=>'fax'), "write OO, faxable"); # the following should fail since there's no type and no filename my $oodata; ok(!$ooim->write(data=>\$oodata), "write with no type and no filename to guess with"); # OO to data ok($ooim->write(data=>\$oodata, type=>'tiff'), "write to data") or print "# ",$ooim->errstr, "\n"; is($oodata, $tiffdata, "check data matches between memory and file"); # make sure we can write non-fine mode ok($oofim->write(file=>'testout/t106_oo_faxlo.tiff', class=>'fax', fax_fine=>0), "write OO, fax standard mode"); # paletted reads my $img4 = Imager->new; ok($img4->read(file=>'testimg/comp4.tif'), "reading 4-bit paletted") or print "# ", $img4->errstr, "\n"; is($img4->type, 'paletted', "image isn't paletted"); print "# colors: ", $img4->colorcount,"\n"; cmp_ok($img4->colorcount, '<=', 16, "more than 16 colors!"); #ok($img4->write(file=>'testout/t106_was4.ppm'), # "Cannot write img4"); # I know I'm using BMP before it's test, but comp4.tif started life # as comp4.bmp my $bmp4 = Imager->new; ok($bmp4->read(file=>'testimg/comp4.bmp'), "reading 4-bit bmp!"); my $diff = i_img_diff($img4->{IMG}, $bmp4->{IMG}); print "# diff $diff\n"; ok($diff == 0, "image mismatch"); my $img4t = Imager->new; ok($img4t->read(file => 'testimg/comp4t.tif'), "read 4-bit paletted, tiled") or print "# ", $img4t->errstr, "\n"; is_image($bmp4, $img4t, "check tiled version matches"); my $img8 = Imager->new; ok($img8->read(file=>'testimg/comp8.tif'), "reading 8-bit paletted"); is($img8->type, 'paletted', "image isn't paletted"); print "# colors: ", $img8->colorcount,"\n"; #ok($img8->write(file=>'testout/t106_was8.ppm'), # "Cannot write img8"); ok($img8->colorcount == 256, "more colors than expected"); my $bmp8 = Imager->new; ok($bmp8->read(file=>'testimg/comp8.bmp'), "reading 8-bit bmp!"); $diff = i_img_diff($img8->{IMG}, $bmp8->{IMG}); print "# diff $diff\n"; ok($diff == 0, "image mismatch"); my $bad = Imager->new; ok($bad->read(file=>'testimg/comp4bad.tif', allow_incomplete=>1), "bad image not returned"); ok(scalar $bad->tags(name=>'i_incomplete'), "incomplete tag not set"); ok($img8->write(file=>'testout/t106_pal8.tif'), "writing 8-bit paletted"); my $cmp8 = Imager->new; ok($cmp8->read(file=>'testout/t106_pal8.tif'), "reading 8-bit paletted"); #print "# ",$cmp8->errstr,"\n"; is($cmp8->type, 'paletted', "pal8 isn't paletted"); is($cmp8->colorcount, 256, "pal8 bad colorcount"); $diff = i_img_diff($img8->{IMG}, $cmp8->{IMG}); print "# diff $diff\n"; ok($diff == 0, "written image doesn't match read"); ok($img4->write(file=>'testout/t106_pal4.tif'), "writing 4-bit paletted"); ok(my $cmp4 = Imager->new->read(file=>'testout/t106_pal4.tif'), "reading 4-bit paletted"); is($cmp4->type, 'paletted', "pal4 isn't paletted"); is($cmp4->colorcount, 16, "pal4 bad colorcount"); $diff = i_img_diff($img4->{IMG}, $cmp4->{IMG}); print "# diff $diff\n"; ok($diff == 0, "written image doesn't match read"); my $work; my $seekpos; sub io_writer { my ($what) = @_; if ($seekpos > length $work) { $work .= "\0" x ($seekpos - length $work); } substr($work, $seekpos, length $what) = $what; $seekpos += length $what; 1; } sub io_reader { my ($size, $maxread) = @_; print "# io_reader($size, $maxread) pos $seekpos\n"; if ($seekpos + $maxread > length $work) { $maxread = length($work) - $seekpos; } my $out = substr($work, $seekpos, $maxread); $seekpos += length $out; $out; } sub io_reader2 { my ($size, $maxread) = @_; print "# io_reader2($size, $maxread) pos $seekpos\n"; my $out = substr($work, $seekpos, $size); $seekpos += length $out; $out; } use IO::Seekable; sub io_seeker { my ($offset, $whence) = @_; print "# io_seeker($offset, $whence)\n"; if ($whence == SEEK_SET) { $seekpos = $offset; } elsif ($whence == SEEK_CUR) { $seekpos += $offset; } else { # SEEK_END $seekpos = length($work) + $offset; } #print "-> $seekpos\n"; $seekpos; } my $did_close; sub io_closer { ++$did_close; } # read via cb $work = $tiffdata; $seekpos = 0; my $IO2 = Imager::io_new_cb(undef, \&io_reader, \&io_seeker, undef); ok($IO2, "new readcb obj"); my $img5 = Imager::File::TIFF::i_readtiff_wiol($IO2); ok($img5, "read via cb"); ok(i_img_diff($img5, $img) == 0, "read from cb diff"); # read via cb2 $work = $tiffdata; $seekpos = 0; my $IO3 = Imager::io_new_cb(undef, \&io_reader2, \&io_seeker, undef); ok($IO3, "new readcb2 obj"); my $img6 = Imager::File::TIFF::i_readtiff_wiol($IO3); ok($img6, "read via cb2"); ok(i_img_diff($img6, $img) == 0, "read from cb2 diff"); # write via cb $work = ''; $seekpos = 0; my $IO4 = Imager::io_new_cb(\&io_writer, \&io_reader, \&io_seeker, \&io_closer); ok($IO4, "new writecb obj"); ok(Imager::File::TIFF::i_writetiff_wiol($img, $IO4), "write to cb"); is($work, $odata, "write cb match"); ok($did_close, "write cb did close"); open D1, ">testout/d1.tiff" or die; print D1 $work; close D1; open D2, ">testout/d2.tiff" or die; print D2 $tiffdata; close D2; # write via cb2 $work = ''; $seekpos = 0; $did_close = 0; my $IO5 = Imager::io_new_cb(\&io_writer, \&io_reader, \&io_seeker, \&io_closer, 1); ok($IO5, "new writecb obj 2"); ok(Imager::File::TIFF::i_writetiff_wiol($img, $IO5), "write to cb2"); is($work, $odata, "write cb2 match"); ok($did_close, "write cb2 did close"); open D3, ">testout/d3.tiff" or die; print D3 $work; close D3; { # check close failures are handled correctly { # single image my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; $work = ''; $seekpos = 0; ok(!$im->write(type => "tiff", readcb => \&io_reader, writecb => \&io_writer, seekcb => \&io_seeker, closecb => $fail_close), "check failing close fails"); like($im->errstr, qr/synthetic close failure/, "check error message"); } { # multiple images my $im = test_image(); my $fail_close = sub { Imager::i_push_error(0, "synthetic close failure"); return 0; }; $work = ''; $seekpos = 0; ok(!Imager->write_multi({type => "tiff", readcb => \&io_reader, writecb => \&io_writer, seekcb => \&io_seeker, closecb => $fail_close}, $im, $im), "check failing close fails"); like(Imager->errstr, qr/synthetic close failure/, "check error message"); } } # multi-image write/read my @imgs; push(@imgs, map $ooim->copy(), 1..3); for my $i (0..$#imgs) { $imgs[$i]->addtag(name=>"tiff_pagename", value=>"Page ".($i+1)); } my $rc = Imager->write_multi({file=>'testout/t106_multi.tif'}, @imgs); ok($rc, "writing multiple images to tiff"); my @out = Imager->read_multi(file=>'testout/t106_multi.tif'); ok(@out == @imgs, "reading multiple images from tiff"); @out == @imgs or print "# ",scalar @out, " ",Imager->errstr,"\n"; for my $i (0..$#imgs) { ok(i_img_diff($imgs[$i]{IMG}, $out[$i]{IMG}) == 0, "comparing image $i"); my ($tag) = $out[$i]->tags(name=>'tiff_pagename'); is($tag, "Page ".($i+1), "tag doesn't match original image"); } # writing even more images to tiff - we weren't handling more than five # correctly on read @imgs = map $ooim->copy(), 1..40; $rc = Imager->write_multi({file=>'testout/t106_multi2.tif'}, @imgs); ok($rc, "writing 40 images to tiff") or diag("writing 40 images: " . Imager->errstr); @out = Imager->read_multi(file=>'testout/t106_multi2.tif'); ok(@imgs == @out, "reading 40 images from tiff") or diag("reading 40 images:" . Imager->errstr); # force some allocation activity - helps crash here if it's the problem @out = @imgs = (); # multi-image fax files ok(Imager->write_multi({file=>'testout/t106_faxmulti.tiff', class=>'fax'}, $oofim, $oofim), "write multi fax image") or diag("writing 40 fax pages: " . Imager->errstr); @imgs = Imager->read_multi(file=>'testout/t106_faxmulti.tiff'); ok(@imgs == 2, "reading multipage fax") or diag("reading 40 fax pages: " . Imager->errstr); ok(Imager::i_img_diff($imgs[0]{IMG}, $oofim->{IMG}) == 0, "compare first fax image"); ok(Imager::i_img_diff($imgs[1]{IMG}, $oofim->{IMG}) == 0, "compare second fax image"); my ($format) = $imgs[0]->tags(name=>'i_format'); is($format, 'tiff', "check i_format tag"); my $unit = $imgs[0]->tags(name=>'tiff_resolutionunit'); ok(defined $unit && $unit == 2, "check tiff_resolutionunit tag"); my $unitname = $imgs[0]->tags(name=>'tiff_resolutionunit_name'); is($unitname, 'inch', "check tiff_resolutionunit_name tag"); my $warned = Imager->new; ok($warned->read(file=>"testimg/tiffwarn.tif"), "read tiffwarn.tif"); my ($warning) = $warned->tags(name=>'i_warning'); ok(defined $warning, "check warning is set"); like($warning, qr/[Uu]nknown field with tag 28712/, "check that warning tag correct"); { # support for reading a given page # first build a simple test image my $im1 = Imager->new(xsize=>50, ysize=>50); $im1->box(filled=>1, color=>$blue); $im1->addtag(name=>'tiff_pagename', value => "Page One"); my $im2 = Imager->new(xsize=>60, ysize=>60); $im2->box(filled=>1, color=>$green); $im2->addtag(name=>'tiff_pagename', value=>"Page Two"); # read second page my $page_file = 'testout/t106_pages.tif'; ok(Imager->write_multi({ file=> $page_file}, $im1, $im2), "build simple multiimage for page tests"); my $imwork = Imager->new; ok($imwork->read(file=>$page_file, page=>1), "read second page"); is($im2->getwidth, $imwork->getwidth, "check width"); is($im2->getwidth, $imwork->getheight, "check height"); is(i_img_diff($imwork->{IMG}, $im2->{IMG}), 0, "check image content"); my ($page_name) = $imwork->tags(name=>'tiff_pagename'); is($page_name, 'Page Two', "check tag we set"); # try an out of range page ok(!$imwork->read(file=>$page_file, page=>2), "check out of range page"); is($imwork->errstr, "could not switch to page 2", "check message"); } { # test writing returns an error message correctly # open a file read only and try to write to it open TIFF, "> testout/t106_empty.tif" or die; close TIFF; open TIFF, "< testout/t106_empty.tif" or skip "Cannot open testout/t106_empty.tif for reading", 8; binmode TIFF; my $im = Imager->new(xsize=>100, ysize=>100); ok(!$im->write(fh => \*TIFF, type=>'tiff', buffered => 0), "fail to write to read only handle"); cmp_ok($im->errstr, '=~', 'Could not create TIFF object: Error writing TIFF header: write\(\)', "check error message"); ok(!Imager->write_multi({ type => 'tiff', fh => \*TIFF, buffered => 0 }, $im), "fail to write multi to read only handle"); cmp_ok(Imager->errstr, '=~', 'Could not create TIFF object: Error writing TIFF header: write\(\)', "check error message"); ok(!$im->write(fh => \*TIFF, type=>'tiff', class=>'fax', buffered => 0), "fail to write to read only handle (fax)"); cmp_ok($im->errstr, '=~', 'Could not create TIFF object: Error writing TIFF header: write\(\)', "check error message"); ok(!Imager->write_multi({ type => 'tiff', fh => \*TIFF, class=>'fax', buffered => 0 }, $im), "fail to write multi to read only handle (fax)"); cmp_ok(Imager->errstr, '=~', 'Could not create TIFF object: Error writing TIFF header: write\(\)', "check error message"); } { # test reading returns an error correctly - use test script as an # invalid TIFF file my $im = Imager->new; ok(!$im->read(file=>'t/t10tiff.t', type=>'tiff'), "fail to read script as image"); # we get different magic number values depending on the platform # byte ordering cmp_ok($im->errstr, '=~', "Error opening file: Not a TIFF (?:or MDI )?file, bad magic number (8483 \\(0x2123\\)|8993 \\(0x2321\\))", "check error message"); my @ims = Imager->read_multi(file =>'t/t106tiff.t', type=>'tiff'); ok(!@ims, "fail to read_multi script as image"); cmp_ok($im->errstr, '=~', "Error opening file: Not a TIFF (?:or MDI )?file, bad magic number (8483 \\(0x2123\\)|8993 \\(0x2321\\))", "check error message"); } { # write_multi to data my $data; my $im = Imager->new(xsize => 50, ysize => 50); ok(Imager->write_multi({ data => \$data, type=>'tiff' }, $im, $im), "write multi to in memory"); ok(length $data, "make sure something written"); my @im = Imager->read_multi(data => $data); is(@im, 2, "make sure we can read it back"); is(Imager::i_img_diff($im[0]{IMG}, $im->{IMG}), 0, "check first image"); is(Imager::i_img_diff($im[1]{IMG}, $im->{IMG}), 0, "check second image"); } { # handling of an alpha channel for various images my $photo_rgb = 2; my $photo_cmyk = 5; my $photo_cielab = 8; my @alpha_images = ( [ 'srgb.tif', 3, $photo_rgb, '003005005' ], [ 'srgba.tif', 4, $photo_rgb, '003005005' ], [ 'srgbaa.tif', 4, $photo_rgb, '003005005' ], [ 'scmyk.tif', 3, $photo_cmyk, '003005005' ], [ 'scmyka.tif', 4, $photo_cmyk, '003005005' ], [ 'scmykaa.tif', 4, $photo_cmyk, '003005005' ], [ 'slab.tif', 3, $photo_cielab, '003006001' ], ); for my $test (@alpha_images) { my ($input, $channels, $photo, $need_ver) = @$test; SKIP: { my $skipped = $channels == 4 ? 4 : 3; $need_ver le $cmp_ver or skip("Your ancient tifflib is buggy/limited for this test", $skipped); my $im = Imager->new; ok($im->read(file => "testimg/$input"), "read alpha test $input") or print "# ", $im->errstr, "\n"; is($im->getchannels, $channels, "channels for $input match"); is($im->tags(name=>'tiff_photometric'), $photo, "photometric for $input match"); $channels == 4 or next; my $c = $im->getpixel(x => 0, 'y' => 7); is(($c->rgba)[3], 0, "bottom row should have 0 alpha"); } } } { ok(grep($_ eq 'tiff', Imager->read_types), "check tiff in read types"); ok(grep($_ eq 'tiff', Imager->write_types), "check tiff in write types"); } { # reading tile based images my $im = Imager->new; ok($im->read(file => 'testimg/pengtile.tif'), "read tiled image") or print "# ", $im->errstr, "\n"; # compare it my $comp = Imager->new; ok($comp->read(file => 'testimg/penguin-base.ppm'), 'read comparison image'); is_image($im, $comp, 'compare them'); } SKIP: { # failing to read tile based images # we grab our tiled image and patch a tile offset to nowhere ok(open(TIFF, '< testimg/pengtile.tif'), 'open pengtile.tif') or skip 'cannot open testimg/pengtile.tif', 4; $cmp_ver ge '003005007' or skip("Your ancient tifflib has bad error handling", 4); binmode TIFF; my $data = do { local $/; ; }; # patch a tile offset substr($data, 0x1AFA0, 4) = pack("H*", "00000200"); #open PIPE, "| bytedump -a | less" or die; #print PIPE $data; #close PIPE; my $allow = Imager->new; ok($allow->read(data => $data, allow_incomplete => 1), "read incomplete tiled"); ok($allow->tags(name => 'i_incomplete'), 'i_incomplete set'); is($allow->tags(name => 'i_lines_read'), 173, 'check i_lines_read set appropriately'); my $fail = Imager->new; ok(!$fail->read(data => $data), "read fail tiled"); } { # read 16-bit/sample my $im16 = Imager->new; ok($im16->read(file => 'testimg/rgb16.tif'), "read 16-bit rgb"); is($im16->bits, 16, 'got a 16-bit image'); my $im16t = Imager->new; ok($im16t->read(file => 'testimg/rgb16t.tif'), "read 16-bit rgb tiled"); is($im16t->bits, 16, 'got a 16-bit image'); is_image($im16, $im16t, 'check they match'); my $grey16 = Imager->new; ok($grey16->read(file => 'testimg/grey16.tif'), "read 16-bit grey") or print "# ", $grey16->errstr, "\n"; is($grey16->bits, 16, 'got a 16-bit image'); is($grey16->getchannels, 1, 'and its grey'); my $comp16 = $im16->convert(matrix => [ [ 0.299, 0.587, 0.114 ] ]); is_image($grey16, $comp16, 'compare grey to converted'); my $grey32 = Imager->new; ok($grey32->read(file => 'testimg/grey32.tif'), "read 32-bit grey") or print "# ", $grey32->errstr, "\n"; is($grey32->bits, 'double', 'got a double image'); is($grey32->getchannels, 2, 'and its grey + alpha'); is($grey32->tags(name => 'tiff_bitspersample'), 32, "check bits per sample"); my $base = test_image_double->convert(preset =>'grey') ->convert(preset => 'addalpha'); is_image($grey32, $base, 'compare to original'); } { # read 16, 32-bit/sample and compare to the original my $rgba = Imager->new; ok($rgba->read(file => 'testimg/srgba.tif'), "read base rgba image"); my $rgba16 = Imager->new; ok($rgba16->read(file => 'testimg/srgba16.tif'), "read 16-bit/sample rgba image"); is_image($rgba, $rgba16, "check they match"); is($rgba16->bits, 16, 'check we got the right type'); my $rgba32 = Imager->new; ok($rgba32->read(file => 'testimg/srgba32.tif'), "read 32-bit/sample rgba image"); is_image($rgba, $rgba32, "check they match"); is($rgba32->bits, 'double', 'check we got the right type'); my $cmyka16 = Imager->new; ok($cmyka16->read(file => 'testimg/scmyka16.tif'), "read cmyk 16-bit") or print "# ", $cmyka16->errstr, "\n"; is($cmyka16->bits, 16, "check we got the right type"); is_image_similar($rgba, $cmyka16, 10, "check image data"); # tiled, non-contig, should fallback to RGBA code my $rgbatsep = Imager->new; ok($rgbatsep->read(file => 'testimg/rgbatsep.tif'), "read tiled, separated rgba image") or diag($rgbatsep->errstr); is_image($rgba, $rgbatsep, "check they match"); } { # read bi-level my $pbm = Imager->new; ok($pbm->read(file => 'testimg/imager.pbm'), "read original pbm"); my $tif = Imager->new; ok($tif->read(file => 'testimg/imager.tif'), "read mono tif"); is_image($pbm, $tif, "compare them"); is($tif->type, 'paletted', 'check image type'); is($tif->colorcount, 2, 'check we got a "mono" image'); } { # check alpha channels scaled correctly for fallback handler my $im = Imager->new; ok($im->read(file=>'testimg/alpha.tif'), 'read alpha check image'); my @colors = ( [ 0, 0, 0 ], [ 255, 255, 255 ], [ 127, 0, 127 ], [ 127, 127, 0 ], ); my @alphas = ( 255, 191, 127, 63 ); my $ok = 1; my $msg = 'alpha check ok'; CHECKER: for my $y (0 .. 3) { for my $x (0 .. 3) { my $c = $im->getpixel(x => $x, 'y' => $y); my @c = $c->rgba; my $alpha = pop @c; if ($alpha != $alphas[$y]) { $ok = 0; $msg = "($x,$y) alpha mismatch $alpha vs $alphas[$y]"; last CHECKER; } my $expect = $colors[$x]; for my $ch (0 .. 2) { if (abs($expect->[$ch]-$c[$ch]) > 3) { $ok = 0; $msg = "($x,$y)[$ch] color mismatch got $c[$ch] vs expected $expect->[$ch]"; last CHECKER; } } } } ok($ok, $msg); } { # check alpha channels scaled correctly for greyscale my $im = Imager->new; ok($im->read(file=>'testimg/gralpha.tif'), 'read alpha check grey image'); my @greys = ( 0, 255, 52, 112 ); my @alphas = ( 255, 191, 127, 63 ); my $ok = 1; my $msg = 'alpha check ok'; CHECKER: for my $y (0 .. 3) { for my $x (0 .. 3) { my $c = $im->getpixel(x => $x, 'y' => $y); my ($grey, $alpha) = $c->rgba; if ($alpha != $alphas[$y]) { $ok = 0; $msg = "($x,$y) alpha mismatch $alpha vs $alphas[$y]"; last CHECKER; } if (abs($greys[$x] - $grey) > 3) { $ok = 0; $msg = "($x,$y) grey mismatch $grey vs $greys[$x]"; last CHECKER; } } } ok($ok, $msg); } { # 16-bit writes my $orig = test_image_16(); my $data; ok($orig->write(data => \$data, type => 'tiff', tiff_compression => 'none'), "write 16-bit/sample"); my $im = Imager->new; ok($im->read(data => $data), "read it back"); is_image($im, $orig, "check read data matches"); is($im->tags(name => 'tiff_bitspersample'), 16, "correct bits"); is($im->bits, 16, 'check image bits'); is($im->tags(name => 'tiff_photometric'), 2, "correct photometric"); is($im->tags(name => 'tiff_compression'), 'none', "no compression"); is($im->getchannels, 3, 'correct channels'); } { # 8-bit writes # and check compression my $compress = Imager::File::TIFF::i_tiff_has_compression('lzw') ? 'lzw' : 'packbits'; my $orig = test_image()->convert(preset=>'grey') ->convert(preset => 'addalpha'); my $data; ok($orig->write(data => \$data, type => 'tiff', tiff_compression=> $compress), "write 8 bit") or print "# ", $orig->errstr, "\n"; my $im = Imager->new; ok($im->read(data => $data), "read it back"); is_image($im, $orig, "check read data matches"); is($im->tags(name => 'tiff_bitspersample'), 8, 'correct bits'); is($im->bits, 8, 'check image bits'); is($im->tags(name => 'tiff_photometric'), 1, 'correct photometric'); is($im->tags(name => 'tiff_compression'), $compress, "$compress compression"); is($im->getchannels, 2, 'correct channels'); } { # double writes my $orig = test_image_double()->convert(preset=>'addalpha'); my $data; ok($orig->write(data => \$data, type => 'tiff', tiff_compression => 'none'), "write 32-bit/sample from double") or print "# ", $orig->errstr, "\n"; my $im = Imager->new; ok($im->read(data => $data), "read it back"); is_image($im, $orig, "check read data matches"); is($im->tags(name => 'tiff_bitspersample'), 32, "correct bits"); is($im->bits, 'double', 'check image bits'); is($im->tags(name => 'tiff_photometric'), 2, "correct photometric"); is($im->tags(name => 'tiff_compression'), 'none', "no compression"); is($im->getchannels, 4, 'correct channels'); } { # bilevel my $im = test_image()->convert(preset => 'grey') ->to_paletted(make_colors => 'mono', translate => 'errdiff'); my $faxdata; # fax compression is written as miniswhite ok($im->write(data => \$faxdata, type => 'tiff', tiff_compression => 'fax3'), "write bilevel fax compressed"); my $fax = Imager->new; ok($fax->read(data => $faxdata), "read it back"); ok($fax->is_bilevel, "got a bi-level image back"); is($fax->tags(name => 'tiff_compression'), 'fax3', "check fax compression used"); is_image($fax, $im, "compare to original"); # other compresion written as minisblack my $packdata; ok($im->write(data => \$packdata, type => 'tiff', tiff_compression => 'jpeg'), "write bilevel packbits compressed"); my $packim = Imager->new; ok($packim->read(data => $packdata), "read it back"); ok($packim->is_bilevel, "got a bi-level image back"); is($packim->tags(name => 'tiff_compression'), 'packbits', "check fallback compression used"); is_image($packim, $im, "compare to original"); } { # fallback handling of tiff is(Imager::File::TIFF::i_tiff_has_compression('none'), 1, "can always do uncompresed"); is(Imager::File::TIFF::i_tiff_has_compression('xxx'), '', "can't do xxx compression"); } { # check file limits are checked my $limit_file = "testout/t106.tiff"; ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149"); my $im = Imager->new; ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image width/, "check message"); ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); ok(!$im->read(file=>$limit_file), "should fail read due to size limits"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/image height/, "check message"); ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside width limit"); ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); ok($im->read(file=>$limit_file), "should succeed - just inside height limit"); # 150 x 150 x 3 channel image uses 67500 bytes ok(Imager->set_file_limits(reset=>1, bytes=>67499), "set bytes limit 67499"); ok(!$im->read(file=>$limit_file), "should fail - too many bytes"); print "# ",$im->errstr,"\n"; like($im->errstr, qr/storage size/, "check error message"); ok(Imager->set_file_limits(reset=>1, bytes=>67500), "set bytes limit 67500"); ok($im->read(file=>$limit_file), "should succeed - just inside bytes limit"); Imager->set_file_limits(reset=>1); } { # this image has an IFD loop, which sends some TIFF readers into a # loop, including Corel PhotoPaint and the GIMP's tiff reader. my $ifdloop_hex = <new; ok($im->read(data => $ifdloop, type => "tiff", page => 1), "read what should be valid"); ok(!$im->read(data => $ifdloop, type => "tiff", page => 2), "third page is after looping back to the start, if this fails, upgrade tifflib") or skip("tifflib is broken", 1); print "# ", $im->errstr, "\n"; my @im = Imager->read_multi(type => "tiff", data => $ifdloop); is(@im, 2, "should be only 2 images"); } SKIP: { # sample format Imager::File::TIFF::i_tiff_has_compression("lzw") or skip "No LZW support", 8; Imager::File::TIFF::i_tiff_ieeefp() or skip "No IEEE FP type", 8; SKIP: { # signed my $cmp = Imager->new(file => "testimg/grey16.tif", filetype => "tiff") or skip "Cannot read grey16.tif: ". Imager->errstr, 4; my $im = Imager->new(file => "testimg/grey16sg.tif", filetype => "tiff"); ok($im, "read image with SampleFormat = signed int") or skip "Couldn't read the file", 3; is_image($im, $cmp, "check the images match"); my %tags = map @$_, $im->tags; is($tags{tiff_sample_format}, 2, "check sample format"); is($tags{tiff_sample_format_name}, "int", "check sample format name"); } SKIP: { # float my $cmp = Imager->new(file => "testimg/srgba32.tif", filetype => "tiff") or skip "Cannot read srgaba32f.tif: ". Imager->errstr, 4; my $im = Imager->new(file => "testimg/srgba32f.tif", filetype => "tiff"); ok($im, "read image with SampleFormat = float") or skip "Couldn't read the file", 3; is_image($im, $cmp, "check the images match"); my %tags = map @$_, $im->tags; is($tags{tiff_sample_format}, 3, "check sample format"); is($tags{tiff_sample_format_name}, "ieeefp", "check sample format name"); } } libimager-perl-1.004+dfsg.orig/TIFF/Makefile.PL0000644000175000017500000000646712567572530020314 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Getopt::Long; use Config; my $verbose = $ENV{IM_VERBOSE}; my @libpaths; my @incpaths; GetOptions("incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$verbose); our $BUILDING_IMAGER; our %IMAGER_LIBS; my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; my $define = ""; my $fp_rep = unpack("H*", pack("f", 1.25)); if ($fp_rep eq "0000a03f" || $fp_rep eq "3fa00000") { $define = "-DIEEEFP_TYPES"; } my %opts = ( NAME => 'Imager::File::TIFF', VERSION_FROM => 'TIFF.pm', OBJECT => 'TIFF.o imtiff.o', DEFINE => $define, clean => { FILES => 'testout' }, ); my @inc; if ($BUILDING_IMAGER) { push @inc, "-I.."; unshift @INC, "../lib"; } else { unshift @INC, "inc"; print "TIFF: building independently\n"; require Imager::ExtUtils; push @inc, Imager::ExtUtils->includes; $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ]; # Imager required configure through use my @Imager_req = ( Imager => "0.94" ); if ($MM_ver >= 6.46) { $opts{META_MERGE} = { configure_requires => { @Imager_req, }, build_requires => { @Imager_req, "Test::More" => "0.47", }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; $opts{PREREQ_PM} = { @Imager_req, XSLoader => 0, }; } } require Imager::Probe; my %probe = ( name => "TIFF", inccheck => sub { -e File::Spec->catfile($_[0], "tiffio.h") }, libbase => "tiff", testcode => _tiff_test_code(), testcodeheaders => [ "tiffio.h", "stdio.h", "string.h" ], incpath => \@incpaths, libpath => \@libpaths, verbose => $verbose, ); my $probe_res = Imager::Probe->probe(\%probe); if ($probe_res) { $IMAGER_LIBS{TIFF} = 1; push @inc, $probe_res->{INC}; $opts{LIBS} = $probe_res->{LIBS}; $opts{DEFINE} .= " $probe_res->{DEFINE}"; $opts{INC} = "@inc"; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'TIFF image file support for Imager'; } WriteMakefile(%opts); } else { $IMAGER_LIBS{TIFF} = 0; if ($BUILDING_IMAGER) { ExtUtils::MakeMaker::WriteEmptyMakefile(%opts); } else { # fail in good way die "OS unsupported: TIFF libraries or headers not found\n"; } } sub _tiff_test_code { return <<'CODE'; static const char ver_base[] = ", Version "; static const size_t ver_base_len = sizeof(ver_base) - 1; const char *ver_str = TIFFGetVersion(); const char *ver_start = strstr(ver_str, ver_base); const char *ver_end; int ver_len; if (ver_start && ver_start[ver_base_len] >= '3' && ver_start[ver_base_len] < '9') { ver_start += ver_base_len; ver_end = ver_start; while (*ver_end && (*ver_end == '.' || *ver_end >= '0' && *ver_end <= '9')) ++ver_end; ver_len = ver_end - ver_start; } else { ver_start = "(unknown)"; ver_len = strlen(ver_start); } fprintf(stderr, "TIFF: library version %.*s, header version %ld\n", ver_len, ver_start, TIFFLIB_VERSION); if (TIFFLIB_VERSION == 20090820) { fprintf(stderr, "TIFF: this appears to be libtiff 3.9.0 which introduced a serious bug\n"); fprintf(stderr, "TIFF: please install 3.9.1\n"); return 1; } return 0; CODE } libimager-perl-1.004+dfsg.orig/TIFF/imtiff.c0000644000175000017500000022336112263740600017742 0ustar gregoagregoa#include #include #include "imtiff.h" #include "imext.h" /* needed to implement our substitute TIFFIsCODECConfigured */ #if TIFFLIB_VERSION < 20031121 static int TIFFIsCODECConfigured(uint16 scheme); #endif /* =head1 NAME tiff.c - implements reading and writing tiff files, uses io layer. =head1 SYNOPSIS io_glue *ig = io_new_fd( fd ); i_img *im = i_readtiff_wiol(ig, -1); // no limit on how much is read // or io_glue *ig = io_new_fd( fd ); return_code = i_writetiff_wiol(im, ig); =head1 DESCRIPTION tiff.c implements the basic functions to read and write tiff files. It uses the iolayer and needs either a seekable source or an entire memory mapped buffer. =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ #define byteswap_macro(x) \ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) #define CLAMP8(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x)) #define CLAMP16(x) ((x) < 0 ? 0 : (x) > 65535 ? 65535 : (x)) #define Sample16To8(num) ((num) / 257) struct tag_name { char *name; uint32 tag; }; static i_img *read_one_rgb_tiled(TIFF *tif, i_img_dim width, i_img_dim height, int allow_incomplete); static i_img *read_one_rgb_lines(TIFF *tif, i_img_dim width, i_img_dim height, int allow_incomplete); static struct tag_name text_tag_names[] = { { "tiff_documentname", TIFFTAG_DOCUMENTNAME, }, { "tiff_imagedescription", TIFFTAG_IMAGEDESCRIPTION, }, { "tiff_make", TIFFTAG_MAKE, }, { "tiff_model", TIFFTAG_MODEL, }, { "tiff_pagename", TIFFTAG_PAGENAME, }, { "tiff_software", TIFFTAG_SOFTWARE, }, { "tiff_datetime", TIFFTAG_DATETIME, }, { "tiff_artist", TIFFTAG_ARTIST, }, { "tiff_hostcomputer", TIFFTAG_HOSTCOMPUTER, }, }; static struct tag_name compress_values[] = { { "none", COMPRESSION_NONE }, { "ccittrle", COMPRESSION_CCITTRLE }, { "fax3", COMPRESSION_CCITTFAX3 }, { "t4", COMPRESSION_CCITTFAX3 }, { "fax4", COMPRESSION_CCITTFAX4 }, { "t6", COMPRESSION_CCITTFAX4 }, { "lzw", COMPRESSION_LZW }, { "jpeg", COMPRESSION_JPEG }, { "packbits", COMPRESSION_PACKBITS }, { "deflate", COMPRESSION_ADOBE_DEFLATE }, { "zip", COMPRESSION_ADOBE_DEFLATE }, { "oldzip", COMPRESSION_DEFLATE }, { "ccittrlew", COMPRESSION_CCITTRLEW }, }; static const int compress_value_count = sizeof(compress_values) / sizeof(*compress_values); static struct tag_name sample_format_values[] = { { "uint", SAMPLEFORMAT_UINT }, { "int", SAMPLEFORMAT_INT }, { "ieeefp", SAMPLEFORMAT_IEEEFP }, { "undefined", SAMPLEFORMAT_VOID }, }; static const int sample_format_value_count = sizeof(sample_format_values) / sizeof(*sample_format_values); static int myTIFFIsCODECConfigured(uint16 scheme); typedef struct read_state_tag read_state_t; /* the setup function creates the image object, allocates the line buffer */ typedef int (*read_setup_t)(read_state_t *state); /* the putter writes the image data provided by the getter to the image, x, y, width, height describe the target area of the image, extras is the extra number of pixels stored for each scanline in the raster buffer, (for tiles against the right side of the image) */ typedef int (*read_putter_t)(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int extras); /* reads from a tiled or strip image and calls the putter. This may need a second type for handling non-contiguous images at some point */ typedef int (*read_getter_t)(read_state_t *state, read_putter_t putter); struct read_state_tag { TIFF *tif; i_img *img; void *raster; i_img_dim pixels_read; int allow_incomplete; void *line_buf; uint32 width, height; uint16 bits_per_sample; uint16 photometric; /* the total number of channels (samples per pixel) */ int samples_per_pixel; /* if non-zero, which channel is the alpha channel, typically 3 for rgb */ int alpha_chan; /* whether or not to scale the color channels based on the alpha channel. TIFF has 2 types of alpha channel, if the alpha channel we use is EXTRASAMPLE_ASSOCALPHA then the color data will need to be scaled to match Imager's conventions */ int scale_alpha; /* number of color samples (not including alpha) */ int color_channels; /* SampleFormat is 2 */ int sample_signed; int sample_format; }; static int tile_contig_getter(read_state_t *state, read_putter_t putter); static int strip_contig_getter(read_state_t *state, read_putter_t putter); static int setup_paletted(read_state_t *state); static int paletted_putter8(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static int paletted_putter4(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static int setup_16_rgb(read_state_t *state); static int setup_16_grey(read_state_t *state); static int putter_16(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static int setup_8_rgb(read_state_t *state); static int setup_8_grey(read_state_t *state); static int putter_8(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static int setup_32_rgb(read_state_t *state); static int setup_32_grey(read_state_t *state); static int putter_32(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static int setup_bilevel(read_state_t *state); static int putter_bilevel(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static int setup_cmyk8(read_state_t *state); static int putter_cmyk8(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static int setup_cmyk16(read_state_t *state); static int putter_cmyk16(read_state_t *, i_img_dim, i_img_dim, i_img_dim, i_img_dim, int); static void rgb_channels(read_state_t *state, int *out_channels); static void grey_channels(read_state_t *state, int *out_channels); static void cmyk_channels(read_state_t *state, int *out_channels); static void fallback_rgb_channels(TIFF *tif, i_img_dim width, i_img_dim height, int *channels, int *alpha_chan); static const int text_tag_count = sizeof(text_tag_names) / sizeof(*text_tag_names); #if TIFFLIB_VERSION >= 20051230 #define USE_EXT_WARN_HANDLER #endif #define TIFFIO_MAGIC 0xC6A340CC static void error_handler(char const *module, char const *fmt, va_list ap) { mm_log((1, "tiff error fmt %s\n", fmt)); i_push_errorvf(0, fmt, ap); } typedef struct { unsigned magic; io_glue *ig; #ifdef USE_EXT_WARN_HANDLER char *warn_buffer; size_t warn_size; #endif } tiffio_context_t; static void tiffio_context_init(tiffio_context_t *c, io_glue *ig); static void tiffio_context_final(tiffio_context_t *c); #define WARN_BUFFER_LIMIT 10000 #ifdef USE_EXT_WARN_HANDLER static void warn_handler_ex(thandle_t h, const char *module, const char *fmt, va_list ap) { tiffio_context_t *c = (tiffio_context_t *)h; char buf[200]; if (c->magic != TIFFIO_MAGIC) return; buf[0] = '\0'; #ifdef IMAGER_VSNPRINTF vsnprintf(buf, sizeof(buf), fmt, ap); #else vsprintf(buf, fmt, ap); #endif mm_log((1, "tiff warning %s\n", buf)); if (!c->warn_buffer || strlen(c->warn_buffer)+strlen(buf)+2 > c->warn_size) { size_t new_size = c->warn_size + strlen(buf) + 2; char *old_buffer = c->warn_buffer; if (new_size > WARN_BUFFER_LIMIT) { new_size = WARN_BUFFER_LIMIT; } c->warn_buffer = myrealloc(c->warn_buffer, new_size); if (!old_buffer) c->warn_buffer[0] = '\0'; c->warn_size = new_size; } if (strlen(c->warn_buffer)+strlen(buf)+2 <= c->warn_size) { strcat(c->warn_buffer, buf); strcat(c->warn_buffer, "\n"); } } #else static char *warn_buffer = NULL; static int warn_buffer_size = 0; static void warn_handler(char const *module, char const *fmt, va_list ap) { char buf[1000]; buf[0] = '\0'; #ifdef IMAGER_VSNPRINTF vsnprintf(buf, sizeof(buf), fmt, ap); #else vsprintf(buf, fmt, ap); #endif mm_log((1, "tiff warning %s\n", buf)); if (!warn_buffer || strlen(warn_buffer)+strlen(buf)+2 > warn_buffer_size) { int new_size = warn_buffer_size + strlen(buf) + 2; char *old_buffer = warn_buffer; if (new_size > WARN_BUFFER_LIMIT) { new_size = WARN_BUFFER_LIMIT; } warn_buffer = myrealloc(warn_buffer, new_size); if (!old_buffer) *warn_buffer = '\0'; warn_buffer_size = new_size; } if (strlen(warn_buffer)+strlen(buf)+2 <= warn_buffer_size) { strcat(warn_buffer, buf); strcat(warn_buffer, "\n"); } } #endif static i_mutex_t mutex; void i_tiff_init(void) { mutex = i_mutex_new(); } static int save_tiff_tags(TIFF *tif, i_img *im); static void pack_4bit_to(unsigned char *dest, const unsigned char *src, i_img_dim count); static toff_t sizeproc(thandle_t x) { return 0; } /* =item comp_seek(h, o, w) Compatability for 64 bit systems like latest freebsd (internal) h - tiff handle, cast an io_glue object o - offset w - whence =cut */ static toff_t comp_seek(thandle_t h, toff_t o, int w) { io_glue *ig = ((tiffio_context_t *)h)->ig; return (toff_t) i_io_seek(ig, o, w); } /* =item comp_mmap(thandle_t, tdata_t*, toff_t*) Dummy mmap stub. This shouldn't ever be called but newer tifflibs want it anyway. =cut */ static int comp_mmap(thandle_t h, tdata_t*p, toff_t*off) { return -1; } /* =item comp_munmap(thandle_t h, tdata_t p, toff_t off) Dummy munmap stub. This shouldn't ever be called but newer tifflibs want it anyway. =cut */ static void comp_munmap(thandle_t h, tdata_t p, toff_t off) { /* do nothing */ } static tsize_t comp_read(thandle_t h, tdata_t p, tsize_t size) { return i_io_read(((tiffio_context_t *)h)->ig, p, size); } static tsize_t comp_write(thandle_t h, tdata_t p, tsize_t size) { return i_io_write(((tiffio_context_t *)h)->ig, p, size); } static int comp_close(thandle_t h) { return i_io_close(((tiffio_context_t *)h)->ig); } static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) { i_img *im; uint32 width, height; uint16 samples_per_pixel; int tiled; float xres, yres; uint16 resunit; int gotXres, gotYres; uint16 photometric; uint16 bits_per_sample; uint16 planar_config; uint16 inkset; uint16 compress; uint16 sample_format; int i; read_state_t state; read_setup_t setupf = NULL; read_getter_t getterf = NULL; read_putter_t putterf = NULL; int channels = MAXCHANNELS; size_t sample_size = ~0; /* force failure if some code doesn't set it */ i_img_dim total_pixels; int samples_integral; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); tiled = TIFFIsTiled(tif); TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planar_config); TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); if (samples_per_pixel == 0) { i_push_error(0, "invalid image: SamplesPerPixel is 0"); return NULL; } TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format); mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, samples_per_pixel)); mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not ")); mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not ")); total_pixels = width * height; memset(&state, 0, sizeof(state)); state.tif = tif; state.allow_incomplete = allow_incomplete; state.width = width; state.height = height; state.bits_per_sample = bits_per_sample; state.samples_per_pixel = samples_per_pixel; state.photometric = photometric; state.sample_signed = sample_format == SAMPLEFORMAT_INT; state.sample_format = sample_format; samples_integral = sample_format == SAMPLEFORMAT_UINT || sample_format == SAMPLEFORMAT_INT || sample_format == SAMPLEFORMAT_VOID; /* sample as UINT */ /* yes, this if() is horrible */ if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8 && samples_integral) { setupf = setup_paletted; if (bits_per_sample == 8) putterf = paletted_putter8; else if (bits_per_sample == 4) putterf = paletted_putter4; else mm_log((1, "unsupported paletted bits_per_sample %d\n", bits_per_sample)); sample_size = sizeof(i_sample_t); channels = 1; } else if (bits_per_sample == 16 && photometric == PHOTOMETRIC_RGB && samples_per_pixel >= 3 && samples_integral) { setupf = setup_16_rgb; putterf = putter_16; sample_size = 2; rgb_channels(&state, &channels); } else if (bits_per_sample == 16 && photometric == PHOTOMETRIC_MINISBLACK && samples_integral) { setupf = setup_16_grey; putterf = putter_16; sample_size = 2; grey_channels(&state, &channels); } else if (bits_per_sample == 8 && photometric == PHOTOMETRIC_MINISBLACK && samples_integral) { setupf = setup_8_grey; putterf = putter_8; sample_size = 1; grey_channels(&state, &channels); } else if (bits_per_sample == 8 && photometric == PHOTOMETRIC_RGB && samples_integral) { setupf = setup_8_rgb; putterf = putter_8; sample_size = 1; rgb_channels(&state, &channels); } else if (bits_per_sample == 32 && photometric == PHOTOMETRIC_RGB && samples_per_pixel >= 3) { setupf = setup_32_rgb; putterf = putter_32; sample_size = sizeof(i_fsample_t); rgb_channels(&state, &channels); } else if (bits_per_sample == 32 && photometric == PHOTOMETRIC_MINISBLACK) { setupf = setup_32_grey; putterf = putter_32; sample_size = sizeof(i_fsample_t); grey_channels(&state, &channels); } else if (bits_per_sample == 1 && (photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE) && samples_per_pixel == 1) { setupf = setup_bilevel; putterf = putter_bilevel; sample_size = sizeof(i_palidx); channels = 1; } else if (bits_per_sample == 8 && photometric == PHOTOMETRIC_SEPARATED && inkset == INKSET_CMYK && samples_per_pixel >= 4 && samples_integral) { setupf = setup_cmyk8; putterf = putter_cmyk8; sample_size = 1; cmyk_channels(&state, &channels); } else if (bits_per_sample == 16 && photometric == PHOTOMETRIC_SEPARATED && inkset == INKSET_CMYK && samples_per_pixel >= 4 && samples_integral) { setupf = setup_cmyk16; putterf = putter_cmyk16; sample_size = 2; cmyk_channels(&state, &channels); } else { int alpha; fallback_rgb_channels(tif, width, height, &channels, &alpha); sample_size = 1; } if (!i_int_check_image_file_limits(width, height, channels, sample_size)) { return NULL; } if (tiled) { if (planar_config == PLANARCONFIG_CONTIG) getterf = tile_contig_getter; } else { if (planar_config == PLANARCONFIG_CONTIG) getterf = strip_contig_getter; } if (setupf && getterf && putterf) { if (!setupf(&state)) return NULL; if (!getterf(&state, putterf) || !state.pixels_read) { if (state.img) i_img_destroy(state.img); if (state.raster) _TIFFfree(state.raster); if (state.line_buf) myfree(state.line_buf); return NULL; } if (allow_incomplete && state.pixels_read < total_pixels) { i_tags_setn(&(state.img->tags), "i_incomplete", 1); i_tags_setn(&(state.img->tags), "i_lines_read", state.pixels_read / width); } im = state.img; if (state.raster) _TIFFfree(state.raster); if (state.line_buf) myfree(state.line_buf); } else { if (tiled) { im = read_one_rgb_tiled(tif, width, height, allow_incomplete); } else { im = read_one_rgb_lines(tif, width, height, allow_incomplete); } } if (!im) return NULL; /* general metadata */ i_tags_setn(&im->tags, "tiff_bitspersample", bits_per_sample); i_tags_setn(&im->tags, "tiff_photometric", photometric); TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); /* resolution tags */ TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit); gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres); gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres); if (gotXres || gotYres) { if (!gotXres) xres = yres; else if (!gotYres) yres = xres; i_tags_setn(&im->tags, "tiff_resolutionunit", resunit); if (resunit == RESUNIT_CENTIMETER) { /* from dots per cm to dpi */ xres *= 2.54; yres *= 2.54; i_tags_set(&im->tags, "tiff_resolutionunit_name", "centimeter", -1); } else if (resunit == RESUNIT_NONE) { i_tags_setn(&im->tags, "i_aspect_only", 1); i_tags_set(&im->tags, "tiff_resolutionunit_name", "none", -1); } else if (resunit == RESUNIT_INCH) { i_tags_set(&im->tags, "tiff_resolutionunit_name", "inch", -1); } else { i_tags_set(&im->tags, "tiff_resolutionunit_name", "unknown", -1); } /* tifflib doesn't seem to provide a way to get to the original rational value of these, which would let me provide a more reasonable precision. So make up a number. */ i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6); i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6); } /* Text tags */ for (i = 0; i < text_tag_count; ++i) { char *data; if (TIFFGetField(tif, text_tag_names[i].tag, &data)) { mm_log((1, "i_readtiff_wiol: tag %d has value %s\n", text_tag_names[i].tag, data)); i_tags_set(&im->tags, text_tag_names[i].name, data, -1); } } i_tags_set(&im->tags, "i_format", "tiff", 4); #ifdef USE_EXT_WARN_HANDLER { tiffio_context_t *ctx = TIFFClientdata(tif); if (ctx->warn_buffer && ctx->warn_buffer[0]) { i_tags_set(&im->tags, "i_warning", ctx->warn_buffer, -1); ctx->warn_buffer[0] = '\0'; } } #else if (warn_buffer && *warn_buffer) { i_tags_set(&im->tags, "i_warning", warn_buffer, -1); *warn_buffer = '\0'; } #endif for (i = 0; i < compress_value_count; ++i) { if (compress_values[i].tag == compress) { i_tags_set(&im->tags, "tiff_compression", compress_values[i].name, -1); break; } } if (TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) { /* only set the tag if the the TIFF tag is present */ i_tags_setn(&im->tags, "tiff_sample_format", sample_format); for (i = 0; i < sample_format_value_count; ++i) { if (sample_format_values[i].tag == sample_format) { i_tags_set(&im->tags, "tiff_sample_format_name", sample_format_values[i].name, -1); break; } } } return im; } /* =item i_readtiff_wiol(ig, allow_incomplete, page) =cut */ i_img* i_readtiff_wiol(io_glue *ig, int allow_incomplete, int page) { TIFF* tif; TIFFErrorHandler old_handler; TIFFErrorHandler old_warn_handler; #ifdef USE_EXT_WARN_HANDLER TIFFErrorHandlerExt old_ext_warn_handler; #endif i_img *im; int current_page; tiffio_context_t ctx; i_mutex_lock(mutex); i_clear_error(); old_handler = TIFFSetErrorHandler(error_handler); #ifdef USE_EXT_WARN_HANDLER old_warn_handler = TIFFSetWarningHandler(NULL); old_ext_warn_handler = TIFFSetWarningHandlerExt(warn_handler_ex); #else old_warn_handler = TIFFSetWarningHandler(warn_handler); if (warn_buffer) *warn_buffer = '\0'; #endif /* Add code to get the filename info from the iolayer */ /* Also add code to check for mmapped code */ mm_log((1, "i_readtiff_wiol(ig %p, allow_incomplete %d, page %d)\n", ig, allow_incomplete, page)); tiffio_context_init(&ctx, ig); tif = TIFFClientOpen("(Iolayer)", "rm", (thandle_t) &ctx, comp_read, comp_write, comp_seek, comp_close, sizeproc, comp_mmap, comp_munmap); if (!tif) { mm_log((1, "i_readtiff_wiol: Unable to open tif file\n")); i_push_error(0, "Error opening file"); TIFFSetErrorHandler(old_handler); TIFFSetWarningHandler(old_warn_handler); #ifdef USE_EXT_WARN_HANDLER TIFFSetWarningHandlerExt(old_ext_warn_handler); #endif tiffio_context_final(&ctx); i_mutex_unlock(mutex); return NULL; } for (current_page = 0; current_page < page; ++current_page) { if (!TIFFReadDirectory(tif)) { mm_log((1, "i_readtiff_wiol: Unable to switch to directory %d\n", page)); i_push_errorf(0, "could not switch to page %d", page); TIFFSetErrorHandler(old_handler); TIFFSetWarningHandler(old_warn_handler); #ifdef USE_EXT_WARN_HANDLER TIFFSetWarningHandlerExt(old_ext_warn_handler); #endif TIFFClose(tif); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return NULL; } } im = read_one_tiff(tif, allow_incomplete); if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n")); TIFFSetErrorHandler(old_handler); TIFFSetWarningHandler(old_warn_handler); #ifdef USE_EXT_WARN_HANDLER TIFFSetWarningHandlerExt(old_ext_warn_handler); #endif TIFFClose(tif); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return im; } /* =item i_readtiff_multi_wiol(ig, *count) Reads multiple images from a TIFF. =cut */ i_img** i_readtiff_multi_wiol(io_glue *ig, int *count) { TIFF* tif; TIFFErrorHandler old_handler; TIFFErrorHandler old_warn_handler; #ifdef USE_EXT_WARN_HANDLER TIFFErrorHandlerExt old_ext_warn_handler; #endif i_img **results = NULL; int result_alloc = 0; tiffio_context_t ctx; i_mutex_lock(mutex); i_clear_error(); old_handler = TIFFSetErrorHandler(error_handler); #ifdef USE_EXT_WARN_HANDLER old_warn_handler = TIFFSetWarningHandler(NULL); old_ext_warn_handler = TIFFSetWarningHandlerExt(warn_handler_ex); #else old_warn_handler = TIFFSetWarningHandler(warn_handler); if (warn_buffer) *warn_buffer = '\0'; #endif tiffio_context_init(&ctx, ig); /* Add code to get the filename info from the iolayer */ /* Also add code to check for mmapped code */ mm_log((1, "i_readtiff_wiol(ig %p)\n", ig)); tif = TIFFClientOpen("(Iolayer)", "rm", (thandle_t) &ctx, comp_read, comp_write, comp_seek, comp_close, sizeproc, comp_mmap, comp_munmap); if (!tif) { mm_log((1, "i_readtiff_wiol: Unable to open tif file\n")); i_push_error(0, "Error opening file"); TIFFSetErrorHandler(old_handler); TIFFSetWarningHandler(old_warn_handler); #ifdef USE_EXT_WARN_HANDLER TIFFSetWarningHandlerExt(old_ext_warn_handler); #endif tiffio_context_final(&ctx); i_mutex_unlock(mutex); return NULL; } *count = 0; do { i_img *im = read_one_tiff(tif, 0); if (!im) break; if (++*count > result_alloc) { if (result_alloc == 0) { result_alloc = 5; results = mymalloc(result_alloc * sizeof(i_img *)); } else { i_img **newresults; result_alloc *= 2; newresults = myrealloc(results, result_alloc * sizeof(i_img *)); if (!newresults) { i_img_destroy(im); /* don't leak it */ break; } results = newresults; } } results[*count-1] = im; } while (TIFFReadDirectory(tif)); TIFFSetWarningHandler(old_warn_handler); TIFFSetErrorHandler(old_handler); #ifdef USE_EXT_WARN_HANDLER TIFFSetWarningHandlerExt(old_ext_warn_handler); #endif TIFFClose(tif); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return results; } undef_int i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) { uint32 width, height; unsigned char *linebuf = NULL; uint32 y; int rc; uint32 x; uint32 rowsperstrip; float vres = fine ? 196 : 98; int luma_chan; width = im->xsize; height = im->ysize; if (width != im->xsize || height != im->ysize) { i_push_error(0, "image too large for TIFF"); return 0; } switch (im->channels) { case 1: case 2: luma_chan = 0; break; case 3: case 4: luma_chan = 1; break; default: /* This means a colorspace we don't handle yet */ mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels)); return 0; } /* Add code to get the filename info from the iolayer */ /* Also add code to check for mmapped code */ mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels)); if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) ) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; } if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) ) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; } if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; } if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; } if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1) ) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; } if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; } if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; } if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; } linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) ); if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; } TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc); mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip)); mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%lu\n", (unsigned long)TIFFScanlineSize(tif) )); mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG)); if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; } if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; } if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0; } if (!save_tiff_tags(tif, im)) { return 0; } for (y=0; y8) bits=8; i_gsamp(im, x, x+8, y, luma, &luma_chan, 1); for(bitpos=0;bitpos>= 1; } linebufpos++; } if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) { mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n")); break; } } if (linebuf) _TIFFfree(linebuf); return 1; } static uint16 find_compression(char const *name, uint16 *compress) { int i; for (i = 0; i < compress_value_count; ++i) { if (strcmp(compress_values[i].name, name) == 0) { *compress = (uint16)compress_values[i].tag; return 1; } } *compress = COMPRESSION_NONE; return 0; } static uint16 get_compression(i_img *im, uint16 def_compress) { int entry; int value; if (i_tags_find(&im->tags, "tiff_compression", 0, &entry) && im->tags.tags[entry].data) { uint16 compress; if (find_compression(im->tags.tags[entry].data, &compress) && myTIFFIsCODECConfigured(compress)) return compress; } if (i_tags_get_int(&im->tags, "tiff_compression", 0, &value)) { if ((uint16)value == value && myTIFFIsCODECConfigured((uint16)value)) return (uint16)value; } return def_compress; } int i_tiff_has_compression(const char *name) { uint16 compress; if (!find_compression(name, &compress)) return 0; return myTIFFIsCODECConfigured(compress); } static int set_base_tags(TIFF *tif, i_img *im, uint16 compress, uint16 photometric, uint16 bits_per_sample, uint16 samples_per_pixel) { double xres, yres; int resunit; int got_xres, got_yres; int aspect_only; if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, im->xsize)) { i_push_error(0, "write TIFF: setting width tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, im->ysize)) { i_push_error(0, "write TIFF: setting length tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) { i_push_error(0, "write TIFF: setting orientation tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { i_push_error(0, "write TIFF: setting planar configuration tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) { i_push_error(0, "write TIFF: setting photometric tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, compress)) { i_push_error(0, "write TIFF: setting compression tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits_per_sample)) { i_push_error(0, "write TIFF: setting bits per sample tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel)) { i_push_error(0, "write TIFF: setting samples per pixel tag"); return 0; } got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres); got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres); if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only)) aspect_only = 0; if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit)) resunit = RESUNIT_INCH; if (got_xres || got_yres) { if (!got_xres) xres = yres; else if (!got_yres) yres = xres; if (aspect_only) { resunit = RESUNIT_NONE; } else { if (resunit == RESUNIT_CENTIMETER) { xres /= 2.54; yres /= 2.54; } else { resunit = RESUNIT_INCH; } } if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) { i_push_error(0, "write TIFF: setting xresolution tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) { i_push_error(0, "write TIFF: setting yresolution tag"); return 0; } if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) { i_push_error(0, "write TIFF: setting resolutionunit tag"); return 0; } } return 1; } static int write_one_bilevel(TIFF *tif, i_img *im, int zero_is_white) { uint16 compress = get_compression(im, COMPRESSION_PACKBITS); uint16 photometric; unsigned char *in_row; unsigned char *out_row; unsigned out_size; i_img_dim x, y; int invert; mm_log((1, "tiff - write_one_bilevel(tif %p, im %p, zero_is_white %d)\n", tif, im, zero_is_white)); /* ignore a silly choice */ if (compress == COMPRESSION_JPEG) compress = COMPRESSION_PACKBITS; switch (compress) { case COMPRESSION_CCITTRLE: case COMPRESSION_CCITTFAX3: case COMPRESSION_CCITTFAX4: /* natural fax photometric */ photometric = PHOTOMETRIC_MINISWHITE; break; default: /* natural for most computer images */ photometric = PHOTOMETRIC_MINISBLACK; break; } if (!set_base_tags(tif, im, compress, photometric, 1, 1)) return 0; if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) { i_push_error(0, "write TIFF: setting rows per strip tag"); return 0; } out_size = TIFFScanlineSize(tif); out_row = (unsigned char *)_TIFFmalloc( out_size ); in_row = mymalloc(im->xsize); invert = (photometric == PHOTOMETRIC_MINISWHITE) != (zero_is_white != 0); for (y = 0; y < im->ysize; ++y) { int mask = 0x80; unsigned char *outp = out_row; memset(out_row, 0, out_size); i_gpal(im, 0, im->xsize, y, in_row); for (x = 0; x < im->xsize; ++x) { if (invert ? !in_row[x] : in_row[x]) { *outp |= mask; } mask >>= 1; if (!mask) { ++outp; mask = 0x80; } } if (TIFFWriteScanline(tif, out_row, y, 0) < 0) { _TIFFfree(out_row); myfree(in_row); i_push_error(0, "write TIFF: write scan line failed"); return 0; } } _TIFFfree(out_row); myfree(in_row); return 1; } static int set_palette(TIFF *tif, i_img *im, int size) { int count; uint16 *colors; uint16 *out[3]; i_color c; int i, ch; colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size); out[0] = colors; out[1] = colors + size; out[2] = colors + 2 * size; count = i_colorcount(im); for (i = 0; i < count; ++i) { i_getcolors(im, i, &c, 1); for (ch = 0; ch < 3; ++ch) out[ch][i] = c.channel[ch] * 257; } for (; i < size; ++i) { for (ch = 0; ch < 3; ++ch) out[ch][i] = 0; } if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) { _TIFFfree(colors); i_push_error(0, "write TIFF: setting color map"); return 0; } _TIFFfree(colors); return 1; } static int write_one_paletted8(TIFF *tif, i_img *im) { uint16 compress = get_compression(im, COMPRESSION_PACKBITS); unsigned char *out_row; unsigned out_size; i_img_dim y; mm_log((1, "tiff - write_one_paletted8(tif %p, im %p)\n", tif, im)); /* ignore a silly choice */ if (compress == COMPRESSION_JPEG || compress == COMPRESSION_CCITTRLE || compress == COMPRESSION_CCITTFAX3 || compress == COMPRESSION_CCITTFAX4) compress = COMPRESSION_PACKBITS; if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) { i_push_error(0, "write TIFF: setting rows per strip tag"); return 0; } if (!set_base_tags(tif, im, compress, PHOTOMETRIC_PALETTE, 8, 1)) return 0; if (!set_palette(tif, im, 256)) return 0; out_size = TIFFScanlineSize(tif); out_row = (unsigned char *)_TIFFmalloc( out_size ); for (y = 0; y < im->ysize; ++y) { i_gpal(im, 0, im->xsize, y, out_row); if (TIFFWriteScanline(tif, out_row, y, 0) < 0) { _TIFFfree(out_row); i_push_error(0, "write TIFF: write scan line failed"); return 0; } } _TIFFfree(out_row); return 1; } static int write_one_paletted4(TIFF *tif, i_img *im) { uint16 compress = get_compression(im, COMPRESSION_PACKBITS); unsigned char *in_row; unsigned char *out_row; size_t out_size; i_img_dim y; mm_log((1, "tiff - write_one_paletted4(tif %p, im %p)\n", tif, im)); /* ignore a silly choice */ if (compress == COMPRESSION_JPEG || compress == COMPRESSION_CCITTRLE || compress == COMPRESSION_CCITTFAX3 || compress == COMPRESSION_CCITTFAX4) compress = COMPRESSION_PACKBITS; if (!set_base_tags(tif, im, compress, PHOTOMETRIC_PALETTE, 4, 1)) return 0; if (!set_palette(tif, im, 16)) return 0; if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) { i_push_error(0, "write TIFF: setting rows per strip tag"); return 0; } in_row = mymalloc(im->xsize); out_size = TIFFScanlineSize(tif); out_row = (unsigned char *)_TIFFmalloc( out_size ); for (y = 0; y < im->ysize; ++y) { i_gpal(im, 0, im->xsize, y, in_row); memset(out_row, 0, out_size); pack_4bit_to(out_row, in_row, im->xsize); if (TIFFWriteScanline(tif, out_row, y, 0) < 0) { _TIFFfree(out_row); i_push_error(0, "write TIFF: write scan line failed"); return 0; } } myfree(in_row); _TIFFfree(out_row); return 1; } static int set_direct_tags(TIFF *tif, i_img *im, uint16 compress, uint16 bits_per_sample) { uint16 extras = EXTRASAMPLE_ASSOCALPHA; uint16 extra_count = im->channels == 2 || im->channels == 4; uint16 photometric = im->channels >= 3 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK; if (!set_base_tags(tif, im, compress, photometric, bits_per_sample, im->channels)) { return 0; } if (extra_count) { if (!TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, extra_count, &extras)) { i_push_error(0, "write TIFF: setting extra samples tag"); return 0; } } if (compress == COMPRESSION_JPEG) { int jpeg_quality; if (i_tags_get_int(&im->tags, "tiff_jpegquality", 0, &jpeg_quality) && jpeg_quality >= 0 && jpeg_quality <= 100) { if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, jpeg_quality)) { i_push_error(0, "write TIFF: setting jpeg quality pseudo-tag"); return 0; } } } return 1; } static int write_one_32(TIFF *tif, i_img *im) { uint16 compress = get_compression(im, COMPRESSION_PACKBITS); unsigned *in_row; size_t out_size; uint32 *out_row; i_img_dim y; size_t sample_count = im->xsize * im->channels; size_t sample_index; mm_log((1, "tiff - write_one_32(tif %p, im %p)\n", tif, im)); /* only 8 and 12 bit samples are supported by jpeg compression */ if (compress == COMPRESSION_JPEG) compress = COMPRESSION_PACKBITS; if (!set_direct_tags(tif, im, compress, 32)) return 0; in_row = mymalloc(sample_count * sizeof(unsigned)); out_size = TIFFScanlineSize(tif); out_row = (uint32 *)_TIFFmalloc( out_size ); for (y = 0; y < im->ysize; ++y) { if (i_gsamp_bits(im, 0, im->xsize, y, in_row, NULL, im->channels, 32) <= 0) { i_push_error(0, "Cannot read 32-bit samples"); return 0; } for (sample_index = 0; sample_index < sample_count; ++sample_index) out_row[sample_index] = in_row[sample_index]; if (TIFFWriteScanline(tif, out_row, y, 0) < 0) { myfree(in_row); _TIFFfree(out_row); i_push_error(0, "write TIFF: write scan line failed"); return 0; } } myfree(in_row); _TIFFfree(out_row); return 1; } static int write_one_16(TIFF *tif, i_img *im) { uint16 compress = get_compression(im, COMPRESSION_PACKBITS); unsigned *in_row; size_t out_size; uint16 *out_row; i_img_dim y; size_t sample_count = im->xsize * im->channels; size_t sample_index; mm_log((1, "tiff - write_one_16(tif %p, im %p)\n", tif, im)); /* only 8 and 12 bit samples are supported by jpeg compression */ if (compress == COMPRESSION_JPEG) compress = COMPRESSION_PACKBITS; if (!set_direct_tags(tif, im, compress, 16)) return 0; in_row = mymalloc(sample_count * sizeof(unsigned)); out_size = TIFFScanlineSize(tif); out_row = (uint16 *)_TIFFmalloc( out_size ); for (y = 0; y < im->ysize; ++y) { if (i_gsamp_bits(im, 0, im->xsize, y, in_row, NULL, im->channels, 16) <= 0) { i_push_error(0, "Cannot read 16-bit samples"); return 0; } for (sample_index = 0; sample_index < sample_count; ++sample_index) out_row[sample_index] = in_row[sample_index]; if (TIFFWriteScanline(tif, out_row, y, 0) < 0) { myfree(in_row); _TIFFfree(out_row); i_push_error(0, "write TIFF: write scan line failed"); return 0; } } myfree(in_row); _TIFFfree(out_row); return 1; } static int write_one_8(TIFF *tif, i_img *im) { uint16 compress = get_compression(im, COMPRESSION_PACKBITS); size_t out_size; unsigned char *out_row; i_img_dim y; size_t sample_count = im->xsize * im->channels; mm_log((1, "tiff - write_one_8(tif %p, im %p)\n", tif, im)); if (!set_direct_tags(tif, im, compress, 8)) return 0; out_size = TIFFScanlineSize(tif); if (out_size < sample_count) out_size = sample_count; out_row = (unsigned char *)_TIFFmalloc( out_size ); for (y = 0; y < im->ysize; ++y) { if (i_gsamp(im, 0, im->xsize, y, out_row, NULL, im->channels) <= 0) { i_push_error(0, "Cannot read 8-bit samples"); return 0; } if (TIFFWriteScanline(tif, out_row, y, 0) < 0) { _TIFFfree(out_row); i_push_error(0, "write TIFF: write scan line failed"); return 0; } } _TIFFfree(out_row); return 1; } static int i_writetiff_low(TIFF *tif, i_img *im) { uint32 width, height; uint16 channels; int zero_is_white; width = im->xsize; height = im->ysize; channels = im->channels; if (width != im->xsize || height != im->ysize) { i_push_error(0, "image too large for TIFF"); return 0; } mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d, bits=%d\n", width, height, channels, im->bits)); if (im->type == i_palette_type) { mm_log((1, "i_writetiff_low: paletted, colors=%d\n", i_colorcount(im))); } if (i_img_is_monochrome(im, &zero_is_white)) { if (!write_one_bilevel(tif, im, zero_is_white)) return 0; } else if (im->type == i_palette_type) { if (i_colorcount(im) <= 16) { if (!write_one_paletted4(tif, im)) return 0; } else { if (!write_one_paletted8(tif, im)) return 0; } } else if (im->bits > 16) { if (!write_one_32(tif, im)) return 0; } else if (im->bits > 8) { if (!write_one_16(tif, im)) return 0; } else { if (!write_one_8(tif, im)) return 0; } if (!save_tiff_tags(tif, im)) return 0; return 1; } /* =item i_writetiff_multi_wiol(ig, imgs, count, fine_mode) Stores an image in the iolayer object. ig - io_object that defines source to write to imgs,count - the images to write =cut */ undef_int i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) { TIFF* tif; TIFFErrorHandler old_handler; int i; tiffio_context_t ctx; i_mutex_lock(mutex); old_handler = TIFFSetErrorHandler(error_handler); i_clear_error(); mm_log((1, "i_writetiff_multi_wiol(ig %p, imgs %p, count %d)\n", ig, imgs, count)); tiffio_context_init(&ctx, ig); tif = TIFFClientOpen("No name", "wm", (thandle_t) &ctx, comp_read, comp_write, comp_seek, comp_close, sizeproc, comp_mmap, comp_munmap); if (!tif) { mm_log((1, "i_writetiff_multi_wiol: Unable to open tif file for writing\n")); i_push_error(0, "Could not create TIFF object"); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } for (i = 0; i < count; ++i) { if (!i_writetiff_low(tif, imgs[i])) { TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } if (!TIFFWriteDirectory(tif)) { i_push_error(0, "Cannot write TIFF directory"); TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } } TIFFSetErrorHandler(old_handler); (void) TIFFClose(tif); tiffio_context_final(&ctx); i_mutex_unlock(mutex); if (i_io_close(ig)) return 0; return 1; } /* =item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode) Stores an image in the iolayer object. ig - io_object that defines source to write to imgs,count - the images to write fine_mode - select fine or normal mode fax images =cut */ undef_int i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) { TIFF* tif; int i; TIFFErrorHandler old_handler; tiffio_context_t ctx; i_mutex_lock(mutex); old_handler = TIFFSetErrorHandler(error_handler); i_clear_error(); mm_log((1, "i_writetiff_multi_wiol(ig %p, imgs %p, count %d)\n", ig, imgs, count)); tiffio_context_init(&ctx, ig); tif = TIFFClientOpen("No name", "wm", (thandle_t) &ctx, comp_read, comp_write, comp_seek, comp_close, sizeproc, comp_mmap, comp_munmap); if (!tif) { mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n")); i_push_error(0, "Could not create TIFF object"); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } for (i = 0; i < count; ++i) { if (!i_writetiff_low_faxable(tif, imgs[i], fine)) { TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } if (!TIFFWriteDirectory(tif)) { i_push_error(0, "Cannot write TIFF directory"); TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } } (void) TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); if (i_io_close(ig)) return 0; return 1; } /* =item i_writetiff_wiol(im, ig) Stores an image in the iolayer object. im - image object to write out ig - io_object that defines source to write to =cut */ undef_int i_writetiff_wiol(i_img *img, io_glue *ig) { TIFF* tif; TIFFErrorHandler old_handler; tiffio_context_t ctx; i_mutex_lock(mutex); old_handler = TIFFSetErrorHandler(error_handler); i_clear_error(); mm_log((1, "i_writetiff_wiol(img %p, ig %p)\n", img, ig)); tiffio_context_init(&ctx, ig); tif = TIFFClientOpen("No name", "wm", (thandle_t) &ctx, comp_read, comp_write, comp_seek, comp_close, sizeproc, comp_mmap, comp_munmap); if (!tif) { mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n")); i_push_error(0, "Could not create TIFF object"); tiffio_context_final(&ctx); TIFFSetErrorHandler(old_handler); i_mutex_unlock(mutex); return 0; } if (!i_writetiff_low(tif, img)) { TIFFClose(tif); tiffio_context_final(&ctx); TIFFSetErrorHandler(old_handler); i_mutex_unlock(mutex); return 0; } (void) TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); if (i_io_close(ig)) return 0; return 1; } /* =item i_writetiff_wiol_faxable(i_img *, io_glue *) Stores an image in the iolayer object in faxable tiff format. im - image object to write out ig - io_object that defines source to write to Note, this may be rewritten to use to simply be a call to a lower-level function that gives more options for writing tiff at some point. =cut */ undef_int i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) { TIFF* tif; TIFFErrorHandler old_handler; tiffio_context_t ctx; i_mutex_lock(mutex); old_handler = TIFFSetErrorHandler(error_handler); i_clear_error(); mm_log((1, "i_writetiff_wiol(img %p, ig %p)\n", im, ig)); tiffio_context_init(&ctx, ig); tif = TIFFClientOpen("No name", "wm", (thandle_t) &ctx, comp_read, comp_write, comp_seek, comp_close, sizeproc, comp_mmap, comp_munmap); if (!tif) { mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n")); i_push_error(0, "Could not create TIFF object"); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } if (!i_writetiff_low_faxable(tif, im, fine)) { TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); return 0; } (void) TIFFClose(tif); TIFFSetErrorHandler(old_handler); tiffio_context_final(&ctx); i_mutex_unlock(mutex); if (i_io_close(ig)) return 0; return 1; } static int save_tiff_tags(TIFF *tif, i_img *im) { int i; for (i = 0; i < text_tag_count; ++i) { int entry; if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) { if (!TIFFSetField(tif, text_tag_names[i].tag, im->tags.tags[entry].data)) { i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name); return 0; } } } return 1; } static void unpack_4bit_to(unsigned char *dest, const unsigned char *src, size_t src_byte_count) { while (src_byte_count > 0) { *dest++ = *src >> 4; *dest++ = *src++ & 0xf; --src_byte_count; } } static void pack_4bit_to(unsigned char *dest, const unsigned char *src, i_img_dim pixel_count) { int i = 0; while (i < pixel_count) { if ((i & 1) == 0) { *dest = *src++ << 4; } else { *dest++ |= *src++; } ++i; } } /* =item fallback_rgb_channels Calculate the number of output channels when we fallback to the RGBA family of functions. =cut */ static void fallback_rgb_channels(TIFF *tif, i_img_dim width, i_img_dim height, int *channels, int *alpha_chan) { uint16 photometric; uint16 in_channels; uint16 extra_count; uint16 *extras; TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &in_channels); TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric); switch (photometric) { case PHOTOMETRIC_SEPARATED: *channels = 3; break; case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: /* the TIFF RGBA functions expand single channel grey into RGB, so reduce it, we move the alpha channel into the right place if needed */ *channels = 1; break; default: *channels = 3; break; } /* TIFF images can have more than one alpha channel, but Imager can't this ignores the possibility of 2 channel images with 2 alpha, but there's not much I can do about that */ *alpha_chan = 0; if (TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, &extra_count, &extras) && extra_count) { *alpha_chan = (*channels)++; } } static i_img * make_rgb(TIFF *tif, i_img_dim width, i_img_dim height, int *alpha_chan) { int channels = 0; fallback_rgb_channels(tif, width, height, &channels, alpha_chan); return i_img_8_new(width, height, channels); } static i_img * read_one_rgb_lines(TIFF *tif, i_img_dim width, i_img_dim height, int allow_incomplete) { i_img *im; uint32* raster = NULL; uint32 rowsperstrip, row; i_color *line_buf; int alpha_chan; int rc; im = make_rgb(tif, width, height, &alpha_chan); if (!im) return NULL; rc = TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); mm_log((1, "i_readtiff_wiol: rowsperstrip=%d rc = %d\n", rowsperstrip, rc)); if (rc != 1 || rowsperstrip==-1) { rowsperstrip = height; } raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32)); if (!raster) { i_img_destroy(im); i_push_error(0, "No space for raster buffer"); return NULL; } line_buf = mymalloc(sizeof(i_color) * width); for( row = 0; row < height; row += rowsperstrip ) { uint32 newrows, i_row; if (!TIFFReadRGBAStrip(tif, row, raster)) { if (allow_incomplete) { i_tags_setn(&im->tags, "i_lines_read", row); i_tags_setn(&im->tags, "i_incomplete", 1); break; } else { i_push_error(0, "could not read TIFF image strip"); _TIFFfree(raster); i_img_destroy(im); return NULL; } } newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip; mm_log((1, "newrows=%d\n", newrows)); for( i_row = 0; i_row < newrows; i_row++ ) { uint32 x; i_color *outp = line_buf; for(x = 0; xrgba.r = TIFFGetR(temp); outp->rgba.g = TIFFGetG(temp); outp->rgba.b = TIFFGetB(temp); if (alpha_chan) { /* the libtiff RGBA code expands greyscale into RGBA, so put the alpha in the right place and scale it */ int ch; outp->channel[alpha_chan] = TIFFGetA(temp); if (outp->channel[alpha_chan]) { for (ch = 0; ch < alpha_chan; ++ch) { outp->channel[ch] = outp->channel[ch] * 255 / outp->channel[alpha_chan]; } } } outp++; } i_plin(im, 0, width, i_row+row, line_buf); } } myfree(line_buf); _TIFFfree(raster); return im; } /* adapted from libtiff libtiff's TIFFReadRGBATile succeeds even when asked to read an invalid tile, which means we have no way of knowing whether the data we received from it is valid or not. So the caller here has set stoponerror to 1 so that TIFFRGBAImageGet() will fail. read_one_rgb_tiled() then takes that into account for i_incomplete or failure. */ static int myTIFFReadRGBATile(TIFFRGBAImage *img, uint32 col, uint32 row, uint32 * raster) { int ok; uint32 tile_xsize, tile_ysize; uint32 read_xsize, read_ysize; uint32 i_row; /* * Verify that our request is legal - on a tile file, and on a * tile boundary. */ TIFFGetFieldDefaulted(img->tif, TIFFTAG_TILEWIDTH, &tile_xsize); TIFFGetFieldDefaulted(img->tif, TIFFTAG_TILELENGTH, &tile_ysize); if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 ) { i_push_errorf(0, "Row/col passed to myTIFFReadRGBATile() must be top" "left corner of a tile."); return 0; } /* * The TIFFRGBAImageGet() function doesn't allow us to get off the * edge of the image, even to fill an otherwise valid tile. So we * figure out how much we can read, and fix up the tile buffer to * a full tile configuration afterwards. */ if( row + tile_ysize > img->height ) read_ysize = img->height - row; else read_ysize = tile_ysize; if( col + tile_xsize > img->width ) read_xsize = img->width - col; else read_xsize = tile_xsize; /* * Read the chunk of imagery. */ img->row_offset = row; img->col_offset = col; ok = TIFFRGBAImageGet(img, raster, read_xsize, read_ysize ); /* * If our read was incomplete we will need to fix up the tile by * shifting the data around as if a full tile of data is being returned. * * This is all the more complicated because the image is organized in * bottom to top format. */ if( read_xsize == tile_xsize && read_ysize == tile_ysize ) return( ok ); for( i_row = 0; i_row < read_ysize; i_row++ ) { memmove( raster + (tile_ysize - i_row - 1) * tile_xsize, raster + (read_ysize - i_row - 1) * read_xsize, read_xsize * sizeof(uint32) ); _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize, 0, sizeof(uint32) * (tile_xsize - read_xsize) ); } for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) { _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize, 0, sizeof(uint32) * tile_xsize ); } return (ok); } static i_img * read_one_rgb_tiled(TIFF *tif, i_img_dim width, i_img_dim height, int allow_incomplete) { i_img *im; uint32* raster = NULL; int ok = 1; uint32 row, col; uint32 tile_width, tile_height; unsigned long pixels = 0; char emsg[1024] = ""; TIFFRGBAImage img; i_color *line; int alpha_chan; im = make_rgb(tif, width, height, &alpha_chan); if (!im) return NULL; if (!TIFFRGBAImageOK(tif, emsg) || !TIFFRGBAImageBegin(&img, tif, 1, emsg)) { i_push_error(0, emsg); i_img_destroy(im); return( 0 ); } TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width); TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height); mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height)); raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32)); if (!raster) { i_img_destroy(im); i_push_error(0, "No space for raster buffer"); TIFFRGBAImageEnd(&img); return NULL; } line = mymalloc(tile_width * sizeof(i_color)); for( row = 0; row < height; row += tile_height ) { for( col = 0; col < width; col += tile_width ) { /* Read the tile into an RGBA array */ if (myTIFFReadRGBATile(&img, col, row, raster)) { uint32 i_row, x; uint32 newrows = (row+tile_height > height) ? height-row : tile_height; uint32 newcols = (col+tile_width > width ) ? width-col : tile_width; mm_log((1, "i_readtiff_wiol: tile(%d, %d) newcols=%d newrows=%d\n", col, row, newcols, newrows)); for( i_row = 0; i_row < newrows; i_row++ ) { i_color *outp = line; for(x = 0; x < newcols; x++) { uint32 temp = raster[x+tile_width*(tile_height-i_row-1)]; outp->rgba.r = TIFFGetR(temp); outp->rgba.g = TIFFGetG(temp); outp->rgba.b = TIFFGetB(temp); outp->rgba.a = TIFFGetA(temp); if (alpha_chan) { /* the libtiff RGBA code expands greyscale into RGBA, so put the alpha in the right place and scale it */ int ch; outp->channel[alpha_chan] = TIFFGetA(temp); if (outp->channel[alpha_chan]) { for (ch = 0; ch < alpha_chan; ++ch) { outp->channel[ch] = outp->channel[ch] * 255 / outp->channel[alpha_chan]; } } } ++outp; } i_plin(im, col, col+newcols, row+i_row, line); } pixels += newrows * newcols; } else { if (allow_incomplete) { ok = 0; } else { goto error; } } } } if (!ok) { if (pixels == 0) { i_push_error(0, "TIFF: No image data could be read from the image"); goto error; } /* incomplete image */ i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", pixels / width); } myfree(line); TIFFRGBAImageEnd(&img); _TIFFfree(raster); return im; error: myfree(line); _TIFFfree(raster); TIFFRGBAImageEnd(&img); i_img_destroy(im); return NULL; } char const * i_tiff_libversion(void) { return TIFFGetVersion(); } static int setup_paletted(read_state_t *state) { uint16 *maps[3]; int i, ch; int color_count = 1 << state->bits_per_sample; state->img = i_img_pal_new(state->width, state->height, 3, 256); if (!state->img) return 0; /* setup the color map */ if (!TIFFGetField(state->tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) { i_push_error(0, "Cannot get colormap for paletted image"); i_img_destroy(state->img); return 0; } for (i = 0; i < color_count; ++i) { i_color c; for (ch = 0; ch < 3; ++ch) { c.channel[ch] = Sample16To8(maps[ch][i]); } i_addcolors(state->img, &c, 1); } return 1; } static int tile_contig_getter(read_state_t *state, read_putter_t putter) { uint32 tile_width, tile_height; uint32 this_tile_height, this_tile_width; uint32 rows_left, cols_left; uint32 x, y; state->raster = _TIFFmalloc(TIFFTileSize(state->tif)); if (!state->raster) { i_push_error(0, "tiff: Out of memory allocating tile buffer"); return 0; } TIFFGetField(state->tif, TIFFTAG_TILEWIDTH, &tile_width); TIFFGetField(state->tif, TIFFTAG_TILELENGTH, &tile_height); rows_left = state->height; for (y = 0; y < state->height; y += this_tile_height) { this_tile_height = rows_left > tile_height ? tile_height : rows_left; cols_left = state->width; for (x = 0; x < state->width; x += this_tile_width) { this_tile_width = cols_left > tile_width ? tile_width : cols_left; if (TIFFReadTile(state->tif, state->raster, x, y, 0, 0) < 0) { if (!state->allow_incomplete) { return 0; } } else { putter(state, x, y, this_tile_width, this_tile_height, tile_width - this_tile_width); } cols_left -= this_tile_width; } rows_left -= this_tile_height; } return 1; } static int strip_contig_getter(read_state_t *state, read_putter_t putter) { uint32 rows_per_strip; tsize_t strip_size = TIFFStripSize(state->tif); uint32 y, strip_rows, rows_left; state->raster = _TIFFmalloc(strip_size); if (!state->raster) { i_push_error(0, "tiff: Out of memory allocating strip buffer"); return 0; } TIFFGetFieldDefaulted(state->tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); rows_left = state->height; for (y = 0; y < state->height; y += strip_rows) { strip_rows = rows_left > rows_per_strip ? rows_per_strip : rows_left; if (TIFFReadEncodedStrip(state->tif, TIFFComputeStrip(state->tif, y, 0), state->raster, strip_size) < 0) { if (!state->allow_incomplete) return 0; } else { putter(state, 0, y, state->width, strip_rows, 0); } rows_left -= strip_rows; } return 1; } static int paletted_putter8(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int extras) { unsigned char *p = state->raster; state->pixels_read += width * height; while (height > 0) { i_ppal(state->img, x, x + width, y, p); p += width + extras; --height; ++y; } return 1; } static int paletted_putter4(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int extras) { uint32 img_line_size = (width + 1) / 2; uint32 skip_line_size = (width + extras + 1) / 2; unsigned char *p = state->raster; if (!state->line_buf) state->line_buf = mymalloc(state->width); state->pixels_read += width * height; while (height > 0) { unpack_4bit_to(state->line_buf, p, img_line_size); i_ppal(state->img, x, x + width, y, state->line_buf); p += skip_line_size; --height; ++y; } return 1; } static void rgb_channels(read_state_t *state, int *out_channels) { uint16 extra_count; uint16 *extras; /* safe defaults */ *out_channels = 3; state->alpha_chan = 0; state->scale_alpha = 0; state->color_channels = 3; /* plain RGB */ if (state->samples_per_pixel == 3) return; if (!TIFFGetField(state->tif, TIFFTAG_EXTRASAMPLES, &extra_count, &extras)) { mm_log((1, "tiff: samples != 3 but no extra samples tag\n")); return; } if (!extra_count) { mm_log((1, "tiff: samples != 3 but no extra samples listed")); return; } ++*out_channels; state->alpha_chan = 3; switch (*extras) { case EXTRASAMPLE_UNSPECIFIED: case EXTRASAMPLE_ASSOCALPHA: state->scale_alpha = 1; break; case EXTRASAMPLE_UNASSALPHA: state->scale_alpha = 0; break; default: mm_log((1, "tiff: unknown extra sample type %d, treating as assoc alpha\n", *extras)); state->scale_alpha = 1; break; } mm_log((1, "tiff alpha channel %d scale %d\n", state->alpha_chan, state->scale_alpha)); } static void grey_channels(read_state_t *state, int *out_channels) { uint16 extra_count; uint16 *extras; /* safe defaults */ *out_channels = 1; state->alpha_chan = 0; state->scale_alpha = 0; state->color_channels = 1; /* plain grey */ if (state->samples_per_pixel == 1) return; if (!TIFFGetField(state->tif, TIFFTAG_EXTRASAMPLES, &extra_count, &extras)) { mm_log((1, "tiff: samples != 1 but no extra samples tag\n")); return; } if (!extra_count) { mm_log((1, "tiff: samples != 1 but no extra samples listed")); return; } ++*out_channels; state->alpha_chan = 1; switch (*extras) { case EXTRASAMPLE_UNSPECIFIED: case EXTRASAMPLE_ASSOCALPHA: state->scale_alpha = 1; break; case EXTRASAMPLE_UNASSALPHA: state->scale_alpha = 0; break; default: mm_log((1, "tiff: unknown extra sample type %d, treating as assoc alpha\n", *extras)); state->scale_alpha = 1; break; } } static int setup_16_rgb(read_state_t *state) { int out_channels; rgb_channels(state, &out_channels); state->img = i_img_16_new(state->width, state->height, out_channels); if (!state->img) return 0; state->line_buf = mymalloc(sizeof(unsigned) * state->width * out_channels); return 1; } static int setup_16_grey(read_state_t *state) { int out_channels; grey_channels(state, &out_channels); state->img = i_img_16_new(state->width, state->height, out_channels); if (!state->img) return 0; state->line_buf = mymalloc(sizeof(unsigned) * state->width * out_channels); return 1; } static int putter_16(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int row_extras) { uint16 *p = state->raster; int out_chan = state->img->channels; state->pixels_read += width * height; while (height > 0) { i_img_dim i; int ch; unsigned *outp = state->line_buf; for (i = 0; i < width; ++i) { for (ch = 0; ch < out_chan; ++ch) { outp[ch] = p[ch]; } if (state->sample_signed) { for (ch = 0; ch < state->color_channels; ++ch) outp[ch] ^= 0x8000; } if (state->alpha_chan && state->scale_alpha && outp[state->alpha_chan]) { for (ch = 0; ch < state->alpha_chan; ++ch) { int result = 0.5 + (outp[ch] * 65535.0 / outp[state->alpha_chan]); outp[ch] = CLAMP16(result); } } p += state->samples_per_pixel; outp += out_chan; } i_psamp_bits(state->img, x, x + width, y, state->line_buf, NULL, out_chan, 16); p += row_extras * state->samples_per_pixel; --height; ++y; } return 1; } static int setup_8_rgb(read_state_t *state) { int out_channels; rgb_channels(state, &out_channels); state->img = i_img_8_new(state->width, state->height, out_channels); if (!state->img) return 0; state->line_buf = mymalloc(sizeof(unsigned) * state->width * out_channels); return 1; } static int setup_8_grey(read_state_t *state) { int out_channels; grey_channels(state, &out_channels); state->img = i_img_8_new(state->width, state->height, out_channels); if (!state->img) return 0; state->line_buf = mymalloc(sizeof(i_color) * state->width * out_channels); return 1; } static int putter_8(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int row_extras) { unsigned char *p = state->raster; int out_chan = state->img->channels; state->pixels_read += width * height; while (height > 0) { i_img_dim i; int ch; i_color *outp = state->line_buf; for (i = 0; i < width; ++i) { for (ch = 0; ch < out_chan; ++ch) { outp->channel[ch] = p[ch]; } if (state->sample_signed) { for (ch = 0; ch < state->color_channels; ++ch) outp->channel[ch] ^= 0x80; } if (state->alpha_chan && state->scale_alpha && outp->channel[state->alpha_chan]) { for (ch = 0; ch < state->alpha_chan; ++ch) { int result = (outp->channel[ch] * 255 + 127) / outp->channel[state->alpha_chan]; outp->channel[ch] = CLAMP8(result); } } p += state->samples_per_pixel; outp++; } i_plin(state->img, x, x + width, y, state->line_buf); p += row_extras * state->samples_per_pixel; --height; ++y; } return 1; } static int setup_32_rgb(read_state_t *state) { int out_channels; rgb_channels(state, &out_channels); state->img = i_img_double_new(state->width, state->height, out_channels); if (!state->img) return 0; state->line_buf = mymalloc(sizeof(i_fcolor) * state->width); return 1; } static int setup_32_grey(read_state_t *state) { int out_channels; grey_channels(state, &out_channels); state->img = i_img_double_new(state->width, state->height, out_channels); if (!state->img) return 0; state->line_buf = mymalloc(sizeof(i_fcolor) * state->width); return 1; } static int putter_32(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int row_extras) { uint32 *p = state->raster; int out_chan = state->img->channels; state->pixels_read += width * height; while (height > 0) { i_img_dim i; int ch; i_fcolor *outp = state->line_buf; for (i = 0; i < width; ++i) { #ifdef IEEEFP_TYPES if (state->sample_format == SAMPLEFORMAT_IEEEFP) { const float *pv = (const float *)p; for (ch = 0; ch < out_chan; ++ch) { outp->channel[ch] = pv[ch]; } } else { #endif for (ch = 0; ch < out_chan; ++ch) { if (state->sample_signed && ch < state->color_channels) outp->channel[ch] = (p[ch] ^ 0x80000000UL) / 4294967295.0; else outp->channel[ch] = p[ch] / 4294967295.0; } #ifdef IEEEFP_TYPES } #endif if (state->alpha_chan && state->scale_alpha && outp->channel[state->alpha_chan]) { for (ch = 0; ch < state->alpha_chan; ++ch) outp->channel[ch] /= outp->channel[state->alpha_chan]; } p += state->samples_per_pixel; outp++; } i_plinf(state->img, x, x + width, y, state->line_buf); p += row_extras * state->samples_per_pixel; --height; ++y; } return 1; } static int setup_bilevel(read_state_t *state) { i_color black, white; state->img = i_img_pal_new(state->width, state->height, 1, 256); if (!state->img) return 0; black.channel[0] = black.channel[1] = black.channel[2] = black.channel[3] = 0; white.channel[0] = white.channel[1] = white.channel[2] = white.channel[3] = 255; if (state->photometric == PHOTOMETRIC_MINISBLACK) { i_addcolors(state->img, &black, 1); i_addcolors(state->img, &white, 1); } else { i_addcolors(state->img, &white, 1); i_addcolors(state->img, &black, 1); } state->line_buf = mymalloc(state->width); return 1; } static int putter_bilevel(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int row_extras) { unsigned char *line_in = state->raster; size_t line_size = (width + row_extras + 7) / 8; /* tifflib returns the bits in MSB2LSB order even when the file is in LSB2MSB, so we only need to handle MSB2LSB */ state->pixels_read += width * height; while (height > 0) { i_img_dim i; unsigned char *outp = state->line_buf; unsigned char *inp = line_in; unsigned mask = 0x80; for (i = 0; i < width; ++i) { *outp++ = *inp & mask ? 1 : 0; mask >>= 1; if (!mask) { ++inp; mask = 0x80; } } i_ppal(state->img, x, x + width, y, state->line_buf); line_in += line_size; --height; ++y; } return 1; } static void cmyk_channels(read_state_t *state, int *out_channels) { uint16 extra_count; uint16 *extras; /* safe defaults */ *out_channels = 3; state->alpha_chan = 0; state->scale_alpha = 0; state->color_channels = 3; /* plain CMYK */ if (state->samples_per_pixel == 4) return; if (!TIFFGetField(state->tif, TIFFTAG_EXTRASAMPLES, &extra_count, &extras)) { mm_log((1, "tiff: CMYK samples != 4 but no extra samples tag\n")); return; } if (!extra_count) { mm_log((1, "tiff: CMYK samples != 4 but no extra samples listed")); return; } ++*out_channels; state->alpha_chan = 4; switch (*extras) { case EXTRASAMPLE_UNSPECIFIED: case EXTRASAMPLE_ASSOCALPHA: state->scale_alpha = 1; break; case EXTRASAMPLE_UNASSALPHA: state->scale_alpha = 0; break; default: mm_log((1, "tiff: unknown extra sample type %d, treating as assoc alpha\n", *extras)); state->scale_alpha = 1; break; } } static int setup_cmyk8(read_state_t *state) { int channels; cmyk_channels(state, &channels); state->img = i_img_8_new(state->width, state->height, channels); state->line_buf = mymalloc(sizeof(i_color) * state->width); return 1; } static int putter_cmyk8(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int row_extras) { unsigned char *p = state->raster; state->pixels_read += width * height; while (height > 0) { i_img_dim i; int ch; i_color *outp = state->line_buf; for (i = 0; i < width; ++i) { unsigned char c, m, y, k; c = p[0]; m = p[1]; y = p[2]; k = 255 - p[3]; if (state->sample_signed) { c ^= 0x80; m ^= 0x80; y ^= 0x80; k ^= 0x80; } outp->rgba.r = (k * (255 - c)) / 255; outp->rgba.g = (k * (255 - m)) / 255; outp->rgba.b = (k * (255 - y)) / 255; if (state->alpha_chan) { outp->rgba.a = p[state->alpha_chan]; if (state->scale_alpha && outp->rgba.a) { for (ch = 0; ch < 3; ++ch) { int result = (outp->channel[ch] * 255 + 127) / outp->rgba.a; outp->channel[ch] = CLAMP8(result); } } } p += state->samples_per_pixel; outp++; } i_plin(state->img, x, x + width, y, state->line_buf); p += row_extras * state->samples_per_pixel; --height; ++y; } return 1; } static int setup_cmyk16(read_state_t *state) { int channels; cmyk_channels(state, &channels); state->img = i_img_16_new(state->width, state->height, channels); state->line_buf = mymalloc(sizeof(unsigned) * state->width * channels); return 1; } static int putter_cmyk16(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_dim height, int row_extras) { uint16 *p = state->raster; int out_chan = state->img->channels; mm_log((4, "putter_cmyk16(%p, %" i_DF ", %" i_DF ", %" i_DF ", %" i_DF ", %d)\n", state, i_DFcp(x, y), i_DFcp(width, height), row_extras)); state->pixels_read += width * height; while (height > 0) { i_img_dim i; int ch; unsigned *outp = state->line_buf; for (i = 0; i < width; ++i) { unsigned c, m, y, k; c = p[0]; m = p[1]; y = p[2]; k = 65535 - p[3]; if (state->sample_signed) { c ^= 0x8000; m ^= 0x8000; y ^= 0x8000; k ^= 0x8000; } outp[0] = (k * (65535U - c)) / 65535U; outp[1] = (k * (65535U - m)) / 65535U; outp[2] = (k * (65535U - y)) / 65535U; if (state->alpha_chan) { outp[3] = p[state->alpha_chan]; if (state->scale_alpha && outp[3]) { for (ch = 0; ch < 3; ++ch) { int result = (outp[ch] * 65535 + 32767) / outp[3]; outp[3] = CLAMP16(result); } } } p += state->samples_per_pixel; outp += out_chan; } i_psamp_bits(state->img, x, x + width, y, state->line_buf, NULL, out_chan, 16); p += row_extras * state->samples_per_pixel; --height; ++y; } return 1; } /* Older versions of tifflib we support don't define this, so define it ourselves. If you want this detection to do anything useful, use a newer release of tifflib. */ #if TIFFLIB_VERSION < 20031121 int TIFFIsCODECConfigured(uint16 scheme) { switch (scheme) { /* these schemes are all shipped with tifflib */ case COMPRESSION_NONE: case COMPRESSION_PACKBITS: case COMPRESSION_CCITTRLE: case COMPRESSION_CCITTRLEW: case COMPRESSION_CCITTFAX3: case COMPRESSION_CCITTFAX4: return 1; /* these require external library support */ default: case COMPRESSION_JPEG: case COMPRESSION_LZW: case COMPRESSION_DEFLATE: case COMPRESSION_ADOBE_DEFLATE: return 0; } } #endif static int myTIFFIsCODECConfigured(uint16 scheme) { #if TIFFLIB_VERSION < 20040724 if (scheme == COMPRESSION_LZW) return 0; #endif return TIFFIsCODECConfigured(scheme); } static void tiffio_context_init(tiffio_context_t *c, io_glue *ig) { c->magic = TIFFIO_MAGIC; c->ig = ig; #ifdef USE_EXT_WARN_HANDLER c->warn_buffer = NULL; c->warn_size = 0; #endif } static void tiffio_context_final(tiffio_context_t *c) { c->magic = TIFFIO_MAGIC; #ifdef USE_EXT_WARN_HANDLER if (c->warn_buffer) myfree(c->warn_buffer); #endif } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson , Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/DynTest/0000755000175000017500000000000012617614576017172 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/DynTest/DynTest.pm0000644000175000017500000000075712263740577021131 0ustar gregoagregoapackage Imager::Filter::DynTest; use strict; use Imager; use vars qw($VERSION @ISA); BEGIN { $VERSION = "0.02"; require XSLoader; XSLoader::load('Imager::Filter::DynTest', $VERSION); } sub _lin_stretch { my %hsh = @_; lin_stretch($hsh{image}, $hsh{a}, $hsh{b}); } Imager->register_filter(type=>'lin_stretch', callsub => \&_lin_stretch, defaults => { a => 0, b => 255 }, callseq => [ qw/image a b/ ]); 1; libimager-perl-1.004+dfsg.orig/DynTest/DynTest.xs0000644000175000017500000000077012031434613021122 0ustar gregoagregoa#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #ifdef __cplusplus } #endif #include "imext.h" #include "imperl.h" extern void lin_stretch(i_img *, int, int); DEFINE_IMAGER_CALLBACKS; MODULE = Imager::Filter::DynTest PACKAGE = Imager::Filter::DynTest PROTOTYPES: ENABLE void lin_stretch(im, a, b) Imager::ImgRaw im int a int b BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; libimager-perl-1.004+dfsg.orig/DynTest/t/0000755000175000017500000000000012617614576017435 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/DynTest/t/t00dyntest.t0000644000175000017500000000071312031434613021617 0ustar gregoagregoa#!perl -w use strict; use blib; use Imager; use Test::More tests => 4; BEGIN { use_ok('Imager::Filter::DynTest') } my $im = Imager->new; SKIP: { ok($im->read(file => '../testimg/penguin-base.ppm'), "load source image") or skip("couldn't load work image", 2); ok($im->filter(type=>'lin_stretch', a => 50, b => 200), "try filter") or print "# ", $im->errstr, "\n"; ok($im->write(file => '../testout/t00dyntest.ppm'), "save result"); } libimager-perl-1.004+dfsg.orig/DynTest/Makefile.PL0000644000175000017500000000061212263740577021141 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; my %opts = ( NAME => 'Imager::Filter::DynTest', VERSION_FROM => 'DynTest.pm', OBJECT => 'DynTest.o linstretch.o', INC => '-I..' ); my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'Demo Imager filter extension'; } WriteMakefile(%opts); libimager-perl-1.004+dfsg.orig/DynTest/linstretch.c0000644000175000017500000000172212263740577021515 0ustar gregoagregoa#include "imext.h" char evalstr[]="Description string of plugin dyntest - kind of like"; void null_plug(void *ptr) { } /* Example dynamic filter - level stretch (linear) - note it only stretches and doesn't compress */ /* input parameters a: the current black b: the current white 0 <= a < b <= 255; output pixel value calculated by: o=((i-a)*255)/(b-a); note that since we do not have the needed functions to manipulate the data structures *** YET *** */ static unsigned char saturate(int in) { if (in>255) { return 255; } else if (in>0) return in; return 0; } void lin_stretch(i_img *im, int a, int b) { i_color rcolor; i_img_dim x,y; int i; /* fprintf(stderr,"parameters: (im 0x%x,a %d,b %d)\n",im,a,b);*/ for(y=0;yysize;y++) for(x=0;xxsize;x++) { i_gpix(im,x,y,&rcolor); for(i=0;ichannels;i++) rcolor.channel[i]=saturate((255*(rcolor.channel[i]-a))/(b-a)); i_ppix(im,x,y,&rcolor); } } libimager-perl-1.004+dfsg.orig/META.yml0000644000175000017500000000150012617614576017045 0ustar gregoagregoa--- abstract: 'Perl extension for Generating 24 bit Images' author: - 'Tony Cook , Arnar M. Hrafnkelsson' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.142690' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Imager no_index: directory: - t - inc - PNG - GIF - TIFF - JPEG - W32 - FT2 - T1 recommends: Parse::RecDescent: '0' requires: Scalar::Util: '1' Test::More: '0.47' XSLoader: '0' resources: bugtracker: http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager homepage: http://imager.perl.org/ repository: git://git.imager.perl.org/imager.git version: '1.004' libimager-perl-1.004+dfsg.orig/Imager.pm0000644000175000017500000036517612617611523017351 0ustar gregoagregoapackage Imager; use strict; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %formats $DEBUG %filters %DSOs $ERRSTR %OPCODES $I2P $FORMATGUESS $warn_obsolete); use IO::File; use Scalar::Util; use Imager::Color; use Imager::Font; use Config; @EXPORT_OK = qw( init init_log DSO_open DSO_close DSO_funclist DSO_call load_plugin unload_plugin i_list_formats i_color_new i_color_set i_color_info i_img_info i_img_setmask i_img_getmask i_line i_line_aa i_box i_box_filled i_arc i_circle_aa i_bezier_multi i_poly_aa i_poly_aa_cfill i_copyto i_rubthru i_scaleaxis i_scale_nn i_haar i_count_colors i_gaussian i_conv i_convert i_map i_img_diff i_tt_set_aa i_tt_cp i_tt_text i_tt_bbox i_readpnm_wiol i_writeppm_wiol i_readraw_wiol i_writeraw_wiol i_contrast i_hardinvert i_noise i_bumpmap i_postlevels i_mosaic i_watermark malloc_state list_formats i_gifquant newfont newcolor newcolour NC NF NCF ); @EXPORT=qw( ); %EXPORT_TAGS= (handy => [qw( newfont newcolor NF NC NCF )], all => [@EXPORT_OK], default => [qw( load_plugin unload_plugin )]); # registered file readers my %readers; # registered file writers my %writers; # modules we attempted to autoload my %attempted_to_load; # errors from loading files my %file_load_errors; # what happened when we tried to load my %reader_load_errors; my %writer_load_errors; # library keys that are image file formats my %file_formats = map { $_ => 1 } qw/tiff pnm gif png jpeg raw bmp tga/; # image pixel combine types my @combine_types = qw/none normal multiply dissolve add subtract diff lighten darken hue saturation value color/; my %combine_types; @combine_types{@combine_types} = 0 .. $#combine_types; $combine_types{mult} = $combine_types{multiply}; $combine_types{'sub'} = $combine_types{subtract}; $combine_types{sat} = $combine_types{saturation}; # this will be used to store global defaults at some point my %defaults; BEGIN { require Exporter; my $ex_version = eval $Exporter::VERSION; if ($ex_version < 5.57) { @ISA = qw(Exporter); } $VERSION = '1.004'; require XSLoader; XSLoader::load(Imager => $VERSION); } my %formats_low; my %format_classes = ( png => "Imager::File::PNG", gif => "Imager::File::GIF", tiff => "Imager::File::TIFF", jpeg => "Imager::File::JPEG", w32 => "Imager::Font::W32", ft2 => "Imager::Font::FT2", t1 => "Imager::Font::T1", ); tie %formats, "Imager::FORMATS", \%formats_low, \%format_classes; BEGIN { for(i_list_formats()) { $formats_low{$_}++; } %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]); $DEBUG=0; # the members of the subhashes under %filters are: # callseq - a list of the parameters to the underlying filter in the # order they are passed # callsub - a code ref that takes a named parameter list and calls the # underlying filter # defaults - a hash of default values # names - defines names for value of given parameters so if the names # field is foo=> { bar=>1 }, and the user supplies "bar" as the # foo parameter, the filter will receive 1 for the foo # parameter $filters{contrast}={ callseq => ['image','intensity'], callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); } }; $filters{noise} ={ callseq => ['image', 'amount', 'subtype'], defaults => { amount=>3,subtype=>0 }, callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); } }; $filters{hardinvert} ={ callseq => ['image'], defaults => { }, callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); } }; $filters{hardinvertall} = { callseq => ['image'], defaults => { }, callsub => sub { my %hsh=@_; i_hardinvertall($hsh{image}); } }; $filters{autolevels_skew} ={ callseq => ['image','lsat','usat','skew'], defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 }, callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); } }; $filters{autolevels} ={ callseq => ['image','lsat','usat'], defaults => { lsat=>0.1,usat=>0.1 }, callsub => sub { my %hsh=@_; i_autolevels_mono($hsh{image},$hsh{lsat},$hsh{usat}); } }; $filters{turbnoise} ={ callseq => ['image'], defaults => { xo=>0.0,yo=>0.0,scale=>10.0 }, callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); } }; $filters{radnoise} ={ callseq => ['image'], defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 }, callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); } }; $filters{conv} = { callseq => ['image', 'coef'], defaults => { }, callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}) or die Imager->_error_as_msg() . "\n"; } }; $filters{gradgen} = { callseq => ['image', 'xo', 'yo', 'colors', 'dist'], defaults => { dist => 0 }, callsub => sub { my %hsh=@_; my @colors = @{$hsh{colors}}; $_ = _color($_) for @colors; i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist}); } }; $filters{nearest_color} = { callseq => ['image', 'xo', 'yo', 'colors', 'dist'], defaults => { }, callsub => sub { my %hsh=@_; # make sure the segments are specified with colors my @colors; for my $color (@{$hsh{colors}}) { my $new_color = _color($color) or die $Imager::ERRSTR."\n"; push @colors, $new_color; } i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist}) or die Imager->_error_as_msg() . "\n"; }, }; $filters{gaussian} = { callseq => [ 'image', 'stddev' ], defaults => { }, callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); }, }; $filters{mosaic} = { callseq => [ qw(image size) ], defaults => { size => 20 }, callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) }, }; $filters{bumpmap} = { callseq => [ qw(image bump elevation lightx lighty st) ], defaults => { elevation=>0, st=> 2 }, callsub => sub { my %hsh = @_; i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation}, $hsh{lightx}, $hsh{lighty}, $hsh{st}); }, }; $filters{bumpmap_complex} = { callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ], defaults => { channel => 0, tx => 0, ty => 0, Lx => 0.2, Ly => 0.4, Lz => -1.0, cd => 1.0, cs => 40, n => 1.3, Ia => [0,0,0], Il => [255,255,255], Is => [255,255,255], }, callsub => sub { my %hsh = @_; for my $cname (qw/Ia Il Is/) { my $old = $hsh{$cname}; my $new_color = _color($old) or die $Imager::ERRSTR, "\n"; $hsh{$cname} = $new_color; } i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel}, $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz}, $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il}, $hsh{Is}); }, }; $filters{postlevels} = { callseq => [ qw(image levels) ], defaults => { levels => 10 }, callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); }, }; $filters{watermark} = { callseq => [ qw(image wmark tx ty pixdiff) ], defaults => { pixdiff=>10, tx=>0, ty=>0 }, callsub => sub { my %hsh = @_; i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty}, $hsh{pixdiff}); }, }; $filters{fountain} = { callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ], names => { ftype => { linear => 0, bilinear => 1, radial => 2, radial_square => 3, revolution => 4, conical => 5 }, repeat => { none => 0, sawtooth => 1, triangle => 2, saw_both => 3, tri_both => 4, }, super_sample => { none => 0, grid => 1, random => 2, circle => 3, }, combine => { none => 0, normal => 1, multiply => 2, mult => 2, dissolve => 3, add => 4, subtract => 5, 'sub' => 5, diff => 6, lighten => 7, darken => 8, hue => 9, sat => 10, value => 11, color => 12, }, }, defaults => { ftype => 0, repeat => 0, combine => 0, super_sample => 0, ssample_param => 4, segments=>[ [ 0, 0.5, 1, [0,0,0], [255, 255, 255], 0, 0, ], ], }, callsub => sub { my %hsh = @_; # make sure the segments are specified with colors my @segments; for my $segment (@{$hsh{segments}}) { my @new_segment = @$segment; $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4]; push @segments, \@new_segment; } i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb}, $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample}, $hsh{ssample_param}, \@segments) or die Imager->_error_as_msg() . "\n"; }, }; $filters{unsharpmask} = { callseq => [ qw(image stddev scale) ], defaults => { stddev=>2.0, scale=>1.0 }, callsub => sub { my %hsh = @_; i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale}); }, }; $FORMATGUESS=\&def_guess_type; $warn_obsolete = 1; } # # Non methods # # initialize Imager # NOTE: this might be moved to an import override later on sub import { my $i = 1; while ($i < @_) { if ($_[$i] eq '-log-stderr') { init_log(undef, 4); splice(@_, $i, 1); } else { ++$i; } } goto &Exporter::import; } sub init_log { Imager->open_log(log => $_[0], level => $_[1]); } sub init { my %parms=(loglevel=>1,@_); if (exists $parms{'warn_obsolete'}) { $warn_obsolete = $parms{'warn_obsolete'}; } if ($parms{'log'}) { Imager->open_log(log => $parms{log}, level => $parms{loglevel}) or return; } if (exists $parms{'t1log'}) { if ($formats{t1}) { if (Imager::Font::T1::i_init_t1($parms{'t1log'})) { Imager->_set_error(Imager->_error_as_msg); return; } } } return 1; } { my $is_logging = 0; sub open_log { my $class = shift; my (%opts) = ( loglevel => 1, @_ ); $is_logging = i_init_log($opts{log}, $opts{loglevel}); unless ($is_logging) { Imager->_set_error(Imager->_error_as_msg()); return; } Imager->log("Imager $VERSION starting\n", 1); return $is_logging; } sub close_log { i_init_log(undef, -1); $is_logging = 0; } sub log { my ($class, $message, $level) = @_; defined $level or $level = 1; i_log_entry($message, $level); } sub is_logging { return $is_logging; } } END { if ($DEBUG) { print "shutdown code\n"; # for(keys %instances) { $instances{$_}->DESTROY(); } malloc_state(); # how do decide if this should be used? -- store something from the import print "Imager exiting\n"; } } # Load a filter plugin sub load_plugin { my ($filename)=@_; my $i; if ($^O eq 'android') { require File::Spec; $filename = File::Spec->rel2abs($filename); } my ($DSO_handle,$str)=DSO_open($filename); if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; } my %funcs=DSO_funclist($DSO_handle); if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } } $i=0; for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } } $DSOs{$filename}=[$DSO_handle,\%funcs]; for(keys %funcs) { my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};'; $DEBUG && print "eval string:\n",$evstr,"\n"; eval $evstr; print $@ if $@; } return 1; } # Unload a plugin sub unload_plugin { my ($filename)=@_; if ($^O eq 'android') { require File::Spec; $filename = File::Spec->rel2abs($filename); } if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; } my ($DSO_handle,$funcref)=@{$DSOs{$filename}}; for(keys %{$funcref}) { delete $filters{$_}; $DEBUG && print "unloading: $_\n"; } my $rc=DSO_close($DSO_handle); if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; } return 1; } # take the results of i_error() and make a message out of it sub _error_as_msg { return join(": ", map $_->[0], i_errors()); } # this function tries to DWIM for color parameters # color objects are used as is # simple scalars are simply treated as single parameters to Imager::Color->new # hashrefs are treated as named argument lists to Imager::Color->new # arrayrefs are treated as list arguments to Imager::Color->new iff any # parameter is > 1 # other arrayrefs are treated as list arguments to Imager::Color::Float sub _color { my $arg = shift; # perl 5.6.0 seems to do weird things to $arg if we don't make an # explicitly stringified copy # I vaguely remember a bug on this on p5p, but couldn't find it # through bugs.perl.org (I had trouble getting it to find any bugs) my $copy = $arg . ""; my $result; if (ref $arg) { if (UNIVERSAL::isa($arg, "Imager::Color") || UNIVERSAL::isa($arg, "Imager::Color::Float")) { $result = $arg; } else { if ($copy =~ /^HASH\(/) { $result = Imager::Color->new(%$arg); } elsif ($copy =~ /^ARRAY\(/) { $result = Imager::Color->new(@$arg); } else { $Imager::ERRSTR = "Not a color"; } } } else { # assume Imager::Color::new knows how to handle it $result = Imager::Color->new($arg); } return $result; } sub _combine { my ($self, $combine, $default) = @_; if (!defined $combine && ref $self) { $combine = $self->{combine}; } defined $combine or $combine = $defaults{combine}; defined $combine or $combine = $default; if (exists $combine_types{$combine}) { $combine = $combine_types{$combine}; } return $combine; } sub _valid_image { my ($self, $method) = @_; $self->{IMG} && Scalar::Util::blessed($self->{IMG}) and return 1; my $msg = $self->{IMG} ? "images do not cross threads" : "empty input image"; $msg = "$method: $msg" if $method; $self->_set_error($msg); return; } # returns first defined parameter sub _first { for (@_) { return $_ if defined $_; } return undef; } # # Methods to be called on objects. # # Create a new Imager object takes very few parameters. # usually you call this method and then call open from # the resulting object sub new { my $class = shift; my $self ={}; my %hsh=@_; bless $self,$class; $self->{IMG}=undef; # Just to indicate what exists $self->{ERRSTR}=undef; # $self->{DEBUG}=$DEBUG; $self->{DEBUG} and print "Initialized Imager\n"; if (defined $hsh{file} || defined $hsh{fh} || defined $hsh{fd} || defined $hsh{callback} || defined $hsh{readcb} || defined $hsh{data} || defined $hsh{io}) { # allow $img = Imager->new(file => $filename) my %extras; # type is already used as a parameter to new(), rename it for the # call to read() if ($hsh{filetype}) { $extras{type} = $hsh{filetype}; } unless ($self->read(%hsh, %extras)) { $Imager::ERRSTR = $self->{ERRSTR}; return; } } elsif (defined $hsh{xsize} || defined $hsh{ysize}) { unless ($self->img_set(%hsh)) { $Imager::ERRSTR = $self->{ERRSTR}; return; } } elsif (%hsh) { Imager->_set_error("new: supply xsize and ysize or a file access parameter or no parameters"); return; } return $self; } # Copy an entire image with no changes # - if an image has magic the copy of it will not be magical sub copy { my $self = shift; $self->_valid_image("copy") or return; unless (defined wantarray) { my @caller = caller; warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n"; return; } my $newcopy=Imager->new(); $newcopy->{IMG} = i_copy($self->{IMG}); return $newcopy; } # Paste a region sub paste { my $self = shift; $self->_valid_image("paste") or return; my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_); my $src = $input{img} || $input{src}; unless($src) { $self->_set_error("no source image"); return; } unless ($src->_valid_image("paste")) { $self->{ERRSTR} = $src->{ERRSTR} . " (for src)"; return; } $input{left}=0 if $input{left} <= 0; $input{top}=0 if $input{top} <= 0; my($r,$b)=i_img_info($src->{IMG}); my ($src_left, $src_top) = @input{qw/src_minx src_miny/}; my ($src_right, $src_bottom); if ($input{src_coords}) { ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}} } else { if (defined $input{src_maxx}) { $src_right = $input{src_maxx}; } elsif (defined $input{width}) { if ($input{width} <= 0) { $self->_set_error("paste: width must me positive"); return; } $src_right = $src_left + $input{width}; } else { $src_right = $r; } if (defined $input{src_maxy}) { $src_bottom = $input{src_maxy}; } elsif (defined $input{height}) { if ($input{height} < 0) { $self->_set_error("paste: height must be positive"); return; } $src_bottom = $src_top + $input{height}; } else { $src_bottom = $b; } } $src_right > $r and $src_right = $r; $src_bottom > $b and $src_bottom = $b; if ($src_right <= $src_left || $src_bottom < $src_top) { $self->_set_error("nothing to paste"); return; } i_copyto($self->{IMG}, $src->{IMG}, $src_left, $src_top, $src_right, $src_bottom, $input{left}, $input{top}); return $self; # What should go here?? } # Crop an image - i.e. return a new image that is smaller sub crop { my $self=shift; $self->_valid_image("crop") or return; unless (defined wantarray) { my @caller = caller; warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n"; return; } my %hsh=@_; my ($w, $h, $l, $r, $b, $t) = @hsh{qw(width height left right bottom top)}; # work through the various possibilities if (defined $l) { if (defined $w) { $r = $l + $w; } elsif (!defined $r) { $r = $self->getwidth; } } elsif (defined $r) { if (defined $w) { $l = $r - $w; } else { $l = 0; } } elsif (defined $w) { $l = int(0.5+($self->getwidth()-$w)/2); $r = $l + $w; } else { $l = 0; $r = $self->getwidth; } if (defined $t) { if (defined $h) { $b = $t + $h; } elsif (!defined $b) { $b = $self->getheight; } } elsif (defined $b) { if (defined $h) { $t = $b - $h; } else { $t = 0; } } elsif (defined $h) { $t=int(0.5+($self->getheight()-$h)/2); $b=$t+$h; } else { $t = 0; $b = $self->getheight; } ($l,$r)=($r,$l) if $l>$r; ($t,$b)=($b,$t) if $t>$b; $l < 0 and $l = 0; $r > $self->getwidth and $r = $self->getwidth; $t < 0 and $t = 0; $b > $self->getheight and $b = $self->getheight; if ($l == $r || $t == $b) { $self->_set_error("resulting image would have no content"); return; } if( $r < $l or $b < $t ) { $self->_set_error("attempting to crop outside of the image"); return; } my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t); i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0); return $dst; } sub _sametype { my ($self, %opts) = @_; $self->_valid_image or return; my $x = $opts{xsize} || $self->getwidth; my $y = $opts{ysize} || $self->getheight; my $channels = $opts{channels} || $self->getchannels; my $out = Imager->new; if ($channels == $self->getchannels) { $out->{IMG} = i_sametype($self->{IMG}, $x, $y); } else { $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels); } unless ($out->{IMG}) { $self->{ERRSTR} = $self->_error_as_msg; return; } return $out; } # Sets an image to a certain size and channel number # if there was previously data in the image it is discarded my %model_channels = ( gray => 1, graya => 2, rgb => 3, rgba => 4, ); sub img_set { my $self=shift; my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_); undef($self->{IMG}); if ($hsh{model}) { if (my $channels = $model_channels{$hsh{model}}) { $hsh{channels} = $channels; } else { $self->_set_error("new: unknown value for model '$hsh{model}'"); return; } } if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') { $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels}, $hsh{maxcolors} || 256); } elsif ($hsh{bits} eq 'double') { $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels}); } elsif ($hsh{bits} == 16) { $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels}); } else { $self->{IMG}= i_img_8_new($hsh{'xsize'}, $hsh{'ysize'}, $hsh{'channels'}); } unless ($self->{IMG}) { $self->_set_error(Imager->_error_as_msg()); return; } $self; } # created a masked version of the current image sub masked { my $self = shift; $self->_valid_image("masked") or return; my %opts = (left => 0, top => 0, right => $self->getwidth, bottom => $self->getheight, @_); my $mask = $opts{mask} ? $opts{mask}{IMG} : undef; my $result = Imager->new; $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left}, $opts{top}, $opts{right} - $opts{left}, $opts{bottom} - $opts{top}); unless ($result->{IMG}) { $self->_set_error(Imager->_error_as_msg); return; } # keep references to the mask and base images so they don't # disappear on us $result->{DEPENDS} = [ $self->{IMG}, $mask ]; return $result; } # convert an RGB image into a paletted image sub to_paletted { my $self = shift; my $opts; if (@_ != 1 && !ref $_[0]) { $opts = { @_ }; } else { $opts = shift; } unless (defined wantarray) { my @caller = caller; warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("to_paletted") or return; my $result = Imager->new; unless ($result->{IMG} = i_img_to_pal($self->{IMG}, $opts)) { $self->_set_error(Imager->_error_as_msg); return; } return $result; } sub make_palette { my ($class, $quant, @images) = @_; unless (@images) { Imager->_set_error("make_palette: supply at least one image"); return; } my $index = 1; for my $img (@images) { unless ($img->{IMG}) { Imager->_set_error("make_palette: image $index is empty"); return; } ++$index; } return i_img_make_palette($quant, map $_->{IMG}, @images); } # convert a paletted (or any image) to an 8-bit/channel RGB image sub to_rgb8 { my $self = shift; unless (defined wantarray) { my @caller = caller; warn "to_rgb8() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("to_rgb8") or return; my $result = Imager->new; unless ($result->{IMG} = i_img_to_rgb($self->{IMG})) { $self->_set_error(Imager->_error_as_msg()); return; } return $result; } # convert a paletted (or any image) to a 16-bit/channel RGB image sub to_rgb16 { my $self = shift; unless (defined wantarray) { my @caller = caller; warn "to_rgb16() called in void context - to_rgb16() returns the converted image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("to_rgb16") or return; my $result = Imager->new; unless ($result->{IMG} = i_img_to_rgb16($self->{IMG})) { $self->_set_error(Imager->_error_as_msg()); return; } return $result; } # convert a paletted (or any image) to an double/channel RGB image sub to_rgb_double { my $self = shift; unless (defined wantarray) { my @caller = caller; warn "to_rgb16() called in void context - to_rgb_double() returns the converted image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("to_rgb_double") or return; my $result = Imager->new; unless ($result->{IMG} = i_img_to_drgb($self->{IMG})) { $self->_set_error(Imager->_error_as_msg()); return; } return $result; } sub addcolors { my $self = shift; my %opts = (colors=>[], @_); $self->_valid_image("addcolors") or return -1; my @colors = @{$opts{colors}} or return undef; for my $color (@colors) { $color = _color($color); unless ($color) { $self->_set_error($Imager::ERRSTR); return; } } return i_addcolors($self->{IMG}, @colors); } sub setcolors { my $self = shift; my %opts = (start=>0, colors=>[], @_); $self->_valid_image("setcolors") or return; my @colors = @{$opts{colors}} or return undef; for my $color (@colors) { $color = _color($color); unless ($color) { $self->_set_error($Imager::ERRSTR); return; } } return i_setcolors($self->{IMG}, $opts{start}, @colors); } sub getcolors { my $self = shift; my %opts = @_; $self->_valid_image("getcolors") or return; if (!exists $opts{start} && !exists $opts{count}) { # get them all $opts{start} = 0; $opts{count} = $self->colorcount; } elsif (!exists $opts{count}) { $opts{count} = 1; } elsif (!exists $opts{start}) { $opts{start} = 0; } return i_getcolors($self->{IMG}, $opts{start}, $opts{count}); } sub colorcount { my ($self) = @_; $self->_valid_image("colorcount") or return -1; return i_colorcount($self->{IMG}); } sub maxcolors { my $self = shift; $self->_valid_image("maxcolors") or return -1; i_maxcolors($self->{IMG}); } sub findcolor { my $self = shift; my %opts = @_; $self->_valid_image("findcolor") or return; unless ($opts{color}) { $self->_set_error("findcolor: no color parameter"); return; } my $color = _color($opts{color}) or return; return i_findcolor($self->{IMG}, $color); } sub bits { my $self = shift; $self->_valid_image("bits") or return; my $bits = i_img_bits($self->{IMG}); if ($bits && $bits == length(pack("d", 1)) * 8) { $bits = 'double'; } return $bits; } sub type { my $self = shift; $self->_valid_image("type") or return; return i_img_type($self->{IMG}) ? "paletted" : "direct"; } sub virtual { my $self = shift; $self->_valid_image("virtual") or return; return i_img_virtual($self->{IMG}); } sub is_bilevel { my ($self) = @_; $self->_valid_image("is_bilevel") or return; return i_img_is_monochrome($self->{IMG}); } sub tags { my ($self, %opts) = @_; $self->_valid_image("tags") or return; if (defined $opts{name}) { my @result; my $start = 0; my $found; while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) { push @result, (i_tags_get($self->{IMG}, $found))[1]; $start = $found+1; } return wantarray ? @result : $result[0]; } elsif (defined $opts{code}) { my @result; my $start = 0; my $found; while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) { push @result, (i_tags_get($self->{IMG}, $found))[1]; $start = $found+1; } return @result; } else { if (wantarray) { return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1; } else { return i_tags_count($self->{IMG}); } } } sub addtag { my $self = shift; my %opts = @_; $self->_valid_image("addtag") or return; if ($opts{name}) { if (defined $opts{value}) { if ($opts{value} =~ /^\d+$/) { # add as a number return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value}); } else { return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0); } } elsif (defined $opts{data}) { # force addition as a string return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0); } else { $self->{ERRSTR} = "No value supplied"; return undef; } } elsif ($opts{code}) { if (defined $opts{value}) { if ($opts{value} =~ /^\d+$/) { # add as a number return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value}); } else { return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0); } } elsif (defined $opts{data}) { # force addition as a string return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0); } else { $self->{ERRSTR} = "No value supplied"; return undef; } } else { return undef; } } sub deltag { my $self = shift; my %opts = @_; $self->_valid_image("deltag") or return 0; if (defined $opts{'index'}) { return i_tags_delete($self->{IMG}, $opts{'index'}); } elsif (defined $opts{name}) { return i_tags_delbyname($self->{IMG}, $opts{name}); } elsif (defined $opts{code}) { return i_tags_delbycode($self->{IMG}, $opts{code}); } else { $self->{ERRSTR} = "Need to supply index, name, or code parameter"; return 0; } } sub settag { my ($self, %opts) = @_; $self->_valid_image("settag") or return; if ($opts{name}) { $self->deltag(name=>$opts{name}); return $self->addtag(name=>$opts{name}, value=>$opts{value}); } elsif (defined $opts{code}) { $self->deltag(code=>$opts{code}); return $self->addtag(code=>$opts{code}, value=>$opts{value}); } else { return undef; } } sub _get_reader_io { my ($self, $input) = @_; if ($input->{io}) { return $input->{io}, undef; } elsif ($input->{fd}) { return io_new_fd($input->{fd}); } elsif ($input->{fh}) { unless (Scalar::Util::openhandle($input->{fh})) { $self->_set_error("Handle in fh option not opened"); return; } return Imager::IO->new_fh($input->{fh}); } elsif ($input->{file}) { my $file = IO::File->new($input->{file}, "r"); unless ($file) { $self->_set_error("Could not open $input->{file}: $!"); return; } binmode $file; return (io_new_fd(fileno($file)), $file); } elsif ($input->{data}) { return io_new_buffer($input->{data}); } elsif ($input->{callback} || $input->{readcb}) { if (!$input->{seekcb}) { $self->_set_error("Need a seekcb parameter"); } if ($input->{maxbuffer}) { return io_new_cb($input->{writecb}, $input->{callback} || $input->{readcb}, $input->{seekcb}, $input->{closecb}, $input->{maxbuffer}); } else { return io_new_cb($input->{writecb}, $input->{callback} || $input->{readcb}, $input->{seekcb}, $input->{closecb}); } } else { $self->_set_error("file/fd/fh/data/callback parameter missing"); return; } } sub _get_writer_io { my ($self, $input) = @_; my $buffered = exists $input->{buffered} ? $input->{buffered} : 1; my $io; my @extras; if ($input->{io}) { $io = $input->{io}; } elsif ($input->{fd}) { $io = io_new_fd($input->{fd}); } elsif ($input->{fh}) { unless (Scalar::Util::openhandle($input->{fh})) { $self->_set_error("Handle in fh option not opened"); return; } $io = Imager::IO->new_fh($input->{fh}); } elsif ($input->{file}) { my $fh = new IO::File($input->{file},"w+"); unless ($fh) { $self->_set_error("Could not open file $input->{file}: $!"); return; } binmode($fh) or die; $io = io_new_fd(fileno($fh)); push @extras, $fh; } elsif ($input->{data}) { $io = io_new_bufchain(); } elsif ($input->{callback} || $input->{writecb}) { if ($input->{maxbuffer} && $input->{maxbuffer} == 1) { $buffered = 0; } $io = io_new_cb($input->{callback} || $input->{writecb}, $input->{readcb}, $input->{seekcb}, $input->{closecb}); } else { $self->_set_error("file/fd/fh/data/callback parameter missing"); return; } unless ($buffered) { $io->set_buffered(0); } return ($io, @extras); } # Read an image from file sub read { my $self = shift; my %input=@_; if (defined($self->{IMG})) { # let IIM_DESTROY do the destruction, since the image may be # referenced from elsewhere #i_img_destroy($self->{IMG}); undef($self->{IMG}); } my ($IO, $fh) = $self->_get_reader_io(\%input) or return; my $type = $input{'type'}; unless ($type) { $type = i_test_format_probe($IO, -1); } if ($input{file} && !$type) { # guess the type $type = $FORMATGUESS->($input{file}); } unless ($type) { my $msg = "type parameter missing and it couldn't be determined from the file contents"; $input{file} and $msg .= " or file name"; $self->_set_error($msg); return undef; } _reader_autoload($type); if ($readers{$type} && $readers{$type}{single}) { return $readers{$type}{single}->($self, $IO, %input); } unless ($formats_low{$type}) { my $read_types = join ', ', sort Imager->read_types(); $self->_set_error("format '$type' not supported - formats $read_types available for reading - $reader_load_errors{$type}"); return; } my $allow_incomplete = $input{allow_incomplete}; defined $allow_incomplete or $allow_incomplete = 0; if ( $type eq 'pnm' ) { $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete ); if ( !defined($self->{IMG}) ) { $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); return undef; } $self->{DEBUG} && print "loading a pnm file\n"; return $self; } if ( $type eq 'bmp' ) { $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete ); if ( !defined($self->{IMG}) ) { $self->{ERRSTR}=$self->_error_as_msg(); return undef; } $self->{DEBUG} && print "loading a bmp file\n"; } if ( $type eq 'tga' ) { $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed if ( !defined($self->{IMG}) ) { $self->{ERRSTR}=$self->_error_as_msg(); return undef; } $self->{DEBUG} && print "loading a tga file\n"; } if ( $type eq 'raw' ) { unless ( $input{xsize} && $input{ysize} ) { $self->_set_error('missing xsize or ysize parameter for raw'); return undef; } my $interleave = _first($input{raw_interleave}, $input{interleave}); unless (defined $interleave) { my @caller = caller; warn "read(type => 'raw') $caller[2] line $caller[1]: supply interleave or raw_interleave for future compatibility\n"; $interleave = 1; } my $data_ch = _first($input{raw_datachannels}, $input{datachannels}, 3); my $store_ch = _first($input{raw_storechannels}, $input{storechannels}, 3); $self->{IMG} = i_readraw_wiol( $IO, $input{xsize}, $input{ysize}, $data_ch, $store_ch, $interleave); if ( !defined($self->{IMG}) ) { $self->{ERRSTR}=$self->_error_as_msg(); return undef; } $self->{DEBUG} && print "loading a raw file\n"; } return $self; } sub register_reader { my ($class, %opts) = @_; defined $opts{type} or die "register_reader called with no type parameter\n"; my $type = $opts{type}; defined $opts{single} || defined $opts{multiple} or die "register_reader called with no single or multiple parameter\n"; $readers{$type} = { }; if ($opts{single}) { $readers{$type}{single} = $opts{single}; } if ($opts{multiple}) { $readers{$type}{multiple} = $opts{multiple}; } return 1; } sub register_writer { my ($class, %opts) = @_; defined $opts{type} or die "register_writer called with no type parameter\n"; my $type = $opts{type}; defined $opts{single} || defined $opts{multiple} or die "register_writer called with no single or multiple parameter\n"; $writers{$type} = { }; if ($opts{single}) { $writers{$type}{single} = $opts{single}; } if ($opts{multiple}) { $writers{$type}{multiple} = $opts{multiple}; } return 1; } sub read_types { my %types = ( map { $_ => 1 } keys %readers, grep($file_formats{$_}, keys %formats), qw(ico sgi), # formats not handled directly, but supplied with Imager ); return keys %types; } sub write_types { my %types = ( map { $_ => 1 } keys %writers, grep($file_formats{$_}, keys %formats), qw(ico sgi), # formats not handled directly, but supplied with Imager ); return keys %types; } sub _load_file { my ($file, $error) = @_; if ($attempted_to_load{$file}) { if ($file_load_errors{$file}) { $$error = $file_load_errors{$file}; return 0; } else { return 1; } } else { local $SIG{__DIE__}; my $loaded = eval { ++$attempted_to_load{$file}; require $file; return 1; }; if ($loaded) { return 1; } else { my $work = $@ || "Unknown error"; chomp $work; $work =~ s/\n?Compilation failed in require at .*Imager\.pm line .*\z//m; $work =~ s/\n/\\n/g; $work =~ s/\s*\.?\z/ loading $file/; $file_load_errors{$file} = $work; $$error = $work; return 0; } } } # probes for an Imager::File::whatever module sub _reader_autoload { my $type = shift; return if $formats_low{$type} || $readers{$type}; return unless $type =~ /^\w+$/; my $file = "Imager/File/\U$type\E.pm"; my $error; my $loaded = _load_file($file, \$error); if (!$loaded && $error =~ /^Can't locate /) { my $filer = "Imager/File/\U$type\EReader.pm"; $loaded = _load_file($filer, \$error); if ($error =~ /^Can't locate /) { $error = "Can't locate $file or $filer"; } } unless ($loaded) { $reader_load_errors{$type} = $error; } } # probes for an Imager::File::whatever module sub _writer_autoload { my $type = shift; return if $formats_low{$type} || $writers{$type}; return unless $type =~ /^\w+$/; my $file = "Imager/File/\U$type\E.pm"; my $error; my $loaded = _load_file($file, \$error); if (!$loaded && $error =~ /^Can't locate /) { my $filew = "Imager/File/\U$type\EWriter.pm"; $loaded = _load_file($filew, \$error); if ($error =~ /^Can't locate /) { $error = "Can't locate $file or $filew"; } } unless ($loaded) { $writer_load_errors{$type} = $error; } } sub _fix_gif_positions { my ($opts, $opt, $msg, @imgs) = @_; my $positions = $opts->{'gif_positions'}; my $index = 0; for my $pos (@$positions) { my ($x, $y) = @$pos; my $img = $imgs[$index++]; $img->settag(name=>'gif_left', value=>$x); $img->settag(name=>'gif_top', value=>$y) if defined $y; } $$msg .= "replaced with the gif_left and gif_top tags"; } my %obsolete_opts = ( gif_each_palette=>'gif_local_map', interlace => 'gif_interlace', gif_delays => 'gif_delay', gif_positions => \&_fix_gif_positions, gif_loop_count => 'gif_loop', ); # options that should be converted to colors my %color_opts = map { $_ => 1 } qw/i_background/; sub _set_opts { my ($self, $opts, $prefix, @imgs) = @_; for my $opt (keys %$opts) { my $tagname = $opt; if ($obsolete_opts{$opt}) { my $new = $obsolete_opts{$opt}; my $msg = "Obsolete option $opt "; if (ref $new) { $new->($opts, $opt, \$msg, @imgs); } else { $msg .= "replaced with the $new tag "; $tagname = $new; } $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1]; warn $msg if $warn_obsolete && $^W; } next unless $tagname =~ /^\Q$prefix/; my $value = $opts->{$opt}; if ($color_opts{$opt}) { $value = _color($value); unless ($value) { $self->_set_error($Imager::ERRSTR); return; } } if (ref $value) { if (UNIVERSAL::isa($value, "Imager::Color")) { my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba); for my $img (@imgs) { $img->settag(name=>$tagname, value=>$tag); } } elsif (ref($value) eq 'ARRAY') { for my $i (0..$#$value) { my $val = $value->[$i]; if (ref $val) { if (UNIVERSAL::isa($val, "Imager::Color")) { my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba); $i < @imgs and $imgs[$i]->settag(name=>$tagname, value=>$tag); } else { $self->_set_error("Unknown reference type " . ref($value) . " supplied in array for $opt"); return; } } else { $i < @imgs and $imgs[$i]->settag(name=>$tagname, value=>$val); } } } else { $self->_set_error("Unknown reference type " . ref($value) . " supplied for $opt"); return; } } else { # set it as a tag for every image for my $img (@imgs) { $img->settag(name=>$tagname, value=>$value); } } } return 1; } # Write an image to file sub write { my $self = shift; my %input=(jpegquality=>75, gifquant=>'mc', lmdither=>6.0, lmfixed=>[], idstring=>"", compress=>1, wierdpack=>0, fax_fine=>1, @_); my $rc; $self->_valid_image("write") or return; $self->_set_opts(\%input, "i_", $self) or return undef; my $type = $input{'type'}; if (!$type and $input{file}) { $type = $FORMATGUESS->($input{file}); } unless ($type) { $self->{ERRSTR}='type parameter missing and not possible to guess from extension'; return undef; } _writer_autoload($type); my ($IO, $fh); if ($writers{$type} && $writers{$type}{single}) { ($IO, $fh) = $self->_get_writer_io(\%input) or return undef; $writers{$type}{single}->($self, $IO, %input, type => $type) or return undef; } else { if (!$formats_low{$type}) { my $write_types = join ', ', sort Imager->write_types(); $self->_set_error("format '$type' not supported - formats $write_types available for writing - $writer_load_errors{$type}"); return undef; } ($IO, $fh) = $self->_get_writer_io(\%input, $type) or return undef; if ( $type eq 'pnm' ) { $self->_set_opts(\%input, "pnm_", $self) or return undef; if ( ! i_writeppm_wiol($self->{IMG},$IO) ) { $self->{ERRSTR} = $self->_error_as_msg(); return undef; } $self->{DEBUG} && print "writing a pnm file\n"; } elsif ( $type eq 'raw' ) { $self->_set_opts(\%input, "raw_", $self) or return undef; if ( !i_writeraw_wiol($self->{IMG},$IO) ) { $self->{ERRSTR} = $self->_error_as_msg(); return undef; } $self->{DEBUG} && print "writing a raw file\n"; } elsif ( $type eq 'bmp' ) { $self->_set_opts(\%input, "bmp_", $self) or return undef; if ( !i_writebmp_wiol($self->{IMG}, $IO) ) { $self->{ERRSTR} = $self->_error_as_msg; return undef; } $self->{DEBUG} && print "writing a bmp file\n"; } elsif ( $type eq 'tga' ) { $self->_set_opts(\%input, "tga_", $self) or return undef; if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) { $self->{ERRSTR}=$self->_error_as_msg(); return undef; } $self->{DEBUG} && print "writing a tga file\n"; } } if (exists $input{'data'}) { my $data = io_slurp($IO); if (!$data) { $self->{ERRSTR}='Could not slurp from buffer'; return undef; } ${$input{data}} = $data; } return $self; } sub write_multi { my ($class, $opts, @images) = @_; my $type = $opts->{type}; if (!$type && $opts->{'file'}) { $type = $FORMATGUESS->($opts->{'file'}); } unless ($type) { $class->_set_error('type parameter missing and not possible to guess from extension'); return; } # translate to ImgRaw my $index = 1; for my $img (@images) { unless ($img->_valid_image("write_multi")) { $class->_set_error($img->errstr . " (image $index)"); return; } ++$index; } $class->_set_opts($opts, "i_", @images) or return; my @work = map $_->{IMG}, @images; _writer_autoload($type); my ($IO, $file); if ($writers{$type} && $writers{$type}{multiple}) { ($IO, $file) = $class->_get_writer_io($opts, $type) or return undef; $writers{$type}{multiple}->($class, $IO, $opts, @images) or return undef; } else { if (!$formats{$type}) { my $write_types = join ', ', sort Imager->write_types(); $class->_set_error("format '$type' not supported - formats $write_types available for writing"); return undef; } ($IO, $file) = $class->_get_writer_io($opts, $type) or return undef; if (0) { # eventually PNM in here, now that TIFF/GIF are elsewhere } else { if (@images == 1) { unless ($images[0]->write(%$opts, io => $IO, type => $type)) { return 1; } } else { $ERRSTR = "Sorry, write_multi doesn't support $type yet"; return 0; } } } if (exists $opts->{'data'}) { my $data = io_slurp($IO); if (!$data) { Imager->_set_error('Could not slurp from buffer'); return undef; } ${$opts->{data}} = $data; } return 1; } # read multiple images from a file sub read_multi { my ($class, %opts) = @_; my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'}) or return; my $type = $opts{'type'}; unless ($type) { $type = i_test_format_probe($IO, -1); } if ($opts{file} && !$type) { # guess the type $type = $FORMATGUESS->($opts{file}); } unless ($type) { my $msg = "type parameter missing and it couldn't be determined from the file contents"; $opts{file} and $msg .= " or file name"; Imager->_set_error($msg); return; } _reader_autoload($type); if ($readers{$type} && $readers{$type}{multiple}) { return $readers{$type}{multiple}->($IO, %opts); } unless ($formats{$type}) { my $read_types = join ', ', sort Imager->read_types(); Imager->_set_error("format '$type' not supported - formats $read_types available for reading"); return; } my @imgs; if ($type eq 'pnm') { @imgs = i_readpnm_multi_wiol($IO, $opts{allow_incomplete}||0); } else { my $img = Imager->new; if ($img->read(%opts, io => $IO, type => $type)) { return ( $img ); } Imager->_set_error($img->errstr); return; } if (!@imgs) { $ERRSTR = _error_as_msg(); return; } return map { bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager' } @imgs; } # Destroy an Imager object sub DESTROY { my $self=shift; # delete $instances{$self}; if (defined($self->{IMG})) { # the following is now handled by the XS DESTROY method for # Imager::ImgRaw object # Re-enabling this will break virtual images # tested for in t/t020masked.t # i_img_destroy($self->{IMG}); undef($self->{IMG}); } else { # print "Destroy Called on an empty image!\n"; # why did I put this here?? } } # Perform an inplace filter of an image # that is the image will be overwritten with the data sub filter { my $self=shift; my %input=@_; my %hsh; $self->_valid_image("filter") or return; if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; } if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) { $self->{ERRSTR}='type parameter not matching any filter'; return undef; } if ($filters{$input{'type'}}{names}) { my $names = $filters{$input{'type'}}{names}; for my $name (keys %$names) { if (defined $input{$name} && exists $names->{$name}{$input{$name}}) { $input{$name} = $names->{$name}{$input{$name}}; } } } if (defined($filters{$input{'type'}}{defaults})) { %hsh=( image => $self->{IMG}, imager => $self, %{$filters{$input{'type'}}{defaults}}, %input ); } else { %hsh=( image => $self->{IMG}, imager => $self, %input ); } my @cs=@{$filters{$input{'type'}}{callseq}}; for(@cs) { if (!defined($hsh{$_})) { $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef; } } eval { local $SIG{__DIE__}; # we don't want this processed by confess, etc &{$filters{$input{'type'}}{callsub}}(%hsh); }; if ($@) { chomp($self->{ERRSTR} = $@); return; } my @b=keys %hsh; $self->{DEBUG} && print "callseq is: @cs\n"; $self->{DEBUG} && print "matching callseq is: @b\n"; return $self; } sub register_filter { my $class = shift; my %hsh = ( defaults => {}, @_ ); defined $hsh{type} or die "register_filter() with no type\n"; defined $hsh{callsub} or die "register_filter() with no callsub\n"; defined $hsh{callseq} or die "register_filter() with no callseq\n"; exists $filters{$hsh{type}} and return; $filters{$hsh{type}} = \%hsh; return 1; } sub scale_calculate { my $self = shift; my %opts = ('type'=>'max', @_); # none of these should be references for my $name (qw/xpixels ypixels xscalefactor yscalefactor width height/) { if (defined $opts{$name} && ref $opts{$name}) { $self->_set_error("scale_calculate: $name parameter cannot be a reference"); return; } } my ($x_scale, $y_scale); my $width = $opts{width}; my $height = $opts{height}; if (ref $self) { defined $width or $width = $self->getwidth; defined $height or $height = $self->getheight; } else { unless (defined $width && defined $height) { $self->_set_error("scale_calculate: width and height parameters must be supplied when called as a class method"); return; } } if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) { $x_scale = $opts{'xscalefactor'}; $y_scale = $opts{'yscalefactor'}; } elsif ($opts{'xscalefactor'}) { $x_scale = $opts{'xscalefactor'}; $y_scale = $opts{'scalefactor'} || $x_scale; } elsif ($opts{'yscalefactor'}) { $y_scale = $opts{'yscalefactor'}; $x_scale = $opts{'scalefactor'} || $y_scale; } else { $x_scale = $y_scale = $opts{'scalefactor'} || 0.5; } # work out the scaling if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) { my ($xpix, $ypix)=( $opts{xpixels} / $width , $opts{ypixels} / $height ); if ($opts{'type'} eq 'min') { $x_scale = $y_scale = _min($xpix,$ypix); } elsif ($opts{'type'} eq 'max') { $x_scale = $y_scale = _max($xpix,$ypix); } elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') { $x_scale = $xpix; $y_scale = $ypix; } else { $self->_set_error('invalid value for type parameter'); return; } } elsif ($opts{xpixels}) { $x_scale = $y_scale = $opts{xpixels} / $width; } elsif ($opts{ypixels}) { $x_scale = $y_scale = $opts{ypixels}/$height; } elsif ($opts{constrain} && ref $opts{constrain} && $opts{constrain}->can('constrain')) { # we've been passed an Image::Math::Constrain object or something # that looks like one my $scalefactor; (undef, undef, $scalefactor) = $opts{constrain}->constrain($self->getwidth, $self->getheight); unless ($scalefactor) { $self->_set_error('constrain method failed on constrain parameter'); return; } $x_scale = $y_scale = $scalefactor; } my $new_width = int($x_scale * $width + 0.5); $new_width > 0 or $new_width = 1; my $new_height = int($y_scale * $height + 0.5); $new_height > 0 or $new_height = 1; return ($x_scale, $y_scale, $new_width, $new_height); } # Scale an image to requested size and return the scaled version sub scale { my $self=shift; my %opts = (qtype=>'normal' ,@_); my $img = Imager->new(); my $tmp = Imager->new(); unless (defined wantarray) { my @caller = caller; warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("scale") or return; my ($x_scale, $y_scale, $new_width, $new_height) = $self->scale_calculate(%opts) or return; if ($opts{qtype} eq 'normal') { $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0); if ( !defined($tmp->{IMG}) ) { $self->{ERRSTR} = 'unable to scale image: ' . $self->_error_as_msg; return undef; } $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1); if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image: ' . $self->_error_as_msg; return undef; } return $img; } elsif ($opts{'qtype'} eq 'preview') { $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale); if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; } return $img; } elsif ($opts{'qtype'} eq 'mixing') { $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height); unless ($img->{IMG}) { $self->_set_error(Imager->_error_as_msg); return; } return $img; } else { $self->_set_error('invalid value for qtype parameter'); return undef; } } # Scales only along the X axis sub scaleX { my $self = shift; my %opts = ( scalefactor=>0.5, @_ ); unless (defined wantarray) { my @caller = caller; warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("scaleX") or return; my $img = Imager->new(); my $scalefactor = $opts{scalefactor}; if ($opts{pixels}) { $scalefactor = $opts{pixels} / $self->getwidth(); } unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; } $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0); if ( !defined($img->{IMG}) ) { $self->{ERRSTR} = 'unable to scale image'; return undef; } return $img; } # Scales only along the Y axis sub scaleY { my $self = shift; my %opts = ( scalefactor => 0.5, @_ ); unless (defined wantarray) { my @caller = caller; warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("scaleY") or return; my $img = Imager->new(); my $scalefactor = $opts{scalefactor}; if ($opts{pixels}) { $scalefactor = $opts{pixels} / $self->getheight(); } unless ($self->{IMG}) { $self->{ERRSTR} = 'empty input image'; return undef; } $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1); if ( !defined($img->{IMG}) ) { $self->{ERRSTR} = 'unable to scale image'; return undef; } return $img; } # Transform returns a spatial transformation of the input image # this moves pixels to a new location in the returned image. # NOTE - should make a utility function to check transforms for # stack overruns sub transform { my $self=shift; my %opts=@_; my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre); # print Dumper(\%opts); # xopcopdes $self->_valid_image("transform") or return; if ( $opts{'xexpr'} and $opts{'yexpr'} ) { if (!$I2P) { eval ("use Affix::Infix2Postfix;"); print $@; if ( $@ ) { $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.'; return undef; } $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'}, {op=>'-',trans=>'Sub'}, {op=>'*',trans=>'Mult'}, {op=>'/',trans=>'Div'}, {op=>'-','type'=>'unary',trans=>'u-'}, {op=>'**'}, {op=>'func','type'=>'unary'}], 'grouping'=>[qw( \( \) )], 'func'=>[qw( sin cos )], 'vars'=>[qw( x y )] ); } @xt=$I2P->translate($opts{'xexpr'}); @yt=$I2P->translate($opts{'yexpr'}); $numre=$I2P->{'numre'}; @pt=(0,0); for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } } for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } } @{$opts{'parm'}}=@pt; } # print Dumper(\%opts); if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) { $self->{ERRSTR}='transform: no xopcodes given.'; return undef; } @op=@{$opts{'xopcodes'}}; for $iop (@op) { if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) { $self->{ERRSTR}="transform: illegal opcode '$_'."; return undef; } push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop ); } # yopcopdes if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) { $self->{ERRSTR}='transform: no yopcodes given.'; return undef; } @op=@{$opts{'yopcodes'}}; for $iop (@op) { if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) { $self->{ERRSTR}="transform: illegal opcode '$_'."; return undef; } push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop ); } #parameters if ( !exists $opts{'parm'}) { $self->{ERRSTR}='transform: no parameter arg given.'; return undef; } # print Dumper(\@ropx); # print Dumper(\@ropy); # print Dumper(\@ropy); my $img = Imager->new(); $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'}); if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; } return $img; } sub transform2 { my ($opts, @imgs) = @_; require "Imager/Expr.pm"; $opts->{variables} = [ qw(x y) ]; my ($width, $height) = @{$opts}{qw(width height)}; if (@imgs) { my $index = 1; for my $img (@imgs) { unless ($img->_valid_image("transform2")) { Imager->_set_error($img->errstr . " (input image $index)"); return; } ++$index; } $width ||= $imgs[0]->getwidth(); $height ||= $imgs[0]->getheight(); my $img_num = 1; for my $img (@imgs) { $opts->{constants}{"w$img_num"} = $img->getwidth(); $opts->{constants}{"h$img_num"} = $img->getheight(); $opts->{constants}{"cx$img_num"} = $img->getwidth()/2; $opts->{constants}{"cy$img_num"} = $img->getheight()/2; ++$img_num; } } if ($width) { $opts->{constants}{w} = $width; $opts->{constants}{cx} = $width/2; } else { $Imager::ERRSTR = "No width supplied"; return; } if ($height) { $opts->{constants}{h} = $height; $opts->{constants}{cy} = $height/2; } else { $Imager::ERRSTR = "No height supplied"; return; } my $code = Imager::Expr->new($opts); if (!$code) { $Imager::ERRSTR = Imager::Expr::error(); return; } my $channels = $opts->{channels} || 3; unless ($channels >= 1 && $channels <= 4) { return Imager->_set_error("channels must be an integer between 1 and 4"); } my $img = Imager->new(); $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $channels, $code->code(), $code->nregs(), $code->cregs(), [ map { $_->{IMG} } @imgs ]); if (!defined $img->{IMG}) { $Imager::ERRSTR = Imager->_error_as_msg(); return; } return $img; } sub rubthrough { my $self=shift; my %opts= @_; $self->_valid_image("rubthrough") or return; unless ($opts{src} && $opts{src}->_valid_image("rubthrough")) { $self->{ERRSTR} = $opts{src}{ERRSTR} . ' (for src)'; return; } %opts = (src_minx => 0, src_miny => 0, src_maxx => $opts{src}->getwidth(), src_maxy => $opts{src}->getheight(), %opts); my $tx = $opts{tx}; defined $tx or $tx = $opts{left}; defined $tx or $tx = 0; my $ty = $opts{ty}; defined $ty or $ty = $opts{top}; defined $ty or $ty = 0; unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $tx, $ty, $opts{src_minx}, $opts{src_miny}, $opts{src_maxx}, $opts{src_maxy})) { $self->_set_error($self->_error_as_msg()); return undef; } return $self; } sub compose { my $self = shift; my %opts = ( opacity => 1.0, mask_left => 0, mask_top => 0, @_ ); $self->_valid_image("compose") or return; unless ($opts{src}) { $self->_set_error("compose: src parameter missing"); return; } unless ($opts{src}->_valid_image("compose")) { $self->_set_error($opts{src}->errstr . " (for src)"); return; } my $src = $opts{src}; my $left = $opts{left}; defined $left or $left = $opts{tx}; defined $left or $left = 0; my $top = $opts{top}; defined $top or $top = $opts{ty}; defined $top or $top = 0; my $src_left = $opts{src_left}; defined $src_left or $src_left = $opts{src_minx}; defined $src_left or $src_left = 0; my $src_top = $opts{src_top}; defined $src_top or $src_top = $opts{src_miny}; defined $src_top or $src_top = 0; my $width = $opts{width}; if (!defined $width && defined $opts{src_maxx}) { $width = $opts{src_maxx} - $src_left; } defined $width or $width = $src->getwidth() - $src_left; my $height = $opts{height}; if (!defined $height && defined $opts{src_maxy}) { $height = $opts{src_maxy} - $src_top; } defined $height or $height = $src->getheight() - $src_top; my $combine = $self->_combine($opts{combine}, 'normal'); if ($opts{mask}) { unless ($opts{mask}->_valid_image("compose")) { $self->_set_error($opts{mask}->errstr . " (for mask)"); return; } my $mask_left = $opts{mask_left}; defined $mask_left or $mask_left = $opts{mask_minx}; defined $mask_left or $mask_left = 0; my $mask_top = $opts{mask_top}; defined $mask_top or $mask_top = $opts{mask_miny}; defined $mask_top or $mask_top = 0; unless (i_compose_mask($self->{IMG}, $src->{IMG}, $opts{mask}{IMG}, $left, $top, $src_left, $src_top, $mask_left, $mask_top, $width, $height, $combine, $opts{opacity})) { $self->_set_error(Imager->_error_as_msg); return; } } else { unless (i_compose($self->{IMG}, $src->{IMG}, $left, $top, $src_left, $src_top, $width, $height, $combine, $opts{opacity})) { $self->_set_error(Imager->_error_as_msg); return; } } return $self; } sub flip { my $self = shift; my %opts = @_; $self->_valid_image("flip") or return; my %xlate = (h=>0, v=>1, hv=>2, vh=>2); my $dir; return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}}; $dir = $xlate{$opts{'dir'}}; return $self if i_flipxy($self->{IMG}, $dir); return (); } sub rotate { my $self = shift; my %opts = @_; unless (defined wantarray) { my @caller = caller; warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n"; return; } $self->_valid_image("rotate") or return; if (defined $opts{right}) { my $degrees = $opts{right}; if ($degrees < 0) { $degrees += 360 * int(((-$degrees)+360)/360); } $degrees = $degrees % 360; if ($degrees == 0) { return $self->copy(); } elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) { my $result = Imager->new(); if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) { return $result; } else { $self->{ERRSTR} = $self->_error_as_msg(); return undef; } } else { $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees"; return undef; } } elsif (defined $opts{radians} || defined $opts{degrees}) { my $amount = $opts{radians} || $opts{degrees} * 3.14159265358979 / 180; my $back = $opts{back}; my $result = Imager->new; if ($back) { $back = _color($back); unless ($back) { $self->_set_error(Imager->errstr); return undef; } $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back); } else { $result->{IMG} = i_rotate_exact($self->{IMG}, $amount); } if ($result->{IMG}) { return $result; } else { $self->{ERRSTR} = $self->_error_as_msg(); return undef; } } else { $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available"; return undef; } } sub matrix_transform { my $self = shift; my %opts = @_; $self->_valid_image("matrix_transform") or return; unless (defined wantarray) { my @caller = caller; warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n"; return; } if ($opts{matrix}) { my $xsize = $opts{xsize} || $self->getwidth; my $ysize = $opts{ysize} || $self->getheight; my $result = Imager->new; if ($opts{back}) { $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize, $opts{matrix}, $opts{back}) or return undef; } else { $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize, $opts{matrix}) or return undef; } return $result; } else { $self->{ERRSTR} = "matrix parameter required"; return undef; } } # blame Leolo :) *yatf = \&matrix_transform; # These two are supported for legacy code only sub i_color_new { return Imager::Color->new(@_); } sub i_color_set { return Imager::Color::set(@_); } # Draws a box between the specified corner points. sub box { my $self=shift; my $raw = $self->{IMG}; $self->_valid_image("box") or return; my %opts = @_; my ($xmin, $ymin, $xmax, $ymax); if (exists $opts{'box'}) { $xmin = _min($opts{'box'}->[0],$opts{'box'}->[2]); $xmax = _max($opts{'box'}->[0],$opts{'box'}->[2]); $ymin = _min($opts{'box'}->[1],$opts{'box'}->[3]); $ymax = _max($opts{'box'}->[1],$opts{'box'}->[3]); } else { defined($xmin = $opts{xmin}) or $xmin = 0; defined($xmax = $opts{xmax}) or $xmax = $self->getwidth()-1; defined($ymin = $opts{ymin}) or $ymin = 0; defined($ymax = $opts{ymax}) or $ymax = $self->getheight()-1; } if ($opts{filled}) { my $color = $opts{'color'}; if (defined $color) { unless (_is_color_object($color)) { $color = _color($color); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } } } else { $color = i_color_new(255,255,255,255); } if ($color->isa("Imager::Color")) { i_box_filled($raw, $xmin, $ymin,$xmax, $ymax, $color); } else { i_box_filledf($raw, $xmin, $ymin,$xmax, $ymax, $color); } } elsif ($opts{fill}) { unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) { # assume it's a hash ref require 'Imager/Fill.pm'; unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) { $self->{ERRSTR} = $Imager::ERRSTR; return undef; } } i_box_cfill($raw, $xmin, $ymin, $xmax, $ymax, $opts{fill}{fill}); } else { my $color = $opts{'color'}; if (defined $color) { unless (_is_color_object($color)) { $color = _color($color); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } } } else { $color = i_color_new(255, 255, 255, 255); } unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } i_box($raw, $xmin, $ymin, $xmax, $ymax, $color); } return $self; } sub arc { my $self=shift; $self->_valid_image("arc") or return; my $dflcl= [ 255, 255, 255, 255]; my $good = 1; my %opts= ( color=>$dflcl, 'r'=>_min($self->getwidth(),$self->getheight())/3, 'x'=>$self->getwidth()/2, 'y'=>$self->getheight()/2, 'd1'=>0, 'd2'=>361, filled => 1, @_, ); if ($opts{aa}) { if ($opts{fill}) { unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) { # assume it's a hash ref require 'Imager/Fill.pm'; unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) { $self->{ERRSTR} = $Imager::ERRSTR; return; } } if ($opts{d1} == 0 && $opts{d2} == 361) { i_circle_aa_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $opts{fill}{fill}); } else { i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'}, $opts{'d2'}, $opts{fill}{fill}); } } elsif ($opts{filled}) { my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) { i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $color); } else { i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'}, $opts{'d1'}, $opts{'d2'}, $color); } } else { my $color = _color($opts{'color'}); if ($opts{d2} - $opts{d1} >= 360) { $good = i_circle_out_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $color); } else { $good = i_arc_out_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $opts{'d1'}, $opts{'d2'}, $color); } } } else { if ($opts{fill}) { unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) { # assume it's a hash ref require 'Imager/Fill.pm'; unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) { $self->{ERRSTR} = $Imager::ERRSTR; return; } } i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'}, $opts{'d2'}, $opts{fill}{fill}); } else { my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } if ($opts{filled}) { i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'}, $opts{'d1'}, $opts{'d2'}, $color); } else { if ($opts{d1} == 0 && $opts{d2} == 361) { $good = i_circle_out($self->{IMG}, $opts{x}, $opts{y}, $opts{r}, $color); } else { $good = i_arc_out($self->{IMG}, $opts{x}, $opts{y}, $opts{r}, $opts{d1}, $opts{d2}, $color); } } } } unless ($good) { $self->_set_error($self->_error_as_msg); return; } return $self; } # Draws a line from one point to the other # the endpoint is set if the endp parameter is set which it is by default. # to turn of the endpoint being set use endp=>0 when calling line. sub line { my $self=shift; my $dflcl=i_color_new(0,0,0,0); my %opts=(color=>$dflcl, endp => 1, @_); $self->_valid_image("line") or return; unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; } unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; } my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } $opts{antialias} = $opts{aa} if defined $opts{aa}; if ($opts{antialias}) { i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2}, $color, $opts{endp}); } else { i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2}, $color, $opts{endp}); } return $self; } # Draws a line between an ordered set of points - It more or less just transforms this # into a list of lines. sub polyline { my $self=shift; my ($pt,$ls,@points); my $dflcl=i_color_new(0,0,0,0); my %opts=(color=>$dflcl,@_); $self->_valid_image("polyline") or return; if (exists($opts{points})) { @points=@{$opts{points}}; } if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) { @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1)); } # print Dumper(\@points); my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } $opts{antialias} = $opts{aa} if defined $opts{aa}; if ($opts{antialias}) { for $pt(@points) { if (defined($ls)) { i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1); } $ls=$pt; } } else { for $pt(@points) { if (defined($ls)) { i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1); } $ls=$pt; } } return $self; } sub polygon { my $self = shift; my ($pt,$ls,@points); my $dflcl = i_color_new(0,0,0,0); my %opts = (color=>$dflcl, @_); $self->_valid_image("polygon") or return; if (exists($opts{points})) { $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ]; $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ]; } if (!exists $opts{'x'} or !exists $opts{'y'}) { $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef; } my $mode = _first($opts{mode}, 0); if ($opts{'fill'}) { unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) { # assume it's a hash ref require 'Imager/Fill.pm'; unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) { $self->{ERRSTR} = $Imager::ERRSTR; return undef; } } i_poly_aa_cfill_m($self->{IMG}, $opts{'x'}, $opts{'y'}, $mode, $opts{'fill'}{'fill'}); } else { my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } i_poly_aa_m($self->{IMG}, $opts{'x'}, $opts{'y'}, $mode, $color); } return $self; } sub polypolygon { my ($self, %opts) = @_; $self->_valid_image("polypolygon") or return; my $points = $opts{points}; $points or return $self->_set_error("polypolygon: missing required points"); my $mode = _first($opts{mode}, "evenodd"); if ($opts{filled}) { my $color = _color(_first($opts{color}, [ 0, 0, 0, 0 ])) or return $self->_set_error($Imager::ERRSTR); i_poly_poly_aa($self->{IMG}, $points, $mode, $color) or return $self->_set_error($self->_error_as_msg); } elsif ($opts{fill}) { my $fill = $opts{fill}; $self->_valid_fill($fill, "polypolygon") or return; i_poly_poly_aa_cfill($self->{IMG}, $points, $mode, $fill->{fill}) or return $self->_set_error($self->_error_as_msg); } else { my $color = _color(_first($opts{color}, [ 0, 0, 0, 255 ])) or return $self->_set_error($Imager::ERRSTR); my $rimg = $self->{IMG}; if (_first($opts{aa}, 1)) { for my $poly (@$points) { my $xp = $poly->[0]; my $yp = $poly->[1]; for my $i (0 .. $#$xp - 1) { i_line_aa($rimg, $xp->[$i], $yp->[$i], $xp->[$i+1], $yp->[$i+1], $color, 0); } i_line_aa($rimg, $xp->[$#$xp], $yp->[$#$yp], $xp->[0], $yp->[0], $color, 0); } } else { for my $poly (@$points) { my $xp = $poly->[0]; my $yp = $poly->[1]; for my $i (0 .. $#$xp - 1) { i_line($rimg, $xp->[$i], $yp->[$i], $xp->[$i+1], $yp->[$i+1], $color, 0); } i_line($rimg, $xp->[$#$xp], $yp->[$#$yp], $xp->[0], $yp->[0], $color, 0); } } } return $self; } # this the multipoint bezier curve # this is here more for testing that actual usage since # this is not a good algorithm. Usually the curve would be # broken into smaller segments and each done individually. sub polybezier { my $self=shift; my ($pt,$ls,@points); my $dflcl=i_color_new(0,0,0,0); my %opts=(color=>$dflcl,@_); $self->_valid_image("polybezier") or return; if (exists $opts{points}) { $opts{'x'}=map { $_->[0]; } @{$opts{'points'}}; $opts{'y'}=map { $_->[1]; } @{$opts{'points'}}; } unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) { $self->{ERRSTR}='Missing or invalid points.'; return; } my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color); return $self; } sub flood_fill { my $self = shift; my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ ); my $rc; $self->_valid_image("flood_fill") or return; unless (exists $opts{'x'} && exists $opts{'y'}) { $self->{ERRSTR} = "missing seed x and y parameters"; return undef; } if ($opts{border}) { my $border = _color($opts{border}); unless ($border) { $self->_set_error($Imager::ERRSTR); return; } if ($opts{fill}) { unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) { # assume it's a hash ref require Imager::Fill; unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) { $self->{ERRSTR} = $Imager::ERRSTR; return; } } $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill}, $border); } else { my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'}, $color, $border); } if ($rc) { return $self; } else { $self->{ERRSTR} = $self->_error_as_msg(); return; } } else { if ($opts{fill}) { unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) { # assume it's a hash ref require 'Imager/Fill.pm'; unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) { $self->{ERRSTR} = $Imager::ERRSTR; return; } } $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill}); } else { my $color = _color($opts{'color'}); unless ($color) { $self->{ERRSTR} = $Imager::ERRSTR; return; } $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color); } if ($rc) { return $self; } else { $self->{ERRSTR} = $self->_error_as_msg(); return; } } } sub setpixel { my ($self, %opts) = @_; $self->_valid_image("setpixel") or return; my $color = $opts{color}; unless (defined $color) { $color = $self->{fg}; defined $color or $color = NC(255, 255, 255); } unless (ref $color && UNIVERSAL::isa($color, "Imager::Color")) { unless ($color = _color($color, 'setpixel')) { $self->_set_error("setpixel: " . Imager->errstr); return; } } unless (exists $opts{'x'} && exists $opts{'y'}) { $self->_set_error('setpixel: missing x or y parameter'); return; } my $x = $opts{'x'}; my $y = $opts{'y'}; if (ref $x || ref $y) { $x = ref $x ? $x : [ $x ]; $y = ref $y ? $y : [ $y ]; unless (@$x) { $self->_set_error("setpixel: x is a reference to an empty array"); return; } unless (@$y) { $self->_set_error("setpixel: y is a reference to an empty array"); return; } # make both the same length, replicating the last element if (@$x < @$y) { $x = [ @$x, ($x->[-1]) x (@$y - @$x) ]; } elsif (@$y < @$x) { $y = [ @$y, ($y->[-1]) x (@$x - @$y) ]; } my $set = 0; if ($color->isa('Imager::Color')) { for my $i (0..$#$x) { i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color) or ++$set; } } else { for my $i (0..$#$x) { i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color) or ++$set; } } return $set; } else { if ($color->isa('Imager::Color')) { i_ppix($self->{IMG}, $x, $y, $color) and return "0 but true"; } else { i_ppixf($self->{IMG}, $x, $y, $color) and return "0 but true"; } return 1; } } sub getpixel { my $self = shift; my %opts = ( "type"=>'8bit', @_); $self->_valid_image("getpixel") or return; unless (exists $opts{'x'} && exists $opts{'y'}) { $self->_set_error('getpixel: missing x or y parameter'); return; } my $x = $opts{'x'}; my $y = $opts{'y'}; my $type = $opts{'type'}; if (ref $x || ref $y) { $x = ref $x ? $x : [ $x ]; $y = ref $y ? $y : [ $y ]; unless (@$x) { $self->_set_error("getpixel: x is a reference to an empty array"); return; } unless (@$y) { $self->_set_error("getpixel: y is a reference to an empty array"); return; } # make both the same length, replicating the last element if (@$x < @$y) { $x = [ @$x, ($x->[-1]) x (@$y - @$x) ]; } elsif (@$y < @$x) { $y = [ @$y, ($y->[-1]) x (@$x - @$y) ]; } my @result; if ($type eq '8bit') { for my $i (0..$#$x) { push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i])); } } elsif ($type eq 'float' || $type eq 'double') { for my $i (0..$#$x) { push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i])); } } else { $self->_set_error("getpixel: type must be '8bit' or 'float'"); return; } return wantarray ? @result : \@result; } else { if ($type eq '8bit') { return i_get_pixel($self->{IMG}, $x, $y); } elsif ($type eq 'float' || $type eq 'double') { return i_gpixf($self->{IMG}, $x, $y); } else { $self->_set_error("getpixel: type must be '8bit' or 'float'"); return; } } } sub getscanline { my $self = shift; my %opts = ( type => '8bit', x=>0, @_); $self->_valid_image("getscanline") or return; defined $opts{width} or $opts{width} = $self->getwidth - $opts{x}; unless (defined $opts{'y'}) { $self->_set_error("missing y parameter"); return; } if ($opts{type} eq '8bit') { return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{'y'}); } elsif ($opts{type} eq 'float') { return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{'y'}); } elsif ($opts{type} eq 'index') { unless (i_img_type($self->{IMG})) { $self->_set_error("type => index only valid on paletted images"); return; } return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width}, $opts{'y'}); } else { $self->_set_error("invalid type parameter - must be '8bit' or 'float'"); return; } } sub setscanline { my $self = shift; my %opts = ( x=>0, @_); $self->_valid_image("setscanline") or return; unless (defined $opts{'y'}) { $self->_set_error("missing y parameter"); return; } if (!$opts{type}) { if (ref $opts{pixels} && @{$opts{pixels}}) { # try to guess the type if ($opts{pixels}[0]->isa('Imager::Color')) { $opts{type} = '8bit'; } elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) { $opts{type} = 'float'; } else { $self->_set_error("missing type parameter and could not guess from pixels"); return; } } else { # default $opts{type} = '8bit'; } } if ($opts{type} eq '8bit') { if (ref $opts{pixels}) { return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}}); } else { return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels}); } } elsif ($opts{type} eq 'float') { if (ref $opts{pixels}) { return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}}); } else { return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels}); } } elsif ($opts{type} eq 'index') { if (ref $opts{pixels}) { return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}}); } else { return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels}); } } else { $self->_set_error("invalid type parameter - must be '8bit' or 'float'"); return; } } sub getsamples { my $self = shift; my %opts = ( type => '8bit', x=>0, offset => 0, @_); $self->_valid_image("getsamples") or return; defined $opts{width} or $opts{width} = $self->getwidth - $opts{x}; unless (defined $opts{'y'}) { $self->_set_error("missing y parameter"); return; } if ($opts{target}) { my $target = $opts{target}; my $offset = $opts{offset}; if ($opts{type} eq '8bit') { my @samples = i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{y}, $opts{channels}) or return; @{$target}[$offset .. $offset + @samples - 1] = @samples; return scalar(@samples); } elsif ($opts{type} eq 'float') { my @samples = i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{y}, $opts{channels}); @{$target}[$offset .. $offset + @samples - 1] = @samples; return scalar(@samples); } elsif ($opts{type} =~ /^(\d+)bit$/) { my $bits = $1; my @data; my $count = i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{y}, $bits, $target, $offset, $opts{channels}); unless (defined $count) { $self->_set_error(Imager->_error_as_msg); return; } return $count; } else { $self->_set_error("invalid type parameter - must be '8bit' or 'float'"); return; } } else { if ($opts{type} eq '8bit') { return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{y}, $opts{channels}); } elsif ($opts{type} eq 'float') { return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{y}, $opts{channels}); } elsif ($opts{type} =~ /^(\d+)bit$/) { my $bits = $1; my @data; i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{y}, $bits, \@data, 0, $opts{channels}) or return; return @data; } else { $self->_set_error("invalid type parameter - must be '8bit' or 'float'"); return; } } } sub setsamples { my $self = shift; $self->_valid_image("setsamples") or return; my %opts = ( x => 0, offset => 0 ); my $data_index; # avoid duplicating the data parameter, it may be a large scalar my $i = 0; while ($i < @_ -1) { if ($_[$i] eq 'data') { $data_index = $i+1; } else { $opts{$_[$i]} = $_[$i+1]; } $i += 2; } unless(defined $data_index) { $self->_set_error('setsamples: data parameter missing'); return; } unless (defined $_[$data_index]) { $self->_set_error('setsamples: data parameter not defined'); return; } my $type = $opts{type}; defined $type or $type = '8bit'; my $width = defined $opts{width} ? $opts{width} : $self->getwidth() - $opts{x}; my $count; if ($type eq '8bit') { $count = i_psamp($self->{IMG}, $opts{x}, $opts{y}, $opts{channels}, $_[$data_index], $opts{offset}, $width); } elsif ($type eq 'float') { $count = i_psampf($self->{IMG}, $opts{x}, $opts{y}, $opts{channels}, $_[$data_index], $opts{offset}, $width); } elsif ($type =~ /^([0-9]+)bit$/) { my $bits = $1; unless (ref $_[$data_index]) { $self->_set_error("setsamples: data must be an array ref for type not 8bit or float"); return; } $count = i_psamp_bits($self->{IMG}, $opts{x}, $opts{y}, $bits, $opts{channels}, $_[$data_index], $opts{offset}, $width); } else { $self->_set_error('setsamples: type parameter invalid'); return; } unless (defined $count) { $self->_set_error(Imager->_error_as_msg); return; } return $count; } # make an identity matrix of the given size sub _identity { my ($size) = @_; my $matrix = [ map { [ (0) x $size ] } 1..$size ]; for my $c (0 .. ($size-1)) { $matrix->[$c][$c] = 1; } return $matrix; } # general function to convert an image sub convert { my ($self, %opts) = @_; my $matrix; $self->_valid_image("convert") or return; unless (defined wantarray) { my @caller = caller; warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n"; return; } # the user can either specify a matrix or preset # the matrix overrides the preset if (!exists($opts{matrix})) { unless (exists($opts{preset})) { $self->{ERRSTR} = "convert() needs a matrix or preset"; return; } else { if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') { # convert to greyscale, keeping the alpha channel if any if ($self->getchannels == 3) { $matrix = [ [ 0.222, 0.707, 0.071 ] ]; } elsif ($self->getchannels == 4) { # preserve the alpha channel $matrix = [ [ 0.222, 0.707, 0.071, 0 ], [ 0, 0, 0, 1 ] ]; } else { # an identity $matrix = _identity($self->getchannels); } } elsif ($opts{preset} eq 'noalpha') { # strip the alpha channel if ($self->getchannels == 2 or $self->getchannels == 4) { $matrix = _identity($self->getchannels); pop(@$matrix); # lose the alpha entry } else { $matrix = _identity($self->getchannels); } } elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') { # extract channel 0 $matrix = [ [ 1 ] ]; } elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') { $matrix = [ [ 0, 1 ] ]; } elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') { $matrix = [ [ 0, 0, 1 ] ]; } elsif ($opts{preset} eq 'alpha') { if ($self->getchannels == 2 or $self->getchannels == 4) { $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ]; } else { # the alpha is just 1 $matrix = [ [ (0) x $self->getchannels, 1 ] ]; } } elsif ($opts{preset} eq 'rgb') { if ($self->getchannels == 1) { $matrix = [ [ 1 ], [ 1 ], [ 1 ] ]; } elsif ($self->getchannels == 2) { # preserve the alpha channel $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ]; } else { $matrix = _identity($self->getchannels); } } elsif ($opts{preset} eq 'addalpha') { if ($self->getchannels == 1) { $matrix = _identity(2); } elsif ($self->getchannels == 3) { $matrix = _identity(4); } else { $matrix = _identity($self->getchannels); } } else { $self->{ERRSTR} = "Unknown convert preset $opts{preset}"; return undef; } } } else { $matrix = $opts{matrix}; } my $new = Imager->new; $new->{IMG} = i_convert($self->{IMG}, $matrix); unless ($new->{IMG}) { # most likely a bad matrix i_push_error(0, "convert"); $self->{ERRSTR} = _error_as_msg(); return undef; } return $new; } # combine channels from multiple input images, a class method sub combine { my ($class, %opts) = @_; my $src = delete $opts{src}; unless ($src) { $class->_set_error("src parameter missing"); return; } my @imgs; my $index = 0; for my $img (@$src) { unless (eval { $img->isa("Imager") }) { $class->_set_error("src must contain image objects"); return; } unless ($img->_valid_image("combine")) { $Imager::ERRSTR = $img->{ERRSTR} . " (src->[$index])"; return; } push @imgs, $img->{IMG}; } my $result; if (my $channels = delete $opts{channels}) { $result = i_combine(\@imgs, $channels); } else { $result = i_combine(\@imgs); } unless ($result) { $class->_set_error($class->_error_as_msg); return; } my $img = $class->new; $img->{IMG} = $result; return $img; } # general function to map an image through lookup tables sub map { my ($self, %opts) = @_; my @chlist = qw( red green blue alpha ); $self->_valid_image("map") or return; if (!exists($opts{'maps'})) { # make maps from channel maps my $chnum; for $chnum (0..$#chlist) { if (exists $opts{$chlist[$chnum]}) { $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]}; } elsif (exists $opts{'all'}) { $opts{'maps'}[$chnum] = $opts{'all'}; } } } if ($opts{'maps'} and $self->{IMG}) { i_map($self->{IMG}, $opts{'maps'} ); } return $self; } sub difference { my ($self, %opts) = @_; $self->_valid_image("difference") or return; defined $opts{mindist} or $opts{mindist} = 0; defined $opts{other} or return $self->_set_error("No 'other' parameter supplied"); unless ($opts{other}->_valid_image("difference")) { $self->_set_error($opts{other}->errstr . " (other image)"); return; } my $result = Imager->new; $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG}, $opts{mindist}) or return $self->_set_error($self->_error_as_msg()); return $result; } # destructive border - image is shrunk by one pixel all around sub border { my ($self,%opts)=@_; my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1); $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts); } # Get the width of an image sub getwidth { my $self = shift; $self->_valid_image("getwidth") or return; return i_img_get_width($self->{IMG}); } # Get the height of an image sub getheight { my $self = shift; $self->_valid_image("getheight") or return; return i_img_get_height($self->{IMG}); } # Get number of channels in an image sub getchannels { my $self = shift; $self->_valid_image("getchannels") or return; return i_img_getchannels($self->{IMG}); } my @model_names = qw(unknown gray graya rgb rgba); sub colormodel { my ($self, %opts) = @_; $self->_valid_image("colormodel") or return; my $model = i_img_color_model($self->{IMG}); return $opts{numeric} ? $model : $model_names[$model]; } sub colorchannels { my ($self) = @_; $self->_valid_image("colorchannels") or return; return i_img_color_channels($self->{IMG}); } sub alphachannel { my ($self) = @_; $self->_valid_image("alphachannel") or return; return scalar(i_img_alpha_channel($self->{IMG})); } # Get channel mask sub getmask { my $self = shift; $self->_valid_image("getmask") or return; return i_img_getmask($self->{IMG}); } # Set channel mask sub setmask { my $self = shift; my %opts = @_; $self->_valid_image("setmask") or return; unless (defined $opts{mask}) { $self->_set_error("mask parameter required"); return; } i_img_setmask( $self->{IMG} , $opts{mask} ); 1; } # Get number of colors in an image sub getcolorcount { my $self=shift; my %opts=('maxcolors'=>2**30,@_); $self->_valid_image("getcolorcount") or return; my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'}); return ($rc==-1? undef : $rc); } # Returns a reference to a hash. The keys are colour named (packed) and the # values are the number of pixels in this colour. sub getcolorusagehash { my $self = shift; $self->_valid_image("getcolorusagehash") or return; my %opts = ( maxcolors => 2**30, @_ ); my $max_colors = $opts{maxcolors}; unless (defined $max_colors && $max_colors > 0) { $self->_set_error('maxcolors must be a positive integer'); return; } my $channels= $self->getchannels; # We don't want to look at the alpha channel, because some gifs using it # doesn't define it for every colour (but only for some) $channels -= 1 if $channels == 2 or $channels == 4; my %color_use; my $height = $self->getheight; for my $y (0 .. $height - 1) { my $colors = $self->getsamples('y' => $y, channels => [ 0 .. $channels - 1 ]); while (length $colors) { $color_use{ substr($colors, 0, $channels, '') }++; } keys %color_use > $max_colors and return; } return \%color_use; } # This will return a ordered array of the colour usage. Kind of the sorted # version of the values of the hash returned by getcolorusagehash. # You might want to add safety checks and change the names, etc... sub getcolorusage { my $self = shift; $self->_valid_image("getcolorusage") or return; my %opts = ( maxcolors => 2**30, @_ ); my $max_colors = $opts{maxcolors}; unless (defined $max_colors && $max_colors > 0) { $self->_set_error('maxcolors must be a positive integer'); return; } return i_get_anonymous_color_histo($self->{IMG}, $max_colors); } # draw string to an image sub string { my $self = shift; $self->_valid_image("string") or return; my %input=('x'=>0, 'y'=>0, @_); defined($input{string}) or $input{string} = $input{text}; unless(defined $input{string}) { $self->{ERRSTR}="missing required parameter 'string'"; return; } unless($input{font}) { $self->{ERRSTR}="missing required parameter 'font'"; return; } unless ($input{font}->draw(image=>$self, %input)) { return; } return $self; } sub align_string { my $self = shift; my $img; if (ref $self) { $self->_valid_image("align_string") or return; $img = $self; } else { $img = undef; } my %input=('x'=>0, 'y'=>0, @_); defined $input{string} or $input{string} = $input{text}; unless(exists $input{string}) { $self->_set_error("missing required parameter 'string'"); return; } unless($input{font}) { $self->_set_error("missing required parameter 'font'"); return; } my @result; unless (@result = $input{font}->align(image=>$img, %input)) { return; } return wantarray ? @result : $result[0]; } my @file_limit_names = qw/width height bytes/; sub set_file_limits { shift; my %opts = @_; my %values; if ($opts{reset}) { @values{@file_limit_names} = (0) x @file_limit_names; } else { @values{@file_limit_names} = i_get_image_file_limits(); } for my $key (keys %values) { defined $opts{$key} and $values{$key} = $opts{$key}; } i_set_image_file_limits($values{width}, $values{height}, $values{bytes}); } sub get_file_limits { i_get_image_file_limits(); } my @check_args = qw(width height channels sample_size); sub check_file_limits { my $class = shift; my %opts = ( channels => 3, sample_size => 1, @_, ); if ($opts{sample_size} && $opts{sample_size} eq 'float') { $opts{sample_size} = length(pack("d", 0)); } for my $name (@check_args) { unless (defined $opts{$name}) { $class->_set_error("check_file_limits: $name must be defined"); return; } unless ($opts{$name} == int($opts{$name})) { $class->_set_error("check_file_limits: $name must be a positive integer"); return; } } my $result = i_int_check_image_file_limits(@opts{@check_args}); unless ($result) { $class->_set_error($class->_error_as_msg()); } return $result; } # Shortcuts that can be exported sub newcolor { Imager::Color->new(@_); } sub newfont { Imager::Font->new(@_); } sub NCF { require Imager::Color::Float; return Imager::Color::Float->new(@_); } *NC=*newcolour=*newcolor; *NF=*newfont; *open=\&read; *circle=\&arc; #### Utility routines sub errstr { ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR } sub _set_error { my ($self, $msg) = @_; if (ref $self) { $self->{ERRSTR} = $msg; } else { $ERRSTR = $msg; } return; } # Default guess for the type of an image from extension my @simple_types = qw(png tga gif raw ico cur xpm mng jng ilbm pcx psd eps); my %ext_types = ( ( map { $_ => $_ } @simple_types ), tiff => "tiff", tif => "tiff", pbm => "pnm", pgm => "pnm", ppm => "pnm", pnm => "pnm", # technically wrong, but historically it works in Imager jpeg => "jpeg", jpg => "jpeg", bmp => "bmp", dib => "bmp", rgb => "sgi", bw => "sgi", sgi => "sgi", fit => "fits", fits => "fits", rle => "utah", ); sub def_guess_type { my $name=lc(shift); my ($ext) = $name =~ /\.([^.]+)$/ or return; my $type = $ext_types{$ext} or return; return $type; } sub combines { return @combine_types; } # get the minimum of a list sub _min { my $mx=shift; for(@_) { if ($_<$mx) { $mx=$_; }} return $mx; } # get the maximum of a list sub _max { my $mx=shift; for(@_) { if ($_>$mx) { $mx=$_; }} return $mx; } # string stuff for iptc headers sub _clean { my($str)=$_[0]; $str = substr($str,3); $str =~ s/[\n\r]//g; $str =~ s/\s+/ /g; $str =~ s/^\s//; $str =~ s/\s$//; return $str; } # A little hack to parse iptc headers. sub parseiptc { my $self=shift; my(@sar,$item,@ar); my($caption,$photogr,$headln,$credit); my $str=$self->{IPTCRAW}; defined $str or return; @ar=split(/8BIM/,$str); my $i=0; foreach (@ar) { if (/^\004\004/) { @sar=split(/\034\002/); foreach $item (@sar) { if ($item =~ m/^x/) { $caption = _clean($item); $i++; } if ($item =~ m/^P/) { $photogr = _clean($item); $i++; } if ($item =~ m/^i/) { $headln = _clean($item); $i++; } if ($item =~ m/^n/) { $credit = _clean($item); $i++; } } } } return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit); } sub Inline { # Inline added a new argument at the beginning my $lang = $_[-1]; $lang eq 'C' or die "Only C language supported"; require Imager::ExtUtils; return Imager::ExtUtils->inline_config; } # threads shouldn't try to close raw Imager objects sub Imager::ImgRaw::CLONE_SKIP { 1 } sub preload { # this serves two purposes: # - a class method to load the file support modules included with Imager # (or were included, once the library dependent modules are split out) # - something for Module::ScanDeps to analyze # https://rt.cpan.org/Ticket/Display.html?id=6566 local $@; eval { require Imager::File::GIF }; eval { require Imager::File::JPEG }; eval { require Imager::File::PNG }; eval { require Imager::File::SGI }; eval { require Imager::File::TIFF }; eval { require Imager::File::ICO }; eval { require Imager::Font::W32 }; eval { require Imager::Font::FT2 }; eval { require Imager::Font::T1 }; eval { require Imager::Color::Table }; 1; } package Imager::IO; use IO::Seekable; sub new_fh { my ($class, $fh) = @_; if (tied(*$fh)) { return $class->new_cb ( sub { local $\; return print $fh $_[0]; }, sub { my $tmp; my $count = CORE::read $fh, $tmp, $_[1]; defined $count or return undef; $count or return ""; return $tmp; }, sub { if ($_[1] != SEEK_CUR || $_[0] != 0) { unless (CORE::seek $fh, $_[0], $_[1]) { return -1; } } return tell $fh; }, undef, ); } else { return $class->_new_perlio($fh); } } # backward compatibility for %formats package Imager::FORMATS; use strict; use constant IX_FORMATS => 0; use constant IX_LIST => 1; use constant IX_INDEX => 2; use constant IX_CLASSES => 3; sub TIEHASH { my ($class, $formats, $classes) = @_; return bless [ $formats, [ ], 0, $classes ], $class; } sub _check { my ($self, $key) = @_; (my $file = $self->[IX_CLASSES]{$key} . ".pm") =~ s(::)(/)g; my $value; my $error; my $loaded = Imager::_load_file($file, \$error); if ($loaded) { $value = 1; } else { if ($error =~ /^Can't locate /) { $error = "Can't locate $file"; } $reader_load_errors{$key} = $writer_load_errors{$key} = $error; $value = undef; } $self->[IX_FORMATS]{$key} = $value; return $value; } sub FETCH { my ($self, $key) = @_; exists $self->[IX_FORMATS]{$key} and return $self->[IX_FORMATS]{$key}; $self->[IX_CLASSES]{$key} or return undef; return $self->_check($key); } sub STORE { die "%Imager::formats is not user monifiable"; } sub DELETE { die "%Imager::formats is not user monifiable"; } sub CLEAR { die "%Imager::formats is not user monifiable"; } sub EXISTS { my ($self, $key) = @_; if (exists $self->[IX_FORMATS]{$key}) { my $value = $self->[IX_FORMATS]{$key} or return; return 1; } $self->_check($key) or return 1==0; return 1==1; } sub FIRSTKEY { my ($self) = @_; unless (@{$self->[IX_LIST]}) { # full populate it @{$self->[IX_LIST]} = grep $self->[IX_FORMATS]{$_}, keys %{$self->[IX_FORMATS]}; for my $key (keys %{$self->[IX_CLASSES]}) { $self->[IX_FORMATS]{$key} and next; $self->_check($key) and push @{$self->[IX_LIST]}, $key; } } @{$self->[IX_LIST]} or return; $self->[IX_INDEX] = 1; return $self->[IX_LIST][0]; } sub NEXTKEY { my ($self) = @_; $self->[IX_INDEX] < @{$self->[IX_LIST]} or return; return $self->[IX_LIST][$self->[IX_INDEX]++]; } sub SCALAR { my ($self) = @_; return scalar @{$self->[IX_LIST]}; } 1; __END__ # Below is the stub of documentation for your module. You better edit it! =head1 NAME Imager - Perl extension for Generating 24 bit Images =head1 SYNOPSIS # Thumbnail example #!/usr/bin/perl -w use strict; use Imager; die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0]; my $file = shift; my $format; # see Imager::Files for information on the read() method my $img = Imager->new(file=>$file) or die Imager->errstr(); $file =~ s/\.[^.]*$//; # Create smaller version # documented in Imager::Transformations my $thumb = $img->scale(scalefactor=>.3); # Autostretch individual channels $thumb->filter(type=>'autolevels'); # try to save in one of these formats SAVE: for $format ( qw( png gif jpeg tiff ppm ) ) { # Check if given format is supported if ($Imager::formats{$format}) { $file.="_low.$format"; print "Storing image as: $file\n"; # documented in Imager::Files $thumb->write(file=>$file) or die $thumb->errstr; last SAVE; } } =head1 DESCRIPTION Imager is a module for creating and altering images. It can read and write various image formats, draw primitive shapes like lines,and polygons, blend multiple images together in various ways, scale, crop, render text and more. =head2 Overview of documentation =over =item * Imager - This document - Synopsis, Example, Table of Contents and Overview. =item * L - installation notes for Imager. =item * L - a brief introduction to Imager. =item * L - how to do various things with Imager. =item * L - Basics of constructing image objects with C: Direct type/virtual images, RGB(A)/paletted images, 8/16/double bits/channel, color maps, channel masks, image tags, color quantization. Also discusses basic image information methods. =item * L - IO interaction, reading/writing images, format specific tags. =item * L - Drawing Primitives, lines, boxes, circles, arcs, flood fill. =item * L - Color specification. =item * L - Fill pattern specification. =item * L - General font rendering, bounding boxes and font metrics. =item * L - Copying, scaling, cropping, flipping, blending, pasting, convert and map. =item * L - Programmable transformations through C, C and C. =item * L - Filters, sharpen, blur, noise, convolve etc. and filter plug-ins. =item * L - Expressions for evaluation engine used by transform2(). =item * L - Helper class for affine transformations. =item * L - Helper for making gradient profiles. =item * L - Imager I/O abstraction. =item * L - using Imager's C API =item * L - API function reference =item * L - using Imager's C API from Inline::C =item * L - tools to get access to Imager's C API. =item * L - brief security notes. =item * L - brief information on working with threads. =back =head2 Basic Overview An Image object is created with C<$img = Imager-Enew()>. Examples: $img=Imager->new(); # create empty image $img->read(file=>'lena.png',type=>'png') or # read image from file die $img->errstr(); # give an explanation # if something failed or if you want to create an empty image: $img=Imager->new(xsize=>400,ysize=>300,channels=>4); This example creates a completely black image of width 400 and height 300 and 4 channels. =head1 ERROR HANDLING In general a method will return false when it fails, if it does use the C method to find out why: =over =item errstr() Returns the last error message in that context. If the last error you received was from calling an object method, such as read, call errstr() as an object method to find out why: my $image = Imager->new; $image->read(file => 'somefile.gif') or die $image->errstr; If it was a class method then call errstr() as a class method: my @imgs = Imager->read_multi(file => 'somefile.gif') or die Imager->errstr; Note that in some cases object methods are implemented in terms of class methods so a failing object method may set both. =back The Cnew> method is described in detail in L. =head1 METHOD INDEX Where to find information on methods for Imager class objects. addcolors() - L - add colors to a paletted image addtag() - L - add image tags align_string() - L - draw text aligned on a point alphachannel() - L - return the channel index of the alpha channel (if any). arc() - L - draw a filled arc bits() - L - number of bits per sample for the image box() - L - draw a filled or outline box. check_file_limits() - L circle() - L - draw a filled circle close_log() - L - close the Imager debugging log. colorchannels() - L - the number of channels used for color. colorcount() - L - the number of colors in an image's palette (paletted images only) colormodel() - L - how color is represented. combine() - L - combine channels from one or more images. combines() - L - return a list of the different combine type keywords compose() - L - compose one image over another. convert() - L - transform the color space copy() - L - make a duplicate of an image crop() - L - extract part of an image def_guess_type() - L - default function used to guess the output file format based on the output file name deltag() - L - delete image tags difference() - L - produce a difference images from two input images. errstr() - L - the error from the last failed operation. filter() - L - image filtering findcolor() - L - search the image palette, if it has one flip() - L - flip an image, vertically, horizontally flood_fill() - L - fill an enclosed or same color area getchannels() - L - the number of samples per pixel for an image getcolorcount() - L - the number of different colors used by an image (works for direct color images) getcolors() - L - get colors from the image palette, if it has one getcolorusage() - L getcolorusagehash() - L get_file_limits() - L getheight() - L - height of the image in pixels getmask() - L - write mask for the image getpixel() - L - retrieve one or more pixel colors getsamples() - L - retrieve samples from a row or partial row of pixels. getscanline() - L - retrieve colors for a row or partial row of pixels. getwidth() - L - width of the image in pixels. img_set() - L - re-use an Imager object for a new image. init() - L is_bilevel() - L - returns whether image write functions should write the image in their bilevel (blank and white, no gray levels) format is_logging() L - test if the debug log is active. line() - L - draw an interval load_plugin() - L log() - L - send a message to the debugging log. make_palette() - L - produce a color palette from one or more input images. map() - L - remap color channel values masked() - L - make a masked image matrix_transform() - L maxcolors() - L NC() - L NCF() - L new() - L newcolor() - L newcolour() - L newfont() - L NF() - L open() - L - an alias for read() open_log() - L - open the debug log. =for stopwords IPTC parseiptc() - L - parse IPTC data from a JPEG image paste() - L - draw an image onto an image polygon() - L polyline() - L polypolygon() - L preload() - L read() - L - read a single image from an image file read_multi() - L - read multiple images from an image file read_types() - L - list image types Imager can read. register_filter() - L register_reader() - L register_writer() - L rotate() - L rubthrough() - L - draw an image onto an image and use the alpha channel scale() - L scale_calculate() - L scaleX() - L scaleY() - L setcolors() - L - set palette colors in a paletted image set_file_limits() - L setmask() - L setpixel() - L setsamples() - L setscanline() - L settag() - L string() - L - draw text on an image tags() - L - fetch image tags to_paletted() - L to_rgb16() - L to_rgb8() - L to_rgb_double() - L - convert to double per sample image. transform() - L transform2() - L type() - L - type of image (direct vs paletted) unload_plugin() - L virtual() - L - whether the image has it's own data write() - L - write an image to a file write_multi() - L - write multiple image to an image file. write_types() - L - list image types Imager can write. =head1 CONCEPT INDEX animated GIF - L aspect ratio - C, C, C in L. blend - alpha blending one image onto another L blur - L, L boxes, drawing - L changes between image - L channels, combine into one image - L color - L color names - L, L combine modes - L compare images - L contrast - L, L convolution - L cropping - L CUR files - L C images - L dpi - C, C in L, L drawing boxes - L drawing lines - L drawing text - L, L error message - L files, font - L files, image - L filling, types of fill - L filling, boxes - L filling, flood fill - L flood fill - L fonts - L fonts, drawing with - L, L, L fonts, metrics - L, L fonts, multiple master - L fountain fill - L, L, L, L GIF files - L GIF files, animated - L gradient fill - L, L, L, L gray scale, convert image to - L gaussian blur - L hatch fills - L ICO files - L invert image - L, L JPEG - L limiting image sizes - L lines, drawing - L matrix - L, L, L metadata, image - L, L mosaic - L noise, filter - L noise, rendered - L, L paste - L, L pseudo-color image - L, L =for stopwords posterize posterize - L PNG files - L, L PNM - L rectangles, drawing - L resizing an image - L, L RGB (SGI) files - L saving an image - L scaling - L security - L SGI files - L sharpen - L, L size, image - L, L size, text - L tags, image metadata - L text, drawing - L, L, L text, wrapping text in an area - L text, measuring - L, L threads - L tiles, color - L transparent images - L, L =for stopwords unsharp unsharp mask - L watermark - L writing an image to a file - L =head1 SUPPORT The best place to get help with Imager is the mailing list. To subscribe send a message with C in the body to: imager-devel+request@molar.is or use the form at: =over L =back where you can also find the mailing list archive. You can report bugs by pointing your browser at: =over L =back or by sending an email to: =over bug-Imager@rt.cpan.org =back Please remember to include the versions of Imager, perl, supporting libraries, and any relevant code. If you have specific images that cause the problems, please include those too. If you don't want to publish your email address on a mailing list you can use CPAN::Forum: http://www.cpanforum.com/dist/Imager You will need to register to post. =head1 CONTRIBUTING TO IMAGER =head2 Feedback I like feedback. If you like or dislike Imager, you can add a public review of Imager at CPAN Ratings: http://cpanratings.perl.org/dist/Imager =for stopwords Bitcard This requires a Bitcard account (http://www.bitcard.org). You can also send email to the maintainer below. If you send me a bug report via email, it will be copied to Request Tracker. =head2 Patches I accept patches, preferably against the master branch in git. Please include an explanation of the reason for why the patch is needed or useful. Your patch should include regression tests where possible, otherwise it will be delayed until I get a chance to write them. To browse Imager's git repository: http://git.imager.perl.org/imager.git To clone: git clone git://git.imager.perl.org/imager.git My preference is that patches are provided in the format produced by C, for example, if you made your changes in a branch from master you might do: git format-patch -k --stdout master >my-patch.txt and then attach that to your bug report, either by adding it as an attachment in your email client, or by using the Request Tracker attachment mechanism. =head1 AUTHOR Tony Cook is the current maintainer for Imager. Arnar M. Hrafnkelsson is the original author of Imager. Many others have contributed to Imager, please see the C for a complete list. =head1 LICENSE Imager is licensed under the same terms as perl itself. =for stopwords makeblendedfont Fontforge A test font, generated by the Debian packaged Fontforge, F, contains a Postscript operator definition copyrighted by Adobe. See F in the source for license information. =head1 SEE ALSO L(1), L(3), L(3), L(3), L(3), L(3), L(3), L(3), L(3), L(3), L(3), L(3), L(3) L L(3), L(3) Other perl imaging modules include: L(3), L(3), L(3), L, L. For manipulating image metadata see L. If you're trying to use Imager for array processing, you should probably using L. =cut libimager-perl-1.004+dfsg.orig/tga.c0000644000175000017500000005527712263740601016521 0ustar gregoagregoa#include "imageri.h" #include "log.h" #include "iolayer.h" #include #include /* =head1 NAME tga.c - implements reading and writing targa files, uses io layer. =head1 SYNOPSIS io_glue *ig = io_new_fd( fd ); i_img *im = i_readtga_wiol(ig, -1); // no limit on how much is read // or io_glue *ig = io_new_fd( fd ); return_code = i_writetga_wiol(im, ig); =head1 DESCRIPTION tga.c implements the basic functions to read and write portable targa files. It uses the iolayer and needs either a seekable source or an entire memory mapped buffer. =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ typedef struct { unsigned char idlength; char colourmaptype; char datatypecode; short int colourmaporigin; short int colourmaplength; char colourmapdepth; short int x_origin; short int y_origin; int width; int height; char bitsperpixel; char imagedescriptor; } tga_header; typedef enum { NoInit, Raw, Rle } rle_state; typedef struct { int compressed; size_t bytepp; rle_state state; unsigned char cval[4]; int len; unsigned char hdr; io_glue *ig; } tga_source; typedef struct { int compressed; int bytepp; io_glue *ig; } tga_dest; #define TGA_MAX_DIM 0xFFFF /* =item bpp_to_bytes(bpp) Convert bits per pixel into bytes per pixel bpp - bits per pixel =cut */ static size_t bpp_to_bytes(unsigned int bpp) { switch (bpp) { case 8: return 1; case 15: case 16: return 2; case 24: return 3; case 32: return 4; } return 0; } /* =item bpp_to_channels(bpp) Convert bits per pixel and the number of attribute bits into channels in the image bpp - bits per pixel attr_bit_count - number of attribute bits =cut */ static int bpp_to_channels(unsigned int bpp, int attr_bit_count) { switch (bpp) { case 8: return 1; case 16: if (attr_bit_count == 1) return 4; case 15: return 3; case 32: if (attr_bit_count == 8) return 4; case 24: return 3; } return 0; } /* * Packing functions - used for (un)packing * datastructures into raw bytes. */ /* =item color_unpack(buf, bytepp, val) Unpacks bytes into colour structures, for 2 byte type the first byte coming from the file will actually be GGGBBBBB, and the second will be ARRRRRGG. "A" represents an attribute bit. The 3 byte entry contains 1 byte each of blue, green, and red. The 4 byte entry contains 1 byte each of blue, green, red, and attribute. buf - pointer to data bytepp - bytes per pixel val - pointer to color to store to =cut */ static void color_unpack(unsigned char *buf, int bytepp, i_color *val) { switch (bytepp) { case 1: val->gray.gray_color = buf[0]; break; case 2: val->rgba.r = (buf[1] & 0x7c) << 1; val->rgba.g = ((buf[1] & 0x03) << 6) | ((buf[0] & 0xe0) >> 2); val->rgba.b = (buf[0] & 0x1f) << 3; val->rgba.a = (buf[1] & 0x80) ? 0 : 255; val->rgba.r |= val->rgba.r >> 5; val->rgba.g |= val->rgba.g >> 5; val->rgba.b |= val->rgba.b >> 5; break; case 3: val->rgb.b = buf[0]; val->rgb.g = buf[1]; val->rgb.r = buf[2]; break; case 4: val->rgba.b = buf[0]; val->rgba.g = buf[1]; val->rgba.r = buf[2]; val->rgba.a = buf[3]; break; } } /* =item color_pack Packs a colour into an array of bytes, for 2 byte type the first byte will be GGGBBBBB, and the second will be ARRRRRGG. "A" represents an attribute bit. The 3 byte entry contains 1 byte each of blue, green, and red. The 4 byte entry contains 1 byte each of blue, green, red, and attribute. buf - destination buffer bitspp - bits per pixel val - color to pack =cut */ static void color_pack(unsigned char *buf, int bitspp, i_color *val) { switch (bitspp) { case 8: buf[0] = val->gray.gray_color; break; case 16: buf[0] = (val->rgba.b >> 3); buf[0] |= (val->rgba.g & 0x38) << 2; buf[1] = (val->rgba.r & 0xf8)>> 1; buf[1] |= (val->rgba.g >> 6); buf[1] |= val->rgba.a > 0x7f ? 0 : 0x80; break; case 15: buf[0] = (val->rgba.b >> 3); buf[0] |= (val->rgba.g & 0x38) << 2; buf[1] = (val->rgba.r & 0xf8)>> 1; buf[1] |= (val->rgba.g >> 6); break; case 24: buf[0] = val->rgb.b; buf[1] = val->rgb.g; buf[2] = val->rgb.r; break; case 32: buf[0] = val->rgba.b; buf[1] = val->rgba.g; buf[2] = val->rgba.r; buf[3] = val->rgba.a; break; } } /* =item find_repeat Helper function for rle compressor to find the next triple repeat of the same pixel value in buffer. buf - buffer length - number of pixel values in buffer bytepp - number of bytes in a pixel value =cut */ static int find_repeat(unsigned char *buf, int length, int bytepp) { int i = 0; while(iidlength = headbuf[0]; header->colourmaptype = headbuf[1]; header->datatypecode = headbuf[2]; header->colourmaporigin = (headbuf[4] << 8) + headbuf[3]; header->colourmaplength = (headbuf[6] << 8) + headbuf[5]; header->colourmapdepth = headbuf[7]; header->x_origin = (headbuf[9] << 8) + headbuf[8]; header->y_origin = (headbuf[11] << 8) + headbuf[10]; header->width = (headbuf[13] << 8) + headbuf[12]; header->height = (headbuf[15] << 8) + headbuf[14]; header->bitsperpixel = headbuf[16]; header->imagedescriptor = headbuf[17]; } /* this function should never produce diagnostics to stdout, maybe to the logfile */ int tga_header_verify(unsigned char headbuf[18]) { tga_header header; tga_header_unpack(&header, headbuf); switch (header.datatypecode) { default: /*printf("bad typecode!\n");*/ return 0; case 1: /* Uncompressed, color-mapped images */ case 3: /* Uncompressed, grayscale images */ case 9: /* Compressed, color-mapped images */ case 11: /* Compressed, grayscale images */ if (header.bitsperpixel != 8) return 0; break; case 0: case 2: /* Uncompressed, rgb images */ case 10: /* Compressed, rgb images */ if (header.bitsperpixel != 15 && header.bitsperpixel != 16 && header.bitsperpixel != 24 && header.bitsperpixel != 32) return 0; break; } switch (header.colourmaptype) { default: /*printf("bad colourmaptype!\n");*/ return 0; case 1: if (header.datatypecode != 1 && header.datatypecode != 9) return 0; /* only get a color map on a color mapped image */ case 0: break; } switch (header.colourmapdepth) { default: return 0; case 0: /* can be 0 if no colour map */ case 15: case 16: case 24: case 32: break; } return 1; } /* =item tga_header_pack(header, headbuf) Packs header structure into buffer for writing. header - header structure headbuf - buffer to pack into =cut */ static void tga_header_pack(tga_header *header, unsigned char headbuf[18]) { headbuf[0] = header->idlength; headbuf[1] = header->colourmaptype; headbuf[2] = header->datatypecode; headbuf[3] = header->colourmaporigin & 0xff; headbuf[4] = header->colourmaporigin >> 8; headbuf[5] = header->colourmaplength & 0xff; headbuf[6] = header->colourmaplength >> 8; headbuf[7] = header->colourmapdepth; headbuf[8] = header->x_origin & 0xff; headbuf[9] = header->x_origin >> 8; headbuf[10] = header->y_origin & 0xff; headbuf[11] = header->y_origin >> 8; headbuf[12] = header->width & 0xff; headbuf[13] = header->width >> 8; headbuf[14] = header->height & 0xff; headbuf[15] = header->height >> 8; headbuf[16] = header->bitsperpixel; headbuf[17] = header->imagedescriptor; } /* =item tga_source_read(s, buf, pixels) Reads pixel number of pixels from source s into buffer buf. Takes care of decompressing the stream if needed. s - data source buf - destination buffer pixels - number of pixels to put into buffer =cut */ static int tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) { int cp = 0, j, k; if (!s->compressed) { if (i_io_read(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0; return 1; } while(cp < pixels) { int ml; if (s->len == 0) s->state = NoInit; switch (s->state) { case NoInit: if (i_io_read(s->ig, &s->hdr, 1) != 1) return 0; s->len = (s->hdr &~(1<<7))+1; s->state = (s->hdr & (1<<7)) ? Rle : Raw; { /* static cnt = 0; printf("%04d %s: %d\n", cnt++, s->state==Rle?"RLE":"RAW", s->len); */ } if (s->state == Rle && i_io_read(s->ig, s->cval, s->bytepp) != s->bytepp) return 0; break; case Rle: ml = i_min(s->len, pixels-cp); for(k=0; kbytepp; j++) buf[(cp+k)*s->bytepp+j] = s->cval[j]; cp += ml; s->len -= ml; break; case Raw: ml = i_min(s->len, pixels-cp); if (i_io_read(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0; cp += ml; s->len -= ml; break; } } return 1; } /* =item tga_dest_write(s, buf, pixels) Writes pixels from buf to destination s. Takes care of compressing if the destination is compressed. s - data destination buf - source buffer pixels - number of pixels to put write to destination =cut */ static int tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) { int cp = 0; if (!s->compressed) { if (i_io_write(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0; return 1; } while(cp < pixels) { int tlen; int nxtrip = find_repeat(buf+cp*s->bytepp, pixels-cp, s->bytepp); tlen = (nxtrip == -1) ? pixels-cp : nxtrip; while(tlen) { unsigned char clen = (tlen>128) ? 128 : tlen; clen--; if (i_io_write(s->ig, &clen, 1) != 1) return 0; clen++; if (i_io_write(s->ig, buf+cp*s->bytepp, clen*s->bytepp) != clen*s->bytepp) return 0; tlen -= clen; cp += clen; } if (cp >= pixels) break; tlen = find_span(buf+cp*s->bytepp, pixels-cp, s->bytepp); if (tlen <3) continue; while (tlen) { unsigned char clen = (tlen>128) ? 128 : tlen; clen = (clen - 1) | 0x80; if (i_io_write(s->ig, &clen, 1) != 1) return 0; clen = (clen & ~0x80) + 1; if (i_io_write(s->ig, buf+cp*s->bytepp, s->bytepp) != s->bytepp) return 0; tlen -= clen; cp += clen; } } return 1; } /* =item tga_palette_read(ig, img, bytepp, colourmaplength) Reads the colormap from a tga file and stores in the paletted image structure. ig - iolayer data source img - image structure bytepp - bytes per pixel colourmaplength - number of colours in colourmap =cut */ static int tga_palette_read(io_glue *ig, i_img *img, int bytepp, int colourmaplength) { int i; size_t palbsize; unsigned char *palbuf; i_color val; palbsize = colourmaplength*bytepp; palbuf = mymalloc(palbsize); if (i_io_read(ig, palbuf, palbsize) != palbsize) { i_push_error(errno, "could not read targa colourmap"); return 0; } /* populate the palette of the new image */ for(i=0; itags, "tga_idstring", 0, idstring, header.idlength, 0); myfree(idstring); } if (mapped && !tga_palette_read(ig, img, bpp_to_bytes(header.colourmapdepth), header.colourmaplength) ) { i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout"); if (idstring) myfree(idstring); if (img) i_img_destroy(img); return NULL; } /* Allocate buffers */ /* width is max 0xffff, src.bytepp is max 4, so this is safe */ databuf = mymalloc(width*src.bytepp); /* similarly here */ if (!mapped) linebuf = mymalloc(width*sizeof(i_color)); for(y=0; ytags, "i_format", 0, "tga", -1, 0); i_tags_addn(&img->tags, "tga_bitspp", 0, mapped?header.colourmapdepth:header.bitsperpixel); if (src.compressed) i_tags_addn(&img->tags, "compressed", 0, 1); return img; } /* =item i_writetga_wiol(img, ig) Writes an image in targa format. Returns 0 on error. img - image to store ig - io_glue object =cut */ undef_int i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen) { tga_header header; tga_dest dest; unsigned char headbuf[18]; unsigned int bitspp; unsigned int attr_bits = 0; int mapped; /* parameters */ /* int compress = 1; char *idstring = "testing"; int wierdpack = 0; */ idlen = strlen(idstring); mapped = img->type == i_palette_type; mm_log((1,"i_writetga_wiol(img %p, ig %p, idstring %p, idlen %ld, wierdpack %d, compress %d)\n", img, ig, idstring, (long)idlen, wierdpack, compress)); mm_log((1, "virtual %d, paletted %d\n", img->virtual, mapped)); mm_log((1, "channels %d\n", img->channels)); i_clear_error(); if (img->xsize > TGA_MAX_DIM || img->ysize > TGA_MAX_DIM) { i_push_error(0, "image too large for TGA"); return 0; } switch (img->channels) { case 1: bitspp = 8; if (wierdpack) { mm_log((1,"wierdpack option ignored for 1 channel images\n")); wierdpack=0; } break; case 2: i_push_error(0, "Cannot store 2 channel image in targa format"); return 0; break; case 3: bitspp = wierdpack ? 15 : 24; break; case 4: bitspp = wierdpack ? 16 : 32; attr_bits = wierdpack ? 1 : 8; break; default: i_push_error(0, "Targa only handles 1,3 and 4 channel images."); return 0; } header.idlength = idlen; header.colourmaptype = mapped ? 1 : 0; header.datatypecode = mapped ? 1 : img->channels == 1 ? 3 : 2; header.datatypecode += compress ? 8 : 0; mm_log((1, "datatypecode %d\n", header.datatypecode)); header.colourmaporigin = 0; header.colourmaplength = mapped ? i_colorcount(img) : 0; header.colourmapdepth = mapped ? bitspp : 0; header.x_origin = 0; header.y_origin = 0; header.width = img->xsize; header.height = img->ysize; header.bitsperpixel = mapped ? 8 : bitspp; header.imagedescriptor = (1<<5) | attr_bits; /* normal order instead of upside down */ tga_header_pack(&header, headbuf); if (i_io_write(ig, &headbuf, sizeof(headbuf)) != sizeof(headbuf)) { i_push_error(errno, "could not write targa header"); return 0; } if (idlen) { if (i_io_write(ig, idstring, idlen) != idlen) { i_push_error(errno, "could not write targa idstring"); return 0; } } /* Make this into a constructor? */ dest.compressed = compress; dest.bytepp = mapped ? 1 : bpp_to_bytes(bitspp); dest.ig = ig; mm_log((1, "dest.compressed = %d\n", dest.compressed)); mm_log((1, "dest.bytepp = %d\n", dest.bytepp)); if (img->type == i_palette_type) { if (!tga_palette_write(ig, img, bitspp, i_colorcount(img))) return 0; if (!img->virtual && !dest.compressed) { if (i_io_write(ig, img->idata, img->bytes) != img->bytes) { i_push_error(errno, "could not write targa image data"); return 0; } } else { int y; i_palidx *vals = mymalloc(sizeof(i_palidx)*img->xsize); for(y=0; yysize; y++) { i_gpal(img, 0, img->xsize, y, vals); tga_dest_write(&dest, vals, img->xsize); } myfree(vals); } } else { /* direct type */ int x, y; size_t bytepp = wierdpack ? 2 : bpp_to_bytes(bitspp); size_t lsize = bytepp * img->xsize; i_color *vals = mymalloc(img->xsize*sizeof(i_color)); unsigned char *buf = mymalloc(lsize); for(y=0; yysize; y++) { i_glin(img, 0, img->xsize, y, vals); for(x=0; xxsize; x++) color_pack(buf+x*bytepp, bitspp, vals+x); tga_dest_write(&dest, buf, img->xsize); } myfree(buf); myfree(vals); } if (i_io_close(ig)) return 0; return 1; } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/fontfiles/0000755000175000017500000000000012617614576017571 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/fontfiles/ImUgly.ttf0000644000175000017500000013772012031434615021510 0ustar gregoagregoa €@OS/2ßI#•ÌVcmapËâ…$Úcvt %Ö*E’glyféÑûÆ”’lheadÕ§/—6hhea õü—8$hmtx‡‡vï—\ °kernþáÿ†¢ –loca±)7¢¤Zmaxpú­¨ nameš3ÔŒ¨ ˆpost¤Õ ª¨%ùôÈÈÈÈÈÈ1  €OPfEd@ $‡¡ý¡“ÔÀl@,~@HOdko~‰¡ØÜßõû3 (¼  )™¡§±¹ÁÇÍÓÝåõù  < C p Ž!!! !! !"!+!$n$‡ÿÿ ¡CLRhnr‰ ÕÛÞôø& '¼  , ¤ª´¼ÄÊÐÖàòø  < C p t!!! !! !"!+!`$`$tÿÿÿãÿÁÿ¿ÿ¼ÿºÿ·ÿµÿ³ÿ©ÿ“ÿ`ÿ^ÿ]ÿIÿGÿ+ÿ!þUþSþNþ4üºø\ø[ãfãdã^ã\ãZãXãVãTãRãPãNãLã@ã>â(âáýáÑáÎá]á\áZáKáFáEá=á Þ)Þ$  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿À!y\cáÛ`WiRÖZ®\•J^KÄN7?iTþùY^òf¸XõHEЇ„8ÎéG42* .&¶ÙN€n $…F<Lèx`½!nš.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!!MþÔ þõšýf!X>›ë°/°3±í±í°Ü°3±í±í01733#>\\\\äýùv\4Q;°/°3±í±í°Ü°3±í±í°/°3±í±í°ܰ3±í±í013#'3#îccºccýÛÞá;l“ÁÕ°/°3°3°3±í°2°3±í°2°3±í±í±í±í±í±í°ܰ3° 3° 3°3°3± í± í± í°2±í±í° 2±í±í°2±í±í°2±í°/°3°3°3°3°3±í±í±í±í±í±í°Ü°3°3°3°3°3±í±í±í± í± í± í0135%3533533#3##5##5#535#÷Ýþg`\Ý\cccc\Ý\``` ìì\ZZZZ\ì\WWWW\ì^ÿ¶Î&67CMW° /° 3°3°3°#3°&3°'3°83°C3±í±í± í± í±(í±)í±5í±6í±Dí±Mí°&/°'3°(3± í± í0115&/5#'&'231356767676'5&/5'&'&=472;1ÂDRE$L®WŽK) ¡*ˆK/Y¡W aU( ,³ Vw&cIWoj2|$ T6#IG:(kZâ'T>.J '  3e_øþÁu< %<þ¤5;> â#5GKû°B/°C3°D3°E3±' í±( í±) í±* í°0ܰ13°23°33±9 í±: í±; í±< í°ܰ3° 3°!3± í± í± í± í° Ü° 3°3°3± í± í± í± í± ?°/°3°J3°K3± í± í± í°Ü°3°3± í± í±# í°>ܰ?3°@3±, í±- í±. í°$ܰ%3°53±6 í±7 í±G í±H ?°I3±HK°H/±I í°K/±JQí±HK°I±H í°J±KQí01%"3276=4'&'2#"'&=476"3276=4'&'2#"'&=4763#  C,5(1D,5(þë  C,5(1D,5(›cþ`Ê     R9'-A,!:&-@-!t     R9'-A,!:&-@-! ý*37Ö E¦°(/°)3°*3°13°23°33°43± í± í± í±í±í±í±í°ܰ3±"í±<í±=í±>í±! ?°$/°%3°&3±í±í±í±"í±6 ?°73°83°93±í±í±í± ° /±Aí°/±B]í± °A± í°B±]í0176?4'#"32?67'#"'&547?&'&=476;27Û;AX+0 1-"½N?4&Bc6$3B Na)2C1'7?Š]?Zã+(("-ª0Z /gH[8#\>P?8D >4 $R ,$0H34±HWHi(ÉÖ °/°3±í±í± ?°/±í±í013#i``Ö®ZÿÂÿ° /° 3±í±í01#3&'&5476þ\< *\< ‡‡/q³MTY†3e²UMÿ³-°/°3°3°3±í±í±í±í° /° 3±í±í013#676=4'&\< )\< ‡‡/p³MTY†3d²UMFÛŸ-°/°3±í±í°/° 3°3°3±í±í±í±í01'773#''7#5Æ@J@AJ@€€@JA@J@€o+oo+oVo+oo+oVBب W°/±í°2°3±í°2°3° 3±í±í±í°2± í±í°2± í°/°3°3° 3±í±í±í±í017#53533##ß\\¯\\=ÿ©÷[(±°/± í°/±Rí±°± í°±Rí0173#š]]][²6¯€ °/°3±í±í°/°3±í±í01!!6Jþ¶ \N«\± ?°/±í±í0173#N\\\\+‰Ö7± ?°/± ?°3±°/±í°/±Ví±°±í°±Ví01 3 þ `þÖý*Ö1'Ö#/± ?°/°3±í± í± í± ?°3°#3±í±í±í01"3276=4'&'2#"'&=476,D.,=+6B/->+5dIMPHbdIMPHzTMl…R9ROm„R8\dk›Ÿl`dk›Ÿl`}5Ö"°/°3°3±í±í± ?°/± ?°30173#}\\\(®ý*(1'Ü+± ?°/±í±í±í0147676!!5676767654'&/&1\*7?9w1_ wH/†þ (loo6 ;8\(^2 I$-„_ W5,[[?JL Vc, #01ÿý'ÜC°3°?30147676'#&'&=33?3676574'�'&#&+"2G6?D)«bQ1&g/>=%=?@`7LI(;6GU0 E d6(E7* "‚€, D4>h.68:: ' A51B=(69 ,1'Ö 1± ?° /°ܰ 3° 3° 3±í±í±í±í±í± ?°3013!33##5!tÖÖþ¾@X\\ZþÂ^þ§Ñþ/V¯¯/ÿú(Ö0± ?°/±í±í01!!60/&'2'61?676=4'&'"#&/õþg«H„J!S 2OO50` $7 Xb:¢cs\² {/'k* / R7Lm1'×/.± ?°/°3±í± í± í°Ü°3°3±$í±%í±&í012#"'&=4763276=4'&#"7676767.O/=*5P1=,=;EiPHbpK?RGa>HF†e6#+A(6"*@(qb’§"!bD/°?3±í±í±í° ܰ 3° 3±í±í±í±+ ?°,3°-3±í±í±$í01%276574'&'#""3276574'&&5'476323#"'&=47.O/=&/ P/<*6; 0!: 1®5F7H];+9WPHbpK?P[7"+A(7"+A(!/7/7Ý4IU7,C2@L66^bDKg f( )RF(”" M,+; Ö S°/°3±í±í°ܰ 3±í±í±í±í± ?°/°3±í±í±í± ?°3°3±í±í± í01#3276?4'&'&!!2=¦¦ORTMKZ þþxhjfZqzýâJMZ\TS ý†Ö[\€„m`C¡Ö y°/°3±í±í°2±í±í°2± í±í°2± í°±í±í°± í± í± í± í± ?°/±í±í±?° 3±í±í± ?°3± í± í01!!5!35#5!¡ý¢^þùùþÖý*[ `·+‰Ö b°/°3±í±í±í°2±í±í°2±í°±í±í°± í± í± ?°/±?°3±í±í± ?°3±í± í01!335#5!‰ý¢`ùùþÖý*e`·3™Ö6<°5/°63±!í±2!í±3!í±4!í±+ ?°,/°-3°.3°Ü°63± í±&í±4í±5í01%'#&'&?67127363&'&+";27676=# %W0&ˆ „).R/iTAVWM-  ?RXWMO^ ò¯6 )RF(”" M,+‹K;xGRgGAQh >Kg V$‚Ö U°/°3±í±í± í± í°ܰ3°3° 3±í±í± ?°/°3°3°ܰ3± í± í± ?°3°3° 3013!3#!$\¦\\þZÖý*eþ›ÖþëE¡Ö°/°3±í±í± ?°/± ?°3013E\Öý*Ö3ÿý„Ö0° /°3±í±í°Ü°3°3°3±í±í±í± ?°/013'#&'&'537676=(\PCeAkMI\#4o! Öþ/vL>PKY~&U&3‘Ö 3°/°3±í±í± í± í± ?°/°3° 3± ?°3°3°301333 #3`•iþ‰wiþ³HÖþqþþ›,?í3‘Ö.°/°3±í±í±"í°2± ?°/±í±í± ?°3013!!3\ý¢Öý†\EùÖ °/°3±í± í± í°ܰ3°3±í±í± ?°/°3° 3° 3° 3± ?°3°3°3± ° ±í° /±]í± °± í°± ]í±°±í°± \í01333##E\þþ\\¾€¾Öýý*Ûþ%Ûþ%iÇÖ f°/°3±í±í± í°ܰ3°3±í±í± ?°/°3° 3± ?°3°3°3±°±#í°±fí±°±#í°±fí01333#i`•iiþkÖýÙ'ý*(ýØ;“Ö+j°%/°&3°'3±í±í±í±í° ܰ 3°3°3±í°2±í±í±í± ?°!/°"3±í± í± í± ?°3°*3°+3±í±í±í01"3276=4'5&'&'2#"'&'547672fW=;H;LU?=J-8xW[YGW xW[ZVwzROl|RBQPmzR1 \di˜˜j<di˜™jfA Ö 5± ?° /° ܰ3°3±í±í±í± ?°3°3±í±í± í0132754'&##!2#ý¨X&+ý\YtMDoAUzèrJ þ¼þÊÖA9Ux7!+ŠÖ.m°&/°'3°(3± í± í±í±í°ܰ3°3°3±í±í±í±í± ?°+/°,3°-3°.3±í± í± í± ?°!3°"3°#3±í±í±í012#"'&=476671'6=4'&'"#"232ZS@@H@OV>;I<øE*IHZVxyX\YVz^zRQjqTKROmyRCýÎE*I†W˜jfdi—™jg3‘Ö !¨°/°3±í±í±í±í°ܱí°2°3°3° 3±í±í±í±í±í± ?°/°3°3° ܰ3°3° 3°!3±í±í±í± ?°3°3±í± í± í±í±° /± í°±Rí±°± í°±Rí0132756=4'&####!2#“ù]%)(-sþÒ]`YvM 'cG[|èTK þ¸þÌ4þÌÖ? /?o=,]ÿûÇÛC°8/°93°:3°;301&/&&3'#&/?676'&'&''&'&=4?63ÁMnD+,ŽK)  žm 1?%"3hk.PW G-*wG."(²$£e;g"4H]Z|6 :* lQ =/%= /T8 5(,s\ J. 0 &#3‘Ö6°/°3±í±$í°2±í± ?°/± ?°3±í±í±í±í015!!#3^þÿ\z\\ý†z+ÿþ‰Ö@°/°3°3°3±í±í±í° ܰ 3° 3°3±í±í±í± ?°/°3°30137676=3'&'&=+`K'0+,Z*i\Ga,+qLEÖþ/W3 G'0Ñþ/yL:PIe+‰Ö=± ?°/± ?°3°3°3±°/±í°/±bí±°±í°±bí0133#+`ÏÆiþûWÖýÙ'ý*›Ö ‚± ?° /° 3° 3± ?°3°3°3°3°3± °/±í° /±[í± °±í°± [í±°/± í°± Yí± ° ±í° /±\í±°/±í°±]í01333# #`¢–]–“aÁ`™–TÖýÙ'ýÙ'ý*(ýØ+‰Ö V± ?°/° 3° 3± ?°3°3°3±°/±í°/±[í±°±í°±[í±°/±í°±Tí0133 # #+`ÏÆiþûiÆÏ`Öþïþþ›þûezÖK°/°3±í±í± ?°/± ?°3°3°3±°/±í°±Tí±°±í°±Tí0133#`ÌÉiþûWÖþïþþ›eE¤Ö )± ?°/±í±í±í± ?°3±í±í± í01!!!5!F^þäý¢àþ ÖZýß[[!i!ÖP°/°3±í±í°2±í±í°2°±%í±%í±%í±%í± ?°/±í±í± ?°3±í±í013#3#i¸\\¸Ö\ýâ\+‰Ö7± ?°/± ?°3±°/±í°/±\í±°±í°±\í01#›îpþÖý*Ön&Ö=°/±í°2°3±í°2±í±í± ?°/±í±í± ?°3±í±í01#3#3&¸\\¸Ö\ýâ\.|  73#'.]3K?'0|¤¤ZZÿ¢Xÿþ °/°3±&í±&í± ?°/±í±í01!!Xý¨\$(áÖ0± ?°/±°/±í°/±Tí±°±í°±Tí013#$`]]Ö®(Å$…°/°3°3°3±í±í±í±í° ܰ 3°3°3°3°3°"3°#3±í±$í± ?°/°3°3°3±í± í± í°±í±í± í±!í±#í±$í°±í±í±í01"3276=4'&#5#"'&=476;253 N/=*5P/;,Ã\EZpI=OF`ZE\i8$,A(7"*@*þ—22M?UeC;22ÿÿ9ÿþÖGG1À@!Ä#/± ?°/°3±í±í±í±?°3°3±í± í±!í013&'&#"32767##"'&=47632²\Y: $;›|<°/°3°3°3±í±í±í±í± ?°/±í±í°Ü°3±í±í01533#;````(TTdþ<ÿ7þ|E°/°3°3°3°3±í±í±í±í±í°/° 3° 3±í±í°ܰ3±í±í013##"/7?275ªTTT;- ,|Tdþÿ‹*s°/± í°2°3°3± í°2°3±í°2±)í±)í±)í±)í±)í±#í°$2±()í±' í°&2±))í±*)í°/°3±*í±*í±*í± ?°3±)í±*)í012+276=473675&'5'54>V 'v"  -H2ÿ þìEQó% H Ü~+¯Ãe-°/°3±í± í± í°ܰ3°3°3±í±í±í01756323276767#"'&'&#"+3Q)* 7 &9!#$(" E( ØZ30$ ]",&" \æÙA°/°3±+í±+í±+í±+í°±,í±,í± ?°/±í±í°ܰ3±-í±-í013'35#\Ї‡‡ýùN„!ÿ, (*.0017&'&=476?6767##&'1'? c C < mD4P/?cf? \? g+[? c Ãh hþ©9A( aO=McC( Q#(1XX"9ö_r m\ÿ&?Ö!6u°/° 3±.í±.í°ܱí±í±í°/°3°3± í± í±í°ܰ3°3°3°3°3±í±í± í±!í±"í±6í±& ?°'3°(3±/í±0í±1í013#17632'&+7676'1#531567632#&'&#"«³¨ c DuRº(+;cI/$QGftI(]6:X.›ZG1E [ …8ZZ)~OEM)8A T3A+̽.01&76?6'&'&7'/'7&?'767J(9+ (:*  I&"4B5JM9?8'" 7B6JM 2?7(*9(*9GO 5A5+8@8GO7B7.2@zÖ²°/°3°3°3± /í± /í±/í±/í°ܰ3±0í°2°3±0í°2°3±í± 1í° 2±í±1í°2±í±1í°2±í± ?°/°ܰ3°3°3± í± í± í± í°Ü°3° 3° 3± í± í± í± í± í± í± ?°3°3° 301#53'33733#3##5#535îžd˜`£Q¡iš~¸1ééWÎΪRÚÚÚÚRERüüRiÉÖ=°/°3°3°3±í±í±í±í± ?°/±.í±.í± ?°3±2í±2í013#3#i````8þÈÖþ¹)‘ÚU'± ?°/°3±S*í±T*í°/ܰ03±5*í±6*í±7*í0167676''&'#"'&74?&'&5'4737676=4/"'7632127Ð?%+EA$•0<1!\8)+51 =x&*-1"&D13H&7+01<0R6,"!5¦:3 8(8-!(<0 0% .88#2$>0!0 (.  > $.Ö <°/°3±*í±*í°Ü°3±í±í± ?°/°3°3±)í±)í±)í±)í013#'3#Ê??œEEHHH9NÖ'LŸ°"/°#3±í±í±í±í°BܰC3°D3°E3±/í±0í±1í±2í° Ü° 3°3°3±í±í± ?°/°3±í± í± í°>ܰ?3°@3±5í±6í±7í°+ܰ,3°-3±Gí±Hí±Ií± ?°3°'3±í±í±í01"3276=4'&'2#"'&/47676&'&#"327673#"'&=47632ÄXRYW{€XRYWzžrn iKh68Ÿrn ijš¯@#O/=%0 C6 \U=GpJ@PHbzF* |UNlrPOUNlqPOZe`‹ŽiJe`‹Žii þ´: 7"+A(2X3$L?VcC

^U b3"ÿÿiÇ´&1a¡Oÿÿ;“¬&2CäÖÿÿ;“g&2uÖIÿÿ;“¢&2AË‚ÿÿ;“´&2apOÿÿ;“F&2iË(ÿÿfÇx‡ôÿm-A-AÒ¾-A*ÿú‰Ö "/o°)/°*3°+3±í±í±í±í° ܰ 3°3°3±í±í±í°/°3°3°3±í±í±í±- ?°.3°ܰ3° 3±$í±%í±&í± ?°!3017&'=47632#"';276754'7#1&#"37²'G9J;27'G9K<25JZxW[OVi*IWxW[NM`&ÃGY}RA*EGY~RA,K8di˜hp6ÿÿ+ÿþ‰¬&8C×Öÿÿ+ÿþ‰g&8uÉIÿÿ+ÿþ‰¢&8A¾‚ÿÿ+ÿþ‰F&8i¾(ÿÿzg&<uºIA  .°/°3°3±í±í±í± ?° 3° 3±í±í± í0132754'&#'32+#3¢øªZ&+øøvLCjCXøa^|ærJ Z@7Tu:%þÊ Bÿ¨ì×?0147676'&/76767676/&'8?6'&'&CO0>\,  %. :3  <(<#e'& 14%N.BX€[2N46A'!) NF,   N 0.+ T ?&..ý€ÿÿ(›&DCœÿÅÿÿ(V&DuŽÿ8ÿÿ(‘&DAƒÿqÿÿ(£&Da'>ÿÿ(5&Diƒÿÿÿ(ÿ&DqqÝ­ÅLµ° /°!3°"3°#3± í± í±í±í°ܰ3°3°3°3°(3°)3°L3±*í±+í±Jí±Kí± ?°/°3°G3°H3°I3°K3°L3±í±í±í±@í±Aí±Bí°:ܰ<3°=3±í±í±2í±%?°&3°'3°)3°*3±í±í±í± í± í±í01!&'&#"%"3276=4'&#"'&=476325363201&132?#"'#*I X* þöO/=*5O/=*gEXqJ@PHcXE]EYqJ% oþï@^6U^YE]A 9K7"+A(7"+A(þÍ2L@UcD<2243L$/ " &4 0""33ÿÿ!ÿOÄ&Fyÿÿ$š&HCœÿÄÿÿ$U&HuŽÿ7ÿÿ$&HAƒÿpÿÿ$4&Hiƒÿÿÿ Ëš&òCêÄÿÿ¼U&òuÿÜÿ7ÿÿÿþÚ&òAÿÑÿpÿÿÿþÚ4&òiÿÑÿi±2k°!/°"3°#3°$3±í±í±í± í± í°ܰ3°3°3±í±í±í±í± ?°/°3°3± í± í±í±&?°'3±í±í±í01"003276=4'&+"'&=4763''7'774A&6!)@&6!|)G9K\=3G9L1NMCFFn9$-I*9%.I*;KhC7L@UhC7_(7(6#6%7%ÿÿ$¾¢&Qaÿú=ÿÿ$š&RCœÿÄÿÿ$U&RuŽÿ7ÿÿ$&RAƒÿpÿÿ$¢&Ra(=ÿÿ$4&Riƒÿ?%Õ• -°/°3±í±í°ܰ3±í±í°ܰ 3± í± í01735'5!'53âVø”óWyTT6VV’TT$ÿÎä */± ?°/°3±í±í±í±?° 3° 3±#í±$í±%í017'7&5476327#"73276=4'7&#"¬@A:AQHb=61A+@QHb= P/!ù¯O/K8DAWcC<973@WcCZ`@ÿÿ&†G&$YÆ(ÿÿ(6&DY’ÿÿÿ&ÿO†Ö&$GyéÀ@ÿÿ(ÿOÅ&DGyµÀ@ÿÿ3™g&&uÙIÿÿ!U&Fu‡ÿ7ÿÿ3™¢&&A΂ÿÿ!&FA|ÿpÿÿ3™Z&&ÿþÿÿ!H&F­ìÿÿ3™I&&Zó(ÿÿ!7&FZ¡ÿÿÿ; I&'Zó(ÿÿ0ÿþI&GZQ(ÿÿ%ïØ‘+ŽÖ-ɰ/°3° 3°!3±í±í±í±í°(ܰ)3±;í±;í° Ü° 3°3°3°3°3°&3°'3±(<í°)2°*3±)<í°(2°+3±í±=í°2±í±í±,í±-í± ?°/°3°3°3±í± í± í±#?°$3°%3±í±í±í°ܰ3°'3°(3±í±)í±*í±-í±+ ?°,301"3276=4'&'##5#"'&=476325#5353$O/=*5O/=%0`n`DVqJ@PHcVD€€`e7"+A(7"+A(Tþºâ00L?VcC<0”TZZÿÿC¡Z&(G<OZ`@ÿÿ$H&HGÿê=Z`@ÿÿC¡G&(Yå(ÿÿ$5&HY’ÿÿÿC¡Z&(þÿÿ$H&H³ìÿÿCÿO¡Ö&(GyÀ@ÿÿ$ÿOÄ&HGy‘À@ÿÿC¡I&(Zû(ÿÿ$7&HZ§ÿÿÿ3™¢&*A΂ÿÿ5ÿ:)&JAˆÿpÿÿ3™G&*YÝ(ÿÿ5ÿ:)5&JY—ÿÿÿ3™Z&*ÿþÿÿ5ÿ:)H&J¸ìÿÿ3ÿO™Ö&*yÓÿÿ5þ†)Ä&JyŒÿ7ÿÿ$‚¢&+A·‚ÿÿÿæ¼¢&KAÿ¹‚ ÀÖ e± ?°/°3°3±?°3±í±í°ܰ3° 3° 3°3°3°3±í±í±í± í± í± í±í±í±í± ?°3°3°3015#!!!'#5;5#3!33'#nhþÂ>þÂ`HH```>hRN|ZZTccTZZTýØeþ›(T*Öš°/°3± >í± >í°ܰ3±í°2°3±í°2°3±í±í±í± í± í° 2± í± í° 2± í°ܰ3°3±í±í±í±í± ?°/°3°3°ܰ3° 3° 3±í±í± í± í± ?°301##53533#6732#4Þ`TT`VVBKj! ZVE9;þÅ(TZZT(5þš>: $ÿÿÿ¤=´&,aÿzOÿÿÿ 8¢&òaÿu=ÿÿÿ‡ZZ&,Gÿ<OZ`@ÿÿÿƒUH&òGÿ7=Z`@ÿÿÞG&,Yä(ÿÿÿþÚ5&òYÿàÿÿÿÿOßÖ&,GyÀ@ÿÿÿýÿOÙ|&LGyÀ@ÿÿE°Z&,þ<œÄ°/°3±í±í± ?°/±?°3013#<``Äþ<ÿÿEÿýuÖ&,-ñÿÿ;ÿ7j|&LMlÿÿ3ÿýÊ¢&-AÁ‚ÿ75Í0°/°3°3±í±í±í°/°3°3± í± í±?°301#"/7?275'73#'þ;- ,P]3K?'0Äþ88BL)z1/ŠKùR\e91Ib'öl!6'p#  '%C5/G'0X0 G? \\ý /^@7ia79áFR°/°3±Aí±Aí°/±í°ܰ3°B3°C3±í±í±CD°C/±Fí°D/±E[í±CD°F±Cí°E±D[í015!3&'&'676'&'&'6766''&/676/739þ{LŠ'1k >!*KE"?5 )X*U>`2!f\O\‡Z\þõ?A%8X/B!C3: / E'I"4 W"Cb X9D/þôýƒÿÖFÖM`°/°3±Bí±Bí°)ܰ*3°+3°,3± í± í± í° Ü°3°3±@ í±A í±B í±C í±ICí°J2± ?°/±í±í±í±í0135!!1'547&'&?676=4'&''&'&'&=476736756?ãcýº„W`$Xk>SI[Fm  #) FIÿâLin-°/°3±UDí±VDí°/°3°T3°U3±í±í±Ví±Wí01!!&'&7277'676=4'1&'#'&'&'5&70367676?=1735!&'&?6&1&'&&7þã‡Zi), jLp;eHCq$@$8 neNL 1OŠ"dþþ*6 P"DL% JC~NA !Y    QMR &6?_   "  ; ?N") $ ( :ý¤8#" 9ÿåŽØ*0137676/!5!#'&5'7676'&'=3( VþúS¥-n> 9I‹W75>?8(C3F¨;*F^^)3f=.mhK 0 :N]at<.<2 "ÿå Ù@°5/°63°73°:3°;3±8í±9í016'6'&'#&'&'&'767&?656'&'&'537674'&#!5!!"?8(C$04' 0!þúèþÆ-G(9:«&S59!*c&¦O–]at;2 ];*7 ^^(5f=ÿÿ&þƆÖ&$q¦ü¶ÿÿ(þÆÅ&Dqsü¶ÿÿG¢Z&%éþÿÿ9ÿþZgG1À@ÿëþÿÿGÿ|¢Ö&% ÿ|ÿÿ9ÿ|ÖgG1À@žÿ|ÿÿGÿ|¢Ö&%G<þÍZ`@ÿÿÿ|ÖgG1À@GÿÒþÍZ`@ÿÿ3ÿO™g&&'yÓuÙIÿÿ!ÿOU&F'yu‡ÿ7ÿÿ; Z&'þÿÿ0ÿþZ&G]þÿÿ;ÿ| Ö&'ÿ|ÿÿ0ÿ|øÖ&GŸÿ|ÿÿ;ÿ| Ö&'G8þÍZ`@ÿÿÿ|øÖ&GGÿÓþÍZ`@ÿÿ;ÿO Ö&'yÖÿÿ0ÿOøÖ&Gyqÿÿ;ý Ö&'5 ýÿÿÿÙý7Ö&G5ÿ¦ýÿÿC¡0&(g<OZ`@CïZÿÿ$&Hgÿê=Z`@CœHÿÿC¡ë&(g<OZ`@uáÍÿÿ$Ù&Hgÿê=Z`@uŽÿ»ÿÿCý¡Ö&(5ýÿÿÿËý*Ä&H5ÿ™ýÿÿCÿ"¡Ö&(a{þsÿÿ$ÿ"Ä&HaþsÿÿCÿO¡G&('yÛYå(ÿÿ$ÿO5&H&ycY’ÿÿÿ+‰Z&)ñþÿÿ2Z&Iiþÿÿ3™Z&*G4OZ`@ÿÿ5ÿ:)H&JGÿú=Z`@ÿÿ$‚Z&+êþÿÿ$¼Z&Kÿëþÿÿ$ÿ|‚Ö&+êÿ|ÿÿ$ÿ|¼Ö&K‡ÿ|ÿÿ$‚F&+i·(ÿÿÿæ¼F&Ki¹(ÿÿ$ÿO‚Ö&+y¼ÿÿ$ÿO¼Ö&KyYÿÿÿ§ÿ"?Ö&,aÿ|þsÿÿÿŸÿ"7|&LaÿtþsÿÿÞ×&,&iÕ(uÿà¹ÿÿÿþÚÅ&ò'iÿÑÿuܧÿÿ3‘g&.uÑIÿÿ „g&NuËIÿÿ3ÿ|‘Ö&.ùÿ|ÿÿ+ÿ|„Ö&Nnÿ|ÿÿ3ÿ|‘Ö&.G,þÍZ`@ÿÿÿîÿ|ÁÖ&NGÿ£þÍZ`@ÿÿ3ÿ|‘Ö&/ùÿ|ÿÿ;ÿ|­Ö&Oÿ|ÿÿÿxÿ|‘Z&/'ùÿ|Gÿ,OZ`@ÿÿÿ‚ÿ|TZ&O'ÿ|Gÿ6OZ`@ÿÿ3ÿ|‘Ö&/G,þÍZ`@ÿÿÿ‚ÿ|TÖ&OGÿ6þÍZ`@ÿÿ3ý‘Ö&/5ýÿÿÿ<ýšÖ&O5ÿ ýÿÿEùg&0uIÿÿ\<U&Pu»ÿ7ÿÿEùZ&06þÿÿ\<H&PãìÿÿEÿ|ùÖ&06ÿ|ÿÿ\ÿ|<Ä&Pãÿ|ÿÿiÇZ&1/þÿÿ$¾H&Qˆìÿÿiÿ|ÇÖ&1/ÿ|ÿÿ$ÿ|¾Ä&Qˆÿ|ÿÿiÿ|ÇÖ&1GbþÍZ`@ÿÿÿ|ÚÄ&QGÿ¼þÍZ`@ÿÿiýÇÖ&156ýÿÿÿÂý Ä&Q5ÿýÿÿ;“E&2'apOuÖ'ÿÿ$3&R'a(=uŽÿÿ;“$&2'apOiËÿÿ$&R'a(=iƒÿôÿÿ;“0&2g1OZ`@CäZÿÿ$&Rgÿê=Z`@CœHÿÿ;“ë&2g1OZ`@uÖÍÿÿ$Ù&Rgÿê=Z`@uŽÿ»ÿÿA g&3ußIÿÿ-ÿ8!U&Su–ÿ7ÿÿA Z&3þÿÿ-ÿ8!H&S½ìÿÿ3‘Z&5ùþÿÿ+„H&Unìÿÿ3ÿ|‘Ö&5ùÿ|ÿÿ+ÿ|„Ä&Uÿòÿ|ÿÿ3ÿ|‘Z&5'ùÿ|G,OZ`@ÿÿÿîÿ|ÁH&U'ÿòÿ|Gÿ£=Z`@ÿÿ3ÿ|‘Ö&5G,þÍZ`@ÿÿÿrÿ|„Ä&UGÿ&þÍZ`@ÿÿ]ÿûÇ_&6,ÿÿ1ËH&V–ìÿÿ]ÿwÇÛ&6,ÿxÿÿ1ÿ|ËÄ&V–ÿ|ÿÿ]ÿûÇð&6'uM,“ÿÿ1ËÙ&V'unÿ7–}ÿÿ]ÿûÇÒ&6'Z,,uÿÿ1Ë»&V'Zˆÿ–_ÿÿ]ÿwÇ_&6',ÿx,ÿÿ1ÿ|ËH&V'–ÿ|–ìÿÿ3‘Z&7ùþÿÿ-V&WP¤ÿÿ3ÿ|‘Ö&7ùÿ|ÿÿ-ÿ|V|&WPÿ|ÿÿ3ÿ|‘Ö&7G,þÍZ`@ÿÿÿÐÿ|£|&WGÿ…þÍZ`@ÿÿ3ý‘Ö&75ýÿÿÿŠýé|&W5ÿXýÿÿ+ÿމÖ&8i¾ü¹ÿÿ$ÿ¾Ä&XiUüºÿÿ+ÿ ‰Ö&8acþrÿÿ$ÿ"¾Ä&Xaÿúþsÿÿ+ý‰Ö&85ÿøýÿÿÿÂý Ä&X5ÿýÿÿ+ÿþ‰E&8'acOuÉ'ÿÿ$¾3&X'aÿú=u`ÿÿ+ÿþ‰Ê&8g$OZ`@i¾¬ÿÿÚ¸&Xgÿ¼=Z`@iUšÿÿ+‰´&9acOÿÿ$¢&Ya'=ÿÿ+ÿ|‰Ö&9ñÿ|ÿÿ$ÿ|Ä&Yµÿ|ÿÿ›¬&:CYÖÿÿkš&ZCÁÿÄÿÿ›g&:uKIÿÿkU&Zu³ÿ7ÿÿ›F&:i@(ÿÿk4&Zi¨ÿÿÿ›Z&:rþÿÿkH&ZÚìÿÿÿ|›Ö&:rÿ|ÿÿÿ|kÄ&ZÚÿ|ÿÿ+‰Z&;ñþÿÿ$áH&[™ìÿÿ+‰F&;i¾(ÿÿ$á4&[igÿÿÿzZ&<âþÿÿ:ÿ:0H&\ÌìÿÿE¤¢&=AÙ‚ÿÿ+ &]AŠÿpÿÿEÿ|¤Ö&= ÿ|ÿÿ+ÿ| Ä&]¼ÿ|ÿÿEÿ|¤Ö&=G?þÍZ`@ÿÿ+ÿ| Ä&]GÿñþÍZ`@ÿÿÿ|ÙÖ&KGÿ»þÍZ`@ÿÿ-Vì&WiÎÿÿkþ&Zq–ÿÜÿÿ:ÿ:0þ&\qˆÿÜÿÿ&ÿ|†Ö&$êÿ|ÿÿ(ÿ|Å&D·ÿ|ÿÿ&†3&$'A·‚uÂÿÿ("&D'AƒÿquŽÿÿ&†x&$'A·‚CТÿÿ(g&D'AƒÿqCœ‘ÿÿ&†€&$'A·‚a\ÿÿ(o&D'Aƒÿqa' ÿÿ&ÿ|†¢&$'êÿ|A·‚ÿÿ(ÿ|‘&D'·ÿ|A…ÿqÿÿ&†Ø&$'YÆ(u¹ÿÿ(Ç&D'Y’ÿuÿ©ÿÿ&†&$'YÆ(CÐFÿÿ( &D'Y’ÿCž5ÿÿ&†%&$'YÆ(a\¿ÿÿ(&D'Y’ÿa)®ÿÿ&ÿ|†G&$'êÿ|YÆ(ÿÿ(ÿ|6&D'·ÿ|Y”ÿÿÿCÿ|¡Ö&( ÿ|ÿÿ$ÿ|Ä&H‘ÿ|ÿÿC¡´&(a{Oÿÿ$¢&Ha'=ÿÿC¡3&('AÖ‚uáÿÿ$!&H'AƒÿpuŽÿÿC¡x&('AÖ‚Cï¢ÿÿ$f&H'AƒÿpCœÿÿC¡€&('AÖ‚a{ÿÿ$n&H'Aƒÿpa' ÿÿCÿ|¡¢&(' ÿ|AÖ‚ÿÿ$ÿ|&H'‘ÿ|AƒÿpÿÿEÿ|µÖ&, ÿ|ÿÿ;ÿ|­|&Lÿ|ÿÿ;ÿ|“Ö&2þÿ|ÿÿ$ÿ|Ä&R¶ÿ|ÿÿ;“3&2'AË‚uÖÿÿ$!&R'AƒÿpuŽÿÿ;“x&2'AË‚Cä¢ÿÿ$f&R'AƒÿpCœÿÿ;“€&2'AË‚apÿÿ$n&R'Aƒÿpa( ÿÿ;ÿ|“¢&2'þÿ|AË‚ÿÿ$ÿ|&R'¶ÿ|Aƒÿpÿÿ;ag&2'j{u=Iÿÿ$èU&R'ðiuõÿ7ÿÿ;a¬&2'j{CKÖÿÿ$èš&R'ðiCÿÄÿÿ;a´&2'j{a×Oÿÿ$è¢&R'ðia=ÿÿ;ÿ|aÖ&2'j{þÿ|ÿÿ$ÿ|èÄ&R'ði¶ÿ|ÿÿ+ÿz‰Ö&8ñÿ{ÿÿ$ÿ|¾Ä&Xˆÿ|ÿÿz¬&<CÈÖÿÿ:ÿ:0š&\C²ÿÄÿÿÿ|zÖ&<àÿ|ÿÿ:þ¶0Ä&\Þþ¶ÿÿz´&<aTOÿÿ:ÿ:0¢&\a>=6¯€°/°3±í±í°/°3±í±í0175!6J¯VV6¯€°/°3±í±í°/°3±í±í0175!6J¯VV6¯°/°3±Eí±Eí°/°3±í±í0175!6è¯VV6¯º°/°3±Aí±Aí°/°3±í±í0175!6„¯VV6¯®°/°3±Fí±Fí°/°3±í±í0175!6x¯VV6¯–°/°3±Gí±Gí°/°3±í±í0175!6`¯VVÿÿ9kÖ&__Òÿÿ>âë&GN¯ e4° /° 3°3°3±Hí±Hí±Hí±Hí°/° 3° 3±9í±9í±9í012#"'&=476¬5-4-e+3+3ÿÿ1€—(€ Ìÿÿ1€—(€ Ìÿÿ1|—'} Ìÿÿ1€—(€ Ìÿÿ1€—(€ Ìÿÿ1€—(€ Ìÿÿ1—(€ Ìÿÿnd Ìÿÿÿò/4Bÿè Ìÿÿ,!’Y $ Ìÿÿÿíw$ ÿÜ„ ÌÿÿÿÞw$ ÿÜ„ ÌÿÿRnQÿù Ìÿÿ1ÿÄ—V(Å ÌÿÿÿÄ+VíÅ Ìÿÿ1ÿÆ—Y'Ç Ìÿÿ1ÿÅ—Y(Æ Ìÿÿ1ÿÄ—V(Å Ìÿÿ1ÿÀ—S' Ìÿÿ1ÿÄ—W(Å Ìÿÿ1ÿÄ—V(Å Ìÿÿ1ÿÄ—V(Å Ìÿÿ1ÿ×V(Å ÌÿÿÿVnÿ¨ÿS Ìÿÿÿòÿs4ÿ†ÿèÿQ Ìÿÿ,ÿe’ÿ $ÿV Ìÿÿÿíÿ»h ÜÈ ÌÿÿÿÞÿ»h ÜÈ Ìÿÿ2ôÖgDÜ#A!{&[GFÍ#Ã%òÿÿ2ÿþäÖgDÔ%Ï"&PGVõÿþ!>&_ÿÿ3™Ö&ÿÿ+£"&q& ÿÿ!ÿÿàígF!Ñ!Ž&üGRÿÿ(M&§ÿÿ,ÿù›gF%1!j&GX«ÿù"W%òÿÿ+¢"&q)A ÚC°/°3±í±í±í±í°/°3°3±í±í±í°ܰ3°3± í± í±í017;3276=4'&#!33732+Ž,J–}K=eFZþ§M,J–_0«–6E8Vj:(ý*x.'tÿÿ+ŠÖ4ÿÿ/x_/6 Ì0Åx Ì${D  ° /°3°30153##55373#5#'$y4^24(%û€€€’’[[[[ÿÿ&†&$q¦îÿÿE¡Ö,ÿÿE’Ö&,,ñÿÿEƒÖ&,',ñ,âÿÿEzÖ&,9ñÿÿ+‰Ö9ÿÿ+cÖ&9,Âÿÿ+TÖ&9',Â,³ÿÿ+EÖ&9',Â',³,¤ÿÿEzÖ&,;ñÿÿ+‰Ö;ÿÿ+[Ö&;,ºÿÿ+LÖ&;',º,«ÿÿ3‘Ö/ÿÿ3™Ö&ÿÿ; Ö'ÿÿEùÖ0ÿÿ;›|Lÿÿ;||&LLáÿÿ;]|&L'LáLÂÿÿ;ú|&LYáÿÿ$ÄYÿÿ$á|&YLFÿÿ$Â|&Y'LFL'ÿÿ$£|&Y'LF'L'Lÿÿ;Â|&L[áÿÿ$áÄ[ÿÿ$«|&[Lÿÿ$Œ|&['LLñÿÿ;›ÖOÿÿ!ÄFÿÿ0ÿþøÖGÿÿ\<ÄPÿÿ}5Öÿÿ1'Üÿÿ1ÿý'Üÿÿ1'Öÿÿ/ÿú(Öÿÿ1'×ÿÿ1'Öÿÿ1'Öÿÿ1ÿÿ'Öÿÿ}Ö&Xÿÿ}Ö&Xÿÿ}Ü&Xÿÿ}ÿýÜ&Xÿÿ}Ö&Xÿÿ}ÿú€Ö&XÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂ& '  cÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »ÿÿZÿÂn& ' 'c »DNЄ_<õè·ßvG·ßvGÿ<ý–¡ ÿ8Ðÿ<ÿG–¬°!MG>Š4æ;è^Ø>]3>i Z 'FB/=º6ùN²+X1X}X1X1X1X/X1X1X1X1; c3N,c3'3Ñ4¬&áGÙ3Ù;éC²+Ù3º$ñEÑ3Â3Ê3>EèiÊ;áA¾+á3è]Ñ3Ê+Â+ɺ+£éE«i²+«nN.X$F((9(!(0N$P^5ñ$á;7Ê+á;˜\é$>$N-N-é+ø1„-é$F$›$Ÿ:U+„lÒ9„>+G\(!Œ&+£/iº)7.Œ9@•-ãdø%ø8Ò…+Õÿü.(ÚAá:6DFDF)ç2%•- !¬" '3¬&¬&¬&¬&¬&¬&6&Ù3éCéCéCéCññ!ññ%èiÊ;Ê;Ê;Ê;Ê;Xf²*Ê+Ê+Ê+Ê+£áA.BF(F(F(F(F(F(Ì(!N$N$N$N$á ááÿþáÿþèié$>$>$>$>$>$?>$é$é$é$é$è:N-è:¬&F(¬&F(¬&F(Ù3(!Ù3(!Ù3(!Ù3(!Ù;N0%²+éCN$éCN$éCN$éCN$éCN$Ù3^5Ù3^5Ù3^5Ù3^5º$ñÿæà @*ñÿ¤áÿ ñÿ‡áÿƒñáÿþñáÿýñEá<ÂE°;Ñ37Â3Ê+æ6ÊáÊ3áÿýÊáÊ3';èié$èié$èié$Ê;>$Ê;>$Œ$á3é+á3éÿíá3é+è]ø1è]ø1è]ø1è]ø1Ñ3„-Ñ3Ê+é$Ê+éÊ+é$Ê+é$É›£è:£éEU+éEU+éEU+%Ê;>$Ê+éÊ+é$Ê+é$¬&F(Ù3^5èié$¬&F(è]ø1Ñ3„-¬&F(éCN$Ê;>$Ê;>$Ê;>$Ê;>$£è:« « V3Ð Ò)F)F(é'V<¬597FLÇ9."¬&F(áG(9áG(9áG(Ù3(!Ù;(0Ù;(0Ù;(Ù;(0Ù;(ÿÙéCN$éCN$éCNÿËéCN$éCN$²+PÙ3^5º$ñ$º$ñ$º$ñÿæº$ñ$ñÿ§áÿŸñáÿþÂ3Ê Â3Ê+Â3ÊÿîÊ3á;Êÿxáÿ‚Ê3áÿ‚Ê3áÿ<>E˜\>E˜\>E˜\èié$èié$èiéèiéÿÂÊ;>$Ê;>$Ê;>$Ê;>$áAN-áAN-á3é+á3é+á3éÿîá3éÿrè]ø1è]ø1è]ø1è]ø1è]ø1Ñ3„-Ñ3„-Ñ3„ÿÐÑ3„ÿŠÊ+é$Ê+é$Ê+éÿÂÊ+é$Ê+éÂ+F$Â+F$ɛɛɛɛɛº+$º+$£Ÿ:éEU+éEU+éEU+ñ„-›Ÿ:¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(¬&F(éCN$éCN$éCN$éCN$éCN$éCN$ñEá;Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê;>$Ê+é$£Ÿ:£Ÿ:£Ÿ:º6º6X6ô6è6Ð6¤9Ž>YNX1X1x1x1x1x1x1kXÿòv,JÿíJÿÞaX1xx1x1x1x1x1x1x1x1kXÿòv,JÿíJÿÞ<2,2Ù3^+$!Ç,7+áA¾+Â/Â$¬&ñEâEÓE³EÂ+³+¤+•+«Eº+«+œ+Ê3Ù3Ù;>Eá;Â;£;';F$'$$é$ñ;$ñ$Ò$á;(!N0˜\X}X1X1X1X/X1X1X1X1°}°}°}°}°}°}nZnZnZnZnZnZnZnZnZÆZÆZÆZÆZÆZÆZÆZÆZÆZÆZÆZ’`ÿÜ3þù3Dÿˆ3Fÿˆ3Gÿˆ3Mÿ°3Rÿ’3Tÿˆ7Dÿ:7FÿN7Gÿ:7HÿL7PÿP7QÿO7RÿK7TÿC7UÿH7Vÿ87XÿO7ZÿM7\ÿ8=Mÿ°=Yÿš++++M|²Xt×MmŠŸÊ9Šò&zÚû€áL`ƒ– ! è F ¾ & ‚ Ö  ‹ Î ë . b ‰ ã,£åaë[ˆ×e­èMx¨¹Õús~Ì:•üŽÓJŠ£P¤q±D­îD`¬0LÄ =“nì­Ýœ¦ù  " Ä Ï! !/!d!´!Õ"$"Z"…"Ö"é"ó"þ##"#4#>#J#V#b#n#z#†#Ç#Ó#ß#ë#÷$$$$&$1$$›$§$³$¿$Ë$×$ä%b%n%z%†%’%ž%Þ&D&P&\&h&t&€&‹'Q']'i'u'''˜'¤'°'¼(;(G(S(_(k(w(ƒ(±) ))!)-)9)E)ª)¶)Ä)Ò)Þ)ê)ø******6*B*N*Z*f*r*~*†+,+:+H+T+`+l+x+†+”+ +¬+¸+Ä+Ð+Ü+è+ô,, ,,$,„,ü---"-0-;-G-U-c-o-‹-—-¢-®-ï-û../.:.E.Q.\.g.r.~.Š.–.¢.®.¹.Å.Ñ.ß.í.ù//X/d/p/|/ˆ/“/Ÿ/«/·/Ã/Ï/Û/ç/ò/þ0 00!0-090E0S0a0m0x0†0”0 0¬0¸0Ä0Ð0Ü0è0ô11 11 1,181J1\1l1{1‹1š1¬1¾1Ê1Ö1â1í1ý2 22$202<2H2T2`2k2}22¡2³2¿2Ë2Ý2ï2ý3 33#333>3l3Ÿ3§3²3ô4!4k4Ú5v66Ì77…7‘77©7¸7Ä7Ó7á7ò8888*868B8P8^8j8u888Ÿ8±8Ã8Õ8á8í8ù999$909<9J9X9d9p9|9ˆ9”9Ÿ9«9¶9Â9Î9Ý9ì9ø::::):7:C:O:a:s:::›:§:³:¿:Ë:×:ã:ï:û;;;;-;;;G;S;c;s;ƒ;“;¥;·;É;Û;ç;ó;ÿ< <<#>>>)>5>A>M>Y>e>q>}>‰>•>¡>­>¹>Å>Ñ>Ý>é>õ?? ??'?5?C?N?Z?f?r?~?Ž?ž?®?¾?Î?Þ?î?þ@@@.@>@N@^@n@~@Š@–@¢@®@¾@Î@Þ@î@þAAA.A:AFARA^AnA~AŽAžA®A¾AÎAÞAîAþBBB.B>BNB^BjBvB‚BŽBšB¦B²B¾BÚBöCC.CJCfCrC~C¶CÀCÊCÔCÞCèCòCüDDDD$D.D8DADJDSD\DeDnDwD€D‰D’DœD¦D°D¹DÂDÖDêDòDþEE&E2E€EˆE—E¾EÊEÒEÞEîEúFFFF2F>FFFRFbFjFrFzF‚FŠF–F¦F²FºFÆFÖFêFöFþG GG"G*G2G:GBGJGRGZGbGjGrGzG‚GŽGšG¦G²G¾GÊGÚGêGúH HH*H:HJHZHnH‚H–HªH¾HÒHæHúII"I6¬o@@û@AHPls{€‚ 6" Zh x €‚    6"  Z h  xCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ImUglyRegularPfaEdit : ImUgly : 2-9-2071ImUgly001.000ImUglyCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ImUglyRegularPfaEdit : ImUgly : 2-9-2071ImUgly001.000ImUglyÿœ2¬  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„…½–膎‹©¤ŠÚƒ“òó—ˆÃÞñžªõôö¢­ÉÇ®bcdËeÈÊÏÌÍÎéfÓÐѯgð‘ÖÔÕhëí‰jikmln oqprsutvwêxzy{}|¸¡~€ìîºýþ    ÿ øù !"#$%&'()*+ú×,-./0123456789:;<=>?@ABCD°±EFGHIJKLMNûüäåOPQRSTUVWXYZ[\]»^_`aæçbcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij²³klmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”Œ•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖר softhyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaronOmacronomacronObreveobreveRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflexuni0162uni0163TcaronUtildeutildeUmacronumacronUringuringUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentuni0189Ohornohornuni01D5uni01D6uni01D7uni01D8uni01DBuni01DCuni01DEuni01DFuni01F4uni01F5uni01F8uni01F9 Aringacute aringacute Scommaaccent scommaaccent Tcommaaccent tcommaaccentuni0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233 gravecomb acutecombuni0302 tildecombuni0306uni030Cuni0327uni0328uni0901uni0902uni0903uni0905uni0906uni0907uni0908uni0909uni090Auni1E00uni1E01uni1E02uni1E03uni1E04uni1E05uni1E06uni1E07uni1E08uni1E09uni1E0Auni1E0Buni1E0Cuni1E0Duni1E0Euni1E0Funi1E10uni1E11uni1E12uni1E13uni1E14uni1E15uni1E16uni1E17uni1E18uni1E19uni1E1Auni1E1Buni1E1Cuni1E1Duni1E1Euni1E1Funi1E20uni1E21uni1E22uni1E23uni1E24uni1E25uni1E26uni1E27uni1E28uni1E29uni1E2Cuni1E2Duni1E2Euni1E2Funi1E30uni1E31uni1E32uni1E33uni1E34uni1E35uni1E36uni1E37uni1E38uni1E39uni1E3Auni1E3Buni1E3Cuni1E3Duni1E3Euni1E3Funi1E40uni1E41uni1E42uni1E43uni1E44uni1E45uni1E46uni1E47uni1E48uni1E49uni1E4Auni1E4Buni1E4Cuni1E4Duni1E4Euni1E4Funi1E50uni1E51uni1E52uni1E53uni1E54uni1E55uni1E56uni1E57uni1E58uni1E59uni1E5Auni1E5Buni1E5Cuni1E5Duni1E5Euni1E5Funi1E60uni1E61uni1E62uni1E63uni1E64uni1E65uni1E66uni1E67uni1E68uni1E69uni1E6Auni1E6Buni1E6Cuni1E6Duni1E6Euni1E6Funi1E70uni1E71uni1E72uni1E73uni1E74uni1E75uni1E76uni1E77uni1E78uni1E79uni1E7Auni1E7Buni1E7Cuni1E7Duni1E7Euni1E7FWgravewgraveWacutewacute Wdieresis wdieresisuni1E86uni1E87uni1E88uni1E89uni1E8Auni1E8Buni1E8Cuni1E8Duni1E8Euni1E8Funi1E90uni1E91uni1E92uni1E93uni1E94uni1E95uni1E96uni1E97uni1E98uni1E99uni1EA0uni1EA1uni1EA4uni1EA5uni1EA6uni1EA7uni1EAAuni1EABuni1EACuni1EADuni1EAEuni1EAFuni1EB0uni1EB1uni1EB4uni1EB5uni1EB6uni1EB7uni1EB8uni1EB9uni1EBCuni1EBDuni1EBEuni1EBFuni1EC0uni1EC1uni1EC4uni1EC5uni1EC6uni1EC7uni1ECAuni1ECBuni1ECCuni1ECDuni1ED0uni1ED1uni1ED2uni1ED3uni1ED6uni1ED7uni1ED8uni1ED9uni1EDAuni1EDBuni1EDCuni1EDDuni1EE0uni1EE1uni1EE2uni1EE3uni1EE4uni1EE5Ygraveygraveuni1EF4uni1EF5uni1EF8uni1EF9uni2010uni2011 figuredash afii00208uni2016 exclamdbluni2043 zerosuperior foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperioruni207Auni207Buni207Cparenleftsuperiorparenrightsuperior nsuperior zeroinferior oneinferior twoinferior threeinferior fourinferior fiveinferior sixinferior seveninferior eightinferior nineinferioruni208Auni208Buni208Cparenleftinferiorparenrightinferioruni2100uni2101uni2102uni2103 afii61248uni2106uni2109uni2119uni211Auni2120uni212Buni2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216Funi2170uni2171uni2172uni2173uni2174uni2175uni2176uni2177uni2178uni2179uni217Auni217Buni217Cuni217Duni217Euni217Funi2460uni2461uni2462uni2463uni2464uni2465uni2466uni2467uni2468uni2469uni246Auni246Buni246Cuni246Duni246Euni2474uni2475uni2476uni2477uni2478uni2479uni247Auni247Buni247Cuni247Duni247Euni247Funi2480uni2481uni2482uni2483uni2484uni2485uni2486uni2487libimager-perl-1.004+dfsg.orig/fontfiles/ExistenceTest.ttf0000644000175000017500000000363412031434615023065 0ustar gregoagregoa €0OS/2QB_¥¼VcmapVÕJcvt å‡`glyfT{0Òp~headÖƒ#ð6hheatþ($hmtx-LlocaÖ` maxpI´l nameIôôŒâpostÿ¨Fp,èô ÈÈÈÈÈÈ1PfEd@ ~ÿÉZ7D(!/ÿÿ!/ÿÿÿâÿÕ!y~.–!nš.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!!MþÔ þõšýf!X3Ïâ*†± ?° 3° 3° 3±í±í±í±í°°Þ° 2°!2°"2±í±í±í±*í°$/°%3°&3°'3°(3±í±í±í°/°3°3°3°3°#3±í±í±í±í±í±,Ì01732+"'&=47632+"'&=476k2!  2!  ,!  ,!  ~ !  ! dþ6!  Ê! ÿÄÿÉ3 °/°/01;K"üµ$üè÷Å¡ƒ_<õèº2ïåº2ïåÿÄÿÉ3 ÿ8ZùÿÄÿÇ3°!M63ùÿÅ+++«¿+@†@ AO$W |Š ’€ ">HN˜´Ä €  " > HN ˜ ´ ÄCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ExistenceTestRegularPfaEdit : ExistenceTest : 28-11-2072ExistenceTest001.000ExistenceTestCreated by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net)ExistenceTestRegularPfaEdit : ExistenceTest : 28-11-2072ExistenceTest001.000ExistenceTestÿœ2libimager-perl-1.004+dfsg.orig/fontfiles/NameTest.ttf0000644000175000017500000000343412031434615022014 0ustar gregoagregoa €@OS/2UÆÿÆHVcmap8#ñ´Rcvt !ygaspÿÿglyfÏ &€headÛê%Ì6hheaèí$hmtx é locaŠÔ maxpIS( name›œzÄpostèäéÜ6¾ ™_<õè½’ßž½’ßž!Zç"@.‡ôŠ»ŒŠ»ß1€PfEd@  ÿ8Z°!M'oçYL0 ! ÿÿ ! ÿÿÿõÿâßô!y+++_~!nš.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!!MþÔ þõšýf!Xo«!747632#"'&7#"'&547632o6<t@Y4f2#!"'&54763tþþfzº ÕHêY t§=|Ìã$4k–¹ z º  Õ Hê Y  t §Created by Tony Cook - test font for the glyph_names() methodCreated by Tony Cook - test font for the glyph_names() methodNameTestNameTestMediumMediumFontForge 1.0 : NameTest : 13-9-2004FontForge 1.0 : NameTest : 13-9-2004NameTestNameTestVersion 001.000 Version 001.000 NameTestNameTestÿœ2 hyphentwoÿÿlibimager-perl-1.004+dfsg.orig/fontfiles/dodge.ttf0000644000175000017500000002543012031434615021356 0ustar gregoagregoa €POS/2‚ep¿ÜNcmap¿ð4€,rglyféjjC žhead,.ºR@6hheaßÎx$hmtxdÁœèlocaŒ¦„ìmaxpZÓ!p nameSM !post C6Ê#¤cvt ŠÝ£%¸âfpgmƒ3ÂO*œprepŽè8r*°f뼊¼ŠÅ2Alts@ /ÿ:/¦DJ(~ ÿÿ ÿÿÿãà  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`anjkhibfgoedqpcmrl(~ ÿÿ ÿÿÿãà?¶/V@ @ Fv/7?'5#>z–@>Ì–@>¬šþÆ$<@šþÆ$<y×a5#×^__ÿ¼°‰!5!3576=4&#!#!546;53!!#Š–ÓQl__ý¤–dVXüìnOÍ–ýe5ššDDMMBL>DDB ––@>¬šþÆ$<ÿZRø#"&546;#R•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8ÿZRø32654&+3•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8m Î #5##3353 ®¯®®¯®Xvvuvvÿ`–š35#>––@>šþÆ$<àÛj=!!ÛþoàŠŠ–š35#––šš F13#¯]¯F°F#54632#!"&%5.#!"3!26'5#nO6OnnOýÊOnF5þ|5HH6Š0Mû–‘$DDB DDB ‘š´F75!35#!"3!26=4&#!463!ÂV„½ýÊOnb_5Rl__ý¤H6ŠšBBžU<þåNLMMBL>0°F#53!2#=4&#!„„½6On–H6þv¨žU<þÜ‘èp 0ÿþ°F(7)5#75!467;6+"&=67&'3štDDüêlQËNTËQl^^lR´n`´Rl^^œàFFŠBMMMMB::BMMMMB::´F!5#3!2656&#&3!#!òýª„½6Onb_ýÊQl__\H6þv¬BBþòžU<NLMMBL>0¯l3#535#53¯¯¯¯¯‘I’ÿo¯l 7#53#26=#¯®®®If®Ú’þU<‘RF%#"&546;#"3R•OnnO•=5HH6žžU<$ŠBþTššN+ú+%!"&=463!2#7.#!"3!/#73#'+#73*ýwC__CæC`TF5þ|5HH6…®I+<-•d.. p 0¨@ô__–°F'#7;#'+#3 5·lLLŒ–ªPZ‚®–ôªdHšýºààd°F%!#)%!5!536#!#ýÊH??ý‚~üì½6Ql^^lRý˽àFÐBšMMB::BMMj°F%3#!"&54637!"3!,„½ýÊOnnO6½ýe5HH6ŠžžU<$Bž‘ÙB°F#54632#!"&%26=.#!"3?3nO6OnnOýÊOn ~0MF5þ|5HH6t–‘$à°F!!3!26=4&#!53!5%"dVXüì½5Rl__ý¤›½ýÊOnŽ(DDBšMMBL>FšU<°F !#+537! –ªà½6½þp¬šš°F%5'3#!"&533!26–nOýÊOn–H6Š0Mðpæ’þÝLBššBL>@¦šš°F%#!=463!3!5#'!3°½ý __\–dVý¨½ýʽ›5šššBL>DDBššÿZRø#"&546;#R•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8 F!#3 ¯þ£¯FÿZRø32654&+3•OnnO•@Z  Z˜‰_Ò_…–"„3±4z8j‘15!j‘‘ÿÿ$®F#26=#If®$U<‘°F'#7;#'+#3 5·lLLŒ–ªPZ‚®–ôªdHšýºààd°F%!#)%!5!536#!#ýÊH??ý‚~üì½6Ql^^lRý˽àFÐBšMMB::BMMj°F%3#!"&54637!"3!,„½ýÊOnnO6½ýe5HH6ŠžžU<$Bž‘ÙB°F#54632#!"&%26=.#!"3?3nO6OnnOýÊOn ~0MF5þ|5HH6t–‘$à°F53%6=4&#!#!54637!#½6Ql__ý¤–dVXüìnO6½ýe5ššMMBL>DDB >LBšýº  °F%#!#5%!5#'!3°½ýǺ"ŽýÖ*½ýʽ›5šššÌÌššF"#"&5463PLh’F’DuB‘~$zF232654&#PLh’F’DuB‘~$z –F5#>––@>¬šþÆ$<2_¥O@@ Fv/7/Ì–@>¦š:$<@š:$< zF 53.753.–@>Ì–@>¬šþÆ$<@šþÆ$< –F#––@>¦š:$< –F53.–@>¬šþÆ$<56µ>@@Fv/7/@@Fv/7/Ì–@>¬šþÆ$<@šþÆ$<nÓò_<õè­³Ñ{­³Ñ{ÿùÿZ´//ÿZÿùÿÞ´zô?XáÆy*¬ÇÇyMÿþÇ{Ç•ÇÇ9×ÿÿ„t„9UeN!øááNú5eeÿýeÿùMHð2eoáŠ||||¢ÔîRRRr²ðð8Rh€îd´òH¢ÚN¬Ìö4Z–ÚZ”ð<â ~ º Ø  R Š Ð n ª  ^ ´ Þ $ N Ž Ø p°Ê<vÒrÄ`¤ÌJ‚È nª^¸â(R’Ô^œœØØØøllÂJzš¸¸P¨ÂÂÂÂnžžžz,@ Êe;;AHNTU v\  Ò Þ  ì  ø   1999 - Iconian Fonts: http://members.xoom.com/iconianfonts/DodgerRegularDodgerDodger1Dodger1999 - Iconian Fonts: http://members.xoom.com/iconianfonts/DodgerRegularDodgerDodger1Dodgerÿ8ó  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘“–—ž ¡¢£¤¦©ª«¬­®¯°±²³´µ¶·¸º»½¾¿ÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÓÔÕÖØÙÚÞäåèéêëìíîïðâãæç’”•˜™š›œŸ¥§¨¹¼ÀÁÒ×ÛÜÝßàáHTglyph105ÿ;ÿø–…—†ˆW8°Á?äfkRC!“qãA:b¦F÷¤Ê¼³æÅF¤† ºñÝ5Hæ'A‰qF80šåœ‰N!´éŒƒo<€Œi6Q“ß´”#7Ö‚8±WEÞÔIá Ñ]1¬÷[+»‚]ƾdÌ×UBçîr€|²RŸì>`¥«%³%‚Ôf$¶}–X˜ÂIa«IŠß_‹}ˆÑ†Sg&Gȯ°uÈ ™àTFFÏñï$©H[â™*™BBûðN54À« 7í®mUKµèÚŸ]-ôµnMN®g—¾Öí8Ü'CwáZŽÁ=k´RùÉ–ˆ#½¾X¢l¢]“­ãþ3Ç=ÌÛ4 ÚÌ•£kßÔž¥(÷öØGM9ÓÃCJ;lž*Ü$äý!uñn¶fÀ(eÀK†±h†x¡ 8Ó%ld_]¦¬ôï5Ö Nü"d9££J/²üÜdV÷­]lN¾€ŽÐÖ0 ~,ËÑ4da5Ýð"|w(9‘ˆ27}Eæ“È¢\w >üàS© ‰¾á4Ç•q¼ZÆm-#BÏôLc¨Kã‚ –¶,feGD¾ŸñóÒ:+yU?çc†¨)6•å¹o1Ø”~v€†Ã鳌FÁ¿z+Fe޹Îó7Êp <>ÛQ†ã(o”<»¥7^ÖÓ}=]ñï)@ú¼‰8¬¦ ^¡ûW2f¸Tˆ­ÈëF’;1ù™¼m{ØÍú¯v7Зϗ}@»®úû¯P¸õñ¢!wg ’ï{B?®Ð"KØúAÜÄs¦ÿY˜Ôh¯ì]Ε äE2'¸Þ/UÚø@*(ÐZ¿7[熩§B^ÉÅ4% JûíŽd ¡þàÞÂ'aq­¸”ƒÑÔ_fàã{™á(‹·sdì–†7Òõ #endif #include #include #include typedef enum { FDSEEK, FDNOSEEK, BUFFER, CBSEEK, CBNOSEEK, BUFCHAIN } io_type; #ifdef _MSC_VER typedef int ssize_t; #endif typedef struct i_io_glue_t i_io_glue_t; /* compatibility for now */ typedef i_io_glue_t io_glue; /* Callbacks we give out */ typedef ssize_t(*i_io_readp_t) (io_glue *ig, void *buf, size_t count); typedef ssize_t(*i_io_writep_t)(io_glue *ig, const void *buf, size_t count); typedef off_t (*i_io_seekp_t) (io_glue *ig, off_t offset, int whence); typedef int (*i_io_closep_t)(io_glue *ig); typedef ssize_t(*i_io_sizep_t) (io_glue *ig); typedef void (*i_io_closebufp_t)(void *p); typedef void (*i_io_destroyp_t)(i_io_glue_t *ig); /* Callbacks we get */ typedef ssize_t(*i_io_readl_t) (void *p, void *buf, size_t count); typedef ssize_t(*i_io_writel_t)(void *p, const void *buf, size_t count); typedef off_t (*i_io_seekl_t) (void *p, off_t offset, int whence); typedef int (*i_io_closel_t)(void *p); typedef void (*i_io_destroyl_t)(void *p); typedef ssize_t(*i_io_sizel_t) (void *p); extern char *io_type_names[]; /* Structures to describe data sources */ struct i_io_glue_t { io_type type; void *exdata; i_io_readp_t readcb; i_io_writep_t writecb; i_io_seekp_t seekcb; i_io_closep_t closecb; i_io_sizep_t sizecb; i_io_destroyp_t destroycb; unsigned char *buffer; unsigned char *read_ptr; unsigned char *read_end; unsigned char *write_ptr; unsigned char *write_end; size_t buf_size; /* non-zero if we encountered EOF */ int buf_eof; /* non-zero if we've seen an error */ int error; /* if non-zero we do write buffering (enabled by default) */ int buffered; im_context_t context; }; #define I_IO_DUMP_CALLBACKS 1 #define I_IO_DUMP_BUFFER 2 #define I_IO_DUMP_STATUS 4 #define I_IO_DUMP_DEFAULT (I_IO_DUMP_BUFFER | I_IO_DUMP_STATUS) #define i_io_type(ig) ((ig)->source.ig_type) #define i_io_raw_read(ig, buf, size) ((ig)->readcb((ig), (buf), (size))) #define i_io_raw_write(ig, data, size) ((ig)->writecb((ig), (data), (size))) #define i_io_raw_seek(ig, offset, whence) ((ig)->seekcb((ig), (offset), (whence))) #define i_io_raw_close(ig) ((ig)->closecb(ig)) #define i_io_is_buffered(ig) ((int)((ig)->buffered)) #define i_io_getc(ig) \ ((ig)->read_ptr < (ig)->read_end ? \ *((ig)->read_ptr++) : \ i_io_getc_imp(ig)) #define i_io_peekc(ig) \ ((ig)->read_ptr < (ig)->read_end ? \ *((ig)->read_ptr) : \ i_io_peekc_imp(ig)) #define i_io_putc(ig, c) \ ((ig)->write_ptr < (ig)->write_end && !(ig)->error ? \ *(ig)->write_ptr++ = (c) : \ i_io_putc_imp(ig, (c))) #define i_io_eof(ig) \ ((ig)->read_ptr == (ig)->read_end && (ig)->buf_eof) #define i_io_error(ig) \ ((ig)->read_ptr == (ig)->read_end && (ig)->error) #endif libimager-perl-1.004+dfsg.orig/imext.c0000644000175000017500000003534712507371373017077 0ustar gregoagregoa#include "imexttypes.h" #include "imager.h" #include "imio.h" static im_context_t get_context(void); static i_img *mathom_i_img_8_new(i_img_dim, i_img_dim, int); static i_img *mathom_i_img_16_new(i_img_dim, i_img_dim, int); static i_img *mathom_i_img_double_new(i_img_dim, i_img_dim, int); static i_img *mathom_i_img_pal_new(i_img_dim, i_img_dim, int, int); static void mathom_i_clear_error(void); static void mathom_i_push_error(int, const char *); static void mathom_i_push_errorvf(int, const char *, va_list); static int mathom_i_set_image_file_limits(i_img_dim, i_img_dim, size_t); static int mathom_i_get_image_file_limits(i_img_dim*, i_img_dim*, size_t*); static int mathom_i_int_check_image_file_limits(i_img_dim, i_img_dim, int, size_t); static i_img *mathom_i_img_alloc(void); static void mathom_i_img_init(i_img *); static i_io_glue_t *mathom_io_new_fd(int); static i_io_glue_t *mathom_io_new_bufchain(void); static i_io_glue_t * mathom_io_new_buffer(const char *data, size_t, i_io_closebufp_t, void *); static i_io_glue_t * mathom_io_new_cb(void *, i_io_readl_t, i_io_writel_t, i_io_seekl_t, i_io_closel_t, i_io_destroyl_t); /* DON'T ADD CASTS TO THESE */ im_ext_funcs imager_function_table = { IMAGER_API_VERSION, IMAGER_API_LEVEL, mymalloc, myfree, myrealloc, mymalloc_file_line, myfree_file_line, myrealloc_file_line, mathom_i_img_8_new, mathom_i_img_16_new, mathom_i_img_double_new, mathom_i_img_pal_new, i_img_destroy, i_sametype, i_sametype_chans, i_img_info, i_ppix, i_gpix, i_ppixf, i_gpixf, i_plin, i_glin, i_plinf, i_glinf, i_gsamp, i_gsampf, i_gpal, i_ppal, i_addcolors, i_getcolors, i_colorcount, i_maxcolors, i_findcolor, i_setcolors, i_new_fill_solid, i_new_fill_solidf, i_new_fill_hatch, i_new_fill_hatchf, i_new_fill_image, i_new_fill_fount, i_fill_destroy, i_quant_makemap, i_quant_translate, i_quant_transparent, mathom_i_clear_error, mathom_i_push_error, i_push_errorf, mathom_i_push_errorvf, i_tags_new, i_tags_set, i_tags_setn, i_tags_destroy, i_tags_find, i_tags_findn, i_tags_delete, i_tags_delbyname, i_tags_delbycode, i_tags_get_float, i_tags_set_float, i_tags_set_float2, i_tags_get_int, i_tags_get_string, i_tags_get_color, i_tags_set_color, i_box, i_box_filled, i_box_cfill, i_line, i_line_aa, i_arc, i_arc_aa, i_arc_cfill, i_arc_aa_cfill, i_circle_aa, i_flood_fill, i_flood_cfill, i_copyto, i_copyto_trans, i_copy, i_rubthru, /* IMAGER_API_LEVEL 2 functions */ mathom_i_set_image_file_limits, mathom_i_get_image_file_limits, mathom_i_int_check_image_file_limits, i_flood_fill_border, i_flood_cfill_border, /* IMAGER_API_LEVEL 3 functions */ i_img_setmask, i_img_getmask, i_img_getchannels, i_img_get_width, i_img_get_height, i_lhead, i_loog, /* IMAGER_API_LEVEL 4 functions */ mathom_i_img_alloc, mathom_i_img_init, /* IMAGER_API_LEVEL 5 functions */ i_img_is_monochrome, i_gsamp_bg, i_gsampf_bg, i_get_file_background, i_get_file_backgroundf, i_utf8_advance, i_render_new, i_render_delete, i_render_color, i_render_fill, i_render_line, i_render_linef, /* level 6 */ i_io_getc_imp, i_io_peekc_imp, i_io_peekn, i_io_putc_imp, i_io_read, i_io_write, i_io_seek, i_io_flush, i_io_close, i_io_set_buffered, i_io_gets, mathom_io_new_fd, mathom_io_new_bufchain, mathom_io_new_buffer, mathom_io_new_cb, io_slurp, io_glue_destroy, /* level 8 */ im_img_8_new, im_img_16_new, im_img_double_new, im_img_pal_new, im_clear_error, im_push_error, im_push_errorvf, im_push_errorf, im_set_image_file_limits, im_get_image_file_limits, im_int_check_image_file_limits, im_img_alloc, im_img_init, im_io_new_fd, im_io_new_bufchain, im_io_new_buffer, im_io_new_cb, get_context, im_lhead, im_loog, im_context_refinc, im_context_refdec, im_errors, i_mutex_new, i_mutex_destroy, i_mutex_lock, i_mutex_unlock, im_context_slot_new, im_context_slot_set, im_context_slot_get, /* level 9 */ i_poly_poly_aa, i_poly_poly_aa_cfill, i_poly_aa_m, i_poly_aa_cfill_m, /* level 10 */ i_img_alpha_channel, i_img_color_model, i_img_color_channels }; /* in general these functions aren't called by Imager internally, but only via the pointers above, since faster macros that call the image vtable pointers are used. () are used around the function names to prevent macro replacement on the function names. */ /* =item i_ppix(im, x, y, color) =category Drawing Sets the pixel at (x,y) to I. Returns 0 if the pixel was drawn, or -1 if not. Does no alpha blending, just copies the channels from the supplied color to the image. =cut */ int (i_ppix)(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) { return i_ppix(im, x, y, val); } /* =item i_gpix(im, C, C, C) =category Drawing Retrieves the C of the pixel (x,y). Returns 0 if the pixel was retrieved, or -1 if not. =cut */ int (i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val) { return i_gpix(im, x, y, val); } /* =item i_ppixf(im, C, C, C) =category Drawing Sets the pixel at (C,C) to the floating point color C. Returns 0 if the pixel was drawn, or -1 if not. Does no alpha blending, just copies the channels from the supplied color to the image. =cut */ int (i_ppixf)(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) { return i_ppixf(im, x, y, val); } /* =item i_gpixf(im, C, C, C) =category Drawing Retrieves the color of the pixel (x,y) as a floating point color into C. Returns 0 if the pixel was retrieved, or -1 if not. =cut */ int (i_gpixf)(i_img *im,i_img_dim x,i_img_dim y,i_fcolor *val) { return i_gpixf(im, x, y, val); } /* =item i_plin(im, l, r, y, colors) =category Drawing Sets (r-l) pixels starting from (l,y) using (r-l) values from I. Returns the number of pixels set. =cut */ i_img_dim (i_plin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) { return i_plin(im, l, r, y, vals); } /* =item i_glin(im, l, r, y, colors) =category Drawing Retrieves (r-l) pixels starting from (l,y) into I. Returns the number of pixels retrieved. =cut */ i_img_dim (i_glin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) { return i_glin(im, l, r, y, vals); } /* =item i_plinf(im, C, C, C) =category Drawing Sets (right-left) pixels starting from (left,y) using (right-left) floating point colors from C. Returns the number of pixels set. =cut */ i_img_dim (i_plinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) { return i_plinf(im, l, r, y, vals); } /* =item i_glinf(im, l, r, y, colors) =category Drawing Retrieves (r-l) pixels starting from (l,y) into I as floating point colors. Returns the number of pixels retrieved. =cut */ i_img_dim (i_glinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) { return i_glinf(im, l, r, y, vals); } /* =item i_gsamp(im, left, right, y, samples, channels, channel_count) =category Drawing Reads sample values from C for the horizontal line (left, y) to (right-1,y) for the channels specified by C, an array of int with C elements. If channels is NULL then the first channels_count channels are retrieved for each pixel. Returns the number of samples read (which should be (right-left) * channel_count) =cut */ i_img_dim (i_gsamp)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp, const int *chans, int chan_count) { return i_gsamp(im, l, r, y, samp, chans, chan_count); } /* =item i_gsampf(im, left, right, y, samples, channels, channel_count) =category Drawing Reads floating point sample values from C for the horizontal line (left, y) to (right-1,y) for the channels specified by C, an array of int with channel_count elements. If C is NULL then the first C channels are retrieved for each pixel. Returns the number of samples read (which should be (C-C) * C) =cut */ i_img_dim (i_gsampf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, const int *chans, int chan_count) { return i_gsampf(im, l, r, y, samp, chans, chan_count); } /* =item i_gsamp_bits(im, left, right, y, samples, channels, channel_count, bits) =category Drawing Reads integer samples scaled to C bits of precision into the C array C. Expect this to be slow unless C<< bits == im->bits >>. Returns the number of samples copied, or -1 on error. Not all image types implement this method. Pushes errors, but does not call C. =cut */ /* =item i_psamp_bits(im, left, right, y, samples, channels, channel_count, bits) =category Drawing Writes integer samples scaled to C bits of precision from the C array C. Expect this to be slow unless C<< bits == im->bits >>. Returns the number of samples copied, or -1 on error. Not all image types implement this method. Pushes errors, but does not call C. =cut */ /* =item i_gpal(im, left, right, y, indexes) =category Drawing Reads palette indexes for the horizontal line (left, y) to (right-1, y) into C. Returns the number of indexes read. Always returns 0 for direct color images. =cut */ i_img_dim (i_gpal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals) { return i_gpal(im, x, r, y, vals); } /* =item i_ppal(im, left, right, y, indexes) =category Drawing Writes palette indexes for the horizontal line (left, y) to (right-1, y) from C. Returns the number of indexes written. Always returns 0 for direct color images. =cut */ i_img_dim (i_ppal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals) { return i_ppal(im, x, r, y, vals); } /* =item i_addcolors(im, colors, count) =category Paletted images Adds colors to the image's palette. On success returns the index of the lowest color added. On failure returns -1. Always fails for direct color images. =cut */ int (i_addcolors)(i_img *im, const i_color *colors, int count) { return i_addcolors(im, colors, count); } /* =item i_getcolors(im, index, colors, count) =category Paletted images Retrieves I colors starting from I in the image's palette. On success stores the colors into I and returns true. On failure returns false. Always fails for direct color images. Fails if there are less than I+I colors in the image's palette. =cut */ int (i_getcolors)(i_img *im, int i, i_color *colors, int count) { return i_getcolors(im, i, colors, count); } /* =item i_colorcount(im) =category Paletted images Returns the number of colors in the image's palette. Returns -1 for direct images. =cut */ int (i_colorcount)(i_img *im) { return i_colorcount(im); } /* =item i_maxcolors(im) =category Paletted images Returns the maximum number of colors the palette can hold for the image. Returns -1 for direct color images. =cut */ int (i_maxcolors)(i_img *im) { return i_maxcolors(im); } /* =item i_findcolor(im, color, &entry) =category Paletted images Searches the images palette for the given color. On success sets *I to the index of the color, and returns true. On failure returns false. Always fails on direct color images. =cut */ int (i_findcolor)(i_img *im, const i_color *color, i_palidx *entry) { return i_findcolor(im, color, entry); } /* =item i_setcolors(im, index, colors, count) =category Paletted images Sets I colors starting from I in the image's palette. On success returns true. On failure returns false. The image must have at least I+I colors in it's palette for this to succeed. Always fails on direct color images. =cut */ int (i_setcolors)(i_img *im, int index, const i_color *colors, int count) { return i_setcolors(im, index, colors, count); } /* =item im_get_context() Retrieve the context object for the current thread. Inside Imager itself this is just a function pointer, which the F BOOT handler initializes for use within perl. If you're taking the Imager code and embedding it elsewhere you need to initialize the C pointer at some point. =cut */ static im_context_t get_context(void) { return im_get_context(); } static i_img * mathom_i_img_8_new(i_img_dim xsize, i_img_dim ysize, int channels) { return i_img_8_new(xsize, ysize, channels); } static i_img * mathom_i_img_16_new(i_img_dim xsize, i_img_dim ysize, int channels) { return i_img_16_new(xsize, ysize, channels); } static i_img * mathom_i_img_double_new(i_img_dim xsize, i_img_dim ysize, int channels) { return i_img_double_new(xsize, ysize, channels); } static i_img * mathom_i_img_pal_new(i_img_dim xsize, i_img_dim ysize, int channels, int maxpal) { return i_img_pal_new(xsize, ysize, channels, maxpal); } static void mathom_i_clear_error(void) { i_clear_error(); } static void mathom_i_push_error(int code, const char *msg) { i_push_error(code, msg); } static void mathom_i_push_errorvf(int code, const char *fmt, va_list args) { i_push_errorvf(code, fmt, args); } static int mathom_i_set_image_file_limits(i_img_dim max_width, i_img_dim max_height, size_t max_bytes) { return i_set_image_file_limits(max_width, max_height, max_bytes); } static int mathom_i_get_image_file_limits(i_img_dim *pmax_width, i_img_dim *pmax_height, size_t *pmax_bytes) { return i_get_image_file_limits(pmax_width, pmax_height, pmax_bytes); } static int mathom_i_int_check_image_file_limits(i_img_dim width, i_img_dim height, int channels, size_t sample_size) { return i_int_check_image_file_limits(width, height, channels, sample_size); } static i_img * mathom_i_img_alloc(void) { return i_img_alloc(); } static void mathom_i_img_init(i_img *im) { i_img_init(im); } static i_io_glue_t * mathom_io_new_fd(int fd) { return io_new_fd(fd); } static i_io_glue_t * mathom_io_new_bufchain(void) { return io_new_bufchain(); } static i_io_glue_t * mathom_io_new_buffer(const char *data, size_t size, i_io_closebufp_t closefp, void *close_data) { return io_new_buffer(data, size, closefp, close_data); } static i_io_glue_t * mathom_io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb) { return io_new_cb(p, readcb, writecb, seekcb, closecb, destroycb); } libimager-perl-1.004+dfsg.orig/log.h0000644000175000017500000000302212263740601016511 0ustar gregoagregoa#ifndef _LOG_H_ #define _LOG_H_ #include #include #include #include "imdatatypes.h" /* input: name of file to log too input: onoff, 0 means no logging global: creates a global variable FILE* lg_file */ int im_init_log(pIMCTX, const char *name, int onoff ); #define i_init_log(name, onoff) im_init_log(aIMCTX, name, onoff) #ifndef IMAGER_NO_CONTEXT void i_fatal ( int exitcode,const char *fmt, ... ); #endif void im_fatal (pIMCTX, int exitcode,const char *fmt, ... ); void im_lhead ( pIMCTX, const char *file, int line ); void i_lhead ( const char *file, int line ); void i_loog(int level,const char *msg, ... ) I_FORMAT_ATTR(2,3); void im_loog(pIMCTX, int level,const char *msg, ... ) I_FORMAT_ATTR(3,4); /* =item im_log((aIMCTX, level, format, ...)) =category Logging This is the main entry point to logging. Note that the extra set of parentheses are required due to limitations in C89 macros. This will format a string with the current file and line number to the log file if logging is enabled. This must be called with a context object defined by one of the C macros in scope. This can also be called as C in which case the currently active context is used and any in scope context is ignored. =cut */ #ifdef IMAGER_LOG #ifndef IMAGER_NO_CONTEXT #define mm_log(x) { i_lhead(__FILE__,__LINE__); i_loog x; } #endif #define im_log(x) { im_lhead(aIMCTX, __FILE__,__LINE__); im_loog x; } #else #define mm_log(x) #define im_log(x) #endif #endif /* _LOG_H_ */ libimager-perl-1.004+dfsg.orig/imerror.h0000644000175000017500000000161112263740601017411 0ustar gregoagregoa#ifndef IMAGER_IMERROR_H #define IMAGER_IMERROR_H /* error handling see error.c for documentation the error information is currently global */ typedef void (*i_error_cb)(int code, char const *msg); typedef void (*i_failed_cb)(i_errmsg *msgs); extern i_error_cb i_set_error_cb(i_error_cb); extern i_failed_cb i_set_failed_cb(i_failed_cb); extern void i_set_argv0(char const *); extern int i_set_errors_fatal(int new_fatal); extern i_errmsg *im_errors(pIMCTX); extern void im_push_error(pIMCTX, int code, char const *msg); #ifndef IMAGER_NO_CONTEXT extern void i_push_errorf(int code, char const *fmt, ...) I_FORMAT_ATTR(2, 3); #endif extern void im_push_errorf(pIMCTX, int code, char const *fmt, ...) I_FORMAT_ATTR(3, 4); extern void im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list); extern void im_clear_error(pIMCTX); extern int i_failed(int code, char const *msg); #endif libimager-perl-1.004+dfsg.orig/imextdef.h0000644000175000017500000000036712031434615017544 0ustar gregoagregoa#ifndef IMAGER_IMEXTDEF_H #define IMAGER_IMEXTDEF_H #include "imexttypes.h" extern im_ext_funcs imager_function_table; #define PERL_SET_GLOBAL_CALLBACKS \ sv_setiv(get_sv(PERL_FUNCTION_TABLE_NAME, 1), PTR2IV(&imager_function_table)); #endif libimager-perl-1.004+dfsg.orig/dynfilt/0000755000175000017500000000000012617614576017251 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/dynfilt/dyntest.c0000644000175000017500000000345212263740600021074 0ustar gregoagregoa#include "pluginst.h" char evalstr[]="Description string of plugin dyntest - kind of like"; void null_plug(void *ptr) { } /* Example dynamic filter - level stretch (linear) - note it only stretches and doesn't compress */ /* input parameters a: the current black b: the current white 0 <= a < b <= 255; output pixel value calculated by: o=((i-a)*255)/(b-a); note that since we do not have the needed functions to manipulate the data structures *** YET *** */ unsigned char static saturate(int in) { if (in>255) { return 255; } else if (in>0) return in; return 0; } void lin_stretch(void *INP) { int a, b; i_img *im; i_color rcolor; int i; i_img_dim x,y; size_t bytes; i_img_dim info[4]; if ( !getOBJ("image","Imager::ImgRaw",&im) ) { fprintf(stderr,"Error: image is missing\n"); } if ( !getINT("a",&a) ) { fprintf(stderr,"Error: a is missing\n"); } if ( !getINT("b",&b) ) { fprintf(stderr,"Error: b is missing\n"); } /* fprintf(stderr,"parameters: (im 0x%x,a %d,b %d)\n",im,a,b);*/ bytes=im->bytes; i_img_info(im,info); for(i=0;i<4;i++) { printf("%d: %" i_DF "\n", i, i_DFc(info[i])); } printf("image info:\n size (" i_DFp ")\n channels (%d)\n", i_DFcp(im->xsize, im->ysize), im->channels); for(y=0;yysize;y++) for(x=0;xxsize;x++) { i_gpix(im,x,y,&rcolor); for(i=0;ichannels;i++) rcolor.channel[i]=saturate((255*(rcolor.channel[i]-a))/(b-a)); i_ppix(im,x,y,&rcolor); } } func_ptr function_list[]={ { "null_plug", null_plug, "callsub => sub { 1; }" },{ "lin_stretch", lin_stretch, "callseq => ['image','a','b'], \ callsub => sub { my %hsh=@_; DSO_call($DSO_handle,1,\\%hsh); } \ " }, {NULL,NULL,NULL}}; /* Remember to double backslash backslashes within Double quotes in C */ libimager-perl-1.004+dfsg.orig/dynfilt/mandelbrot.c0000644000175000017500000000347312370401737021540 0ustar gregoagregoa#include "pluginst.h" #include char evalstr[]="Mandlebrot renderer"; /* Example Mandlebrot generator */ /* input parameters image is the image object. */ #define MXITER 256 static int mandel(double x, double y) { double xn, yn; double xo, yo; int iter = 1; /* Z(n+1) = Z(n) ^2 + c */ /* printf("(%.2f, %.2f) -> \n", x,y); */ xo = x; yo = y; while( xo*xo+yo*yo <= 10 && iter < MXITER) { xn = xo*xo-yo*yo + x; yn = 2*xo*yo + y; xo=xn; yo=yn; iter++; } return (iter == MXITER)?0:iter; } void mandlebrot(void *INP) { i_img *im; int i; i_img_dim x,y; int idx; double xs, ys; double div; i_color icl[256]; srand(12235); for(i=1;i<256; i++) { icl[i].rgb.r = 100+(int) (156.0*rand()/(RAND_MAX+1.0)); icl[i].rgb.g = 100+(int) (156.0*rand()/(RAND_MAX+1.0)); icl[i].rgb.b = 100+(int) (156.0*rand()/(RAND_MAX+1.0)); } icl[0].rgb.r = 0; icl[0].rgb.g = 0; icl[0].rgb.b = 0; if ( !getOBJ("image","Imager::ImgRaw",&im) ) { fprintf(stderr,"Error: image is missing\n"); } fprintf(stderr,"mandlebrot: parameters: (im %p)\n",im); fprintf(stderr, "mandlebrot: image info:\n size (" i_DFp ")\n channels (%d)\n", i_DFcp(im->xsize,im->ysize),im->channels); div = 2.5; xs = 0.8*div; ys = 0.5*div; div /= im->xsize; fprintf(stderr, "Divider: %f \n", div); for(y = 0; y < im->ysize; y ++) { for(x = 0; x < im->xsize; x ++ ) { idx = mandel(x*div-xs , y*div-ys); idx = (idx>255)?255:idx; i_ppix(im,x,y,&icl[idx]); } } } func_ptr function_list[]={ { "mandlebrot", mandlebrot, "callseq => ['image'], \ callsub => sub { my %hsh=@_; DSO_call($DSO_handle,0,\\%hsh); } \ " }, {NULL,NULL,NULL}}; /* Remember to double backslash backslashes within Double quotes in C */ libimager-perl-1.004+dfsg.orig/dynfilt/pluginst.h0000644000175000017500000000051412031434614021246 0ustar gregoagregoa#include "../plug.h" #ifdef WIN32 #define WIN32_EXPORT __declspec(dllexport) #else /* this may need to change for other Win32 compilers */ #define WIN32_EXPORT #endif symbol_table_t *symbol_table; UTIL_table_t *util_table; void WIN32_EXPORT install_tables(symbol_table_t *s,UTIL_table_t *u) { symbol_table=s; util_table=u; } libimager-perl-1.004+dfsg.orig/dynfilt/mandelbrot.exp0000644000175000017500000000004612031434614022075 0ustar gregoagregoafunction_list evalstr install_tables libimager-perl-1.004+dfsg.orig/dynfilt/dt2.c0000644000175000017500000000244012263740600020067 0ustar gregoagregoa#include "pluginst.h" #include char evalstr[]="Plugin for creating html tables from images"; /* input parameters fname - file to add the html to. */ void html_art(void *INP) { i_img *im; i_color rcolor; i_img_dim x,y; FILE *fp; char *fname; if ( !getSTR("fname",&fname) ) { fprintf(stderr,"Error: filename is missing\n"); return; } if ( !getOBJ("image","Imager::ImgRaw",&im) ) { fprintf(stderr,"Error: image is missing\n"); return; } printf("parameters: (im %p,fname %s)\n",im,fname); printf("image info:\n size ("i_DFp ")\n channels (%d)\n", i_DFcp(im->xsize, im->ysize), im->channels); fp=fopen(fname,"ab+"); fprintf(fp,""); for(y=0;yysize;y+=2) { fprintf(fp,""); for(x=0;xxsize;x++) { i_gpix(im,x,y,&rcolor); fprintf(fp,"",rcolor.rgb.r,rcolor.rgb.g,rcolor.rgb.b); } fprintf(fp,""); } fprintf(fp,"
  
"); fclose(fp); } func_ptr function_list[]={ { "html_art", html_art, "callseq => ['image','fname'], \ callsub => sub { my %hsh=@_; DSO_call($DSO_handle,0,\\%hsh); } \ " }, {NULL,NULL,NULL}}; /* Remember to double backslash backslashes within Double quotes in C */ libimager-perl-1.004+dfsg.orig/dynfilt/compile.txt0000644000175000017500000000025012031434614021416 0ustar gregoagregoalinux - solaris : gcc -o dyntest.so -fPIC -G dyntest.c AIX: LD_RUN_PATH="" ld -o dyntest.a -bhalt:4 -bM:SRE -bE:dyntest.exp -b noentry -lc -L/usr/local/lib dyntest.o libimager-perl-1.004+dfsg.orig/dynfilt/t/0000755000175000017500000000000012617614576017514 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/dynfilt/t/t60dyntest.t0000644000175000017500000000241512263740600021710 0ustar gregoagregoa#!perl -w use strict; use lib '../t'; use Test::More tests => 8; BEGIN { use_ok(Imager => qw(:default)); } use Config; use Imager::Test qw(test_image); #$Imager::DEBUG=1; -d "testout" or mkdir "testout"; Imager->open_log(log => 'testout/t60dyntest.log'); my $img=Imager->new() || die "unable to create image object\n"; $img->read(file=>'../testimg/penguin-base.ppm',type=>'pnm') || die "failed: ",$img->{ERRSTR},"\n"; my $plug='./dyntest.'.$Config{'so'}; ok(load_plugin($plug), "load plugin") || die "unable to load plugin: $Imager::ERRSTR\n"; my %hsh=(a=>35,b=>200,type=>'lin_stretch'); ok($img->filter(%hsh), "call filter"); $img->write(type=>'pnm',file=>'testout/linstretch.ppm') || die "error in write()\n"; ok(unload_plugin($plug), "unload plugin") || die "unable to unload plugin: $Imager::ERRSTR\n"; { my $flines = "./flines.$Config{so}"; ok(load_plugin($flines), "load flines"); my $im = test_image(); ok($im->filter(type => "flines"), "do the flines test"); ok($im->write(file => "testout/flines.ppm"), "save flines result"); ok(unload_plugin($flines), "unload flines"); } Imager->close_log; unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/linstretch.ppm"; unlink "testout/flines.ppm"; unlink "testout/t60dyntest.log"; rmdir "testout"; } libimager-perl-1.004+dfsg.orig/dynfilt/dyntest.exp0000644000175000017500000000004612031434614021440 0ustar gregoagregoafunction_list evalstr install_tables libimager-perl-1.004+dfsg.orig/dynfilt/Makefile.PL0000644000175000017500000000340612031434614021205 0ustar gregoagregoause strict; use Config; use ExtUtils::MakeMaker; my $Verbose = 1; my $lddl=$Config{"lddlflags"}; my @plugins= qw(dyntest dt2 mandelbrot flines); my $libstr=join(' ',map { $_.'.$(SO)' } @plugins); #print $libstr,"\n"; #print $objstr,"\n"; #print MY::top_targets(); WriteMakefile( NAME => 'Imager::plugins', SKIP => [qw(all dynamic static )], clean => {'FILES' => $libstr}, ); sub lddl_magic { my $t; $t=$lddl; $t=~s/-bI:\$\(PERL_INC\)\/perl.exp//; $t=~s/\$\(BASEEXT\)/$_[0]/; return $t; } sub MY::top_targets { use Config; if ($^O eq 'aix') { ' all :: dynamic dynamic :: '.$libstr.(join("\n",map { qq{ $_.\$(SO): $_\$(OBJ_EXT) LD_RUN_PATH="\$(LD_RUN_PATH)" \$(LD) -o \$\@ }.lddl_magic($_).qq{ \$(OTHERLDFLAGS) $_\$(OBJ_EXT) } } @plugins)).' pure_all :: $(NOOP) '; } elsif ($^O =~ /win32/i && $Config{cc} =~ /cl/) { my @libpth = grep /\S/, split /("[^"]*"|\S+)/,$Config{libpth}; ' all :: dynamic dynamic :: '.$libstr.(join("\n",map { qq{ $_.\$(SO): $_\$(OBJ_EXT) \$(LD) /OUT:\$\@ }.lddl_magic($_).qq{ \$(OTHERLDFLAGS) $_\$(OBJ_EXT) $Config{libs} }.join(' ', map "/libpath:$_", @libpth).qq{ } } @plugins)).' pure_all :: $(NOOP) '; } else { my $ldrun = $^O =~ /win32/i ? '' : 'LD_RUN_PATH="$(LD_RUN_PATH)"'; my $phony_colon = $Config{make} eq 'dmake' ? ':' : '::'; " all $phony_colon dynamic dynamic $phony_colon ".$libstr.(join("\n",map { qq{ $_.\$(SO): $_\$(OBJ_EXT) $ldrun \$(LD) -o \$\@ \$(LDDLFLAGS) \$(OTHERLDFLAGS) $_\$(OBJ_EXT) } } @plugins)).' pure_all :: $(NOOP) '; } } # EU::MM crashes without this when we define it in the base Makefile.PL # but then warns about redefinition, so delete the GLOB entry BEGIN { delete $MY::{metafile} } sub MY::metafile { ''; } libimager-perl-1.004+dfsg.orig/dynfilt/flines.exp0000644000175000017500000000004612031434614021226 0ustar gregoagregoafunction_list evalstr install_tables libimager-perl-1.004+dfsg.orig/dynfilt/flines.c0000644000175000017500000000237412263740600020664 0ustar gregoagregoa#include "pluginst.h" char evalstr[]="Fancy lines"; /* input parameters image is the image object. */ unsigned char static saturate(int in) { if (in>255) { return 255; } else if (in>0) return in; return 0; } void flines(void *INP) { i_img *im; i_color vl; i_img_dim x,y; if ( !getOBJ("image","Imager::ImgRaw",&im) ) { fprintf(stderr,"Error: image is missing\n"); return; } fprintf(stderr, "flines: parameters: (im %p)\n",im); fprintf(stderr, "flines: image info:\n size (" i_DFp ")\n channels (%d)\n", i_DFcp(im->xsize,im->ysize), im->channels); for(y = 0; y < im->ysize; y ++) { float yf, mf; if (!(y%2)) { yf = y/(double)im->ysize; } else { yf = (im->ysize-y)/(double)im->ysize; } mf = 1.2-0.8*yf; for(x = 0; x < im->xsize; x ++ ) { i_gpix(im,x,y,&vl); vl.rgb.r = saturate(vl.rgb.r*mf); vl.rgb.g = saturate(vl.rgb.g*mf); vl.rgb.b = saturate(vl.rgb.b*mf); i_ppix(im,x,y,&vl); } } } func_ptr function_list[]={ { "flines", flines, "callseq => ['image'], \ callsub => sub { my %hsh=@_; DSO_call($DSO_handle,0,\\%hsh); } \ " }, {NULL,NULL,NULL}}; /* Remember to double backslash backslashes within Double quotes in C */ libimager-perl-1.004+dfsg.orig/dynfilt/dt2.exp0000644000175000017500000000004612031434614020437 0ustar gregoagregoafunction_list evalstr install_tables libimager-perl-1.004+dfsg.orig/bmp.c0000644000175000017500000011022312263740600016502 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include #include "imageri.h" /* =head1 NAME bmp.c - read and write windows BMP files =head1 SYNOPSIS i_img *im; io_glue *ig; if (!i_writebmp_wiol(im, ig)) { ... error ... } im = i_readbmp(ig); =head1 DESCRIPTION Reads and writes Windows BMP files. =over =cut */ #define FILEHEAD_SIZE 14 #define INFOHEAD_SIZE 40 #define BI_RGB 0 #define BI_RLE8 1 #define BI_RLE4 2 #define BI_BITFIELDS 3 #define BMPRLE_ENDOFLINE 0 #define BMPRLE_ENDOFBMP 1 #define BMPRLE_DELTA 2 #define SIGNBIT32 ((i_upacked_t)1U << 31) #define SIGNBIT16 ((i_upacked_t)1U << 15) #define SIGNMAX32 ((1UL << 31) - 1) static int read_packed(io_glue *ig, char *format, ...); static int write_packed(io_glue *ig, char *format, ...); static int write_bmphead(io_glue *ig, i_img *im, int bit_count, int data_size); static int write_1bit_data(io_glue *ig, i_img *im); static int write_4bit_data(io_glue *ig, i_img *im); static int write_8bit_data(io_glue *ig, i_img *im); static int write_24bit_data(io_glue *ig, i_img *im); static int read_bmp_pal(io_glue *ig, i_img *im, int count); static i_img *read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int compression, long offbits, int allow_incomplete); static i_img *read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int compression, long offbits, int allow_incomplete); static i_img *read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int compression, long offbits, int allow_incomplete); static i_img *read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, int clr_used, int compression, long offbits, int allow_incomplete); /* used for the read_packed() and write_packed() functions, an integer * type */ typedef long i_packed_t; typedef unsigned long i_upacked_t; /* =item i_writebmp_wiol(im, io_glue) Writes the image as a BMP file. Uses 1-bit, 4-bit, 8-bit or 24-bit formats depending on the image. Never compresses the image. =cut */ int i_writebmp_wiol(i_img *im, io_glue *ig) { dIMCTXim(im); i_clear_error(); /* pick a format */ if (im->type == i_direct_type) { return write_24bit_data(ig, im); } else { int pal_size; /* must be paletted */ pal_size = i_colorcount(im); if (pal_size <= 2) { return write_1bit_data(ig, im); } else if (pal_size <= 16) { return write_4bit_data(ig, im); } else { return write_8bit_data(ig, im); } } } /* =item i_readbmp_wiol(ig) Reads a Windows format bitmap from the given file. Handles BI_RLE4 and BI_RLE8 compressed images. Attempts to handle BI_BITFIELDS images too, but I need a test image. =cut */ i_img * i_readbmp_wiol(io_glue *ig, int allow_incomplete) { i_packed_t b_magic, m_magic, filesize, res1, res2, infohead_size; i_packed_t xsize, ysize, planes, bit_count, compression, size_image, xres, yres; i_packed_t clr_used, clr_important, offbits; i_img *im; dIMCTXio(ig); im_log((aIMCTX, 1, "i_readbmp_wiol(ig %p)\n", ig)); i_clear_error(); if (!read_packed(ig, "CCVvvVVV!V!vvVVVVVV", &b_magic, &m_magic, &filesize, &res1, &res2, &offbits, &infohead_size, &xsize, &ysize, &planes, &bit_count, &compression, &size_image, &xres, &yres, &clr_used, &clr_important)) { i_push_error(0, "file too short to be a BMP file"); return 0; } if (b_magic != 'B' || m_magic != 'M' || infohead_size != INFOHEAD_SIZE || planes != 1) { i_push_error(0, "not a BMP file"); return 0; } im_log((aIMCTX, 1, " bmp header: filesize %d offbits %d xsize %d ysize %d planes %d " "bit_count %d compression %d size %d xres %d yres %d clr_used %d " "clr_important %d\n", (int)filesize, (int)offbits, (int)xsize, (int)ysize, (int)planes, (int)bit_count, (int)compression, (int)size_image, (int)xres, (int)yres, (int)clr_used, (int)clr_important)); if (!i_int_check_image_file_limits(xsize, abs(ysize), 3, sizeof(i_sample_t))) { im_log((aIMCTX, 1, "i_readbmp_wiol: image size exceeds limits\n")); return NULL; } switch (bit_count) { case 1: im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits, allow_incomplete); break; case 4: im = read_4bit_bmp(ig, xsize, ysize, clr_used, compression, offbits, allow_incomplete); break; case 8: im = read_8bit_bmp(ig, xsize, ysize, clr_used, compression, offbits, allow_incomplete); break; case 32: case 24: case 16: im = read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression, offbits, allow_incomplete); break; default: im_push_errorf(aIMCTX, 0, "unknown bit count for BMP file (%d)", (int)bit_count); return NULL; } if (im) { /* store the resolution */ if (xres && !yres) yres = xres; else if (yres && !xres) xres = yres; if (xres) { i_tags_set_float2(&im->tags, "i_xres", 0, xres * 0.0254, 4); i_tags_set_float2(&im->tags, "i_yres", 0, yres * 0.0254, 4); } i_tags_addn(&im->tags, "bmp_compression", 0, compression); i_tags_addn(&im->tags, "bmp_important_colors", 0, clr_important); i_tags_addn(&im->tags, "bmp_used_colors", 0, clr_used); i_tags_addn(&im->tags, "bmp_filesize", 0, filesize); i_tags_addn(&im->tags, "bmp_bit_count", 0, bit_count); i_tags_add(&im->tags, "i_format", 0, "bmp", 3, 0); } return im; } /* =back =head1 IMPLEMENTATION FUNCTIONS Internal functions used in the implementation. =over =item read_packed(ig, format, ...) Reads from the specified "file" the specified sizes. The format codes match those used by perl's pack() function, though only a few are implemented. In all cases the vararg arguement is an int *. Returns non-zero if all of the arguments were read. =cut */ static int read_packed(io_glue *ig, char *format, ...) { unsigned char buf[4]; va_list ap; i_packed_t *p; i_packed_t work; int code; int shrieking; /* format code has a ! flag */ va_start(ap, format); while (*format) { p = va_arg(ap, i_packed_t *); code = *format++; shrieking = *format == '!'; if (shrieking) ++format; switch (code) { case 'v': if (i_io_read(ig, buf, 2) != 2) return 0; work = buf[0] + ((i_packed_t)buf[1] << 8); if (shrieking) *p = (work ^ SIGNBIT16) - SIGNBIT16; else *p = work; break; case 'V': if (i_io_read(ig, buf, 4) != 4) return 0; work = buf[0] + (buf[1] << 8) + ((i_packed_t)buf[2] << 16) + ((i_packed_t)buf[3] << 24); if (shrieking) *p = (work ^ SIGNBIT32) - SIGNBIT32; else *p = work; break; case 'C': if (i_io_read(ig, buf, 1) != 1) return 0; *p = buf[0]; break; case 'c': if (i_io_read(ig, buf, 1) != 1) return 0; *p = (char)buf[0]; break; case '3': /* extension - 24-bit number */ if (i_io_read(ig, buf, 3) != 3) return 0; *p = buf[0] + (buf[1] << 8) + ((i_packed_t)buf[2] << 16); break; default: { dIMCTXio(ig); im_fatal(aIMCTX, 1, "Unknown read_packed format code 0x%02x", code); } } } return 1; } /* =item write_packed(ig, format, ...) Writes packed data to the specified io_glue. Returns non-zero on success. =cut */ static int write_packed(io_glue *ig, char *format, ...) { unsigned char buf[4]; va_list ap; int i; va_start(ap, format); while (*format) { i = va_arg(ap, i_upacked_t); switch (*format) { case 'v': buf[0] = i & 255; buf[1] = i / 256; if (i_io_write(ig, buf, 2) == -1) return 0; break; case 'V': buf[0] = i & 0xFF; buf[1] = (i >> 8) & 0xFF; buf[2] = (i >> 16) & 0xFF; buf[3] = (i >> 24) & 0xFF; if (i_io_write(ig, buf, 4) == -1) return 0; break; case 'C': case 'c': buf[0] = i & 0xFF; if (i_io_write(ig, buf, 1) == -1) return 0; break; default: { dIMCTXio(ig); im_fatal(aIMCTX, 1, "Unknown write_packed format code 0x%02x", *format); } } ++format; } va_end(ap); return 1; } /* =item write_bmphead(ig, im, bit_count, data_size) Writes a Windows BMP header to the file. Returns non-zero on success. =cut */ static int write_bmphead(io_glue *ig, i_img *im, int bit_count, int data_size) { double xres, yres; int got_xres, got_yres, aspect_only; int colors_used = 0; int offset = FILEHEAD_SIZE + INFOHEAD_SIZE; dIMCTXim(im); if (im->xsize > SIGNMAX32 || im->ysize > SIGNMAX32) { i_push_error(0, "image too large to write to BMP"); return 0; } got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres); got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres); if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only)) aspect_only = 0; if (!got_xres) { if (!got_yres) xres = yres = 72; else xres = yres; } else { if (!got_yres) yres = xres; } if (xres <= 0 || yres <= 0) xres = yres = 72; if (aspect_only) { /* scale so the smaller value is 72 */ double ratio; if (xres < yres) { ratio = 72.0 / xres; } else { ratio = 72.0 / yres; } xres *= ratio; yres *= ratio; } /* now to pels/meter */ xres *= 100.0/2.54; yres *= 100.0/2.54; if (im->type == i_palette_type) { colors_used = i_colorcount(im); offset += 4 * colors_used; } if (!write_packed(ig, "CCVvvVVVVvvVVVVVV", 'B', 'M', (i_upacked_t)(data_size+offset), (i_upacked_t)0, (i_upacked_t)0, (i_upacked_t)offset, (i_upacked_t)INFOHEAD_SIZE, (i_upacked_t)im->xsize, (i_upacked_t)im->ysize, (i_upacked_t)1, (i_upacked_t)bit_count, (i_upacked_t)BI_RGB, (i_upacked_t)data_size, (i_upacked_t)(xres+0.5), (i_upacked_t)(yres+0.5), (i_upacked_t)colors_used, (i_upacked_t)colors_used)){ i_push_error(0, "cannot write bmp header"); return 0; } if (im->type == i_palette_type) { int i; i_color c; for (i = 0; i < colors_used; ++i) { i_getcolors(im, i, &c, 1); if (im->channels >= 3) { if (!write_packed(ig, "CCCC", (i_upacked_t)(c.channel[2]), (i_upacked_t)(c.channel[1]), (i_upacked_t)(c.channel[0]), (i_upacked_t)0)) { i_push_error(0, "cannot write palette entry"); return 0; } } else { i_upacked_t v = c.channel[0]; if (!write_packed(ig, "CCCC", v, v, v, 0)) { i_push_error(0, "cannot write palette entry"); return 0; } } } } return 1; } /* =item write_1bit_data(ig, im) Writes the image data as a 1-bit/pixel image. Returns non-zero on success. =cut */ static int write_1bit_data(io_glue *ig, i_img *im) { i_palidx *line; unsigned char *packed; int byte; int mask; unsigned char *out; int line_size = (im->xsize+7) / 8; int x, y; int unpacked_size; dIMCTXim(im); /* round up to nearest multiple of four */ line_size = (line_size + 3) / 4 * 4; if (!write_bmphead(ig, im, 1, line_size * im->ysize)) return 0; /* this shouldn't be an issue, but let's be careful */ unpacked_size = im->xsize + 8; if (unpacked_size < im->xsize) { i_push_error(0, "integer overflow during memory allocation"); return 0; } line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */ memset(line + im->xsize, 0, 8); /* size allocated here is always much smaller than xsize, hence can't overflow int */ packed = mymalloc(line_size); /* checked 29jun05 tonyc */ memset(packed, 0, line_size); for (y = im->ysize-1; y >= 0; --y) { i_gpal(im, 0, im->xsize, y, line); mask = 0x80; byte = 0; out = packed; for (x = 0; x < im->xsize; ++x) { if (line[x]) byte |= mask; if ((mask >>= 1) == 0) { *out++ = byte; byte = 0; mask = 0x80; } } if (mask != 0x80) { *out++ = byte; } if (i_io_write(ig, packed, line_size) < 0) { myfree(packed); myfree(line); i_push_error(0, "writing 1 bit/pixel packed data"); return 0; } } myfree(packed); myfree(line); if (i_io_close(ig)) return 0; return 1; } /* =item write_4bit_data(ig, im) Writes the image data as a 4-bit/pixel image. Returns non-zero on success. =cut */ static int write_4bit_data(io_glue *ig, i_img *im) { i_palidx *line; unsigned char *packed; unsigned char *out; int line_size = (im->xsize+1) / 2; int x, y; int unpacked_size; dIMCTXim(im); /* round up to nearest multiple of four */ line_size = (line_size + 3) / 4 * 4; if (!write_bmphead(ig, im, 4, line_size * im->ysize)) return 0; /* this shouldn't be an issue, but let's be careful */ unpacked_size = im->xsize + 2; if (unpacked_size < im->xsize) { i_push_error(0, "integer overflow during memory allocation"); return 0; } line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */ memset(line + im->xsize, 0, 2); /* size allocated here is always much smaller than xsize, hence can't overflow int */ packed = mymalloc(line_size); /* checked 29jun05 tonyc */ memset(packed, 0, line_size); for (y = im->ysize-1; y >= 0; --y) { i_gpal(im, 0, im->xsize, y, line); out = packed; for (x = 0; x < im->xsize; x += 2) { *out++ = (line[x] << 4) + line[x+1]; } if (i_io_write(ig, packed, line_size) < 0) { myfree(packed); myfree(line); i_push_error(0, "writing 4 bit/pixel packed data"); return 0; } } myfree(packed); myfree(line); if (i_io_close(ig)) return 0; return 1; } /* =item write_8bit_data(ig, im) Writes the image data as a 8-bit/pixel image. Returns non-zero on success. =cut */ static int write_8bit_data(io_glue *ig, i_img *im) { i_palidx *line; int line_size = im->xsize; int y; int unpacked_size; dIMCTXim(im); /* round up to nearest multiple of four */ line_size = (line_size + 3) / 4 * 4; if (!write_bmphead(ig, im, 8, line_size * im->ysize)) return 0; /* this shouldn't be an issue, but let's be careful */ unpacked_size = im->xsize + 4; if (unpacked_size < im->xsize) { i_push_error(0, "integer overflow during memory allocation"); return 0; } line = mymalloc(unpacked_size); /* checked 29jun05 tonyc */ memset(line + im->xsize, 0, 4); for (y = im->ysize-1; y >= 0; --y) { i_gpal(im, 0, im->xsize, y, line); if (i_io_write(ig, line, line_size) < 0) { myfree(line); i_push_error(0, "writing 8 bit/pixel packed data"); return 0; } } myfree(line); if (i_io_close(ig)) return 0; return 1; } /* =item write_24bit_data(ig, im) Writes the image data as a 24-bit/pixel image. Returns non-zero on success. =cut */ static int write_24bit_data(io_glue *ig, i_img *im) { unsigned char *samples; int y; int line_size = 3 * im->xsize; i_color bg; dIMCTXim(im); i_get_file_background(im, &bg); /* just in case we implement a direct format with 2bytes/pixel (unlikely though) */ if (line_size / 3 != im->xsize) { i_push_error(0, "integer overflow during memory allocation"); return 0; } line_size = (line_size + 3) / 4 * 4; if (!write_bmphead(ig, im, 24, line_size * im->ysize)) return 0; samples = mymalloc(4 * im->xsize); memset(samples, 0, line_size); for (y = im->ysize-1; y >= 0; --y) { unsigned char *samplep = samples; int x; i_gsamp_bg(im, 0, im->xsize, y, samples, 3, &bg); for (x = 0; x < im->xsize; ++x) { unsigned char tmp = samplep[2]; samplep[2] = samplep[0]; samplep[0] = tmp; samplep += 3; } if (i_io_write(ig, samples, line_size) < 0) { i_push_error(0, "writing image data"); myfree(samples); return 0; } } myfree(samples); if (i_io_close(ig)) return 0; return 1; } /* =item read_bmp_pal(ig, im, count) Reads count palette entries from the file and add them to the image. Returns non-zero on success. =cut */ static int read_bmp_pal(io_glue *ig, i_img *im, int count) { int i; i_packed_t r, g, b, x; i_color c; dIMCTXio(ig); for (i = 0; i < count; ++i) { if (!read_packed(ig, "CCCC", &b, &g, &r, &x)) { i_push_error(0, "reading BMP palette"); return 0; } c.channel[0] = r; c.channel[1] = g; c.channel[2] = b; if (i_addcolors(im, &c, 1) < 0) { i_push_error(0, "out of space in image palette"); return 0; } } return 1; } /* =item read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits) Reads in the palette and image data for a 1-bit/pixel image. Returns the image or NULL. =cut */ static i_img * read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int compression, long offbits, int allow_incomplete) { i_img *im; int x, y, lasty, yinc, start_y; i_palidx *line, *p; unsigned char *packed; int line_size = (xsize + 7)/8; int bit; unsigned char *in; long base_offset; dIMCTXio(ig); if (compression != BI_RGB) { im_push_errorf(aIMCTX, 0, "unknown 1-bit BMP compression (%d)", compression); return NULL; } if ((i_img_dim)((i_img_dim_u)xsize + 8) < xsize) { /* if there was overflow */ /* we check with 8 because we allocate that much for the decoded line buffer */ i_push_error(0, "integer overflow during memory allocation"); return NULL; } /* if xsize+7 is ok then (xsize+7)/8 will be and the minor adjustments below won't make it overflow */ line_size = (line_size+3) / 4 * 4; if (ysize > 0) { start_y = ysize-1; lasty = -1; yinc = -1; } else { /* when ysize is -ve it's a top-down image */ ysize = -ysize; start_y = 0; lasty = ysize; yinc = 1; } y = start_y; if (!clr_used) clr_used = 2; if (clr_used < 0 || clr_used > 2) { im_push_errorf(aIMCTX, 0, "out of range colors used (%d)", clr_used); return NULL; } base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4; if (offbits < base_offset) { im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits); return NULL; } im = i_img_pal_new(xsize, ysize, 3, 256); if (!im) return NULL; if (!read_bmp_pal(ig, im, clr_used)) { i_img_destroy(im); return NULL; } if (offbits > base_offset) { /* this will be slow if the offset is large, but that should be rare */ char buffer; while (base_offset < offbits) { if (i_io_read(ig, &buffer, 1) != 1) { i_img_destroy(im); i_push_error(0, "failed skipping to image data offset"); return NULL; } ++base_offset; } } i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0); packed = mymalloc(line_size); /* checked 29jun05 tonyc */ line = mymalloc(xsize+8); /* checked 29jun05 tonyc */ while (y != lasty) { if (i_io_read(ig, packed, line_size) != line_size) { myfree(packed); myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(start_y - y)); return im; } else { i_push_error(0, "failed reading 1-bit bmp data"); i_img_destroy(im); return NULL; } } in = packed; bit = 0x80; p = line; for (x = 0; x < xsize; ++x) { *p++ = (*in & bit) ? 1 : 0; bit >>= 1; if (!bit) { ++in; bit = 0x80; } } i_ppal(im, 0, xsize, y, line); y += yinc; } myfree(packed); myfree(line); return im; } /* =item read_4bit_bmp(ig, xsize, ysize, clr_used, compression) Reads in the palette and image data for a 4-bit/pixel image. Returns the image or NULL. Hopefully this will be combined with the following function at some point. =cut */ static i_img * read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int compression, long offbits, int allow_incomplete) { i_img *im; int x, y, lasty, yinc; i_palidx *line, *p; unsigned char *packed; int line_size = (xsize + 1)/2; unsigned char *in; int size, i; long base_offset; int starty; dIMCTXio(ig); /* line_size is going to be smaller than xsize in most cases (and when it's not, xsize is itself small), and hence not overflow */ line_size = (line_size+3) / 4 * 4; if (ysize > 0) { starty = ysize-1; lasty = -1; yinc = -1; } else { /* when ysize is -ve it's a top-down image */ ysize = -ysize; starty = 0; lasty = ysize; yinc = 1; } y = starty; if (!clr_used) clr_used = 16; if (clr_used > 16 || clr_used < 0) { im_push_errorf(aIMCTX, 0, "out of range colors used (%d)", clr_used); return NULL; } base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4; if (offbits < base_offset) { im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits); return NULL; } im = i_img_pal_new(xsize, ysize, 3, 256); if (!im) /* error should have been pushed already */ return NULL; if (!read_bmp_pal(ig, im, clr_used)) { i_img_destroy(im); return NULL; } if (offbits > base_offset) { /* this will be slow if the offset is large, but that should be rare */ char buffer; while (base_offset < offbits) { if (i_io_read(ig, &buffer, 1) != 1) { i_img_destroy(im); i_push_error(0, "failed skipping to image data offset"); return NULL; } ++base_offset; } } if (line_size < 260) packed = mymalloc(260); /* checked 29jun05 tonyc */ else packed = mymalloc(line_size); /* checked 29jun05 tonyc */ /* xsize won't approach MAXINT */ line = mymalloc(xsize+1); /* checked 29jun05 tonyc */ if (compression == BI_RGB) { i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0); while (y != lasty) { if (i_io_read(ig, packed, line_size) != line_size) { myfree(packed); myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(y - starty)); return im; } else { i_push_error(0, "failed reading 4-bit bmp data"); i_img_destroy(im); return NULL; } } in = packed; p = line; for (x = 0; x < xsize; x+=2) { *p++ = *in >> 4; *p++ = *in & 0x0F; ++in; } i_ppal(im, 0, xsize, y, line); y += yinc; } myfree(packed); myfree(line); } else if (compression == BI_RLE4) { int read_size; int count; i_img_dim xlimit = (xsize + 1) / 2 * 2; /* rounded up */ i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE4", -1, 0); x = 0; while (1) { /* there's always at least 2 bytes in a sequence */ if (i_io_read(ig, packed, 2) != 2) { myfree(packed); myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(y - starty)); return im; } else { i_push_error(0, "missing data during decompression"); i_img_destroy(im); return NULL; } } else if (packed[0]) { int count = packed[0]; if (x + count > xlimit) { /* this file is corrupt */ myfree(packed); myfree(line); i_push_error(0, "invalid data during decompression"); im_log((aIMCTX, 1, "read 4-bit: scanline overflow x %d + count %d vs xlimit %d (y %d)\n", (int)x, count, (int)xlimit, (int)y)); i_img_destroy(im); return NULL; } /* fill in the line */ for (i = 0; i < count; i += 2) line[i] = packed[1] >> 4; for (i = 1; i < count; i += 2) line[i] = packed[1] & 0x0F; i_ppal(im, x, x+count, y, line); x += count; } else { switch (packed[1]) { case BMPRLE_ENDOFLINE: x = 0; y += yinc; break; case BMPRLE_ENDOFBMP: myfree(packed); myfree(line); return im; case BMPRLE_DELTA: if (i_io_read(ig, packed, 2) != 2) { myfree(packed); myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(y - starty)); return im; } else { i_push_error(0, "missing data during decompression"); i_img_destroy(im); return NULL; } } x += packed[0]; y += yinc * packed[1]; break; default: count = packed[1]; if (x + count > xlimit) { /* this file is corrupt */ myfree(packed); myfree(line); i_push_error(0, "invalid data during decompression"); im_log((aIMCTX, 1, "read 4-bit: scanline overflow (unpacked) x %d + count %d vs xlimit %d (y %d)\n", (int)x, count, (int)xlimit, (int)y)); i_img_destroy(im); return NULL; } size = (count + 1) / 2; read_size = (size+1) / 2 * 2; if (i_io_read(ig, packed, read_size) != read_size) { myfree(packed); myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(y - starty)); return im; } else { i_push_error(0, "missing data during decompression"); i_img_destroy(im); return NULL; } } for (i = 0; i < size; ++i) { line[0] = packed[i] >> 4; line[1] = packed[i] & 0xF; i_ppal(im, x, x+2, y, line); x += 2; } break; } } } } else { /*if (compression == BI_RLE4) {*/ myfree(packed); myfree(line); im_push_errorf(aIMCTX, 0, "unknown 4-bit BMP compression (%d)", compression); i_img_destroy(im); return NULL; } return im; } /* =item read_8bit_bmp(ig, xsize, ysize, clr_used, compression, allow_incomplete) Reads in the palette and image data for a 8-bit/pixel image. Returns the image or NULL. =cut */ static i_img * read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int compression, long offbits, int allow_incomplete) { i_img *im; int x, y, lasty, yinc, start_y; i_palidx *line; int line_size = xsize; long base_offset; dIMCTXio(ig); line_size = (line_size+3) / 4 * 4; if (line_size < xsize) { /* if it overflowed (unlikely, but check) */ i_push_error(0, "integer overflow during memory allocation"); return NULL; } if (ysize > 0) { start_y = ysize-1; lasty = -1; yinc = -1; } else { /* when ysize is -ve it's a top-down image */ ysize = -ysize; start_y = 0; lasty = ysize; yinc = 1; } y = start_y; if (!clr_used) clr_used = 256; if (clr_used > 256 || clr_used < 0) { im_push_errorf(aIMCTX, 0, "out of range colors used (%d)", clr_used); return NULL; } base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4; if (offbits < base_offset) { im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits); return NULL; } im = i_img_pal_new(xsize, ysize, 3, 256); if (!im) return NULL; if (!read_bmp_pal(ig, im, clr_used)) { i_img_destroy(im); return NULL; } if (offbits > base_offset) { /* this will be slow if the offset is large, but that should be rare */ char buffer; while (base_offset < offbits) { if (i_io_read(ig, &buffer, 1) != 1) { i_img_destroy(im); i_push_error(0, "failed skipping to image data offset"); return NULL; } ++base_offset; } } line = mymalloc(line_size); /* checked 29jun05 tonyc */ if (compression == BI_RGB) { i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0); while (y != lasty) { if (i_io_read(ig, line, line_size) != line_size) { myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(start_y - y)); return im; } else { i_push_error(0, "failed reading 8-bit bmp data"); i_img_destroy(im); return NULL; } } i_ppal(im, 0, xsize, y, line); y += yinc; } myfree(line); } else if (compression == BI_RLE8) { int read_size; int count; unsigned char packed[2]; i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE8", -1, 0); x = 0; while (1) { /* there's always at least 2 bytes in a sequence */ if (i_io_read(ig, packed, 2) != 2) { myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(start_y-y)); return im; } else { i_push_error(0, "missing data during decompression"); i_img_destroy(im); return NULL; } } if (packed[0]) { if (x + packed[0] > xsize) { /* this file isn't incomplete, it's corrupt */ myfree(line); i_push_error(0, "invalid data during decompression"); i_img_destroy(im); return NULL; } memset(line, packed[1], packed[0]); i_ppal(im, x, x+packed[0], y, line); x += packed[0]; } else { switch (packed[1]) { case BMPRLE_ENDOFLINE: x = 0; y += yinc; break; case BMPRLE_ENDOFBMP: myfree(line); return im; case BMPRLE_DELTA: if (i_io_read(ig, packed, 2) != 2) { myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(start_y-y)); return im; } else { i_push_error(0, "missing data during decompression"); i_img_destroy(im); return NULL; } } x += packed[0]; y += yinc * packed[1]; break; default: count = packed[1]; if (x + count > xsize) { /* runs shouldn't cross a line boundary */ /* this file isn't incomplete, it's corrupt */ myfree(line); i_push_error(0, "invalid data during decompression"); i_img_destroy(im); return NULL; } read_size = (count+1) / 2 * 2; if (i_io_read(ig, line, read_size) != read_size) { myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(start_y-y)); return im; } else { i_push_error(0, "missing data during decompression"); i_img_destroy(im); return NULL; } } i_ppal(im, x, x+count, y, line); x += count; break; } } } } else { myfree(line); im_push_errorf(aIMCTX, 0, "unknown 8-bit BMP compression (%d)", compression); i_img_destroy(im); return NULL; } return im; } struct bm_masks { unsigned masks[3]; int shifts[3]; int bits[3]; }; static struct bm_masks std_masks[] = { { /* 16-bit */ { 0076000, 00001740, 00000037, }, { 10, 5, 0, }, { 5, 5, 5, } }, { /* 24-bit */ { 0xFF0000, 0x00FF00, 0x0000FF, }, { 16, 8, 0, }, { 8, 8, 8, }, }, { /* 32-bit */ { 0xFF0000, 0x00FF00, 0x0000FF, }, { 16, 8, 0, }, { 8, 8, 8, }, }, }; /* multiplier and shift for converting from N bits to 8 bits */ struct bm_sampconverts { int mult; int shift; }; static struct bm_sampconverts samp_converts[] = { { 0xff, 0 }, /* 1 bit samples */ { 0x55, 0 }, { 0111, 1 }, { 0x11, 0 }, { 0x21, 2 }, { 0x41, 4 }, { 0x81, 6 } /* 7 bit samples */ }; /* =item read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression, allow_incomplete) Skips the palette and reads in the image data for a direct colour image. Returns the image or NULL. =cut */ static i_img * read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, int clr_used, int compression, long offbits, int allow_incomplete) { i_img *im; int x, y, starty, lasty, yinc; i_color *line, *p; int pix_size = bit_count / 8; int line_size = xsize * pix_size; struct bm_masks masks; char unpack_code[2] = ""; int i; int extras; char junk[4]; const char *compression_name; int bytes; long base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE; dIMCTXio(ig); unpack_code[0] = *("v3V"+pix_size-2); unpack_code[1] = '\0'; line_size = (line_size+3) / 4 * 4; extras = line_size - xsize * pix_size; if (ysize > 0) { starty = ysize-1; lasty = -1; yinc = -1; } else { /* when ysize is -ve it's a top-down image */ ysize = -ysize; starty = 0; lasty = ysize; yinc = 1; } y = starty; if (compression == BI_RGB) { compression_name = "BI_RGB"; masks = std_masks[pix_size-2]; /* there's a potential "palette" after the header */ for (i = 0; i < clr_used; ++clr_used) { char buf[4]; if (i_io_read(ig, buf, 4) != 4) { i_push_error(0, "skipping colors"); return 0; } base_offset += 4; } } else if (compression == BI_BITFIELDS) { int pos; unsigned bits; compression_name = "BI_BITFIELDS"; for (i = 0; i < 3; ++i) { i_packed_t rmask; if (!read_packed(ig, "V", &rmask)) { i_push_error(0, "reading pixel masks"); return 0; } if (rmask == 0) { im_push_errorf(aIMCTX, 0, "Zero mask for channel %d", i); return NULL; } masks.masks[i] = rmask; /* work out a shift for the mask */ pos = 0; bits = masks.masks[i]; while (!(bits & 1)) { ++pos; bits >>= 1; } masks.shifts[i] = pos; pos = 0; while (bits & 1) { ++pos; bits >>= 1; } masks.bits[i] = pos; /*fprintf(stderr, "%d: mask %08x shift %d bits %d\n", i, masks.masks[i], masks.shifts[i], masks.bits[i]);*/ } /* account for the masks */ base_offset += 3 * 4; } else { im_push_errorf(aIMCTX, 0, "unknown 24-bit BMP compression (%d)", compression); return NULL; } if (offbits < base_offset) { im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits); return NULL; } if (offbits > base_offset) { /* this will be slow if the offset is large, but that should be rare */ char buffer; while (base_offset < offbits) { if (i_io_read(ig, &buffer, 1) != 1) { i_push_error(0, "failed skipping to image data offset"); return NULL; } ++base_offset; } } im = i_img_empty(NULL, xsize, ysize); if (!im) return NULL; i_tags_add(&im->tags, "bmp_compression_name", 0, compression_name, -1, 0); /* I wasn't able to make this overflow in testing, but better to be safe */ bytes = sizeof(i_color) * xsize; if (bytes / sizeof(i_color) != xsize) { i_img_destroy(im); i_push_error(0, "integer overflow calculating buffer size"); return NULL; } line = mymalloc(bytes); /* checked 29jun05 tonyc */ while (y != lasty) { p = line; for (x = 0; x < xsize; ++x) { i_packed_t pixel; if (!read_packed(ig, unpack_code, &pixel)) { myfree(line); if (allow_incomplete) { i_tags_setn(&im->tags, "i_incomplete", 1); i_tags_setn(&im->tags, "i_lines_read", abs(starty - y)); return im; } else { i_push_error(0, "failed reading image data"); i_img_destroy(im); return NULL; } } for (i = 0; i < 3; ++i) { int sample = (pixel & masks.masks[i]) >> masks.shifts[i]; int bits = masks.bits[i]; if (bits < 8) { sample = (sample * samp_converts[bits-1].mult) >> samp_converts[bits-1].shift; } else if (bits) { sample >>= bits - 8; } p->channel[i] = sample; } ++p; } i_plin(im, 0, xsize, y, line); if (extras) i_io_read(ig, junk, extras); y += yinc; } myfree(line); return im; } /* =head1 SEE ALSO Imager(3) =head1 AUTHOR Tony Cook =head1 RESTRICTIONS Cannot save as compressed BMP. =head1 BUGS Doesn't handle OS/2 bitmaps. 16-bit/pixel images haven't been tested. (I need an image). BI_BITFIELDS compression hasn't been tested (I need an image). The header handling for paletted images needs to be refactored =cut */ libimager-perl-1.004+dfsg.orig/inc/0000755000175000017500000000000012617614576016351 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/inc/Devel/0000755000175000017500000000000012617614576017410 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/inc/Devel/CheckLib.pm0000644000175000017500000004010012460670607021376 0ustar gregoagregoa# $Id: CheckLib.pm,v 1.25 2008/10/27 12:16:23 drhyde Exp $ # This is a modified version of Devel::CheckLib 0.93 including the patches from # RT issues 60176 and 61645 and other changes I need to backport package # Devel::CheckLib; use 5.00405; #postfix foreach use strict; use vars qw($VERSION @ISA @EXPORT); $VERSION = '0.93_002'; use Config qw(%Config); use Text::ParseWords 'quotewords'; use File::Spec; use File::Temp; use File::Path qw(rmtree); require Exporter; @ISA = qw(Exporter); @EXPORT = qw(assert_lib check_lib_or_exit check_lib); # localising prevents the warningness leaking out of this module local $^W = 1; # use warnings is a 5.6-ism _findcc(); # bomb out early if there's no compiler =head1 NAME Devel::CheckLib - check that a library is available =head1 DESCRIPTION Devel::CheckLib is a perl module that checks whether a particular C library and its headers are available. =head1 SYNOPSIS use Devel::CheckLib; check_lib_or_exit( lib => 'jpeg', header => 'jpeglib.h' ); check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] ); # or prompt for path to library and then do this: check_lib_or_exit( lib => 'jpeg', libpath => $additional_path ); =head1 USING IT IN Makefile.PL or Build.PL If you want to use this from Makefile.PL or Build.PL, do not simply copy the module into your distribution as this may cause problems when PAUSE and search.cpan.org index the distro. Instead, use the use-devel-checklib script. =head1 HOW IT WORKS You pass named parameters to a function, describing to it how to build and link to the libraries. It works by trying to compile some code - which defaults to this: int main(void) { return 0; } and linking it to the specified libraries. If something pops out the end which looks executable, it gets executed, and if main() returns 0 we know that it worked. That tiny program is built once for each library that you specify, and (without linking) once for each header file. If you want to check for the presence of particular functions in a library, or even that those functions return particular results, then you can pass your own function body for main() thus: check_lib_or_exit( function => 'foo();if(libversion() > 5) return 0; else return 1;' incpath => ... libpath => ... lib => ... header => ... ); In that case, it will fail to build if either foo() or libversion() don't exist, and main() will return the wrong value if libversion()'s return value isn't what you want. =head1 FUNCTIONS All of these take the same named parameters and are exported by default. To avoid exporting them, C. =head2 assert_lib This takes several named parameters, all of which are optional, and dies with an error message if any of the libraries listed can not be found. B: dying in a Makefile.PL or Build.PL may provoke a 'FAIL' report from CPAN Testers' automated smoke testers. Use C instead. The named parameters are: =over =item lib Must be either a string with the name of a single library or a reference to an array of strings of library names. Depending on the compiler found, library names will be fed to the compiler either as C<-l> arguments or as C<.lib> file names. (E.g. C<-ljpeg> or C) =item libpath a string or an array of strings representing additional paths to search for libraries. =item LIBS a C-style space-seperated list of libraries (each preceded by '-l') and directories (preceded by '-L'). This can also be supplied on the command-line. =back And libraries are no use without header files, so ... =over =item header Must be either a string with the name of a single header file or a reference to an array of strings of header file names. =item incpath a string or an array of strings representing additional paths to search for headers. =item INC a C-style space-seperated list of incpaths, each preceded by '-I'. This can also be supplied on the command-line. =back If you need to perform know more than "does it link?" you can provide code to be compiled and run: =over =item function the body of the function. If not provided C is used. =item prologue code to insert between the C<#include> of the headers and the definition of main. =back =head2 check_lib_or_exit This behaves exactly the same as C except that instead of dieing, it warns (with exactly the same error message) and exits. This is intended for use in Makefile.PL / Build.PL when you might want to prompt the user for various paths and things before checking that what they've told you is sane. If any library or header is missing, it exits with an exit value of 0 to avoid causing a CPAN Testers 'FAIL' report. CPAN Testers should ignore this result -- which is what you want if an external library dependency is not available. =head2 check_lib This behaves exactly the same as C except that it is silent, returning false instead of dieing, or true otherwise. =cut sub check_lib_or_exit { eval 'assert_lib(@_)'; if($@) { warn $@; exit; } } sub check_lib { eval 'assert_lib(@_)'; return $@ ? 0 : 1; } sub assert_lib { my %args = @_; my (@libs, @libpaths, @headers, @incpaths); # FIXME: these four just SCREAM "refactor" at me @libs = (ref($args{lib}) ? @{$args{lib}} : $args{lib}) if $args{lib}; @libpaths = (ref($args{libpath}) ? @{$args{libpath}} : $args{libpath}) if $args{libpath}; @headers = (ref($args{header}) ? @{$args{header}} : $args{header}) if $args{header}; @incpaths = (ref($args{incpath}) ? @{$args{incpath}} : $args{incpath}) if $args{incpath}; # each entry is an arrayref containing: # 0: arrayref of library search paths # 1: arrayref of library names my @link_cfgs = map [ \@libpaths, [ $_ ] ], @libs; # work-a-like for Makefile.PL's LIBS and INC arguments # if given as command-line argument, append to %args for my $arg (@ARGV) { for my $mm_attr_key (qw(LIBS INC)) { if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) { # it is tempting to put some \s* into the expression, but the # MM command-line parser only accepts LIBS etc. followed by =, # so we should not be any more lenient with whitespace than that $args{$mm_attr_key} .= " $mm_attr_value"; } } } # using special form of split to trim whitespace if(defined($args{LIBS})) { if (ref $args{LIBS}) { foreach my $arg (@{$args{LIBS}}) { my @sep = split ' ', $arg; my @libs = map { /^-l(.+)$/ ? $1 : () } @sep; my @paths = map { /^-L(.+)$/ ? $1 : () } @sep; push @link_cfgs, [ \@paths, \@libs ]; } } else { my @libs; my @paths; foreach my $arg (split(' ', $args{LIBS})) { die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-l/i); push @{$arg =~ /^-l/ ? \@libs : \@paths}, substr($arg, 2); } push @link_cfgs, map [ \@paths, [ $_ ] ], @libs; } } if(defined($args{INC})) { foreach my $arg (_shellwords($args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; # first figure out which headers we can't find ... for my $header (@headers) { push @use_headers, $header; my($ch, $cfile) = File::Temp::tempfile( 'assertlibXXXXXXXX', SUFFIX => '.c' ); print $ch qq{#include <$_>\n} for @use_headers; print $ch qq{int main(void) { return 0; }\n}; close($ch); my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe}; my @sys_cmd; # FIXME: re-factor - almost identical code later when linking if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( @$cc, $cfile, "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( @$cc, (map { "-I$_" } @incpaths), "-o$exefile", $cfile, @$ld ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( @$cc, @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" ); } warn "# @sys_cmd\n" if $args{debug}; my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd); push @missing, $header if $rv != 0 || ! -x $exefile; _cleanup_exe($exefile); unlink $cfile; } # now do each library in turn with headers my($ch, $cfile) = File::Temp::tempfile( 'assertlibXXXXXXXX', SUFFIX => '.c' ); print $ch qq{#include <$_>\n} foreach (@headers); print $ch "\n$args{prologue}\n" if $args{prologue}; print $ch "int main(void) { ".($args{function} || 'return 0;')." }\n"; close($ch); for my $link_cfg ( @link_cfgs ) { my ($paths, $libs) = @$link_cfg; my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe}; my @sys_cmd; if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; my @libpath = map { q{/libpath:} . Win32::GetShortPathName($_) } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( @$cc, $cfile, ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( @$cc, @$ld, "-o$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), (map { "-L$_" } @$paths), $cfile); } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( @$cc, @$ld, $cfile, "-o", "$exefile", (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), (map { "-L$_" } @$paths) ); } warn "# @sys_cmd\n" if $args{debug}; my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd); push @missing, @$libs if $rv != 0 || ! -x $exefile; my $absexefile = File::Spec->rel2abs($exefile); $absexefile = '"'.$absexefile.'"' if $absexefile =~ m/\s/; push @wrongresult, @$libs if $rv == 0 && -x $exefile && system($absexefile) != 0; _cleanup_exe($exefile); } unlink $cfile; my $miss_string = join( q{, }, map { qq{'$_'} } @missing ); die("Can't link/include $miss_string\n") if @missing; my $wrong_string = join( q{, }, map { qq{'$_'} } @wrongresult); die("wrong result: $wrong_string\n") if @wrongresult; } sub _cleanup_exe { my ($exefile) = @_; my $ofile = $exefile; $ofile =~ s/$Config{_exe}$/$Config{_o}/; unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; if ( $Config{cc} eq 'cl' ) { # MSVC also creates foo.ilk and foo.pdb my $ilkfile = $exefile; $ilkfile =~ s/$Config{_exe}$/.ilk/; my $pdbfile = $exefile; $pdbfile =~ s/$Config{_exe}$/.pdb/; unlink $ilkfile if -f $ilkfile; unlink $pdbfile if -f $pdbfile; } # created by clang on darwin my $dsym_dir = $exefile; $dsym_dir =~ s/\Q$Config{_exe}\E$/.dSYM/; rmtree $dsym_dir if -d $dsym_dir; return } # return ($cc, $ld) # where $cc is an array ref of compiler name, compiler flags # where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile my @Config_ldflags = @Config{qw(ldflags perllibs)}; my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags); my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . ($^O eq 'cygwin' ? '' : $Config{_exe}); return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) if -x $compiler; next if ! length $Config{_exe}; $compiler = File::Spec->catfile($path, $cc[0]); return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) if -x $compiler; } die("Couldn't find your C compiler\n"); } sub _shellwords { my $line = shift; if ($^O eq "MSWin32") { my @elements; $line =~ s/^\s+//; while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) { push @elements, $1; $line =~ s/^\s+//; } return @elements; } else { return grep defined && /\S/, quotewords('\s+', 0, $line); } } # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; # save handles local *STDOUT_SAVE; local *STDERR_SAVE; open STDOUT_SAVE, ">&STDOUT" or die "CheckLib: $! saving STDOUT"; open STDERR_SAVE, ">&STDERR" or die "CheckLib: $! saving STDERR"; # redirect to nowhere local *DEV_NULL; open DEV_NULL, ">" . File::Spec->devnull or die "CheckLib: $! opening handle to null device"; open STDOUT, ">&" . fileno DEV_NULL or die "CheckLib: $! redirecting STDOUT to null handle"; open STDERR, ">&" . fileno DEV_NULL or die "CheckLib: $! redirecting STDERR to null handle"; # run system command my $rv = system(@cmd); # restore handles open STDOUT, ">&" . fileno STDOUT_SAVE or die "CheckLib: $! restoring STDOUT handle"; open STDERR, ">&" . fileno STDERR_SAVE or die "CheckLib: $! restoring STDERR handle"; return $rv; } =head1 PLATFORMS SUPPORTED You must have a C compiler installed. We check for C<$Config{cc}>, both literally as it is in Config.pm and also in the $PATH. It has been tested with varying degrees on rigourousness on: =over =item gcc (on Linux, *BSD, Mac OS X, Solaris, Cygwin) =item Sun's compiler tools on Solaris =item IBM's tools on AIX =item SGI's tools on Irix 6.5 =item Microsoft's tools on Windows =item MinGW on Windows (with Strawberry Perl) =item Borland's tools on Windows =item QNX =back =head1 WARNINGS, BUGS and FEEDBACK This is a very early release intended primarily for feedback from people who have discussed it. The interface may change and it has not been adequately tested. Feedback is most welcome, including constructive criticism. Bug reports should be made using L or by email. When submitting a bug report, please include the output from running: perl -V perl -MDevel::CheckLib -e0 =head1 SEE ALSO L L =head1 AUTHORS David Cantrell Edavid@cantrell.org.ukE David Golden Edagolden@cpan.orgE Yasuhiro Matsumoto Emattn@cpan.orgE Thanks to the cpan-testers-discuss mailing list for prompting us to write it in the first place; to Chris Williams for help with Borland support; to Tony Cook for help with Microsoft compiler command-line options =head1 COPYRIGHT and LICENCE Copyright 2007 David Cantrell. Portions copyright 2007 David Golden. This module is free-as-in-speech software, and may be used, distributed, and modified under the same conditions as perl itself. =head1 CONSPIRACY This module is also free-as-in-mason software. =cut 1; libimager-perl-1.004+dfsg.orig/META.json0000644000175000017500000000261012617614576017220 0ustar gregoagregoa{ "abstract" : "Perl extension for Generating 24 bit Images", "author" : [ "Tony Cook , Arnar M. Hrafnkelsson" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.142690", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Imager", "no_index" : { "directory" : [ "t", "inc", "PNG", "GIF", "TIFF", "JPEG", "W32", "FT2", "T1" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "recommends" : { "Parse::RecDescent" : "0" }, "requires" : { "Scalar::Util" : "1", "Test::More" : "0.47", "XSLoader" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager" }, "homepage" : "http://imager.perl.org/", "repository" : { "url" : "git://git.imager.perl.org/imager.git" } }, "version" : "1.004" } libimager-perl-1.004+dfsg.orig/image.c0000644000175000017500000012325512616363730017026 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" /* =head1 NAME image.c - implements most of the basic functions of Imager and much of the rest =head1 SYNOPSIS i_img *i; i_color *c; c = i_color_new(red, green, blue, alpha); ICL_DESTROY(c); i = i_img_8_new(); i_img_destroy(i); // and much more =head1 DESCRIPTION image.c implements the basic functions to create and destroy image and color objects for Imager. =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ im_context_t (*im_get_context)(void) = NULL; #define XAXIS 0 #define YAXIS 1 #define XYAXIS 2 #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 i_linker_bug_fake(void) { ceil(1); } /* =item im_img_alloc(aIMCTX) XX =category Image Implementation =synopsis i_img *im = im_img_alloc(aIMCTX); =synopsis i_img *im = i_img_alloc(); Allocates a new i_img structure. When implementing a new image type perform the following steps in your image object creation function: =over =item 1. allocate the image with i_img_alloc(). =item 2. initialize any function pointers or other data as needed, you can overwrite the whole block if you need to. =item 3. initialize Imager's internal data by calling i_img_init() on the image object. =back =cut */ i_img * im_img_alloc(pIMCTX) { return mymalloc(sizeof(i_img)); } /* =item im_img_init(aIMCTX, image) XX =category Image Implementation =synopsis im_img_init(aIMCTX, im); =synopsis i_img_init(im); Imager internal initialization of images. See L for more information. =cut */ void im_img_init(pIMCTX, i_img *img) { img->im_data = NULL; img->context = aIMCTX; im_context_refinc(aIMCTX, "img_init"); } /* =item ICL_new_internal(r, g, b, a) Return a new color object with values passed to it. r - red component (range: 0 - 255) g - green component (range: 0 - 255) b - blue component (range: 0 - 255) a - alpha component (range: 0 - 255) =cut */ i_color * ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) { i_color *cl = NULL; dIMCTX; 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) im_fatal(aIMCTX, 2,"malloc() error\n"); cl->rgba.r = r; cl->rgba.g = g; cl->rgba.b = b; cl->rgba.a = a; im_log((aIMCTX,1,"(%p) <- ICL_new_internal\n",cl)); return cl; } /* =item ICL_set_internal(cl, r, g, b, a) Overwrite a color with new values. cl - pointer to color object r - red component (range: 0 - 255) g - green component (range: 0 - 255) b - blue component (range: 0 - 255) a - alpha component (range: 0 - 255) =cut */ i_color * ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char 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) im_fatal(aIMCTX, 2,"malloc() error\n"); cl->rgba.r=r; cl->rgba.g=g; cl->rgba.b=b; cl->rgba.a=a; im_log((aIMCTX,1,"(%p) <- ICL_set_internal\n",cl)); return cl; } /* =item ICL_add(dst, src, ch) Add src to dst inplace - dst is modified. dst - pointer to destination color object src - pointer to color object that is added ch - number of channels =cut */ void ICL_add(i_color *dst,i_color *src,int ch) { int tmp,i; for(i=0;ichannel[i]+src->channel[i]; dst->channel[i]= tmp>255 ? 255:tmp; } } /* =item ICL_info(cl) Dump color information to log - strictly for debugging. cl - pointer to color object =cut */ void ICL_info(i_color const *cl) { 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)); } /* =item ICL_DESTROY Destroy ancillary data for Color object. cl - pointer to color object =cut */ void ICL_DESTROY(i_color *cl) { dIMCTX; im_log((aIMCTX, 1,"ICL_DESTROY(cl* %p)\n",cl)); myfree(cl); } /* =item i_fcolor_new(double r, double g, double b, double a) =cut */ i_fcolor *i_fcolor_new(double r, double g, double b, double a) { i_fcolor *cl = NULL; dIMCTX; 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) im_fatal(aIMCTX, 2,"malloc() error\n"); cl->rgba.r = r; cl->rgba.g = g; cl->rgba.b = b; cl->rgba.a = a; im_log((aIMCTX, 1,"(%p) <- i_fcolor_new\n",cl)); return cl; } /* =item i_fcolor_destroy(i_fcolor *cl) =cut */ void i_fcolor_destroy(i_fcolor *cl) { myfree(cl); } /* =item i_img_exorcise(im) Free image data. im - Image pointer =cut */ void i_img_exorcise(i_img *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); if (im->idata != NULL) { myfree(im->idata); } im->idata = NULL; im->xsize = 0; im->ysize = 0; im->channels = 0; im->ext_data=NULL; } /* =item i_img_destroy(C) =order 90 =category Image creation/destruction =synopsis i_img_destroy(img) Destroy an image object =cut */ void i_img_destroy(i_img *im) { dIMCTXim(im); im_log((aIMCTX, 1,"i_img_destroy(im %p)\n",im)); i_img_exorcise(im); if (im) { myfree(im); } im_context_refdec(aIMCTX, "img_destroy"); } /* =item i_img_info(im, info) =category Image Return image information im - Image pointer info - pointer to array to return data info is an array of 4 integers with the following values: info[0] - width info[1] - height info[2] - channels info[3] - channel mask =cut */ void i_img_info(i_img *im, i_img_dim *info) { dIMCTXim(im); im_log((aIMCTX,1,"i_img_info(im %p)\n",im)); if (im != NULL) { 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; } else { info[0] = 0; info[1] = 0; info[2] = 0; info[3] = 0; } } /* =item i_img_setmask(C, C) =category Image Information =synopsis // only channel 0 writable =synopsis i_img_setmask(img, 0x01); Set the image channel mask for C to C. The image channel mask gives some control over which channels can be written to in the image. =cut */ void i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; } /* =item i_img_getmask(C) =category Image Information =synopsis int mask = i_img_getmask(img); Get the image channel mask for C. =cut */ int i_img_getmask(i_img *im) { return im->ch_mask; } /* =item i_img_getchannels(C) =category Image Information =synopsis int channels = i_img_getchannels(img); Get the number of channels in C. =cut */ int i_img_getchannels(i_img *im) { return im->channels; } /* =item i_img_get_width(C) =category Image Information =synopsis i_img_dim width = i_img_get_width(im); Returns the width in pixels of the image. =cut */ i_img_dim i_img_get_width(i_img *im) { return im->xsize; } /* =item i_img_get_height(C) =category Image Information =synopsis i_img_dim height = i_img_get_height(im); Returns the height in pixels of the image. =cut */ i_img_dim i_img_get_height(i_img *im) { 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 may be C. =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, C, C, C, C, C, C, C, C) =category Image (C,C) (C,C) specifies the region to copy (in the source coordinates) (C,C) specifies the upper left corner for the target image. pass NULL in C for non transparent i_colors. =cut */ void i_copyto_trans(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans) { i_color pv; i_img_dim x,y,t,ttx,tty,tt; int ch; dIMCTXim(im); 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)); if (x2channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++; if (tt) i_ppix(im,ttx,tty,&pv); } else i_ppix(im,ttx,tty,&pv); tty++; } ttx++; } } /* =item i_copy(source) =category Image Creates a new image that is a copy of the image C. Tags are not copied, only the image data. Returns: i_img * =cut */ 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); im_log((aIMCTX,1,"i_copy(src %p)\n", 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; pv = mymalloc(sizeof(i_color) * x1); for (y = 0; y < y1; ++y) { i_glin(src, 0, x1, y, pv); i_plin(im, 0, x1, y, pv); } myfree(pv); } else { i_fcolor *pv; pv = mymalloc(sizeof(i_fcolor) * x1); for (y = 0; y < y1; ++y) { i_glinf(src, 0, x1, y, pv); i_plinf(im, 0, x1, y, pv); } myfree(pv); } } else { i_palidx *vals; vals = mymalloc(sizeof(i_palidx) * x1); for (y = 0; y < y1; ++y) { i_gpal(src, 0, x1, y, vals); i_ppal(im, 0, x1, y, vals); } myfree(vals); } return im; } /* http://en.wikipedia.org/wiki/Lanczos_resampling */ static float Lanczos(float x) { float PIx, PIx2; PIx = PI * x; PIx2 = PIx / 2.0; if ((x >= 2.0) || (x <= -2.0)) return (0.0); else if (x == 0.0) return (1.0); else return(sin(PIx) / PIx * sin(PIx2) / PIx2); } /* =item i_scaleaxis(im, value, axis) Returns a new image object which is I scaled by I along wither the x-axis (I == 0) or the y-axis (I == 1). =cut */ i_img* i_scaleaxis(i_img *im, double Value, int Axis) { i_img_dim hsize, vsize, i, j, k, l, lMax, iEnd, jEnd; i_img_dim LanczosWidthFactor; float *l0, *l1; double OldLocation; i_img_dim T; double t; float F, PictureValue[MAXCHANNELS]; short psave; i_color val,val1,val2; 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(); 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); if (hsize < 1) { hsize = 1; Value = 1.0 / im->xsize; } vsize = im->ysize; jEnd = hsize; iEnd = vsize; } else { hsize = im->xsize; vsize = (i_img_dim)(0.5 + im->ysize * Value); if (vsize < 1) { vsize = 1; Value = 1.0 / im->ysize; } jEnd = vsize; iEnd = hsize; } new_img = i_img_8_new(hsize, vsize, im->channels); if (!new_img) { i_push_error(0, "cannot create output image"); return NULL; } /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */ LanczosWidthFactor = (Value >= 1) ? 1 : (i_img_dim) (1.4/Value); lMax = LanczosWidthFactor << 1; l0 = mymalloc(lMax * sizeof(float)); l1 = mymalloc(lMax * sizeof(float)); for (j=0; jchannels; k++) PictureValue[k] = 0.0; for (l=0; l= im->xsize) ? im->xsize-1 : Mx; i_gpix(im, Mx, i, &val1); i_gpix(im, mx, i, &val2); if (has_alpha) { i_sample_t alpha1 = val1.channel[color_chans]; i_sample_t alpha2 = val2.channel[color_chans]; for (k=0; k < color_chans; k++) { PictureValue[k] += l1[l] * val1.channel[k] * alpha1 / 255; PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255; } PictureValue[color_chans] += l1[l] * val1.channel[color_chans]; PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans]; } else { for (k=0; kchannels; k++) { PictureValue[k] += l1[l] * val1.channel[k]; PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; } } } if (has_alpha) { float fa = PictureValue[color_chans] / LanczosWidthFactor; int alpha = minmax(0, 255, fa+0.5); if (alpha) { for (k = 0; k < color_chans; ++k) { psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa)); val.channel[k]=minmax(0,255,psave); } val.channel[color_chans] = alpha; } else { /* zero alpha, so the pixel has no color */ for (k = 0; k < im->channels; ++k) val.channel[k] = 0; } } else { for(k=0;kchannels;k++) { psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor)); val.channel[k]=minmax(0,255,psave); } } i_ppix(new_img, j, i, &val); } } else { for (i=0; ichannels; k++) PictureValue[k] = 0.0; for (l=0; l < lMax; l++) { i_img_dim mx = T-lMax+l+1; i_img_dim 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); if (has_alpha) { i_sample_t alpha1 = val1.channel[color_chans]; i_sample_t alpha2 = val2.channel[color_chans]; for (k=0; k < color_chans; k++) { PictureValue[k] += l1[l] * val1.channel[k] * alpha1 / 255; PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255; } PictureValue[color_chans] += l1[l] * val1.channel[color_chans]; PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans]; } else { for (k=0; kchannels; k++) { PictureValue[k] += l1[l] * val1.channel[k]; PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; } } } if (has_alpha) { float fa = PictureValue[color_chans] / LanczosWidthFactor; int alpha = minmax(0, 255, fa+0.5); if (alpha) { for (k = 0; k < color_chans; ++k) { psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa)); val.channel[k]=minmax(0,255,psave); } val.channel[color_chans] = alpha; } else { for (k = 0; k < im->channels; ++k) val.channel[k] = 0; } } else { for(k=0;kchannels;k++) { psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor)); val.channel[k]=minmax(0,255,psave); } } i_ppix(new_img, i, j, &val); } } } myfree(l0); myfree(l1); im_log((aIMCTX, 1,"(%p) <- i_scaleaxis\n", new_img)); return new_img; } /* =item i_scale_nn(im, scx, scy) Scale by using nearest neighbor Both axes scaled at the same time since nothing is gained by doing it in two steps =cut */ i_img* i_scale_nn(i_img *im, double scx, double scy) { i_img_dim nxsize,nysize,nx,ny; i_img *new_img; i_color val; dIMCTXim(im); 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) { nxsize = 1; scx = 1.0 / im->xsize; } nysize = (i_img_dim) ((double) im->ysize * scy); if (nysize < 1) { nysize = 1; scy = 1.0 / im->ysize; } im_assert(scx != 0 && scy != 0); new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels); for(ny=0;ny, C, C) =category Image creation/destruction =synopsis i_img *img = i_sametype(src, width, height); Returns an image of the same type (sample size, channels, paletted/direct). For paletted images the palette is copied from the source. =cut */ 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); } 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; } } else { i_color col; int i; i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src)); for (i = 0; i < i_colorcount(src); ++i) { i_getcolors(src, i, &col, 1); i_addcolors(targ, &col, 1); } return targ; } } /* =item i_sametype_chans(C, C, C, C) =category Image creation/destruction =synopsis i_img *img = i_sametype_chans(src, width, height, channels); 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, 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); } 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) Spatially transforms I returning a new image. opx for a length of opxl and opy for a length of opy are arrays of operators that modify the x and y positions to retreive the pixel data from. parm and parmlen define extra parameters that the operators may use. Note that this function is largely superseded by the more flexible L. Returns the new image. The operators for this function are defined in L. =cut */ i_img* i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) { double rx,ry; i_img_dim nxsize,nysize,nx,ny; i_img *new_img; i_color val; dIMCTXim(im); 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 ; new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels); /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */ for(ny=0;ny",nx,ny); */ 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); } im_log((aIMCTX, 1,"(%p) <- i_transform\n",new_img)); return new_img; } /* =item i_img_diff(im1, im2) Calculates the sum of the squares of the differences between correspoding channels in two images. If the images are not the same size then only the common area is compared, hence even if images are different sizes this function can return zero. =cut */ float i_img_diff(i_img *im1,i_img *im2) { i_img_dim x, y, xb, yb; int ch, chb; float tdiff; i_color val1,val2; dIMCTXim(im1); im_log((aIMCTX, 1,"i_img_diff(im1 %p,im2 %p)\n",im1,im2)); xb=(im1->xsizexsize)?im1->xsize:im2->xsize; yb=(im1->ysizeysize)?im1->ysize:im2->ysize; chb=(im1->channelschannels)?im1->channels:im2->channels; im_log((aIMCTX, 1,"i_img_diff: b=(" i_DFp ") chb=%d\n", i_DFcp(xb,yb), chb)); tdiff=0; for(y=0;yxsizexsize)?im1->xsize:im2->xsize; yb=(im1->ysizeysize)?im1->ysize:im2->ysize; chb=(im1->channelschannels)?im1->channels:im2->channels; im_log((aIMCTX, 1,"i_img_diffd: b(" i_DFp ") chb=%d\n", i_DFcp(xb, yb), chb)); tdiff=0; for(y=0;yxsizexsize)?im1->xsize:im2->xsize; yb=(im1->ysizeysize)?im1->ysize:im2->ysize; chb=(im1->channelschannels)?im1->channels:im2->channels; 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(x = 0; x < xb; x++) { i_gpixf(im1, x, y, &val1); i_gpixf(im2, x, y, &val2); for(ch = 0; ch < chb; ch++) { double sdiff = val1.channel[ch] - val2.channel[ch]; if (fabs(sdiff) > epsilon) { im_log((aIMCTX, 1,"i_img_samef <- different %g @(" i_DFp ")\n", sdiff, i_DFcp(x, y))); return 0; } } } } im_log((aIMCTX, 1,"i_img_samef <- same\n")); return 1; } /* just a tiny demo of haar wavelets */ i_img* i_haar(i_img *im) { i_img_dim mx,my; i_img_dim fx,fy; i_img_dim x,y; int ch; i_img *new_img,*new_img2; i_color val1,val2,dval1,dval2; dIMCTXim(im); mx=im->xsize; my=im->ysize; fx=(mx+1)/2; fy=(my+1)/2; /* horizontal pass */ 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); for(y=0;ychannels;ch++) { dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2; dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2; } i_ppix(new_img,x,y,&dval1); i_ppix(new_img,x+fx,y,&dval2); } for(y=0;ychannels;ch++) { dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2; dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2; } i_ppix(new_img2,x,y,&dval1); i_ppix(new_img2,x,y+fy,&dval2); } i_img_destroy(new_img); return new_img2; } /* =item i_count_colors(im, maxc) returns number of colors or -1 to indicate that it was more than max colors =cut */ /* This function has been changed and is now faster. It's using * i_gsamp instead of i_gpix */ int i_count_colors(i_img *im,int maxc) { struct octt *ct; i_img_dim x,y; int colorcnt; int channels[3]; int *samp_chans; i_sample_t * samp; i_img_dim xsize = im->xsize; i_img_dim ysize = im->ysize; int samp_cnt = 3 * xsize; if (im->channels >= 3) { samp_chans = NULL; } else { channels[0] = channels[1] = channels[2] = 0; samp_chans = channels; } ct = octt_new(); samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t)); colorcnt = 0; for(y = 0; y < ysize; ) { i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3); for(x = 0; x < samp_cnt; ) { colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]); x += 3; if (colorcnt > maxc) { octt_delete(ct); return -1; } } } myfree(samp); octt_delete(ct); return colorcnt; } /* sorts the array ra[0..n-1] into increasing order using heapsort algorithm * (adapted from the Numerical Recipes) */ /* Needed by get_anonymous_color_histo */ static void hpsort(unsigned int n, unsigned *ra) { unsigned int i, ir, j, l, rra; if (n < 2) return; l = n >> 1; ir = n - 1; for(;;) { if (l > 0) { rra = ra[--l]; } else { rra = ra[ir]; ra[ir] = ra[0]; if (--ir == 0) { ra[0] = rra; break; } } i = l; j = 2 * l + 1; while (j <= ir) { if (j < ir && ra[j] < ra[j+1]) j++; if (rra < ra[j]) { ra[i] = ra[j]; i = j; j++; j <<= 1; j--; } else break; } ra[i] = rra; } } /* This function constructs an ordered list which represents how much the * different colors are used. So for instance (100, 100, 500) means that one * color is used for 500 pixels, another for 100 pixels and another for 100 * pixels. It's tuned for performance. You might not like the way I've hardcoded * the maxc ;-) and you might want to change the name... */ /* Uses octt_histo */ int i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) { struct octt *ct; i_img_dim x,y; int colorcnt; unsigned int *col_usage_it; i_sample_t * samp; int channels[3]; int *samp_chans; i_img_dim xsize = im->xsize; i_img_dim ysize = im->ysize; int samp_cnt = 3 * xsize; ct = octt_new(); samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t)); if (im->channels >= 3) { samp_chans = NULL; } else { channels[0] = channels[1] = channels[2] = 0; samp_chans = channels; } colorcnt = 0; for(y = 0; y < ysize; ) { i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3); for(x = 0; x < samp_cnt; ) { colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]); x += 3; if (colorcnt > maxc) { octt_delete(ct); return -1; } } } myfree(samp); /* Now that we know the number of colours... */ col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * sizeof(unsigned int)); octt_histo(ct, &col_usage_it); hpsort(colorcnt, *col_usage); octt_delete(ct); return colorcnt; } /* =back =head2 Image method wrappers These functions provide i_fsample_t functions in terms of their i_sample_t versions. =over =item i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) =cut */ int i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) { i_color temp; int ch; for (ch = 0; ch < im->channels; ++ch) temp.channel[ch] = SampleFTo8(pix->channel[ch]); return i_ppix(im, x, y, &temp); } /* =item i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) =cut */ int i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) { i_color temp; int ch; if (i_gpix(im, x, y, &temp) == 0) { for (ch = 0; ch < im->channels; ++ch) pix->channel[ch] = Sample8ToF(temp.channel[ch]); return 0; } else return -1; } /* =item i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix) =cut */ i_img_dim i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *pix) { i_color *work; if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; if (r > l) { i_img_dim ret; i_img_dim i; int ch; work = mymalloc(sizeof(i_color) * (r-l)); for (i = 0; i < r-l; ++i) { for (ch = 0; ch < im->channels; ++ch) work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]); } ret = i_plin(im, l, r, y, work); myfree(work); return ret; } else { return 0; } } else { return 0; } } /* =item i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix) =cut */ i_img_dim i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix) { i_color *work; if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; if (r > l) { i_img_dim ret; i_img_dim i; int ch; work = mymalloc(sizeof(i_color) * (r-l)); ret = i_plin(im, l, r, y, work); for (i = 0; i < r-l; ++i) { for (ch = 0; ch < im->channels; ++ch) pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]); } myfree(work); return ret; } else { return 0; } } else { return 0; } } /* =item i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, int *chans, int chan_count) =cut */ i_img_dim i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, int const *chans, int chan_count) { i_sample_t *work; if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; if (r > l) { i_img_dim ret; i_img_dim i; work = mymalloc(sizeof(i_sample_t) * (r-l)); ret = i_gsamp(im, l, r, y, work, chans, chan_count); for (i = 0; i < ret; ++i) { samp[i] = Sample8ToF(work[i]); } myfree(work); return ret; } else { return 0; } } else { return 0; } } /* =back =head2 Palette wrapper functions Used for virtual images, these forward palette calls to a wrapped image, assuming the wrapped image is the first pointer in the structure that im->ext_data points at. =over =item i_addcolors_forward(i_img *im, const i_color *colors, int count) =cut */ 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_getcolors_forward(i_img *im, int i, i_color *color, int count) =cut */ int i_getcolors_forward(i_img *im, int i, i_color *color, int count) { return i_getcolors(*(i_img **)im->ext_data, i, color, 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, const i_color *color, int count) { return i_setcolors(*(i_img **)im->ext_data, i, color, count); } /* =item i_colorcount_forward(i_img *im) =cut */ int i_colorcount_forward(i_img *im) { return i_colorcount(*(i_img **)im->ext_data); } /* =item i_maxcolors_forward(i_img *im) =cut */ int i_maxcolors_forward(i_img *im) { return i_maxcolors(*(i_img **)im->ext_data); } /* =item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) =cut */ int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) { return i_findcolor(*(i_img **)im->ext_data, color, entry); } /* =back =head2 Fallback handler =over =item i_gsamp_bits_fb =cut */ 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; } if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { double scale; int ch; i_img_dim count, i, w; if (bits == 32) scale = 4294967295.0; else scale = (double)(1 << bits) - 1; if (r > im->xsize) r = im->xsize; w = r - l; count = 0; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } } for (i = 0; i < w; ++i) { i_fcolor c; i_gpixf(im, l+i, y, &c); for (ch = 0; ch < chan_count; ++ch) { *samps++ = (unsigned)(c.channel[ch] * scale + 0.5); ++count; } } } else { if (chan_count <= 0 || chan_count > im->channels) { i_push_error(0, "Invalid channel count"); return -1; } for (i = 0; i < w; ++i) { i_fcolor c; i_gpixf(im, l+i, y, &c); for (ch = 0; ch < chan_count; ++ch) { *samps++ = (unsigned)(c.channel[ch] * scale + 0.5); ++count; } } } return count; } else { i_push_error(0, "Image position outside of image"); 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) { 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", "sgi"), FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"), FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"), FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"), 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"), /* WEBP http://code.google.com/speed/webp/docs/riff_container.html */ FORMAT_ENTRY2("RIFF WEBP", "webp", "xxxx xxxx"), /* JPEG 2000 This might match a little loosely */ FORMAT_ENTRY("\x00\x00\x00\x0CjP \x0D\x0A\x87\x0A", "jp2"), }; 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; rc = i_io_peekn(data, head, 18); if (rc == -1) return NULL; #if 0 { int i; fprintf(stderr, "%d bytes -", (int)rc); for (i = 0; i < rc; ++i) fprintf(stderr, " %02x", head[i]); fprintf(stderr, "\n"); } #endif for(i=0; iname; } if ((rc == 18) && tga_header_verify(head)) return "tga"; for(i=0; iname; } return NULL; } /* =item i_img_is_monochrome(img, &zero_is_white) =category Image Information 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. C for C. For performance of encoders we require monochrome images: =over =item * be paletted =item * have a palette of two colors, containing only C<(0,0,0)> and C<(255,255,255)> in either order. =back C is set to non-zero if 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 = 1; 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 = 0; return 1; } } else if (im->channels == 1) { if (colors[0].channel[0] == 255 && colors[1].channel[0] == 0) { *zero_is_white = 1; return 1; } else if (colors[0].channel[0] == 0 && colors[1].channel[0] == 255) { *zero_is_white = 0; return 1; } } } *zero_is_white = 0; return 0; } /* =item i_get_file_background(im, &bg) =category Files Retrieve the file write background color tag from the image. If not present, C is set to black. Returns 1 if the C tag was found and valid. =cut */ int i_get_file_background(i_img *im, i_color *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; } /* =item i_get_file_backgroundf(im, &bg) =category Files Retrieve the file write background color tag from the image as a floating point color. Implemented in terms of i_get_file_background(). If not present, C is set to black. Returns 1 if the C tag was found and valid. =cut */ int i_get_file_backgroundf(i_img *im, i_fcolor *fbg) { i_color 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; } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson Tony Cook =head1 SEE ALSO L, L =cut */ libimager-perl-1.004+dfsg.orig/log.c0000644000175000017500000000704312263740601016513 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imageri.h" #include "imconfig.h" #include "log.h" #include #include #include "imerror.h" #ifdef IMAGER_LOG #define DTBUFF 50 #define DATABUFF DTBUFF+3+10+1+5+1+1 #define LOG_DATE_FORMAT "%Y/%m/%d %H:%M:%S" static i_mutex_t log_mutex; static void im_vloog(pIMCTX, int level, const char *fmt, va_list ap); /* * Logging is active */ int im_init_log(pIMCTX, const char* name,int level) { i_clear_error(); if (!log_mutex) { log_mutex = i_mutex_new(); } if (aIMCTX->lg_file) { if (aIMCTX->own_log) fclose(aIMCTX->lg_file); aIMCTX->lg_file = NULL; } aIMCTX->log_level = level; if (level < 0) { aIMCTX->lg_file = NULL; } else { if (name == NULL) { aIMCTX->lg_file = stderr; aIMCTX->own_log = 0; } else { if (NULL == (aIMCTX->lg_file = fopen(name, "w+")) ) { im_push_errorf(aIMCTX, errno, "Cannot open file '%s': (%d)", name, errno); return 0; } aIMCTX->own_log = 1; setvbuf(aIMCTX->lg_file, NULL, _IONBF, BUFSIZ); } } if (aIMCTX->lg_file) { im_log((aIMCTX, 0,"Imager - log started (level = %d)\n", level)); } return aIMCTX->lg_file != NULL; } void i_fatal(int exitcode,const char *fmt, ... ) { va_list ap; dIMCTX; if (aIMCTX->lg_file != NULL) { va_start(ap,fmt); im_vloog(aIMCTX, 0, fmt, ap); va_end(ap); } exit(exitcode); } void im_fatal(pIMCTX, int exitcode,const char *fmt, ... ) { va_list ap; if (aIMCTX->lg_file != NULL) { va_start(ap,fmt); im_vloog(aIMCTX, 0, fmt, ap); va_end(ap); } exit(exitcode); } /* =item i_loog(level, format, ...) =category Logging This is an internal function called by the mm_log() macro. =cut */ static void im_vloog(pIMCTX, int level, const char *fmt, va_list ap) { time_t timi; struct tm *str_tm; char date_buffer[DTBUFF]; if (!aIMCTX->lg_file || level > aIMCTX->log_level) return; i_mutex_lock(log_mutex); timi = time(NULL); str_tm = localtime(&timi); strftime(date_buffer, DTBUFF, LOG_DATE_FORMAT, str_tm); fprintf(aIMCTX->lg_file, "[%s] %10s:%-5d %3d: ", date_buffer, aIMCTX->filename, aIMCTX->line, level); vfprintf(aIMCTX->lg_file, fmt, ap); fflush(aIMCTX->lg_file); i_mutex_unlock(log_mutex); } void i_loog(int level,const char *fmt, ... ) { dIMCTX; va_list ap; if (!aIMCTX->lg_file || level > aIMCTX->log_level) return; va_start(ap,fmt); im_vloog(aIMCTX, level, fmt, ap); va_end(ap); } void im_loog(pIMCTX, int level,const char *fmt, ... ) { va_list ap; if (!aIMCTX->lg_file || level > aIMCTX->log_level) return; va_start(ap,fmt); im_vloog(aIMCTX, level, fmt, ap); va_end(ap); } /* =item i_lhead(file, line) =category Logging This is an internal function called by the mm_log() macro. =cut */ void im_lhead(pIMCTX, const char *file, int line) { if (aIMCTX->lg_file != NULL) { aIMCTX->filename = file; aIMCTX->line = line; } } void i_lhead(const char *file, int line) { dIMCTX; im_lhead(aIMCTX, file, line); } #else /* * Logging is inactive - insert dummy functions */ int im_init_log(pIMCTX, const char* name,int onoff) { i_clear_error(); i_push_error(0, "Logging disabled"); return 0; } void i_fatal(int exitcode,const char *fmt, ... ) { exit(exitcode); } void im_fatal(pIMCTX, int exitcode,const char *fmt, ... ) { exit(exitcode); } void i_loog(int level,const char *fmt, ... ) { } void im_loog(pIMCTX, int level,const char *fmt, ... ) { } void i_lhead(const char *file, int line) { } void im_lhead(pIMCTX, const char *file, int line) { } #endif libimager-perl-1.004+dfsg.orig/feat.c0000644000175000017500000000036612263740600016651 0ustar gregoagregoa#include "feat.h" /* only for use as a placeholder in the old dynamic module code */ undef_int i_has_format(char *frmt) { int rc,i; rc=0; i=0; while(i_format_list[i] != NULL) if ( !strcmp(frmt,i_format_list[i++]) ) rc=1; return(rc); } libimager-perl-1.004+dfsg.orig/imexttypes.h0000644000175000017500000003564112507371373020166 0ustar gregoagregoa#ifndef IMAGER_IMEXTTYPES_H_ #define IMAGER_IMEXTTYPES_H_ /* keep this file simple - apidocs.perl parses it. */ #include "imdatatypes.h" #include /* IMAGER_API_VERSION is similar to the version number in the third and fourth bytes of TIFF files - if it ever changes then the API has changed too much for any application to remain compatible. Version 2 changed the types of some parameters and pointers. A simple recompile should be enough in most cases. Version 3 changed the behaviour of some of the I/O layer functions, and in some cases the initial seek position when calling file readers. Switching away from calling readcb etc to i_io_read() etc should fix your code. Version 4 added i_psamp() and i_psampf() pointers to the i_img structure. Version 5 changed the return types of i_get_file_background() and i_get_file_backgroundf() from void to int. */ #define IMAGER_API_VERSION 5 /* IMAGER_API_LEVEL is the level of the structure. New function pointers will always remain at the end (unless IMAGER_API_VERSION changes), and will result in an increment of IMAGER_API_LEVEL. */ #define IMAGER_API_LEVEL 9 typedef struct { int version; int level; /* IMAGER_API_LEVEL 1 functions */ void * (*f_mymalloc)(size_t size); void (*f_myfree)(void *block); void * (*f_myrealloc)(void *block, size_t newsize); void* (*f_mymalloc_file_line)(size_t size, char* file, int line); void (*f_myfree_file_line)(void *p, char*file, int line); void* (*f_myrealloc_file_line)(void *p, size_t newsize, char* file,int line); i_img *(*f_i_img_8_new)(i_img_dim xsize, i_img_dim ysize, int channels); /* SKIP */ i_img *(*f_i_img_16_new)(i_img_dim xsize, i_img_dim ysize, int channels); /* SKIP */ i_img *(*f_i_img_double_new)(i_img_dim xsize, i_img_dim ysize, int channels); /* SKIP */ i_img *(*f_i_img_pal_new)(i_img_dim xsize, i_img_dim ysize, int channels, int maxpal); /* SKIP */ void (*f_i_img_destroy)(i_img *im); i_img *(*f_i_sametype)(i_img *im, i_img_dim xsize, i_img_dim ysize); i_img *(*f_i_sametype_chans)(i_img *im, i_img_dim xsize, i_img_dim ysize, int channels); void (*f_i_img_info)(i_img *im, i_img_dim *info); int (*f_i_ppix)(i_img *im, i_img_dim x, i_img_dim y, const i_color *val); int (*f_i_gpix)(i_img *im, i_img_dim x, i_img_dim y, i_color *val); int (*f_i_ppixf)(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val); int (*f_i_gpixf)(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val); i_img_dim (*f_i_plin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals); i_img_dim (*f_i_glin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals); i_img_dim (*f_i_plinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals); i_img_dim (*f_i_glinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals); i_img_dim (*f_i_gsamp)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp, const int *chans, int chan_count); i_img_dim (*f_i_gsampf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, const int *chans, int chan_count); i_img_dim (*f_i_gpal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals); i_img_dim (*f_i_ppal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals); int (*f_i_addcolors)(i_img *im, const i_color *colors, int count); int (*f_i_getcolors)(i_img *im, int i, i_color *, int count); int (*f_i_colorcount)(i_img *im); int (*f_i_maxcolors)(i_img *im); int (*f_i_findcolor)(i_img *im, const i_color *color, i_palidx *entry); int (*f_i_setcolors)(i_img *im, int index, const i_color *colors, int count); i_fill_t *(*f_i_new_fill_solid)(const i_color *c, int combine); i_fill_t *(*f_i_new_fill_solidf)(const i_fcolor *c, int combine); i_fill_t *(*f_i_new_fill_hatch)(const i_color *fg, const i_color *bg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy); i_fill_t *(*f_i_new_fill_hatchf)(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy); i_fill_t *(*f_i_new_fill_image)(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine); i_fill_t *(*f_i_new_fill_fount)(double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, int combine, int super_sample, double ssample_param, int count, i_fountain_seg *segs); void (*f_i_fill_destroy)(i_fill_t *fill); void (*f_i_quant_makemap)(i_quantize *quant, i_img **imgs, int count); i_palidx * (*f_i_quant_translate)(i_quantize *quant, i_img *img); void (*f_i_quant_transparent)(i_quantize *quant, i_palidx *indices, i_img *img, i_palidx trans_index); void (*f_i_clear_error)(void); /* SKIP */ void (*f_i_push_error)(int code, char const *msg); /* SKIP */ void (*f_i_push_errorf)(int code, char const *fmt, ...) I_FORMAT_ATTR(2,3); void (*f_i_push_errorvf)(int code, char const *fmt, va_list); /* SKIP */ void (*f_i_tags_new)(i_img_tags *tags); int (*f_i_tags_set)(i_img_tags *tags, char const *name, char const *data, int size); int (*f_i_tags_setn)(i_img_tags *tags, char const *name, int idata); void (*f_i_tags_destroy)(i_img_tags *tags); int (*f_i_tags_find)(i_img_tags *tags, char const *name, int start, int *entry); int (*f_i_tags_findn)(i_img_tags *tags, int code, int start, int *entry); int (*f_i_tags_delete)(i_img_tags *tags, int entry); int (*f_i_tags_delbyname)(i_img_tags *tags, char const *name); int (*f_i_tags_delbycode)(i_img_tags *tags, int code); int (*f_i_tags_get_float)(i_img_tags *tags, char const *name, int code, double *value); int (*f_i_tags_set_float)(i_img_tags *tags, char const *name, int code, double value); int (*f_i_tags_set_float2)(i_img_tags *tags, char const *name, int code, double value, int places); int (*f_i_tags_get_int)(i_img_tags *tags, char const *name, int code, int *value); int (*f_i_tags_get_string)(i_img_tags *tags, char const *name, int code, char *value, size_t value_size); int (*f_i_tags_get_color)(i_img_tags *tags, char const *name, int code, i_color *value); int (*f_i_tags_set_color)(i_img_tags *tags, char const *name, int code, i_color const *value); void (*f_i_box)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val); void (*f_i_box_filled)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val); void (*f_i_box_cfill)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_fill_t *fill); void (*f_i_line)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp); void (*f_i_line_aa)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp); void (*f_i_arc)(i_img *im, i_img_dim x, i_img_dim y, double rad, double d1, double d2, const i_color *val); void (*f_i_arc_aa)(i_img *im, double x, double y, double rad, double d1, double d2, const i_color *val); void (*f_i_arc_cfill)(i_img *im, i_img_dim x, i_img_dim y, double rad, double d1, double d2, i_fill_t *val); void (*f_i_arc_aa_cfill)(i_img *im, double x, double y, double rad, double d1, double d2, i_fill_t *fill); void (*f_i_circle_aa)(i_img *im, double x, double y, double rad, const i_color *val); int (*f_i_flood_fill)(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol); int (*f_i_flood_cfill)(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill); void (*f_i_copyto)(i_img *im, i_img *src, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_img_dim tx, i_img_dim ty); void (*f_i_copyto_trans)(i_img *im, i_img *src, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_img_dim tx, i_img_dim ty, const i_color *trans); i_img *(*f_i_copy)(i_img *im); int (*f_i_rubthru)(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy); /* IMAGER_API_LEVEL 2 functions */ int (*f_i_set_image_file_limits)(i_img_dim width, i_img_dim height, size_t bytes); /* SKIP */ int (*f_i_get_image_file_limits)(i_img_dim *width, i_img_dim *height, size_t *bytes); /* SKIP */ int (*f_i_int_check_image_file_limits)(i_img_dim width, i_img_dim height, int channels, size_t sample_size); /* SKIP */ int (*f_i_flood_fill_border)(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol, const i_color *border); int (*f_i_flood_cfill_border)(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill, const i_color *border); /* IMAGER_API_LEVEL 3 functions */ void (*f_i_img_setmask)(i_img *im, int ch_mask); int (*f_i_img_getmask)(i_img *im); int (*f_i_img_getchannels)(i_img *im); i_img_dim (*f_i_img_get_width)(i_img *im); i_img_dim (*f_i_img_get_height)(i_img *im); void (*f_i_lhead)(const char *file, int line_number); void (*f_i_loog)(int level, const char *msg, ...) I_FORMAT_ATTR(2,3); /* IMAGER_API_LEVEL 4 functions will be added here */ i_img *(*f_i_img_alloc)(void); /* SKIP */ void (*f_i_img_init)(i_img *); /* SKIP */ /* IMAGER_API_LEVEL 5 functions will be added here */ /* added i_psampf?_bits macros */ int (*f_i_img_is_monochrome)(i_img *, int *zero_is_white); int (*f_i_gsamp_bg)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samples, int out_channels, i_color const * bg); int (*f_i_gsampf_bg)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samples, int out_channels, i_fcolor const * bg); int (*f_i_get_file_background)(i_img *im, i_color *bg); int (*f_i_get_file_backgroundf)(i_img *im, i_fcolor *bg); unsigned long (*f_i_utf8_advance)(char const **p, size_t *len); i_render *(*f_i_render_new)(i_img *im, i_img_dim width); void (*f_i_render_delete)(i_render *r); void (*f_i_render_color)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color); void (*f_i_render_fill)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_fill_t *fill); void (*f_i_render_line)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, const i_sample_t *src, i_color *line, i_fill_combine_f combine); void (*f_i_render_linef)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, const double *src, i_fcolor *line, i_fill_combinef_f combine); /* Level 6 lost to mis-numbering */ /* IMAGER_API_LEVEL 7 */ int (*f_i_io_getc_imp)(io_glue *ig); int (*f_i_io_peekc_imp)(io_glue *ig); ssize_t (*f_i_io_peekn)(io_glue *ig, void *buf, size_t size); int (*f_i_io_putc_imp)(io_glue *ig, int c); ssize_t (*f_i_io_read)(io_glue *, void *buf, size_t size); ssize_t (*f_i_io_write)(io_glue *, const void *buf, size_t size); off_t (*f_i_io_seek)(io_glue *, off_t offset, int whence); int (*f_i_io_flush)(io_glue *ig); int (*f_i_io_close)(io_glue *ig); int (*f_i_io_set_buffered)(io_glue *ig, int buffered); ssize_t (*f_i_io_gets)(io_glue *ig, char *, size_t, int); i_io_glue_t *(*f_io_new_fd)(int fd); /* SKIP */ i_io_glue_t *(*f_io_new_bufchain)(void); /* SKIP */ i_io_glue_t *(*f_io_new_buffer)(const char *data, size_t len, i_io_closebufp_t closecb, void *closedata); /* SKIP */ i_io_glue_t *(*f_io_new_cb)(void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb); /* SKIP */ size_t (*f_io_slurp)(i_io_glue_t *ig, unsigned char **c); void (*f_io_glue_destroy)(i_io_glue_t *ig); /* IMAGER_API_LEVEL 8 */ i_img *(*f_im_img_8_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels); i_img *(*f_im_img_16_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels); i_img *(*f_im_img_double_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels); i_img *(*f_im_img_pal_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels, int maxpal); void (*f_im_clear_error)(im_context_t ctx); void (*f_im_push_error)(im_context_t ctx, int code, char const *msg); void (*f_im_push_errorvf)(im_context_t ctx, int code, char const *fmt, va_list); void (*f_im_push_errorf)(im_context_t , int code, char const *fmt, ...) I_FORMAT_ATTR(3,4); int (*f_im_set_image_file_limits)(im_context_t ctx, i_img_dim width, i_img_dim height, size_t bytes); int (*f_im_get_image_file_limits)(im_context_t ctx, i_img_dim *width, i_img_dim *height, size_t *bytes); int (*f_im_int_check_image_file_limits)(im_context_t ctx, i_img_dim width, i_img_dim height, int channels, size_t sample_size); i_img *(*f_im_img_alloc)(im_context_t ctx); void (*f_im_img_init)(im_context_t ctx, i_img *); i_io_glue_t *(*f_im_io_new_fd)(im_context_t ctx, int fd); i_io_glue_t *(*f_im_io_new_bufchain)(im_context_t ctx); i_io_glue_t *(*f_im_io_new_buffer)(im_context_t ctx, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata); i_io_glue_t *(*f_im_io_new_cb)(im_context_t ctx, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb); im_context_t (*f_im_get_context)(void); void (*f_im_lhead)( im_context_t, const char *file, int line ); void (*f_im_loog)(im_context_t, int level,const char *msg, ... ) I_FORMAT_ATTR(3,4); void (*f_im_context_refinc)(im_context_t, const char *where); void (*f_im_context_refdec)(im_context_t, const char *where); i_errmsg *(*f_im_errors)(im_context_t); i_mutex_t (*f_i_mutex_new)(void); void (*f_i_mutex_destroy)(i_mutex_t m); void (*f_i_mutex_lock)(i_mutex_t m); void (*f_i_mutex_unlock)(i_mutex_t m); im_slot_t (*f_im_context_slot_new)(im_slot_destroy_t); int (*f_im_context_slot_set)(im_context_t, im_slot_t, void *); void *(*f_im_context_slot_get)(im_context_t, im_slot_t); /* IMAGER_API_LEVEL 9 */ int (*f_i_poly_poly_aa)(i_img *im, int count, const i_polygon_t *polys, i_poly_fill_mode_t mode, const i_color *val); int (*f_i_poly_poly_aa_cfill)(i_img *im, int count, const i_polygon_t *polys, i_poly_fill_mode_t mode, i_fill_t *fill); int (*f_i_poly_aa_m)(i_img *im, int l, const double *x, const double *y, i_poly_fill_mode_t mode, const i_color *val); int (*f_i_poly_aa_cfill_m)(i_img *im, int l, const double *x, const double *y, i_poly_fill_mode_t mode, i_fill_t *fill); int (*f_i_img_alpha_channel)(i_img *im, int *channel); i_color_model_t (*f_i_img_color_model)(i_img *im); int (*f_i_img_color_channels)(i_img *im); /* IMAGER_API_LEVEL 10 functions will be added here */ } im_ext_funcs; #define PERL_FUNCTION_TABLE_NAME "Imager::__ext_func_table" #endif libimager-perl-1.004+dfsg.orig/stackmach.h0000644000175000017500000000051012031434615017663 0ustar gregoagregoa#ifndef _STACKMACH_H_ #define _STACKMACH_H_ #include #include enum ByteCodes { bcAdd, bcSubtract, bcMult, bcDiv, bcParm, bcSin, bcCos }; double i_op_run(int codes[], size_t code_size, double parms[], size_t parm_size); /* op_run(fx, sizeof(fx), parms, 2)) */ #endif /* _STACKMACH_H_ */ libimager-perl-1.004+dfsg.orig/apidocs.perl0000644000175000017500000001337112507371373020104 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::Manifest 'maniread'; my $outname = shift || '-'; my @funcs = make_func_list(); my %funcs = map { $_ => 1 } @funcs; # look for files to parse my $mani = maniread; my @files = sort grep /\.(c|im|h)$/, keys %$mani; # scan each file for =item \b my $func; my $start; my %alldocs; my @funcdocs; my %from; my $category; my %funccats; my %cats; my $synopsis = ''; my %funcsyns; my $order; my %order; for my $file (@files) { open SRC, "< $file" or die "Cannot open $file for documentation: $!\n"; while () { if (/^=item (\w+)\b/ && $funcs{$1}) { $func = $1; $start = $.; @funcdocs = $_; } elsif ($func && /^=(cut|head)/) { if ($funcs{$func}) { # only save the API functions $alldocs{$func} = [ @funcdocs ]; $from{$func} = "File $file"; if ($category) { $funccats{$func} = $category; push @{$cats{$category}}, $func; } if ($synopsis) { $funcsyns{$func} = $synopsis; } defined $order or $order = 50; $order{$func} = $order; } undef $func; undef $category; undef $order; $synopsis = ''; } elsif ($func) { if (/^=category (.*)/) { $category = $1; } elsif (/^=synopsis (.*)/) { unless (length $synopsis) { push @funcdocs, "\n"; } $synopsis .= "$1\n"; push @funcdocs, " $1\n"; } elsif (/^=order (.*)$/) { $order = $1; $order =~ /^\d+$/ or die "=order must specify a number for $func in $file\n"; } else { push @funcdocs, $_; } } } $func and die "Documentation for $func not followed by =cut or =head in $file\n"; close SRC; } open OUT, "> $outname" or die "Cannot open $outname: $!"; # I keep this file in git and as part of the dist, make sure newlines # don't mess me up binmode OUT; print OUT <<'EOS'; Do not edit this file, it is generated automatically by apidocs.perl from Imager's source files. Each function description has a comment listing the source file where you can find the documentation. =head1 NAME Imager::APIRef - Imager's C API - reference. =head1 SYNOPSIS i_color color; color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255; double x[] = { ... }; double y[] = { ... }; i_polygon_t poly; poly.count = sizeof(x) / sizeof(*x); poly.x = x; poly.y = y; EOS for my $cat (sort { lc $a cmp lc $b } keys %cats) { print OUT "\n # $cat\n"; my @funcs = @{$cats{$cat}}; my %orig; @orig{@funcs} = 0 .. $#funcs; @funcs = sort { $order{$a} <=> $order{$b} || $orig{$a} <=> $orig{$b} } @funcs; for my $func (grep $funcsyns{$_}, @funcs) { my $syn = $funcsyns{$func}; $syn =~ s/^/ /gm; print OUT $syn; } } print OUT <<'EOS'; =head1 DESCRIPTION EOS my %undoc = %funcs; for my $cat (sort { lc $a cmp lc $b } keys %cats) { print OUT "=head2 $cat\n\n=over\n\n"; my @ordered_funcs = sort { $order{$a} <=> $order{$b} || lc $a cmp lc $b } @{$cats{$cat}}; for my $func (@ordered_funcs) { print OUT @{$alldocs{$func}}, "\n"; print OUT "=for comment\nFrom: $from{$func}\n\n"; delete $undoc{$func}; } print OUT "\n=back\n\n"; } # see if we have an uncategorised section if (grep $alldocs{$_}, keys %undoc) { print OUT "=head2 Uncategorized functions\n\n=over\n\n"; #print join(",", grep !exists $order{$_}, @funcs), "\n"; for my $func (sort { $order{$a} <=> $order{$b} || $a cmp $b } grep $undoc{$_} && $alldocs{$_}, @funcs) { print OUT @{$alldocs{$func}}, "\n"; print OUT "=for comment\nFrom: $from{$func}\n\n"; delete $undoc{$func}; } print OUT "\n\n=back\n\n"; } if (keys %undoc) { print OUT <<'EOS'; =head1 UNDOCUMENTED The following API functions are undocumented so far, hopefully this will change: =over EOS print OUT "=item *\n\nB<$_>\n\n" for sort keys %undoc; print OUT "\n\n=back\n\n"; } print OUT <<'EOS'; =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::API, Imager::ExtUtils, Imager::Inline =cut EOS close OUT; sub make_func_list { my @funcs = qw(i_img i_color i_fcolor i_fill_t mm_log mm_log i_color_model_t im_context_t i_img_dim i_img_dim_u im_slot_t i_polygon_t i_poly_fill_mode_t i_mutex_t i_img_has_alpha i_DF i_DFc i_DFp i_DFcp i_psamp_bits i_gsamp_bits i_psamp i_psampf); open FUNCS, "< imexttypes.h" or die "Cannot open imexttypes.h: $!\n"; my $in_struct; while () { /^typedef struct/ && ++$in_struct; if ($in_struct && !/SKIP/ && /\(\*f_(i[om]?_\w+)/) { my $name = $1; $name =~ s/_imp$//; push @funcs, $name; } if (/^\} im_ext_funcs;$/) { $in_struct or die "Found end of functions structure but not the start"; close FUNCS; return @funcs; } } if ($in_struct) { die "Found start of the functions structure but not the end\n"; } else { die "Found neither the start nor end of the functions structure\n"; } } =head1 NAME apidocs.perl - parse Imager's source for POD documenting the C API =head1 SYNOPSIS perl apidocs.perl lib/Imager/APIRef.pod =head1 DESCRIPTION Parses Imager's C sources, including .c, .h and .im files searching for function documentation. Besides the normal POD markup, the following can be included: =over =item =category I The category the function should be in. =item =synopsis I Sample code using the function to include in the Imager::APIRef SYNOPSIS =item =order I Allows a function to be listed out of order. If this isn't specified it defaults to 50, so a value of 10 will cause the function to be listed at the beginning of its category, or 90 to list at the end. Functions with equal order are otherwise ordered by name. =back =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/typemap.oldperl0000644000175000017500000000163712263740601020633 0ustar gregoagregoa# typemaps for perl before 5.8 # STRLEN isn't in the default typemap in older perls STRLEN T_UV PerlIO * T_INOUT ############################################################################# INPUT # the pre-5.8.0 T_AVREF input map was fixed in 5.8.0 T_AVREF STMT_START { SV *const xsub_tmp_sv = $arg; SvGETMAGIC(xsub_tmp_sv); if (SvROK(xsub_tmp_sv) && SvTYPE(SvRV(xsub_tmp_sv))==SVt_PVAV) $var = (AV*)SvRV(xsub_tmp_sv); else Perl_croak(aTHX_ \"$var is not an array reference\"); } STMT_END # the pre-5.8.0 T_HVREF input map was fixed in 5.8.0 T_HVREF STMT_START { SV *const xsub_tmp_sv = $arg; SvGETMAGIC(xsub_tmp_sv); if (SvROK(xsub_tmp_sv) && SvTYPE(SvRV(xsub_tmp_sv))==SVt_PVHV) $var = (HV*)SvRV(xsub_tmp_sv); else Perl_croak(aTHX_ \"$var is not a hash reference\"); } STMT_END libimager-perl-1.004+dfsg.orig/imio.h0000644000175000017500000000100012031434615016655 0ustar gregoagregoa#ifndef IMAGER_IMIO_H_ #define IMAGER_IMIO_H_ #include #include #include "imconfig.h" #include "log.h" typedef struct i_mempool { void **p; unsigned int alloc; unsigned int used; } i_mempool; void i_mempool_init(i_mempool *mp); void i_mempool_extend(i_mempool *mp); void *i_mempool_alloc(i_mempool *mp, size_t size); void i_mempool_destroy(i_mempool *mp); #ifdef _MSC_VER #undef min #undef max #endif extern unsigned long i_utf8_advance(char const **p, size_t *len); #endif libimager-perl-1.004+dfsg.orig/raw.c0000644000175000017500000001211112263740601016513 0ustar gregoagregoa#include "imager.h" #include #include "iolayer.h" #ifndef _MSC_VER #include #endif #include #include /* Image loader for raw files. This is a barebones raw loader... fd: filedescriptor x: xsize y: ysize datachannels: the number of channels the file contains storechannels: the bitmap of channels we will read intrl: interlace flag, 0 = sample interleaving 1 = line interleaving 2 = image interleaving (not implemented) */ static void interleave(unsigned char *inbuffer,unsigned char *outbuffer,i_img_dim rowsize,int channels) { i_img_dim ind,i; int ch; i=0; if (inbuffer == outbuffer) return; /* Check if data is already in interleaved format */ for (ind=0; ind datachannels ? datachannels : storechannels; if (inbuffer == outbuffer) return; /* Check if data is already in expanded format */ for(x = 0; x < xsize; x++) { for (ch = 0; ch < copy_chans; ch++) outbuffer[x*storechannels+ch] = inbuffer[x*datachannels+ch]; for (; ch < storechannels; ch++) outbuffer[x*storechannels+ch] = 0; } } i_img * i_readraw_wiol(io_glue *ig, i_img_dim x, i_img_dim y, int datachannels, int storechannels, int intrl) { i_img* im; ssize_t rc; i_img_dim k; unsigned char *inbuffer; unsigned char *ilbuffer; unsigned char *exbuffer; size_t inbuflen,ilbuflen,exbuflen; i_clear_error(); mm_log((1, "i_readraw(ig %p,x %" i_DF ",y %" i_DF ",datachannels %d,storechannels %d,intrl %d)\n", ig, i_DFc(x), i_DFc(y), datachannels, storechannels, intrl)); if (intrl != 0 && intrl != 1) { i_push_error(0, "raw_interleave must be 0 or 1"); return NULL; } if (storechannels < 1 || storechannels > 4) { i_push_error(0, "raw_storechannels must be between 1 and 4"); return NULL; } im = i_img_empty_ch(NULL,x,y,storechannels); if (!im) return NULL; inbuflen = im->xsize*datachannels; ilbuflen = inbuflen; exbuflen = im->xsize*storechannels; inbuffer = (unsigned char*)mymalloc(inbuflen); mm_log((1,"inbuflen: %ld, ilbuflen: %ld, exbuflen: %ld.\n", (long)inbuflen, (long)ilbuflen, (long)exbuflen)); if (intrl==0) ilbuffer = inbuffer; else ilbuffer=mymalloc(inbuflen); if (datachannels==storechannels) exbuffer=ilbuffer; else exbuffer= mymalloc(exbuflen); k=0; while( kysize ) { rc = i_io_read(ig, inbuffer, inbuflen); if (rc != inbuflen) { if (rc < 0) i_push_error(0, "error reading file"); else i_push_error(0, "premature end of file"); i_img_destroy(im); myfree(inbuffer); if (intrl != 0) myfree(ilbuffer); if (datachannels != storechannels) myfree(exbuffer); return NULL; } interleave(inbuffer,ilbuffer,im->xsize,datachannels); expandchannels(ilbuffer,exbuffer,im->xsize,datachannels,storechannels); /* FIXME: Do we ever want to save to a virtual image? */ memcpy(&(im->idata[im->xsize*storechannels*k]),exbuffer,exbuflen); k++; } myfree(inbuffer); if (intrl != 0) myfree(ilbuffer); if (datachannels != storechannels) myfree(exbuffer); i_tags_add(&im->tags, "i_format", 0, "raw", -1, 0); return im; } undef_int i_writeraw_wiol(i_img* im, io_glue *ig) { ssize_t rc; i_clear_error(); mm_log((1,"writeraw(im %p,ig %p)\n", im, ig)); if (im == NULL) { mm_log((1,"Image is empty\n")); return(0); } if (!im->virtual) { rc = i_io_write(ig,im->idata,im->bytes); if (rc != im->bytes) { i_push_error(errno, "Could not write to file"); mm_log((1,"i_writeraw: Couldn't write to file\n")); return(0); } } else { if (im->type == i_direct_type) { /* just save it as 8-bits, maybe support saving higher bit count raw images later */ size_t line_size = im->xsize * im->channels; unsigned char *data = mymalloc(line_size); i_img_dim y = 0; rc = line_size; while (rc == line_size && y < im->ysize) { i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels); rc = i_io_write(ig, data, line_size); ++y; } if (rc != line_size) { i_push_error(errno, "write error"); return 0; } myfree(data); } else { /* paletted image - assumes the caller puts the palette somewhere else */ size_t line_size = sizeof(i_palidx) * im->xsize; i_palidx *data = mymalloc(sizeof(i_palidx) * im->xsize); i_img_dim y = 0; rc = line_size; while (rc == line_size && y < im->ysize) { i_gpal(im, 0, im->xsize, y, data); rc = i_io_write(ig, data, line_size); ++y; } myfree(data); if (rc != line_size) { i_push_error(errno, "write error"); return 0; } } } if (i_io_close(ig)) return 0; return(1); } libimager-perl-1.004+dfsg.orig/convert.im0000644000175000017500000001701012263740600017567 0ustar gregoagregoa/* =head1 NAME convert.im - image conversions =head1 SYNOPSIS out = i_convert(srcimage, coeff, outchans, inchans) =head1 DESCRIPTION Converts images from one format to another, typically in this case for converting from RGBA to greyscale and back. =over =cut */ #define IMAGER_NO_CONTEXT #include "imager.h" struct chan_copy { /* channels to copy */ int copy_count; int from[MAXCHANNELS]; int to[MAXCHANNELS]; /* channels to zero */ int zero_count; int zero[MAXCHANNELS]; /* channels to set to maxsample */ int one_count; int one[MAXCHANNELS]; }; static int is_channel_copy(i_img *im, const double *coeff, int outchan, int inchan, struct chan_copy *info); static i_img * convert_via_copy(i_img *im, i_img *src, struct chan_copy *info); /* =item i_convert(src, coeff, outchan, inchan) Converts the image src into another image. coeff contains the co-efficients of an outchan x inchan matrix, for each output pixel: coeff[0], coeff[1] ... im[x,y] = [ coeff[inchan], coeff[inchan+1]... ] * [ src[x,y], 1] ... coeff[inchan*outchan-1] If im has the wrong number of channels or is the wrong size then i_convert() will re-create it. Now handles images with more than 8-bits/sample. =cut */ i_img * i_convert(i_img *src, const double *coeff, int outchan, int inchan) { double work[MAXCHANNELS]; i_img_dim x, y; int i, j; int ilimit; i_img *im = NULL; dIMCTXim(src); im_log((aIMCTX,1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n", im, src, coeff, outchan, inchan)); im_clear_error(aIMCTX); ilimit = inchan; if (ilimit > src->channels) ilimit = src->channels; if (outchan > MAXCHANNELS) { im_push_error(aIMCTX, 0, "cannot have outchan > MAXCHANNELS"); return 0; } if (src->type == i_direct_type) { struct chan_copy info; im = i_sametype_chans(src, src->xsize, src->ysize, outchan); if (is_channel_copy(src, coeff, outchan, inchan, &info)) { return convert_via_copy(im, src, &info); } else { #code src->bits <= i_8_bits IM_COLOR *vals; /* we can always allocate a single scanline of i_color */ vals = mymalloc(sizeof(IM_COLOR) * src->xsize); /* checked 04Jul05 tonyc */ for (y = 0; y < src->ysize; ++y) { IM_GLIN(src, 0, src->xsize, y, vals); for (x = 0; x < src->xsize; ++x) { for (j = 0; j < outchan; ++j) { work[j] = 0; for (i = 0; i < ilimit; ++i) { work[j] += coeff[i+inchan*j] * vals[x].channel[i]; } if (i < inchan) { work[j] += coeff[i+inchan*j] * IM_SAMPLE_MAX; } } for (j = 0; j < outchan; ++j) { if (work[j] < 0) vals[x].channel[j] = 0; else if (work[j] >= IM_SAMPLE_MAX) vals[x].channel[j] = IM_SAMPLE_MAX; else vals[x].channel[j] = work[j]; } } IM_PLIN(im, 0, src->xsize, y, vals); } myfree(vals); #/code } } else { int count; int outcount; int index; i_color *colors; i_palidx *vals; im = im_img_pal_new(aIMCTX, src->xsize, src->ysize, outchan, i_maxcolors(src)); /* just translate the color table */ count = i_colorcount(src); outcount = i_colorcount(im); /* color table allocated for image, so it must fit */ colors = mymalloc(count * sizeof(i_color)); /* check 04Jul05 tonyc */ i_getcolors(src, 0, colors, count); for (index = 0; index < count; ++index) { for (j = 0; j < outchan; ++j) { work[j] = 0; for (i = 0; i < ilimit; ++i) { work[j] += coeff[i+inchan*j] * colors[index].channel[i]; } if (i < inchan) { work[j] += coeff[i+inchan*j] * 255.9; } } for (j = 0; j < outchan; ++j) { if (work[j] < 0) colors[index].channel[j] = 0; else if (work[j] >= 255) colors[index].channel[j] = 255; else colors[index].channel[j] = work[j]; } } if (count < outcount) { i_setcolors(im, 0, colors, count); } else { i_setcolors(im, 0, colors, outcount); i_addcolors(im, colors, count-outcount); } /* and copy the indicies */ /* i_palidx is always unsigned char and will never be bigger than short and since a line of 4-byte i_colors can fit then a line of i_palidx will fit */ vals = mymalloc(sizeof(i_palidx) * im->xsize); /* checked 4jul05 tonyc */ for (y = 0; y < im->ysize; ++y) { i_gpal(src, 0, im->xsize, y, vals); i_ppal(im, 0, im->xsize, y, vals); } myfree(vals); myfree(colors); } return im; } /* =item is_channel_copy(coeff, outchan, inchan, chan_copy_info) Test if the coefficients represent just copying channels around, and initialize lists of the channels to copy, zero or set to max. =cut */ static int is_channel_copy(i_img *im, const double *coeff, int outchan, int inchan, struct chan_copy *info) { int srcchan[MAXCHANNELS]; int onechan[MAXCHANNELS]; int i, j; int ilimit = im->channels > inchan ? inchan : im->channels; for (j = 0; j < outchan; ++j) { srcchan[j] = -1; onechan[j] = 0; } for (j = 0; j < outchan; ++j) { for (i = 0; i < ilimit; ++i) { if (coeff[i+inchan*j] == 1.0) { if (srcchan[j] != -1) { /* from two or more channels, not a copy */ return 0; } srcchan[j] = i; } else if (coeff[i+inchan*j]) { /* some other non-zero value, not a copy */ return 0; } } if (i < inchan) { if (coeff[i+inchan*j] == 1.0) { if (srcchan[j] != -1) { /* can't do both */ return 0; } onechan[j] = 1; } else if (coeff[i+inchan*j]) { /* some other non-zero value, not a copy */ return 0; } } } /* build our working data structures */ info->copy_count = info->zero_count = info->one_count = 0; for (j = 0; j < outchan; ++j) { if (srcchan[j] != -1) { info->from[info->copy_count] = srcchan[j]; info->to[info->copy_count] = j; ++info->copy_count; } else if (onechan[j]) { info->one[info->one_count] = j; ++info->one_count; } else { info->zero[info->zero_count] = j; ++info->zero_count; } } #if 0 { for (i = 0; i < info->copy_count; ++i) { printf("From %d to %d\n", info->from[i], info->to[i]); } for (i = 0; i < info->one_count; ++i) { printf("One %d\n", info->one[i]); } for (i = 0; i < info->zero_count; ++i) { printf("Zero %d\n", info->zero[i]); } fflush(stdout); } #endif return 1; } /* =item convert_via_copy(im, src, chan_copy_info) Perform a convert that only requires channel copies. =cut */ static i_img * convert_via_copy(i_img *im, i_img *src, struct chan_copy *info) { #code src->bits <= i_8_bits IM_COLOR *in_line = mymalloc(sizeof(IM_COLOR) * src->xsize); IM_COLOR *out_line = mymalloc(sizeof(IM_COLOR) * src->xsize); i_img_dim x, y; int i; IM_COLOR *inp, *outp; for (y = 0; y < src->ysize; ++y) { IM_GLIN(src, 0, src->xsize, y, in_line); inp = in_line; outp = out_line; for (x = 0; x < src->xsize; ++x) { for (i = 0; i < info->copy_count; ++i) { outp->channel[info->to[i]] = inp->channel[info->from[i]]; } for (i = 0; i < info->one_count; ++i) { outp->channel[info->one[i]] = IM_SAMPLE_MAX; } for (i = 0; i < info->zero_count; ++i) { outp->channel[info->zero[i]] = 0; } ++inp; ++outp; } IM_PLIN(im, 0, src->xsize, y, out_line); } myfree(in_line); myfree(out_line); #/code return im; } /* =back =head1 SEE ALSO Imager(3) =head1 AUTHOR Tony Cook =cut */ libimager-perl-1.004+dfsg.orig/error.c0000644000175000017500000001747712263740600017076 0ustar gregoagregoa/* =head1 NAME error.c - error reporting code for Imager =head1 SYNOPSIS // user code: int new_fatal; // non-zero if errors are fatal int old_fatal = i_set_failure_fatal(new_fatal); i_set_argv0("name of your program"); extern void error_cb(char const *); i_error_cb old_ecb; old_ecb = i_set_error_cb(error_cb); i_failed_cb old_fcb; extern void failed_cb(char **errors); old_fcb = i_set_failed_cb(failed_cb); if (!i_something(...)) { char **errors = i_errors(); } // imager code: undef_int i_something(...) { i_clear_error(); if (!some_lower_func(...)) { return i_failed("could not something"); } return 1; } undef_int some_lower_func(...) { if (somethingelse_failed()) { i_push_error("could not somethingelse"); return 0; } return 1; } =head1 DESCRIPTION This module provides the C level error handling functionality for Imager. A few functions return or pass in an i_errmsg *, this is list of error structures, terminated by an entry with a NULL msg value, each of which contains a msg and an error code. Even though these aren't passed as i_errmsg const * pointers, don't modify the strings or the pointers. The interface as currently defined isn't thread safe, unfortunately. This code uses Imager's mymalloc() for memory allocation, so out of memory errors are I fatal. =head1 INTERFACE These functions form the interface that a user of Imager sees (from C). The Perl level won't use all of this. =over =cut */ #include "imageri.h" #include #include /* =item im_errors(ctx) =synopsis i_errmsg *errors = im_errors(aIMCTX); =synopsis i_errmsg *errors = i_errors(); Returns a pointer to the first element of an array of error messages, terminated by a NULL pointer. The highest level message is first. Also callable as C. =cut */ i_errmsg *im_errors(im_context_t ctx) { return ctx->error_stack + ctx->error_sp; } /* =back =head1 INTERNAL FUNCTIONS These functions are called by Imager to report errors through the above interface. It may be desirable to have functions to mark the stack and reset to the mark. =over =item im_clear_error(ctx) XX =synopsis im_clear_error(aIMCTX); =synopsis i_clear_error(); =category Error handling Clears the error stack. Called by any Imager function before doing any other processing. Also callable as C. =cut */ void im_clear_error(im_context_t ctx) { #ifdef IMAGER_DEBUG_MALLOC int i; for (i = 0; i < IM_ERROR_COUNT; ++i) { if (ctx->error_space[i]) { myfree(ctx->error_stack[i].msg); ctx->error_stack[i].msg = NULL; ctx->error_space[i] = 0; } } #endif ctx->error_sp = IM_ERROR_COUNT-1; } /* =item im_push_error(ctx, code, message) XX =synopsis i_push_error(0, "Yep, it's broken"); =synopsis i_push_error(errno, "Error writing"); =synopsis im_push_error(aIMCTX, 0, "Something is wrong"); =category Error handling Called by an Imager function to push an error message onto the stack. No message is pushed if the stack is full (since this means someone forgot to call i_clear_error(), or that a function that doesn't do error handling is calling function that does.). =cut */ void im_push_error(im_context_t ctx, int code, char const *msg) { size_t size = strlen(msg)+1; if (ctx->error_sp <= 0) /* bad, bad programmer */ return; --ctx->error_sp; if (ctx->error_alloc[ctx->error_sp] < size) { if (ctx->error_stack[ctx->error_sp].msg) myfree(ctx->error_stack[ctx->error_sp].msg); /* memory allocated on the following line is only ever released when we need a bigger string */ /* size is size (len+1) of an existing string, overflow would mean the system is broken anyway */ ctx->error_stack[ctx->error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */ ctx->error_alloc[ctx->error_sp] = size; } strcpy(ctx->error_stack[ctx->error_sp].msg, msg); ctx->error_stack[ctx->error_sp].code = code; } /* =item im_push_errorvf(ctx, code, format, args) XX =synopsis va_args args; =synopsis va_start(args, lastarg); =synopsis im_push_errorvf(ctx, code, format, args); =category Error handling Intended for use by higher level functions, takes a varargs pointer and a format to produce the finally pushed error message. Does not support perl specific format codes. Also callable as C =cut */ void im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) { char buf[1024]; #if defined(IMAGER_VSNPRINTF) vsnprintf(buf, sizeof(buf), fmt, ap); #elif defined(_MSC_VER) _vsnprintf(buf, sizeof(buf), fmt, ap); #else /* is there a way to detect vsnprintf()? for this and other functions we need some mechanism to handle detection (like perl's Configure, or autoconf) */ vsprintf(buf, fmt, ap); #endif im_push_error(ctx, code, buf); } /* =item i_push_errorf(int code, char const *fmt, ...) =synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno); =category Error handling A version of i_push_error() that does printf() like formatting. Does not support perl specific format codes. =cut */ void i_push_errorf(int code, char const *fmt, ...) { va_list ap; va_start(ap, fmt); i_push_errorvf(code, fmt, ap); va_end(ap); } /* =item im_push_errorf(ctx, code, char const *fmt, ...) =synopsis im_push_errorf(aIMCTX, errno, "Cannot open file %s: %d", filename, errno); =category Error handling A version of im_push_error() that does printf() like formatting. Does not support perl specific format codes. =cut */ void im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) { va_list ap; va_start(ap, fmt); im_push_errorvf(ctx, code, fmt, ap); va_end(ap); } #ifdef IMAGER_I_FAILED #error "This isn't used and is untested" /* =item i_failed(char const *msg) Called by Imager code to indicate that a top-level has failed. msg can be NULL, in which case no error is pushed. Calls the current failed callback, if any. Aborts the program with an error, if failures have been set to be fatal. Returns zero if it does not abort. =cut */ int i_failed(int code, char const *msg) { if (msg) i_push_error(code, msg); if (failed_cb) failed_cb(error_stack + error_sp); if (failures_fatal) { int sp; size_t total; /* total length of error messages */ char *full; /* full message for logging */ if (argv0) fprintf(stderr, "%s: ", argv0); fputs("error:\n", stderr); sp = error_sp; while (error_stack[sp].msg) { fprintf(stderr, " %s\n", error_stack[sp].msg); ++sp; } /* we want to log the error too, build an error message to hand to i_fatal() */ total = 1; /* remember the NUL */ for (sp = error_sp; error_stack[sp].msg; ++sp) { size_t new_total += strlen(error_stack[sp].msg) + 2; if (new_total < total) { /* overflow, somehow */ break; } } full = mymalloc(total); if (!full) { /* just quit, at least it's on stderr */ exit(EXIT_FAILURE); } *full = 0; for (sp = error_sp; error_stack[sp].msg; ++sp) { strcat(full, error_stack[sp].msg); strcat(full, ": "); } /* lose the extra ": " */ full[strlen(full)-2] = '\0'; i_fatal(EXIT_FAILURE, "%s", full); } return 0; } #endif #ifdef IM_ASSERT /* =item im_assert_fail(file, line, message) Called when an im_assert() assertion fails. Only available when Imager is built with assertions. =cut */ void im_assert_fail(char const *file, int line, char const *message) { fprintf(stderr, "Assertion failed line %d file %s: %s\n", line, file, message); abort(); } #endif /* =back =head1 BUGS This interface isn't thread safe. =head1 AUTHOR Tony Cook Stack concept by Arnar Mar Hrafnkelsson =cut */ libimager-perl-1.004+dfsg.orig/palimg.c0000644000175000017500000004365612263740601017215 0ustar gregoagregoa/* =head1 NAME palimg.c - implements paletted images for Imager. =head1 SYNOPSIS =head1 DESCRIPTION Implements paletted images using the new image interface. =over =item IIM_base_8bit_pal Basic 8-bit/sample paletted image =cut */ #define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" #define PALEXT(im) ((i_img_pal_ext*)((im)->ext_data)) static int i_ppix_p(i_img *im, i_img_dim x, i_img_dim y, const i_color *val); static int i_gpix_p(i_img *im, i_img_dim x, i_img_dim y, i_color *val); static i_img_dim i_glin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals); static i_img_dim i_plin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals); static i_img_dim i_gsamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int const *chans, int chan_count); static i_img_dim i_gpal_p(i_img *pm, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals); static i_img_dim i_ppal_p(i_img *pm, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals); static int i_addcolors_p(i_img *im, const i_color *color, int count); static int i_getcolors_p(i_img *im, int i, i_color *color, int count); static int i_colorcount_p(i_img *im); static int i_maxcolors_p(i_img *im); static int i_findcolor_p(i_img *im, const i_color *color, i_palidx *entry); static int i_setcolors_p(i_img *im, int index, const i_color *color, int count); static void i_destroy_p(i_img *im); static i_img_dim i_psamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count); static i_img_dim i_psampf_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count); static i_img IIM_base_8bit_pal = { 0, /* channels set */ 0, 0, 0, /* xsize, ysize, bytes */ ~0U, /* ch_mask */ i_8_bits, /* bits */ i_palette_type, /* type */ 0, /* virtual */ NULL, /* idata */ { 0, 0, NULL }, /* tags */ NULL, /* ext_data */ i_ppix_p, /* i_f_ppix */ i_ppixf_fp, /* i_f_ppixf */ i_plin_p, /* i_f_plin */ i_plinf_fp, /* i_f_plinf */ i_gpix_p, /* i_f_gpix */ i_gpixf_fp, /* i_f_gpixf */ i_glin_p, /* i_f_glin */ i_glinf_fp, /* i_f_glinf */ i_gsamp_p, /* i_f_gsamp */ i_gsampf_fp, /* i_f_gsampf */ i_gpal_p, /* i_f_gpal */ i_ppal_p, /* i_f_ppal */ i_addcolors_p, /* i_f_addcolors */ i_getcolors_p, /* i_f_getcolors */ i_colorcount_p, /* i_f_colorcount */ i_maxcolors_p, /* i_f_maxcolors */ i_findcolor_p, /* i_f_findcolor */ i_setcolors_p, /* i_f_setcolors */ i_destroy_p, /* i_f_destroy */ i_gsamp_bits_fb, NULL, /* i_f_psamp_bits */ i_psamp_p, i_psampf_p }; /* =item im_img_pal_new(ctx, C, C, C, C) XX =category Image creation/destruction =synopsis i_img *img = im_img_pal_new(aIMCTX, width, height, channels, max_palette_size) =synopsis i_img *img = i_img_pal_new(width, height, channels, max_palette_size) Creates a new paletted image of the supplied dimensions. C is the maximum palette size and should normally be 256. Returns a new image or NULL on failure. Also callable as C. =cut */ i_img * im_img_pal_new(pIMCTX, i_img_dim x, i_img_dim y, int channels, int maxpal) { i_img *im; i_img_pal_ext *palext; size_t bytes, line_bytes; i_clear_error(); if (maxpal < 1 || maxpal > 256) { i_push_error(0, "Maximum of 256 palette entries"); return NULL; } if (x < 1 || y < 1) { i_push_error(0, "Image sizes must be positive"); return NULL; } if (channels < 1 || channels > MAXCHANNELS) { im_push_errorf(aIMCTX, 0, "Channels must be positive and <= %d", MAXCHANNELS); return NULL; } bytes = sizeof(i_palidx) * x * y; if (bytes / y / sizeof(i_palidx) != x) { i_push_error(0, "integer overflow calculating image allocation"); return NULL; } /* basic assumption: we can always allocate a buffer representing a line from the image, otherwise we're going to have trouble working with the image */ line_bytes = sizeof(i_color) * x; if (line_bytes / x != sizeof(i_color)) { i_push_error(0, "integer overflow calculating scanline allocation"); return NULL; } im = i_img_alloc(); memcpy(im, &IIM_base_8bit_pal, sizeof(i_img)); palext = mymalloc(sizeof(i_img_pal_ext)); palext->pal = mymalloc(sizeof(i_color) * maxpal); palext->count = 0; palext->alloc = maxpal; palext->last_found = -1; im->ext_data = palext; i_tags_new(&im->tags); im->bytes = bytes; im->idata = mymalloc(im->bytes); im->channels = channels; memset(im->idata, 0, im->bytes); im->xsize = x; im->ysize = y; i_img_init(im); return im; } /* =item i_img_rgb_convert(i_img *targ, i_img *src) Converts paletted data in src to RGB data in targ Internal function. src must be a paletted image and targ must be an RGB image with the same width, height and channels. =cut */ static void i_img_rgb_convert(i_img *targ, i_img *src) { i_color *row = mymalloc(sizeof(i_color) * targ->xsize); i_img_dim y; for (y = 0; y < targ->ysize; ++y) { i_glin(src, 0, src->xsize, y, row); i_plin(targ, 0, src->xsize, y, row); } myfree(row); } /* =item i_img_to_rgb_inplace(im) Converts im from a paletted image to an RGB image. The conversion is done in place. The conversion cannot be done for virtual images. =cut */ int i_img_to_rgb_inplace(i_img *im) { i_img temp; dIMCTXim(im); if (im->virtual) return 0; if (im->type == i_direct_type) return 1; /* trivial success */ i_img_empty_ch(&temp, im->xsize, im->ysize, im->channels); i_img_rgb_convert(&temp, im); /* nasty hack */ (im->i_f_destroy)(im); myfree(im->idata); *im = temp; return 1; } /* =item i_img_to_pal(i_img *im, i_quantize *quant) Converts an RGB image to a paletted image =cut */ i_img *i_img_to_pal(i_img *src, i_quantize *quant) { i_palidx *result; i_img *im; dIMCTXim(src); i_clear_error(); i_quant_makemap(quant, &src, 1); result = i_quant_translate(quant, src); if (result) { im = i_img_pal_new(src->xsize, src->ysize, src->channels, quant->mc_size); /* copy things over */ memcpy(im->idata, result, im->bytes); PALEXT(im)->count = quant->mc_count; memcpy(PALEXT(im)->pal, quant->mc_colors, sizeof(i_color) * quant->mc_count); myfree(result); return im; } else { return NULL; } } /* =item i_img_to_rgb(i_img *src) =cut */ i_img * i_img_to_rgb(i_img *src) { dIMCTXim(src); i_img *im = i_img_empty_ch(NULL, src->xsize, src->ysize, src->channels); i_img_rgb_convert(im, src); return im; } /* =item i_destroy_p(i_img *im) Destroys data related to a paletted image. =cut */ static void i_destroy_p(i_img *im) { if (im) { i_img_pal_ext *palext = im->ext_data; if (palext) { if (palext->pal) myfree(palext->pal); myfree(palext); } } } /* =item i_ppix_p(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) Write to a pixel in the image. Warning: converts the image to a RGB image if the color isn't already present in the image. =cut */ static int i_ppix_p(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) { const i_color *work_val = val; i_color workc; i_palidx which; const unsigned all_mask = ( 1 << im->channels ) - 1; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) return -1; if ((im->ch_mask & all_mask) != all_mask) { unsigned mask = 1; int ch; i_gpix(im, x, y, &workc); for (ch = 0; ch < im->channels; ++ch) { if (im->ch_mask & mask) workc.channel[ch] = val->channel[ch]; mask <<= 1; } work_val = &workc; } if (i_findcolor(im, work_val, &which)) { ((i_palidx *)im->idata)[x + y * im->xsize] = which; return 0; } else { dIMCTXim(im); im_log((aIMCTX, 1, "i_ppix: color(%d,%d,%d) not found, converting to rgb\n", val->channel[0], val->channel[1], val->channel[2])); if (i_img_to_rgb_inplace(im)) { return i_ppix(im, x, y, val); } else return -1; } } /* =item i_gpix_p(i_img *im, i_img_dim x, i_img_dim y, i_color *val) Retrieve a pixel, converting from a palette index to a color. =cut */ static int i_gpix_p(i_img *im, i_img_dim x, i_img_dim y, i_color *val) { i_palidx which; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { return -1; } which = ((i_palidx *)im->idata)[x + y * im->xsize]; if (which > PALEXT(im)->count) return -1; *val = PALEXT(im)->pal[which]; return 0; } /* =item i_glinp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) Retrieve a row of pixels. =cut */ static i_img_dim i_glin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) { if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { int palsize = PALEXT(im)->count; i_color *pal = PALEXT(im)->pal; i_palidx *data; i_img_dim count, i; if (r > im->xsize) r = im->xsize; data = ((i_palidx *)im->idata) + l + y * im->xsize; count = r - l; for (i = 0; i < count; ++i) { i_palidx which = *data++; if (which < palsize) vals[i] = pal[which]; } return count; } else { return 0; } } /* =item i_plin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) Write a line of color data to the image. If any color value is not in the image when the image is converted to RGB. =cut */ static i_img_dim i_plin_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) { i_img_dim count, i; i_palidx *data; i_palidx which; if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) r = im->xsize; data = ((i_palidx *)im->idata) + l + y * im->xsize; count = r - l; for (i = 0; i < count; ++i) { if (i_findcolor(im, vals+i, &which)) { ((i_palidx *)data)[i] = which; } else { if (i_img_to_rgb_inplace(im)) { return i+i_plin(im, l+i, r, y, vals+i); } } } return count; } else { return 0; } } /* =item i_gsamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int chans, int chan_count) =cut */ static i_img_dim i_gsamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps, int const *chans, int chan_count) { int ch; if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { int palsize = PALEXT(im)->count; i_color *pal = PALEXT(im)->pal; i_palidx *data; i_img_dim count, i, w; if (r > im->xsize) r = im->xsize; data = ((i_palidx *)im->idata) + l + y * im->xsize; count = 0; w = r - l; if (chans) { for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); } } for (i = 0; i < w; ++i) { i_palidx which = *data++; if (which < palsize) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = pal[which].channel[chans[ch]]; ++count; } } } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return 0; } for (i = 0; i < w; ++i) { i_palidx which = *data++; if (which < palsize) { for (ch = 0; ch < chan_count; ++ch) { *samps++ = pal[which].channel[ch]; ++count; } } } } return count; } else { return 0; } } /* =item i_gpal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals) =cut */ static i_img_dim i_gpal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_palidx *vals) { if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { i_palidx *data; i_img_dim i, w; if (r > im->xsize) r = im->xsize; data = ((i_palidx *)im->idata) + l + y * im->xsize; w = r - l; for (i = 0; i < w; ++i) { *vals++ = *data++; } return i; } else { return 0; } } /* =item i_ppal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals) =cut */ static i_img_dim i_ppal_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_palidx *vals) { if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { i_palidx *data; i_img_dim i, w; if (r > im->xsize) r = im->xsize; data = ((i_palidx *)im->idata) + l + y * im->xsize; w = r - l; for (i = 0; i < w; ++i) { *data++ = *vals++; } return i; } else { return 0; } } /* =item i_addcolors_p(i_img *im, const i_color *color, int count) =cut */ static int i_addcolors_p(i_img *im, const i_color *color, int count) { if (PALEXT(im)->count + count <= PALEXT(im)->alloc) { int result = PALEXT(im)->count; int index = result; PALEXT(im)->count += count; while (count) { PALEXT(im)->pal[index++] = *color++; --count; } return result; } else return -1; } /* =item i_getcolors_p(i_img *im, int i, i_color *color, int count) =cut */ static int i_getcolors_p(i_img *im, int i, i_color *color, int count) { if (i >= 0 && i+count <= PALEXT(im)->count) { while (count) { *color++ = PALEXT(im)->pal[i++]; --count; } return 1; } else return 0; } static int color_eq(i_img *im, const i_color *c1, const i_color *c2) { int ch; for (ch = 0; ch < im->channels; ++ch) { if (c1->channel[ch] != c2->channel[ch]) return 0; } return 1; } /* =item i_colorcount_p(i_img *im) =cut */ static int i_colorcount_p(i_img *im) { return PALEXT(im)->count; } /* =item i_maxcolors_p(i_img *im) =cut */ static int i_maxcolors_p(i_img *im) { return PALEXT(im)->alloc; } /* =item i_setcolors_p(i_img *im, int index, const i_color *colors, int count) =cut */ static int i_setcolors_p(i_img *im, int index, const i_color *colors, int count) { if (index >= 0 && count >= 1 && index + count <= PALEXT(im)->count) { while (count) { PALEXT(im)->pal[index++] = *colors++; --count; } return 1; } return 0; } /* =item i_findcolor_p(i_img *im) =cut */ static int i_findcolor_p(i_img *im, const i_color *color, i_palidx *entry) { if (PALEXT(im)->count) { int i; /* often the same color comes up several times in a row */ if (PALEXT(im)->last_found >= 0) { if (color_eq(im, color, PALEXT(im)->pal + PALEXT(im)->last_found)) { *entry = PALEXT(im)->last_found; return 1; } } for (i = 0; i < PALEXT(im)->count; ++i) { if (color_eq(im, color, PALEXT(im)->pal + i)) { PALEXT(im)->last_found = *entry = i; return 1; } } } return 0; } /* =item i_psamp_p(im, l, r, y, samps, chans, chan_count) Implement psamp() for paletted images. Since writing samples doesn't really work as a concept for paletted images, this is slow. Also, writing samples may convert the image to a direct image in the process, so use i_ppix/i_gpix instead of directly calling the paletted handlers. =cut */ static i_img_dim i_psamp_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count) { if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { i_img_dim count = 0; int ch; if (r > im->xsize) r = im->xsize; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } } while (l < r) { i_color c; i_gpix(im, l, y, &c); for (ch = 0; ch < chan_count; ++ch) c.channel[chans[ch]] = *samps++; i_ppix(im, l, y, &c); count += chan_count; ++l; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } while (l < r) { i_color c; i_gpix(im, l, y, &c); for (ch = 0; ch < chan_count; ++ch) c.channel[ch] = *samps++; i_ppix(im, l, y, &c); count += chan_count; ++l; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =item i_psampf_p(im, l, r, y, samps, chans, chan_count) Implement psampf() for paletted images. Since writing samples doesn't really work as a concept for paletted images, this is slow. Also, writing samples may convert the image to a direct image in the process, so use i_ppixf/i_gpixf instead of directly calling the paletted handlers. =cut */ static i_img_dim i_psampf_p(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count) { if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) { i_img_dim count = 0; int ch; if (r > im->xsize) r = im->xsize; if (chans) { /* make sure we have good channel numbers */ for (ch = 0; ch < chan_count; ++ch) { if (chans[ch] < 0 || chans[ch] >= im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]); return -1; } } while (l < r) { i_fcolor c; i_gpixf(im, l, y, &c); for (ch = 0; ch < chan_count; ++ch) c.channel[chans[ch]] = *samps++; i_ppixf(im, l, y, &c); count += chan_count; ++l; } } else { if (chan_count <= 0 || chan_count > im->channels) { dIMCTXim(im); im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels", chan_count); return -1; } while (l < r) { i_fcolor c; i_gpixf(im, l, y, &c); for (ch = 0; ch < chan_count; ++ch) c.channel[ch] = *samps++; i_ppixf(im, l, y, &c); count += chan_count; ++l; } } return count; } else { dIMCTXim(im); i_push_error(0, "Image position outside of image"); return -1; } } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/iolayer.h0000644000175000017500000000276512263740601017411 0ustar gregoagregoa#ifndef _IOLAYER_H_ #define _IOLAYER_H_ /* How the IO layer works: * * Start by getting an io_glue object by calling the appropriate * io_new...() function. After that data can be read via the * io_glue->readcb() method. * */ #include "iolayert.h" /* #define BBSIZ 1096 */ #define BBSIZ 16384 #define IO_FAKE_SEEK 1<<0L #define IO_TEMP_SEEK 1<<1L void io_glue_gettypes (io_glue *ig, int reqmeth); /* XS functions */ io_glue *im_io_new_fd(pIMCTX, int fd); io_glue *im_io_new_bufchain(pIMCTX); io_glue *im_io_new_buffer(pIMCTX, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata); io_glue *im_io_new_cb(pIMCTX, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb); size_t io_slurp(io_glue *ig, unsigned char **c); void io_glue_destroy(io_glue *ig); void i_io_dump(io_glue *ig, int flags); /* Buffered I/O */ extern int i_io_getc_imp(io_glue *ig); extern int i_io_peekc_imp(io_glue *ig); extern ssize_t i_io_peekn(io_glue *ig, void *buf, size_t size); extern int i_io_putc_imp(io_glue *ig, int c); extern ssize_t i_io_read(io_glue *ig, void *buf, size_t size); extern ssize_t i_io_write(io_glue *ig, const void *buf, size_t size); extern off_t i_io_seek(io_glue *ig, off_t offset, int whence); extern int i_io_flush(io_glue *ig); extern int i_io_close(io_glue *ig); extern int i_io_set_buffered(io_glue *ig, int buffered); extern ssize_t i_io_gets(io_glue *ig, char *, size_t, int); #endif /* _IOLAYER_H_ */ libimager-perl-1.004+dfsg.orig/fontft1.c0000644000175000017500000011023412263740600017307 0ustar gregoagregoa#include "imager.h" #include "imrender.h" #include #include #include #include #include /* =head1 NAME fontft1.c - Freetype 1.x font driver for Imager =head1 SYNOPSIS handle = i_tt_new(path_to_ttf); rc = i_tt_bbox(handle, points, "foo", 3, int cords[6], utf8); i_tt_destroy(handle); // and much more =head1 DESCRIPTION fontft1.c implements font creation, rendering, bounding box functions and more for Imager using Freetype 1.x. In general this driver should be ignored in favour of the FT2 driver. =head1 FUNCTION REFERENCE Some of these functions are internal. =over =cut */ /* Truetype font support */ /* These are enabled by default when configuring Freetype 1.x I haven't a clue how to reliably detect it at compile time. We need a compilation probe in Makefile.PL */ #define FTXPOST 1 #define FTXERR18 1 #include #define TT_CHC 5 #ifdef FTXPOST #include #endif #ifdef FTXERR18 #include #endif /* some versions of FT1.x don't seem to define this - it's font defined so it won't change */ #ifndef TT_MS_LANGID_ENGLISH_GENERAL #define TT_MS_LANGID_ENGLISH_GENERAL 0x0409 #endif static im_slot_t slot = -1; /* convert a code point into an index in the glyph cache */ #define TT_HASH(x) ((x) & 0xFF) typedef struct { int initialized; TT_Engine engine; } i_tt_engine; typedef struct i_glyph_entry_ { TT_Glyph glyph; unsigned long ch; } i_tt_glyph_entry; #define TT_NOCHAR (~0UL) struct TT_Instancehandle_ { TT_Instance instance; TT_Instance_Metrics imetrics; TT_Glyph_Metrics gmetrics[256]; i_tt_glyph_entry glyphs[256]; int smooth; int order; i_img_dim ptsize; }; typedef struct TT_Instancehandle_ TT_Instancehandle; struct TT_Fonthandle_ { TT_Face face; TT_Face_Properties properties; TT_Instancehandle instanceh[TT_CHC]; TT_CharMap char_map; #ifdef FTXPOST int loaded_names; TT_Error load_cond; #endif }; /* Defines */ #define USTRCT(x) ((x).z) #define TT_VALID( handle ) ( ( handle ).z != NULL ) static void i_tt_push_error(TT_Error rc); static void i_tt_uninit(void *); /* Prototypes */ static int i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth ); static void i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth ); static void i_tt_done_raster_map( TT_Raster_Map *bit ); static void i_tt_clear_raster_map( TT_Raster_Map* bit ); static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off ); static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j ); static void i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim x_off, i_img_dim y_off, int smooth ); static int i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim cords[6], char const* txt, size_t len, int smooth, int utf8 ); static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth ); static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth ); static int i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6], double points, char const* txt, size_t len, int smooth, int utf8 ); static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[6], int utf8 ); /* static globals needed */ static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */ static int LTT_hinted = 1; /* FIXME: this too */ /* * FreeType interface */ void i_tt_start(void) { if (slot == -1) slot = im_context_slot_new(i_tt_uninit); } /* =item init_tt() Initializes the freetype font rendering engine (if needed) =cut */ static i_tt_engine * i_init_tt(void) { TT_Error error; im_context_t ctx = im_get_context(); TT_Byte palette[] = { 0, 64, 127, 191, 255 }; i_tt_engine *result = im_context_slot_get(ctx, slot); i_clear_error(); if (result == NULL) { result = mymalloc(sizeof(i_tt_engine)); memset(result, 0, sizeof(*result)); im_context_slot_set(ctx, slot, result); mm_log((1, "allocated FT1 state %p\n", result)); } mm_log((1,"init_tt()\n")); if (result->initialized) return result; error = TT_Init_FreeType( &result->engine ); if ( error ){ mm_log((1,"Initialization of freetype failed, code = 0x%x\n", (unsigned)error)); i_tt_push_error(error); i_push_error(0, "Could not initialize freetype 1.x"); return NULL; } #ifdef FTXPOST error = TT_Init_Post_Extension( result->engine ); if (error) { mm_log((1, "Initialization of Post extension failed = 0x%x\n", (unsigned)error)); i_tt_push_error(error); i_push_error(0, "Could not initialize FT 1.x POST extension"); return NULL; } #endif error = TT_Set_Raster_Gray_Palette(result->engine, palette); if (error) { mm_log((1, "Initialization of gray levels failed = 0x%x\n", (unsigned)error)); i_tt_push_error(error); i_push_error(0, "Could not initialize FT 1.x POST extension"); return NULL; } mm_log((1, "initialized FT1 state %p\n", result)); result->initialized = 1; return result; } static void i_tt_uninit(void *p) { i_tt_engine *tteng = p; if (tteng->initialized) { mm_log((1, "finalizing FT1 state %p\n", tteng)); TT_Done_FreeType(tteng->engine); } mm_log((1, "freeing FT1 state %p\n", tteng)); myfree(tteng); } /* =item i_tt_get_instance(handle, points, smooth) Finds a points+smooth instance or if one doesn't exist in the cache allocates room and returns its cache entry fontname - path to the font to load handle - handle to the font. points - points of the requested font smooth - boolean (True: antialias on, False: antialias is off) =cut */ static int i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth ) { int i,idx; TT_Error error; mm_log((1,"i_tt_get_instance(handle %p, points %" i_DF ", smooth %d)\n", handle, i_DFc(points), smooth)); if (smooth == -1) { /* Smooth doesn't matter for this search */ for(i=0;iinstanceh[i].ptsize==points) { mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i)); return i; } } smooth=1; /* We will be adding a font - add it as smooth then */ } else { /* Smooth doesn't matter for this search */ for(i=0;iinstanceh[i].ptsize == points && handle->instanceh[i].smooth == smooth) { mm_log((1,"i_tt_get_instance: in cache returning %d\n",i)); return i; } } } /* Found the instance in the cache - return the cache index */ for(idx=0;idxinstanceh[idx].order)) break; /* find the lru item */ } mm_log((1,"i_tt_get_instance: lru item is %d\n",idx)); mm_log((1,"i_tt_get_instance: lru pointer %p\n", USTRCT(handle->instanceh[idx].instance) )); if ( USTRCT(handle->instanceh[idx].instance) ) { mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx)); /* Free cached glyphs */ for(i=0;i<256;i++) if ( USTRCT(handle->instanceh[idx].glyphs[i].glyph) ) TT_Done_Glyph( handle->instanceh[idx].glyphs[i].glyph ); for(i=0;i<256;i++) { handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR; USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL; } /* Free instance if needed */ TT_Done_Instance( handle->instanceh[idx].instance ); } /* create and initialize instance */ /* FIXME: probably a memory leak on fail */ (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) || ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) || ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) ); if ( error ) { mm_log((1, "Could not create and initialize instance: error %x.\n", (unsigned)error )); return -1; } /* Now that the instance should the inplace we need to lower all of the ru counts and put `this' one with the highest entry */ for(i=0;iinstanceh[i].order--; handle->instanceh[idx].order=TT_CHC-1; handle->instanceh[idx].ptsize=points; handle->instanceh[idx].smooth=smooth; TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) ); /* Zero the memory for the glyph storage so they are not thought as cached if they haven't been cached since this new font was loaded */ for(i=0;i<256;i++) { handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR; USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL; } return idx; } /* =item i_tt_new(fontname) Creates a new font handle object, finds a character map and initialise the the font handle's cache fontname - path to the font to load =cut */ TT_Fonthandle* i_tt_new(const char *fontname) { TT_Error error; TT_Fonthandle *handle; unsigned short i,n; unsigned short platform,encoding; i_tt_engine *tteng; if ((tteng = i_init_tt()) == NULL) { i_push_error(0, "Could not initialize FT1 engine"); return NULL; } i_clear_error(); mm_log((1,"i_tt_new(fontname '%s')\n",fontname)); /* allocate memory for the structure */ handle = mymalloc( sizeof(TT_Fonthandle) ); /* checked 5Nov05 tonyc */ /* load the typeface */ error = TT_Open_Face( tteng->engine, fontname, &handle->face ); if ( error ) { if ( error == TT_Err_Could_Not_Open_File ) { mm_log((1, "Could not find/open %s.\n", fontname )); } else { mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname, (unsigned)error )); } i_tt_push_error(error); return NULL; } TT_Get_Face_Properties( handle->face, &(handle->properties) ); /* First, look for a Unicode charmap */ n = handle->properties.num_CharMaps; USTRCT( handle->char_map )=NULL; /* Invalidate character map */ for ( i = 0; i < n; i++ ) { TT_Get_CharMap_ID( handle->face, i, &platform, &encoding ); if ( (platform == 3 && encoding == 1 ) || (platform == 0 && encoding == 0 ) ) { mm_log((2,"i_tt_new - found char map platform %u encoding %u\n", platform, encoding)); TT_Get_CharMap( handle->face, i, &(handle->char_map) ); break; } } if (!USTRCT(handle->char_map) && n != 0) { /* just use the first one */ TT_Get_CharMap( handle->face, 0, &(handle->char_map)); } /* Zero the pointsizes - and ordering */ for(i=0;iinstanceh[i].instance)=NULL; handle->instanceh[i].order=i; handle->instanceh[i].ptsize=0; handle->instanceh[i].smooth=-1; } #ifdef FTXPOST handle->loaded_names = 0; #endif mm_log((1,"i_tt_new <- %p\n",handle)); return handle; } /* * raster map management */ /* =item i_tt_init_raster_map(bit, width, height, smooth) Allocates internal memory for the bitmap as needed by the parameters (internal) bit - bitmap to allocate into width - width of the bitmap height - height of the bitmap smooth - boolean (True: antialias on, False: antialias is off) =cut */ static void i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth ) { mm_log((1,"i_tt_init_raster_map( bit %p, width %" i_DF ", height %" i_DF ", smooth %d)\n", bit, i_DFc(width), i_DFc(height), smooth)); bit->rows = height; bit->width = ( width + 3 ) & -4; bit->flow = TT_Flow_Down; if ( smooth ) { bit->cols = bit->width; bit->size = bit->rows * bit->width; } else { bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */ bit->size = bit->rows * bit->cols; /* number of bytes in buffer */ } /* rows can be 0 for some glyphs, for example ' ' */ if (bit->rows && bit->size / bit->rows != bit->cols) { i_fatal(0, "Integer overflow calculating bitmap size (%d, %d)\n", bit->width, bit->rows); } mm_log((1,"i_tt_init_raster_map: bit->width %d, bit->cols %d, bit->rows %d, bit->size %ld)\n", bit->width, bit->cols, bit->rows, bit->size )); bit->bitmap = (void *) mymalloc( bit->size ); /* checked 6Nov05 tonyc */ if ( !bit->bitmap ) i_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size ); } /* =item i_tt_clear_raster_map(bit) Frees the bitmap data and sets pointer to NULL (internal) bit - bitmap to free =cut */ static void i_tt_done_raster_map( TT_Raster_Map *bit ) { myfree( bit->bitmap ); bit->bitmap = NULL; } /* =item i_tt_clear_raster_map(bit) Clears the specified bitmap (internal) bit - bitmap to zero =cut */ static void i_tt_clear_raster_map( TT_Raster_Map* bit ) { memset( bit->bitmap, 0, bit->size ); } /* =item i_tt_blit_or(dst, src, x_off, y_off) function that blits one raster map into another (internal) dst - destination bitmap src - source bitmap x_off - x offset into the destination bitmap y_off - y offset into the destination bitmap =cut */ static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off ) { i_img_dim x, y; i_img_dim x1, x2, y1, y2; unsigned char *s, *d; x1 = x_off < 0 ? -x_off : 0; y1 = y_off < 0 ? -y_off : 0; x2 = (int)dst->cols - x_off; if ( x2 > src->cols ) x2 = src->cols; y2 = (int)dst->rows - y_off; if ( y2 > src->rows ) y2 = src->rows; if ( x1 >= x2 ) return; /* do the real work now */ for ( y = y1; y < y2; ++y ) { s = ( (unsigned char*)src->bitmap ) + y * src->cols + x1; d = ( (unsigned char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off; for ( x = x1; x < x2; ++x ) { if (*s > *d) *d = *s; d++; s++; } } } /* useful for debugging */ #if 0 static void dump_raster_map(FILE *out, TT_Raster_Map *bit ) { int x, y; fprintf(out, "cols %d rows %d flow %d\n", bit->cols, bit->rows, bit->flow); for (y = 0; y < bit->rows; ++y) { fprintf(out, "%2d:", y); for (x = 0; x < bit->cols; ++x) { if ((x & 7) == 0 && x) putc(' ', out); fprintf(out, "%02x", ((unsigned char *)bit->bitmap)[y*bit->cols+x]); } putc('\n', out); } } #endif /* =item i_tt_get_glyph(handle, inst, j) Function to see if a glyph exists and if so cache it (internal) handle - pointer to font handle inst - font instance j - charcode of glyph =cut */ static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) { unsigned short load_flags, code; TT_Error error; mm_log((1, "i_tt_get_glyph(handle %p, inst %d, j %lu (%c))\n", handle,inst,j, (int)((j >= ' ' && j <= '~') ? j : '.'))); /*mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));*/ if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) && handle->instanceh[inst].glyphs[TT_HASH(j)].ch == j) { mm_log((1,"i_tt_get_glyph: %lu in cache\n",j)); return 1; } if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) ) { /* clean up the entry */ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR; } /* Ok - it wasn't cached - try to get it in */ load_flags = TTLOAD_SCALE_GLYPH; if ( LTT_hinted ) load_flags |= TTLOAD_HINT_GLYPH; if ( !TT_VALID(handle->char_map) ) { code = (j - ' ' + 1) < 0 ? 0 : (j - ' ' + 1); if ( code >= handle->properties.num_Glyphs ) code = 0; } else code = TT_Char_Index( handle->char_map, j ); if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)) ) { mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error )); i_push_error(error, "TT_New_Glyph()"); return 0; } if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, code, load_flags)) ) { mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error )); /* Don't leak */ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; i_push_error(error, "TT_Load_Glyph()"); return 0; } /* At this point the glyph should be allocated and loaded */ handle->instanceh[inst].glyphs[TT_HASH(j)].ch = j; /* Next get the glyph metrics */ error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, &handle->instanceh[inst].gmetrics[TT_HASH(j)] ); if (error) { mm_log((1, "TT_Get_Glyph_Metrics: error %#x.\n", (unsigned)error )); TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR; i_push_error(error, "TT_Get_Glyph_Metrics()"); return 0; } return 1; } /* =item i_tt_has_chars(handle, text, len, utf8, out) Check if the given characters are defined by the font. Note that len is the number of bytes, not the number of characters (when utf8 is non-zero). Returns the number of characters that were checked. =cut */ size_t i_tt_has_chars(TT_Fonthandle *handle, char const *text, size_t len, int utf8, char *out) { size_t count = 0; mm_log((1, "i_tt_has_chars(handle %p, text %p, len %ld, utf8 %d)\n", handle, text, (long)len, utf8)); while (len) { unsigned long c; int index; if (utf8) { c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { c = (unsigned char)*text++; --len; } if (TT_VALID(handle->char_map)) { index = TT_Char_Index(handle->char_map, c); } else { index = (c - ' ' + 1) < 0 ? 0 : (c - ' ' + 1); if (index >= handle->properties.num_Glyphs) index = 0; } *out++ = index != 0; ++count; } return count; } /* =item i_tt_destroy(handle) Clears the data taken by a font including all cached data such as pixmaps and glyphs handle - pointer to font handle =cut */ void i_tt_destroy( TT_Fonthandle *handle) { TT_Close_Face( handle->face ); myfree( handle ); /* FIXME: Should these be freed automatically by the library? TT_Done_Instance( instance ); void i_tt_done_glyphs( void ) { int i; if ( !glyphs ) return; for ( i = 0; i < 256; ++i ) TT_Done_Glyph( glyphs[i] ); free( glyphs ); glyphs = NULL; } */ } /* * FreeType Rendering functions */ /* =item i_tt_render_glyph(handle, gmetrics, bit, smallbit, x_off, y_off, smooth) Renders a single glyph into the bit rastermap (internal) handle - pointer to font handle gmetrics - the metrics for the glyph to be rendered bit - large bitmap that is the destination for the text smallbit - small bitmap that is used only if smooth is true x_off - x offset of glyph y_off - y offset of glyph smooth - boolean (True: antialias on, False: antialias is off) =cut */ static void i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim x_off, i_img_dim y_off, int smooth ) { mm_log((1,"i_tt_render_glyph(glyph %p, gmetrics %p, bit %p, small_bit %p, x_off %" i_DF ", y_off %" i_DF ", smooth %d)\n", USTRCT(glyph), gmetrics, bit, small_bit, i_DFc(x_off), i_DFc(y_off), smooth)); if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64); else { TT_F26Dot6 xmin, ymin; xmin = gmetrics->bbox.xMin & -64; ymin = gmetrics->bbox.yMin & -64; i_tt_clear_raster_map( small_bit ); TT_Get_Glyph_Pixmap( glyph, small_bit, -xmin, -ymin ); i_tt_blit_or( bit, small_bit, xmin/64 + x_off, -ymin/64 - y_off ); } } /* =item i_tt_render_all_glyphs(handle, inst, bit, small_bit, cords, txt, len, smooth) calls i_tt_render_glyph to render each glyph into the bit rastermap (internal) handle - pointer to font handle inst - font instance bit - large bitmap that is the destination for the text smallbit - small bitmap that is used only if smooth is true txt - string to render len - length of the string to render smooth - boolean (True: antialias on, False: antialias is off) =cut */ static int i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim cords[6], char const* txt, size_t len, int smooth, int utf8 ) { unsigned long j; TT_F26Dot6 x,y; mm_log((1,"i_tt_render_all_glyphs( handle %p, inst %d, bit %p, small_bit %p, txt '%.*s', len %ld, smooth %d, utf8 %d)\n", handle, inst, bit, small_bit, (int)len, txt, (long)len, smooth, utf8)); /* y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM); */ x=-cords[0]; /* FIXME: If you font is antialiased this should be expanded by one to allow for aa expansion and the allocation too - do before passing here */ y=-cords[4]; while (len) { if (utf8) { j = i_utf8_advance(&txt, &len); if (j == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { j = (unsigned char)*txt++; --len; } if ( !i_tt_get_glyph(handle,inst,j) ) continue; i_tt_render_glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, &handle->instanceh[inst].gmetrics[TT_HASH(j)], bit, small_bit, x, y, smooth ); x += handle->instanceh[inst].gmetrics[TT_HASH(j)].advance / 64; } return 1; } /* * Functions to render rasters (single channel images) onto images */ /* =item i_tt_dump_raster_map2(im, bit, xb, yb, cl, smooth) Function to dump a raster onto an image in color used by i_tt_text() (internal). im - image to dump raster on bit - bitmap that contains the text to be dumped to im xb, yb - coordinates, left edge and baseline cl - color to use for text smooth - boolean (True: antialias on, False: antialias is off) =cut */ static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth ) { unsigned char *bmap; i_img_dim x, y; mm_log((1,"i_tt_dump_raster_map2(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", cl %p)\n", im, bit, i_DFc(xb), i_DFc(yb), cl)); bmap = bit->bitmap; if ( smooth ) { i_render r; i_render_init(&r, im, bit->cols); for(y=0;yrows;y++) { i_render_color(&r, xb, yb+y, bit->cols, bmap + y*bit->cols, cl); } i_render_done(&r); } else { unsigned char *bmp = mymalloc(bit->width); i_render r; i_render_init(&r, im, bit->width); for(y=0;yrows;y++) { unsigned mask = 0x80; unsigned char *p = bmap + y * bit->cols; unsigned char *pout = bmp; for(x = 0; x < bit->width; x++) { *pout++ = (*p & mask) ? 0xFF : 0; mask >>= 1; if (!mask) { mask = 0x80; ++p; } } i_render_color(&r, xb, yb+y, bit->width, bmp, cl); } i_render_done(&r); myfree(bmp); } } /* =item i_tt_dump_raster_map_channel(im, bit, xb, yb, channel, smooth) Function to dump a raster onto a single channel image in color (internal) im - image to dump raster on bit - bitmap that contains the text to be dumped to im xb, yb - coordinates, left edge and baseline channel - channel to copy to smooth - boolean (True: antialias on, False: antialias is off) =cut */ static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth ) { unsigned char *bmap; i_color val; int c; i_img_dim x,y; int old_mask = im->ch_mask; im->ch_mask = 1 << channel; mm_log((1,"i_tt_dump_raster_channel(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", channel %d)\n", im, bit, i_DFc(xb), i_DFc(yb), channel)); bmap = bit->bitmap; if ( smooth ) { for(y=0;yrows;y++) for(x=0;xwidth;x++) { c = bmap[y*(bit->cols)+x]; val.channel[channel] = c; i_ppix(im,x+xb,y+yb,&val); } } else { for(y=0;yrows;y++) { unsigned mask = 0x80; unsigned char *p = bmap + y * bit->cols; for(x=0;xwidth;x++) { val.channel[channel] = (*p & mask) ? 255 : 0; i_ppix(im,x+xb,y+yb,&val); mask >>= 1; if (!mask) { ++p; mask = 0x80; } } } } im->ch_mask = old_mask; } /* =item i_tt_rasterize(handle, bit, cords, points, txt, len, smooth) interface for generating single channel raster of text (internal) handle - pointer to font handle bit - the bitmap that is allocated, rendered into and NOT freed cords - the bounding box (modified in place) points - font size to use txt - string to render len - length of the string to render smooth - boolean (True: antialias on, False: antialias is off) =cut */ static int i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6], double points, char const* txt, size_t len, int smooth, int utf8 ) { int inst; i_img_dim width, height; TT_Raster_Map small_bit; /* find or install an instance */ if ( (inst=i_tt_get_instance(handle,points,smooth)) < 0) { mm_log((1,"i_tt_rasterize: get instance failed\n")); return 0; } /* calculate bounding box */ if (!i_tt_bbox_inst( handle, inst, txt, len, cords, utf8 )) return 0; width = cords[2]-cords[0]; height = cords[5]-cords[4]; mm_log((1,"i_tt_rasterize: width=%" i_DF ", height=%" i_DF "\n", i_DFc(width), i_DFc(height) )); i_tt_init_raster_map ( bit, width, height, smooth ); i_tt_clear_raster_map( bit ); if ( smooth ) i_tt_init_raster_map( &small_bit, handle->instanceh[inst].imetrics.x_ppem + 32, height, smooth ); if (!i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len, smooth, utf8 )) { if ( smooth ) i_tt_done_raster_map( &small_bit ); return 0; } if ( smooth ) i_tt_done_raster_map( &small_bit ); return 1; } /* * Exported text rendering interfaces */ /* =item i_tt_cp(handle, im, xb, yb, channel, points, txt, len, smooth, utf8) Interface to text rendering into a single channel in an image handle - pointer to font handle im - image to render text on to xb, yb - coordinates, left edge and baseline channel - channel to render into points - font size to use txt - string to render len - length of the string to render smooth - boolean (True: antialias on, False: antialias is off) =cut */ undef_int i_tt_cp( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, int channel, double points, char const* txt, size_t len, int smooth, int utf8, int align ) { i_img_dim cords[BOUNDING_BOX_COUNT]; i_img_dim ascent, st_offset, y; TT_Raster_Map bit; i_clear_error(); if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0; ascent=cords[BBOX_ASCENT]; st_offset=cords[BBOX_NEG_WIDTH]; y = align ? yb-ascent : yb; i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , y, channel, smooth ); i_tt_done_raster_map( &bit ); return 1; } /* =item i_tt_text(handle, im, xb, yb, cl, points, txt, len, smooth, utf8) Interface to text rendering in a single color onto an image handle - pointer to font handle im - image to render text on to xb, yb - coordinates, left edge and baseline cl - color to use for text points - font size to use txt - string to render len - length of the string to render smooth - boolean (True: antialias on, False: antialias is off) =cut */ undef_int i_tt_text( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, const i_color *cl, double points, char const* txt, size_t len, int smooth, int utf8, int align) { i_img_dim cords[BOUNDING_BOX_COUNT]; i_img_dim ascent, st_offset, y; TT_Raster_Map bit; i_clear_error(); if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0; ascent=cords[BBOX_ASCENT]; st_offset=cords[BBOX_NEG_WIDTH]; y = align ? yb-ascent : yb; i_tt_dump_raster_map2( im, &bit, xb+st_offset, y, cl, smooth ); i_tt_done_raster_map( &bit ); return 1; } /* =item i_tt_bbox_inst(handle, inst, txt, len, cords, utf8) Function to get texts bounding boxes given the instance of the font (internal) handle - pointer to font handle inst - font instance txt - string to measure len - length of the string to render cords - the bounding box (modified in place) =cut */ static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[BOUNDING_BOX_COUNT], int utf8 ) { int upm, casc, cdesc, first; int start = 0; i_img_dim width = 0; int gdescent = 0; int gascent = 0; int descent = 0; int ascent = 0; int rightb = 0; unsigned long j; mm_log((1,"i_tt_box_inst(handle %p,inst %d,txt '%.*s', len %ld, utf8 %d)\n", handle, inst, (int)len, txt, (long)len, utf8)); upm = handle->properties.header->Units_Per_EM; gascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem + upm - 1) / upm; gdescent = ( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem - upm + 1) / upm; width = 0; start = 0; mm_log((1, "i_tt_box_inst: gascent=%d gdescent=%d\n", gascent, gdescent)); first=1; while (len) { if (utf8) { j = i_utf8_advance(&txt, &len); if (j == ~0UL) { i_push_error(0, "invalid UTF8 character"); return 0; } } else { j = (unsigned char)*txt++; --len; } if ( i_tt_get_glyph(handle,inst,j) ) { TT_Glyph_Metrics *gm = handle->instanceh[inst].gmetrics + TT_HASH(j); width += gm->advance / 64; casc = (gm->bbox.yMax+63) / 64; cdesc = (gm->bbox.yMin-63) / 64; mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n", (int)((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc)); if (first) { start = gm->bbox.xMin / 64; ascent = (gm->bbox.yMax+63) / 64; descent = (gm->bbox.yMin-63) / 64; first = 0; } if (!len) { /* if at end of string */ /* the right-side bearing - in case the right-side of a character goes past the right of the advance width, as is common for italic fonts */ rightb = gm->advance - gm->bearingX - (gm->bbox.xMax - gm->bbox.xMin); /* fprintf(stderr, "font info last: %d %d %d %d\n", gm->bbox.xMax, gm->bbox.xMin, gm->advance, rightb); */ } ascent = (ascent > casc ? ascent : casc ); descent = (descent < cdesc ? descent : cdesc); } } cords[BBOX_NEG_WIDTH]=start; cords[BBOX_GLOBAL_DESCENT]=gdescent; cords[BBOX_POS_WIDTH]=width; if (rightb < 0) cords[BBOX_POS_WIDTH] -= rightb / 64; cords[BBOX_GLOBAL_ASCENT]=gascent; cords[BBOX_DESCENT]=descent; cords[BBOX_ASCENT]=ascent; cords[BBOX_ADVANCE_WIDTH] = width; cords[BBOX_RIGHT_BEARING] = rightb / 64; return BBOX_RIGHT_BEARING + 1; } /* =item i_tt_bbox(handle, points, txt, len, cords, utf8) Interface to get a strings bounding box handle - pointer to font handle points - font size to use txt - string to render len - length of the string to render cords - the bounding box (modified in place) =cut */ undef_int i_tt_bbox( TT_Fonthandle *handle, double points,const char *txt,size_t len,i_img_dim cords[6], int utf8) { int inst; i_clear_error(); mm_log((1,"i_tt_box(handle %p,points %f,txt '%.*s', len %ld, utf8 %d)\n", handle, points, (int)len, txt, (long)len, utf8)); if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) { i_push_errorf(0, "i_tt_get_instance(%g)", points); mm_log((1,"i_tt_text: get instance failed\n")); return 0; } return i_tt_bbox_inst(handle, inst, txt, len, cords, utf8); } /* =item i_tt_face_name(handle, name_buf, name_buf_size) Retrieve's the font's postscript name. This is complicated by the need to handle encodings and so on. =cut */ size_t i_tt_face_name(TT_Fonthandle *handle, char *name_buf, size_t name_buf_size) { TT_Face_Properties props; int name_count; int i; TT_UShort platform_id, encoding_id, lang_id, name_id; TT_UShort name_len; TT_String *name; int want_index = -1; /* an acceptable but not perfect name */ int score = 0; i_clear_error(); TT_Get_Face_Properties(handle->face, &props); name_count = props.num_Names; for (i = 0; i < name_count; ++i) { TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id, &name_id); TT_Get_Name_String(handle->face, i, &name, &name_len); if (platform_id != TT_PLATFORM_APPLE_UNICODE && name_len && name_id == TT_NAME_ID_PS_NAME) { int might_want_index = -1; int might_score = 0; if ((platform_id == TT_PLATFORM_MACINTOSH && encoding_id == TT_MAC_ID_ROMAN) || (platform_id == TT_PLATFORM_MICROSOFT && encoding_id == TT_MS_LANGID_ENGLISH_UNITED_STATES)) { /* exactly what we want */ want_index = i; break; } if (platform_id == TT_PLATFORM_MICROSOFT && (encoding_id & 0xFF) == TT_MS_LANGID_ENGLISH_GENERAL) { /* any english is good */ might_want_index = i; might_score = 9; } /* there might be something in between */ else { /* anything non-unicode is better than nothing */ might_want_index = i; might_score = 1; } if (might_score > score) { score = might_score; want_index = might_want_index; } } } if (want_index != -1) { TT_Get_Name_String(handle->face, want_index, &name, &name_len); strncpy(name_buf, name, name_buf_size); name_buf[name_buf_size-1] = '\0'; return strlen(name) + 1; } else { i_push_error(0, "no face name present"); return 0; } } void i_tt_dump_names(TT_Fonthandle *handle) { TT_Face_Properties props; int name_count; int i; TT_UShort platform_id, encoding_id, lang_id, name_id; TT_UShort name_len; TT_String *name; TT_Get_Face_Properties(handle->face, &props); name_count = props.num_Names; for (i = 0; i < name_count; ++i) { TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id, &name_id); TT_Get_Name_String(handle->face, i, &name, &name_len); printf("# %d: plat %d enc %d lang %d name %d value ", i, platform_id, encoding_id, lang_id, name_id); if (platform_id == TT_PLATFORM_APPLE_UNICODE) { printf("(unicode)\n"); } else { printf("'%s'\n", name); } } fflush(stdout); } size_t i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf, size_t name_buf_size) { #ifdef FTXPOST TT_Error rc; TT_String *psname; TT_UShort index; i_clear_error(); if (!handle->loaded_names) { TT_Post post; mm_log((1, "Loading PS Names")); handle->load_cond = TT_Load_PS_Names(handle->face, &post); ++handle->loaded_names; } if (handle->load_cond) { i_push_errorf(handle->load_cond, "error loading names (%#x)", (unsigned)handle->load_cond); return 0; } index = TT_Char_Index(handle->char_map, ch); if (!index) { i_push_error(0, "no such character"); return 0; } rc = TT_Get_PS_Name(handle->face, index, &psname); if (rc) { i_push_error(rc, "error getting name"); return 0; } strncpy(name_buf, psname, name_buf_size); name_buf[name_buf_size-1] = '\0'; return strlen(psname) + 1; #else mm_log((1, "FTXPOST extension not enabled\n")); i_clear_error(); i_push_error(0, "Use of FTXPOST extension disabled"); return 0; #endif } /* =item i_tt_push_error(code) Push an error message and code onto the Imager error stack. =cut */ static void i_tt_push_error(TT_Error rc) { #ifdef FTXERR18 TT_String const *msg = TT_ErrToString18(rc); i_push_error(rc, msg); #else i_push_errorf(rc, "Error code 0x%04x", (unsigned)rc); #endif } /* =back =head1 AUTHOR Arnar M. Hrafnkelsson =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/tags.c0000644000175000017500000003420212031434615016663 0ustar gregoagregoa/* =head1 NAME tags.c - functions for manipulating an images tags list =head1 SYNOPSIS i_img_tags tags; i_tags_new(&tags); i_tags_destroy(&tags); i_tags_addn(&tags, "name", code, idata); i_tags_add(&tags, "name", code, data, data_size, idata); if (i_tags_find(&tags, name, start, &entry)) { found } if (i_tags_findn(&tags, code, start, &entry)) { found } i_tags_delete(&tags, index); count = i_tags_delbyname(tags, name); count = i_tags_delbycode(tags, code); if (i_tags_get_float(&tags, name, code, &float_value)) { found } i_tags_set_float(&tags, name, code, value); i_tags_set_float2(&tags, name, code, value, sig_digits); i_tags_get_int(&tags, name, code, &int_value); =head1 DESCRIPTION Provides functions which give write access to the tags list of an image. For read access directly access the fields (do not write any fields directly). A tag is represented by an i_img_tag structure: typedef enum { itt_double, iit_text } i_tag_type; typedef struct { char *name; // name of a given tag, might be NULL int code; // number of a given tag, -1 if it has no meaning char *data; // value of a given tag if it's not an int, may be NULL int size; // size of the data int idata; // value of a given tag if data is NULL } i_img_tag; =over =cut */ #include "imager.h" #include #include #include #include /* useful for debugging */ void i_tags_print(i_img_tags *tags); /* =item i_tags_new(i_img_tags *tags) =category Tags Initialize a tags structure. Should not be used if the tags structure has been previously used. This should be called tags member of an i_img object on creation (in i_img_*_new() functions). To destroy the contents use i_tags_destroy() =cut */ void i_tags_new(i_img_tags *tags) { tags->count = tags->alloc = 0; tags->tags = NULL; } /* =item i_tags_addn(i_img_tags *tags, char *name, int code, int idata) Adds a tag that has an integer value. A simple wrapper around i_tags_add(). Use i_tags_setn() instead, this function may be removed in the future. Returns non-zero on success. =cut */ int i_tags_addn(i_img_tags *tags, char const *name, int code, int idata) { return i_tags_add(tags, name, code, NULL, 0, idata); } /* =item i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, i_tag_type type, int idata) Adds a tag to the tags list. Use i_tags_set() instead, this function may be removed in the future. Returns non-zero on success. =cut */ int i_tags_add(i_img_tags *tags, char const *name, int code, char const *data, int size, int idata) { i_img_tag work = {0}; /*printf("i_tags_add(tags %p [count %d], name %s, code %d, data %p, size %d, idata %d)\n", tags, tags->count, name, code, data, size, idata);*/ if (tags->tags == NULL) { int alloc = 10; tags->tags = mymalloc(sizeof(i_img_tag) * alloc); if (!tags->tags) return 0; tags->alloc = alloc; } else if (tags->count == tags->alloc) { int newalloc = tags->alloc + 10; void *newtags = myrealloc(tags->tags, sizeof(i_img_tag) * newalloc); if (!newtags) { return 0; } tags->tags = newtags; tags->alloc = newalloc; } if (name) { work.name = mymalloc(strlen(name)+1); if (!work.name) return 0; strcpy(work.name, name); } if (data) { if (size == -1) size = strlen(data); work.data = mymalloc(size+1); if (!work.data) { if (work.name) myfree(work.name); return 0; } memcpy(work.data, data, size); work.data[size] = '\0'; /* convenience */ work.size = size; } work.code = code; work.idata = idata; tags->tags[tags->count++] = work; /*i_tags_print(tags);*/ return 1; } /* =item i_tags_destroy(tags) =category Tags Destroys the given tags structure. Called by i_img_destroy(). =cut */ void i_tags_destroy(i_img_tags *tags) { if (tags->tags) { int i; for (i = 0; i < tags->count; ++i) { if (tags->tags[i].name) myfree(tags->tags[i].name); if (tags->tags[i].data) myfree(tags->tags[i].data); } myfree(tags->tags); } } /* =item i_tags_find(tags, name, start, &entry) =category Tags Searches for a tag of the given I starting from index I. On success returns true and sets *I. On failure returns false. =cut */ int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry) { if (tags->tags) { while (start < tags->count) { if (tags->tags[start].name && strcmp(name, tags->tags[start].name) == 0) { *entry = start; return 1; } ++start; } } return 0; } /* =item i_tags_findn(tags, code, start, &entry) =category Tags Searches for a tag of the given I starting from index I. On success returns true and sets *I. On failure returns false. =cut */ int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) { if (tags->tags) { while (start < tags->count) { if (tags->tags[start].code == code) { *entry = start; return 1; } ++start; } } return 0; } /* =item i_tags_delete(tags, index) =category Tags Delete a tag by index. Returns true on success. =cut */ int i_tags_delete(i_img_tags *tags, int entry) { /*printf("i_tags_delete(tags %p [count %d], entry %d)\n", tags, tags->count, entry);*/ if (tags->tags && entry >= 0 && entry < tags->count) { i_img_tag old = tags->tags[entry]; memmove(tags->tags+entry, tags->tags+entry+1, (tags->count-entry-1) * sizeof(i_img_tag)); if (old.name) myfree(old.name); if (old.data) myfree(old.data); --tags->count; return 1; } return 0; } /* =item i_tags_delbyname(tags, name) =category Tags Delete any tags with the given name. Returns the number of tags deleted. =cut */ int i_tags_delbyname(i_img_tags *tags, char const *name) { int count = 0; int i; /*printf("i_tags_delbyname(tags %p [count %d], name %s)\n", tags, tags->count, name);*/ if (tags->tags) { for (i = tags->count-1; i >= 0; --i) { if (tags->tags[i].name && strcmp(name, tags->tags[i].name) == 0) { ++count; i_tags_delete(tags, i); } } } /*i_tags_print(tags);*/ return count; } /* =item i_tags_delbycode(tags, code) =category Tags Delete any tags with the given code. Returns the number of tags deleted. =cut */ int i_tags_delbycode(i_img_tags *tags, int code) { int count = 0; int i; if (tags->tags) { for (i = tags->count-1; i >= 0; --i) { if (tags->tags[i].code == code) { ++count; i_tags_delete(tags, i); } } } return count; } /* =item i_tags_get_float(tags, name, code, value) =category Tags Retrieves a tag as a floating point value. If the tag has a string value then that is parsed as a floating point number, otherwise the integer value of the tag is used. On success sets *I and returns true. On failure returns false. =cut */ int i_tags_get_float(i_img_tags *tags, char const *name, int code, double *value) { int index; i_img_tag *entry; if (name) { if (!i_tags_find(tags, name, 0, &index)) return 0; } else { if (!i_tags_findn(tags, code, 0, &index)) return 0; } entry = tags->tags+index; if (entry->data) *value = atof(entry->data); else *value = entry->idata; return 1; } /* =item i_tags_set_float(tags, name, code, value) =category Tags Equivalent to i_tags_set_float2(tags, name, code, value, 30). =cut */ int i_tags_set_float(i_img_tags *tags, char const *name, int code, double value) { return i_tags_set_float2(tags, name, code, value, 30); } /* =item i_tags_set_float2(tags, name, code, value, places) =category Tags Sets the tag with the given name and code to the given floating point value. Since tags are strings or ints, we convert the value to a string before storage at the precision specified by C. =cut */ int i_tags_set_float2(i_img_tags *tags, char const *name, int code, double value, int places) { char temp[40]; if (places < 0) places = 30; else if (places > 30) places = 30; sprintf(temp, "%.*g", places, value); if (name) i_tags_delbyname(tags, name); else i_tags_delbycode(tags, code); return i_tags_add(tags, name, code, temp, strlen(temp), 0); } /* =item i_tags_get_int(tags, name, code, &value) =category Tags Retrieve a tag specified by name or code as an integer. On success sets the int *I to the integer and returns true. On failure returns false. =cut */ int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value) { int index; i_img_tag *entry; if (name) { if (!i_tags_find(tags, name, 0, &index)) return 0; } else { if (!i_tags_findn(tags, code, 0, &index)) return 0; } entry = tags->tags+index; if (entry->data) *value = atoi(entry->data); else *value = entry->idata; return 1; } static int parse_long(char *data, char **end, long *out) { long result; int savederr = errno; char *myend; errno = 0; result = strtol(data, &myend, 10); if (((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE) || myend == data) { errno = savederr; return 0; } errno = savederr; *out = result; *end = myend; return 1; } /* parse a comma-separated list of integers returns when it has maxcount numbers, finds a non-comma after a number or can't parse a number if it can't parse a number after a comma, that's considered an error */ static int parse_long_list(char *data, char **end, int maxcount, long *out) { int i; i = 0; while (i < maxcount-1) { if (!parse_long(data, &data, out)) return 0; out++; i++; if (*data != ',') return i; ++data; } if (!parse_long(data, &data, out)) return 0; ++i; *end = data; return i; } /* parse "color(red,green,blue,alpha)" */ static int parse_color(char *data, char **end, i_color *value) { long n[4]; int count, i; if (memcmp(data, "color(", 6)) return 0; /* not a color */ data += 6; count = parse_long_list(data, &data, 4, n); if (count < 3) return 0; for (i = 0; i < count; ++i) value->channel[i] = n[i]; if (count < 4) value->channel[3] = 255; return 1; } /* =item i_tags_get_color(tags, name, code, &value) =category Tags Retrieve a tag specified by name or code as color. On success sets the i_color *I to the color and returns true. On failure returns false. =cut */ int i_tags_get_color(i_img_tags *tags, char const *name, int code, i_color *value) { int index; i_img_tag *entry; char *end; if (name) { if (!i_tags_find(tags, name, 0, &index)) return 0; } else { if (!i_tags_findn(tags, code, 0, &index)) return 0; } entry = tags->tags+index; if (!entry->data) return 0; if (!parse_color(entry->data, &end, value)) return 0; /* for now we're sloppy about the end */ return 1; } /* =item i_tags_set_color(tags, name, code, &value) =category Tags Stores the given color as a tag with the given name and code. =cut */ int i_tags_set_color(i_img_tags *tags, char const *name, int code, i_color const *value) { char temp[80]; sprintf(temp, "color(%d,%d,%d,%d)", value->channel[0], value->channel[1], value->channel[2], value->channel[3]); if (name) i_tags_delbyname(tags, name); else i_tags_delbycode(tags, code); return i_tags_add(tags, name, code, temp, strlen(temp), 0); } /* =item i_tags_get_string(tags, name, code, value, value_size) =category Tags Retrieves a tag by name or code as a string. On success copies the string to value for a max of value_size and returns true. On failure returns false. value_size must be at least large enough for a string representation of an integer. The copied value is always C terminated. =cut */ int i_tags_get_string(i_img_tags *tags, char const *name, int code, char *value, size_t value_size) { int index; i_img_tag *entry; if (name) { if (!i_tags_find(tags, name, 0, &index)) return 0; } else { if (!i_tags_findn(tags, code, 0, &index)) return 0; } entry = tags->tags+index; if (entry->data) { size_t cpsize = value_size < entry->size ? value_size : entry->size; memcpy(value, entry->data, cpsize); if (cpsize == value_size) --cpsize; value[cpsize] = '\0'; } else { sprintf(value, "%d", entry->idata); } return 1; } /* =item i_tags_set(tags, name, data, size) =synopsis i_tags_set(&img->tags, "i_comment", -1); =category Tags Sets the given tag to the string I If size is -1 then the strlen(I) bytes are stored. Even on failure, if an existing tag I exists, it will be removed. =cut */ int i_tags_set(i_img_tags *tags, char const *name, char const *data, int size) { i_tags_delbyname(tags, name); return i_tags_add(tags, name, 0, data, size, 0); } /* =item i_tags_setn(C, C, C) =synopsis i_tags_setn(&img->tags, "i_xres", 204); =synopsis i_tags_setn(&img->tags, "i_yres", 196); =category Tags Sets the given tag to the integer C Even on failure, if an existing tag C exists, it will be removed. =cut */ int i_tags_setn(i_img_tags *tags, char const *name, int idata) { i_tags_delbyname(tags, name); return i_tags_addn(tags, name, 0, idata); } void i_tags_print(i_img_tags *tags) { int i; printf("Alloc %d\n", tags->alloc); printf("Count %d\n", tags->count); for (i = 0; i < tags->count; ++i) { i_img_tag *tag = tags->tags + i; printf("Tag %d\n", i); if (tag->name) printf(" Name : %s (%p)\n", tag->name, tag->name); printf(" Code : %d\n", tag->code); if (tag->data) { int pos; printf(" Data : %d (%p) => '", tag->size, tag->data); for (pos = 0; pos < tag->size; ++pos) { if (tag->data[pos] == '\\' || tag->data[pos] == '\'') { putchar('\\'); putchar(tag->data[pos]); } else if (tag->data[pos] < ' ' || tag->data[pos] >= '\x7E') printf("\\x%02X", tag->data[pos]); else putchar(tag->data[pos]); } printf("'\n"); printf(" Idata: %d\n", tag->idata); } } } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/bigtest.perl0000644000175000017500000000520412031434614020105 0ustar gregoagregoa#!perl -w use strict; # tests Imager with every combination of options my @opts = qw(jpeg tiff png gif ungif T1-fonts TT-fonts freetype2); # each option gets a bit my %bits; @bits{@opts} = map { 1 << $_ } 0..(@opts-1); my $perl = $ENV{PERLBIN} || "perl"; my $make = $ENV{MAKEBIN} || "make"; my $makeopts = $ENV{MAKEOPTS} || ''; use Getopt::Std; my %opts; getopts('vd', \%opts); my $top = (1 << @opts)-1; my @results; my $testlog = "bigtest.txt"; unlink $testlog; my $total = 0; my $good = 0; system("$make clean") if -e 'Makefile' && !$opts{d}; for my $set (0..$top) { ++$total; $ENV{IM_ENABLE} = join(' ', grep($set & $bits{$_}, @opts)); print STDERR $opts{v} ? "$set/$top Enable: $ENV{IM_ENABLE}\n" : '.'; system("echo '****' \$IM_ENABLE >>$testlog"); if ($opts{d}) { if (system("$make $makeopts disttest >>$testlog.txt 2>&1")) { push(@results, [ $ENV{IM_ENABLE}, 'disttest failed' ]); next; } } else { unlink 'Makefile'; if (system("$perl Makefile.PL >>$testlog 2>&1")) { push(@results, [ $ENV{IM_ENABLE}, 'Makefile.PL failed' ]); next; } if (system("$make $makeopts >>$testlog 2>&1")) { push(@results, [ $ENV{IM_ENABLE}, 'make failed' ]); next; } if (system("$make test >>$testlog 2>&1")) { push(@results, [ $ENV{IM_ENABLE}, 'test failed' ]); next; } if (system("$make clean >>$testlog 2>&1")) { push(@results, [ $ENV{IM_ENABLE}, 'clean failed' ]); next; } } push(@results, [ $ENV{IM_ENABLE}, 'success' ]); ++$good; } print STDERR "\n"; printf("%-20s %-50s\n", "Result", "Options"); printf("%-20s %-50s\n", "-" x 20, "-" x 50); foreach my $row (@results) { printf("%-20s %-50s\n", @$row[1,0]); } print "-" x 71, "\n"; print "Total: $total Successes: $good Failures: ",$total-$good,"\n"; print "Output in $testlog\n"; __END__ =head1 NAME bigtest.perl - tests combinations of libraries usable by Imager =head1 SYNOPSYS perl bigtest.perl # grab a cup of coffee or four - this takes a while =head1 DESCRIPTION bigtest.perl uses the new IM_ENABLE environment variable of Makefile.PL to built Imager for all possible combinations of libraries that Imager uses. At the time of writing this is 128 combinations, which takes quite a while. =head1 OPTIONS -v - verbose output -d - perform disttest for each combination =head1 ENVIRONMENT VARIABLES PERLBIN - the perl binary to use MAKEBIN - the make binary to use Any other variables used by Imager's Makefile.PL, except for IM_MANUAL or IM_ENABLE. =head1 BUGS Doesn't test other possible options, like IM_NOLOG or IM_DEBUG_MALLOC. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/samples/0000755000175000017500000000000012617614576017244 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/samples/samp-image.cgi0000755000175000017500000000311612031434615021734 0ustar gregoagregoa#!/usr/bin/perl -w use strict; use CGI; use Imager; my $cgi = CGI->new; my $color = $cgi->param('color'); defined $color or $color = ''; # Imager allows a number of different color specs, but keep this # simple, only accept simple RRGGBB hex colors my %errors; # note that you need to perform validation here as well as in # the form script, since the user can view image and manipulate the # URL (or even fetch the URL using LWP and modify the request in any way # they like. # Since we're producing an image, we don't have a mechanism to # report errors (unless we choose to draw text on an image), so # just product a default image. if (!defined $color || $color !~ /^[0-9a-f]{6}$/i) { $color = '000000'; } my $im = Imager->new(xsize=>40, ysize=>40); $im->box(filled=>1, color=>$color); # this will force the flushing of the headers, otherwise the server (and # your web browser) may see the image data before the content type. ++$|; print "Content-Type: image/jpeg\n\n"; # use binmode to prevent LF expanding to CRLF on windows binmode STDOUT; # we have to supply the type of output since we haven't supplied a # filename $im->write(fd=>fileno(STDOUT), type=>'jpeg') or die "Cannot write to stdout: ", $im->errstr; =head1 NAME samp-image.cgi - demonstrates interaction of HTML generation with image generation =head1 SYNOPSIS /cgi-bin/samp-image.cgi?color=RRGGBB =head1 DESCRIPTION This is the image generation program that samp-form.cgi uses to generate the image. See samp-form.cgi for more detail. =head1 REVISION $Revision$ =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/samples/inline_capture2image.pl0000644000175000017500000000357412263740601023662 0ustar gregoagregoa#!perl -w use strict; use Imager; # this is just to exercise the code, see the capture2image # function below for the meat my $from = shift; my $to = shift; my $width = shift || 320; my $height = shift || 240; $to or die "Usage: $0 from to [width [height]]\n"; my $data; open RAWVIDEO, "< $from" or die "Cannot open $from: $!\n"; binmode RAWVIDEO; $data = do { local $/; }; close RAWVIDEO; length $data >= $width * $height * 3 or die "Not enough data for video frame\n"; my $im = Imager->new(xsize=>$width, ysize=>$height); capture2image($im, $data); $im->write(file=>$to) or die "Cannot save $to: $!\n"; use Inline C => <<'EOS' => WITH => 'Imager'; void capture2image(Imager::ImgRaw out, unsigned char *data) { i_color *line_buf = mymalloc(sizeof(i_color) * out->xsize); i_color *pixelp; int x, y; for (y = 0; y < out->ysize; ++y) { pixelp = line_buf; for (x = 0; x < out->xsize; ++x) { pixelp->rgba.b = *data++; pixelp->rgba.g = *data++; pixelp->rgba.r = *data++; ++pixelp; } i_plin(out, 0, out->xsize, y, line_buf); } myfree(line_buf); } EOS __END__ =head1 NAME inline_capture2image.pl - convert captured C data to any Imager supported format =head1 SYNOPSIS perl inline_capture2image.pl rawbgr foo.ext perl inline_capture2image.pl rawbgr foo.ext width perl inline_capture2image.pl rawbgr foo.ext width height =head1 DESCRIPTION This was inspired by the discussion at http://www.perlmonks.org/?node_id=539316 (Feeding video data to Imager). inline_capture2image.pl takes V4L raw captured image data and outputs an image in any image format supported by Imager. =head1 SEE ALSO Imager, Imager::API Perl and Video Capture http://www.perlmonks.org/?node=474047 Feeding video data to Imager http://www.perlmonks.org/?node_id=539316 =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/samples/gifscale.pl0000644000175000017500000000463212263740601021345 0ustar gregoagregoa#!perl -w use strict; use Imager; use POSIX qw(ceil); $Imager::formats{gif} || $Imager::formats{ungif} or die "Your build of Imager doesn't support gif\n"; $Imager::formats{gif} or warn "Your build of Imager output's uncompressed GIFs, install libgif instead of libungif (the patents have expired)"; my $factor = shift; my $in_name = shift; my $out_name = shift or die "Usage: $0 scalefactor input.gif output.gif\n"; $factor > 0 or die "scalefactor must be positive\n"; my @in = Imager->read_multi(file => $in_name) or die "Cannot read image file: ", Imager->errstr, "\n"; # the sizes need to be based on the screen size of the image, but # that's only present in GIF, make sure the image was read as gif $in[0]->tags(name => 'i_format') eq 'gif' or die "File $in_name is not a GIF image\n"; my $src_screen_width = $in[0]->tags(name => 'gif_screen_width'); my $src_screen_height = $in[0]->tags(name => 'gif_screen_height'); my $out_screen_width = ceil($src_screen_width * $factor); my $out_screen_height = ceil($src_screen_height * $factor); my @out; for my $in (@in) { my $scaled = $in->scale(scalefactor => $factor, qtype=>'mixing'); # roughly preserve the relative position $scaled->settag(name => 'gif_left', value => $factor * $in->tags(name => 'gif_left')); $scaled->settag(name => 'gif_top', value => $factor * $in->tags(name => 'gif_top')); $scaled->settag(name => 'gif_screen_width', value => $out_screen_width); $scaled->settag(name => 'gif_screen_height', value => $out_screen_height); # set some other tags from the source for my $tag (qw/gif_delay gif_user_input gif_loop gif_disposal/) { $scaled->settag(name => $tag, value => $in->tags(name => $tag)); } if ($in->tags(name => 'gif_local_map')) { $scaled->settag(name => 'gif_local_map', value => 1); } push @out, $scaled; } Imager->write_multi({ file => $out_name }, @out) or die "Cannot save $out_name: ", Imager->errstr, "\n"; =head1 NAME =for stopwords gifscale.pl gifscale.pl - demonstrates adjusting tags when scaling a GIF image =head1 SYNOPSIS perl gifscale.pl scalefactor input.gif output.gif =head1 DESCRIPTION Scales an input multiple-image GIF file. Unlike a simple scale each file solution this: =over =item * preserves GIF animation attributes =item * adjusts the sub-images positions on the background accounting for the scale factor. =back =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/samples/anaglyph.pl0000644000175000017500000000655012614520132021367 0ustar gregoagregoa#!perl -w use strict; use Imager; use Getopt::Long; my $grey; my $pure; my $green; GetOptions('grey|gray|g'=>\$grey, 'pure|p' => \$pure, 'green' => \$green); if ($grey && $pure) { die "Only one of --grey or --pure can be used at a time\n"; } my $left_name = shift; my $right_name = shift; my $out_name = shift or usage(); my $left = Imager->new; $left->read(file=>$left_name) or die "Cannot load $left_name: ", $left->errstr, "\n"; my $right = Imager->new; $right->read(file=>$right_name) or die "Cannot load $right_name: ", $right->errstr, "\n"; $left->getwidth == $right->getwidth && $left->getheight == $right->getheight or die "Images must be the same width and height\n"; $left->getwidth == $right->getwidth or die "Images must have the same number of channels\n"; my $out; if ($grey) { $out = grey_anaglyph($left, $right); } elsif ($pure) { $out = pure_anaglyph($left, $right, $green); } else { $out = anaglyph_images($left, $right); } $out->write(file=>$out_name, jpegquality => 100) or die "Cannot write $out_name: ", $out->errstr, "\n"; sub usage { print <$expr, }, $left, $right) or die Imager->errstr; $out; } sub grey_anaglyph { my ($left, $right) = @_; $left = $left->convert(preset=>'grey'); $right = $right->convert(preset=>'grey'); my $expr = <<'EXPR'; x y getp1 red x y getp2 red !right @right @right rgb EXPR return Imager::transform2({ rpnexpr=>$expr }, $left, $right); } sub pure_anaglyph { my ($left, $right, $green) = @_; $left = $left->convert(preset=>'grey'); $right = $right->convert(preset=>'grey'); my $expr; if ($green) { # output is rgb(first channel of left, first channel of right, 0) $expr = <<'EXPR' x y getp1 red x y getp2 red 0 rgb EXPR } else { # output is rgb(first channel of left, 0, first channel of right) $expr = <<'EXPR'; x y getp1 red 0 x y getp2 red rgb EXPR } return Imager::transform2({ rpnexpr=>$expr }, $left, $right); } =head1 NAME =for stopwords anaglyph anaglyph.pl anaglyph.pl - create a anaglyph from the source images =head1 SYNOPSIS # color anaglyph perl anaglyph.pl left_input right_input output # grey anaglyph perl anaglyph.pl -g left_input right_input output perl anaglyph.pl --grey left_input right_input output perl anaglyph.pl --gray left_input right_input output # pure anaglyph (blue) perl anaglyph.pl -p left_input right_input output perl anaglyph.pl --pure left_input right_input output # pure anaglyph (green) perl anaglyph.pl -p --green left_input right_input output perl anaglyph.pl --pure --green left_input right_input output =head1 DESCRIPTION See L for an example where this might be useful. Implementation based on the description at http://www.recordedlight.com/stereo/tutorials/ps/anaglyph/pstut04.htm though obviously the interactive component is missing. =head1 CAVEAT Using JPEG as the output format is not recommended. =head1 AUTHOR Tony Cook =for stopwords Oppenheim Thanks to Dan Oppenheim, who provided the impetus for this sample. =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/samples/samp-form.cgi0000755000175000017500000001423012263740601021616 0ustar gregoagregoa#!/usr/bin/perl -w use strict; use CGI; use HTML::Entities; my $cgi = CGI->new; # get our parameter, make sure it's defined to avoid my $color = $cgi->param('color'); # Imager allows a number of different color specs, but keep this # simple, only accept simple RRGGBB hex colors my %errors; if (defined $color && $color !~ /^[0-9a-f]{6}$/i) { $errors{color} = "Color must be hex RRGGBB"; } # validated, make it defined to avoid warnings in the HTML generation defined $color or $color = ''; # print the content type header and the start of out HTML print "Content-Type: text/html\n\n", < Sample HTML and Image generation with Imager

HTML # link to the image if we got a good color # START LINK GENERATION (see the POD) if ($color && !keys %errors) { # since color only contains word characters it doesn't need to be # escaped, in most cases you'd load URI::Escape and call uri_escape() on it print < HTML } # END LINK GENERATION # finish off the page # one reason template systems are handy... my $color_encoded = encode_entities($color); my $color_msg_encoded = encode_entities($errors{color} || ''); print <Color: $color_msg_encoded

HTML =head1 NAME samp-form.cgi - demonstrates interaction of HTML generation with image generation =head1 SYNOPSIS /cgi-bin/samp-form.cgi?color=RRGGBB =head1 DESCRIPTION This is the HTML side of a sample for Imager that demonstrates generating an image linked from a HTML form. See samp-image.cgi for the image generation side of this sample. One common mistake seen in generating images is attempting to generate the image inline, for example: # DON'T DO THIS, IT'S WRONG my $img = Imager->new(...); ... draw on the image ... print ''; This sample code demonstrates one of the possible correct ways to generate an image linked from a HTML page. This has the limitation that some processing is done twice, for example, the validation of the parameters, but it's good when the same image will never be generated again. The basic approach is to have one program generate the HTML which links to a second program that generates the image. This sample is only intended to demonstrate embedding a generated image in a page, it's missing some best practice: =over =item * a templating system, like HTML::Mason, or Template::Toolkit should be used to generate the HTML, so that the HTML can be maintained separately from the code. Such a system should also be able to HTML or URI escape values embedded in the page to avoid the separate code used above. =item * a more complex system would probably do some validation as part of business rules, in a module. =back =head1 ANOTHER APPROACH A different way of doing this is to have the HTML generation script write the images to a directory under the web server document root, for example, the code from C<# START LINK GENERATION> to C<# END LINK # GENERATION> in samp-form.cgi would be replaced with something like: if ($color && !keys %errors) { # make a fairly unique filename # in this case we could also use: # my $filename = lc($color) . ".jpg"; # but that's not a general solution use Time::HiRes; my $filename = time . $$ . ".jpg"; my $image_path = $docroot . "/images/dynamic/" . $filename; my $image_url = "/images/dynamic/" . $filename; my $im = Imager->new(xsize=>40, ysize=>40); $im->box(filled=>1, color=>$color); $im->write(file=>$image_path) or die "Cannot write to $image_path:", $im->errstr, "\n"; print < HTML } This has the advantage that you aren't handling a second potentially expensive CGI request to generate the image, but it means you need some mechanism to manage the files (for example, a cron job to delete old files), and you need to make some directory under the document root writable by the user that your web server runs CGI programs as, which may be a security concern. Also, if you're generating large numbers of large images, you may end up using significant disk space. =head1 SECURITY It's important to remember that any value supplied by the user can be abused by the user, in this example there's only one parameter, the color of the sample image, but in a real application the values supplied coule include font filenames, URLs, image filename and so on. It's important that these are validated and in some cases limited to prevent a user from using your program to obtain access or deny access to things they shouldn't be able to. For example of limiting a parameter, you might have a select like: and then build a font filename with: my $fontname = $cgi->param('font'); my $fontfile=$fontpath . $fontname; but watch out when the user manually supplies font with a value like C<../../../some_file_that_crashes_freetype>. So limit the values and validate them: and code like: my $fontname = $cgi->param('font'); $fontname =~ /^\w+$/ or $fontname = 'arial'; # use a default if invalid -e $fontpath . $fontname . ".ttf" or $fontname = 'arial'; my $fontfile = $fontpath . $fontname . '.ttf'; or use a lookup table: my %fonts = ( arial => "arial.ttf", arialb => "arialb.ttf", xfont_helv => "x11/helv.pfb", ); ... my $fontname = $cgi->param('font'); exists $fonts{$fontname} or $fontname = 'arial'; my $fontfile = $fontpath . $fonts{$fontname}; Remember that with perl your code isn't in a sandbox, it's up to you to prevent shooting yourself in the foot. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/samples/samp-tags.html0000644000175000017500000000052612031434615022011 0ustar gregoagregoa Sample form for Imager handling of uploaded images

File:

libimager-perl-1.004+dfsg.orig/samples/samp-scale.cgi0000755000175000017500000000340512263740601021744 0ustar gregoagregoa#!/usr/bin/perl -w =head1 NAME samp-scale.cgi - sample CGI that takes an uploaded image to make a new image using Imager =head1 SYNOPSIS Copy samp-scale.html to your document tree. Copy samp-scale.cgi to your /cgi-bin Browse to samp-scale.html in your browser Select an image file Click on "Scale Image" =cut use strict; use Imager; use CGI; my $cgi = CGI->new; my $filename = $cgi->param('image'); if ($filename) { my $fh = $cgi->upload('image'); if ($fh) { binmode $fh; my $image = Imager->new; if ($image->read(fh=>$fh)) { # scale it to max 200 x 200 my $scaled = $image->scale(xpixels=>200, ypixels=>200, type=>'min'); if ($scaled) { # no line end conversion (or UTF or whatever) binmode STDOUT; # send in the order we provide it ++$|; # give it back to the user - as a JPEG print "Content-Type: image/jpeg\n\n"; $scaled->write(fd=>fileno(STDOUT), type=>'jpeg'); } else { # this should only fail in strange circumstances error("Cannot scale image: ", $image->errstr); } } else { error("Cannot read image: ".$image->errstr); } } else { error("Incorrect form or input tag - check enctype and that the file upload field is type file"); } } else { error("No image was supplied"); } # simple error handler, ideally you'd display the form again with # an error in the right place, but this is a sample sub error { my ($msg) = @_; print "Content-Type: text/plain\n\nError processing form:\n$msg\n"; exit; } =head1 DESCRIPTION This is a sample CGI program that accepts an image file from the browser. Please read L for cautions and explanations. =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/samples/align-string.pl0000644000175000017500000000414212263740601022162 0ustar gregoagregoa#!perl -w use strict; use Imager; my ($font_filename, $size, $out_filename, @text) = @ARGV; @text or usage(); $size =~ /^\d+$/ && $size >= 10 or die "size must be 10 or greater"; my $text = "@text"; my $mark_color = Imager::Color->new('#00F'); my $text_color = Imager::Color->new('#fff'); my $font = Imager::Font->new(file=>$font_filename, size => $size, color => $text_color, aa => 1) or die "Cannot create font from $font_filename: ", Imager->errstr; my @valigns = qw(top center bottom baseline); my @haligns = qw(left start center end right); my $bounds = $font->bounding_box(string => $text); my $text_width = $bounds->total_width; my $text_height = $bounds->text_height; my $img = Imager->new(xsize => $text_width * 2 * @haligns, ysize => $text_height * 2 * @valigns); my $xpos = $text_width; for my $halign (@haligns) { my $ypos = $text_height; for my $valign (@valigns) { # mark the align point $img->line(x1 => $xpos - $size, y1 => $ypos, x2 => $xpos + $size, y2 => $ypos, color => $mark_color); $img->line(x1 => $xpos, y1 => $ypos - $size, x2 => $xpos, y2 => $ypos + $size, color => $mark_color); $img->align_string(font => $font, string => $text, x => $xpos, y => $ypos, halign => $halign, valign => $valign); $ypos += 2 * $text_height; } $xpos += 2 * $text_width; } $img->write(file => $out_filename) or die "Cannot write $out_filename: ", $img->errstr, "\n"; sub usage { die < C displaying a grid of the various C and C options for the Imager align_string() method. Try it with different fonts and strings to get a better understanding of the effect of the different alignments. =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Font =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/samples/flasher.pl0000644000175000017500000000744712031434615021221 0ustar gregoagregoa#!perl use strict; use Imager; use Getopt::Long; my $delay = 10; my $frames = 20; my $low_pct = 30; my $back = '#FFFFFF'; my $verbose = 0; GetOptions('delay|d=i', \$delay, 'frames|f=i', \$frames, 'lowpct|p=i', \$low_pct, 'back|b=s', \$back, 'verbose|v' => \$verbose); my $back_color = Imager::Color->new($back) or die "Cannot convert $back to a color: ", Imager->errstr, "\n"; $low_pct >= 0 && $low_pct < 100 or die "lowpct must be >=0 and < 100\n"; $delay > 0 and $delay < 255 or die "delay must be between 1 and 255\n"; $frames > 1 or die "frames must be > 1\n"; my $in_name = shift or usage(); my $out_name = shift or usage(); my $base = Imager->new; $base->read(file => $in_name) or die "Cannot read image file $in_name: ", $base->errstr, "\n"; # convert to RGBA to simplify the convert() matrix $base = $base->convert(preset => 'rgb') unless $base->getchannels >=3; $base = $base->convert(preset => 'addalpha') unless $base->getchannels == 4; my $width = $base->getwidth; my $height = $base->getheight; my @down; my $down_frames = $frames / 2; my $step = (100 - $low_pct) / $down_frames; my $percent = 100 - $step; ++$|; print "Generating frames\n" if $verbose; for my $frame_no (1 .. $down_frames) { print "\rFrame $frame_no/$down_frames"; # canvas with our background color my $canvas = Imager->new(xsize => $width, ysize => $height); $canvas->box(filled => 1, color => $back_color); # make a version of our original with the alpha scaled my $scale = $percent / 100.0; my $draw = $base->convert(matrix => [ [ 1, 0, 0, 0 ], [ 0, 1, 0, 0 ], [ 0, 0, 1, 0 ], [ 0, 0, 0, $scale ] ]); # draw it on the canvas $canvas->rubthrough(src => $draw); push @down, $canvas; $percent -= $step; } print "\n" if $verbose; # generate a sequence going from the original down to the most faded my @frames = $base; push @frames, @down; # remove the most faded frame so it isn't repeated pop @down; # and back up again push @frames, reverse @down; print "Writing frames\n" if $verbose; Imager->write_multi({ file => $out_name, type => 'gif', gif_loop => 0, # loop forever gif_delay => $delay, translate => 'errdiff', make_colors => 'mediancut', }, @frames) or die "Cannot write $out_name: ", Imager->errstr, "\n"; sub usage { die < | --delay Delay between frames in 1/100 sec. Default 10. -p | --percent Low percentage coverage. Default: 30 -b | --back Color to fade towards, in some format Imager understands. Default: #FFFFFF -f | --frames Rough total number of frames to produce. Default: 20. EOS } =head1 NAME flasher.pl - produces a slowly flashing GIF based on an input image =head1 SYNOPSIS perl flasher.pl [options] input output.gif =head1 DESCRIPTION flasher.pl generates an animation from the given image to C% coverage on a blank image of color C. =head1 OPTIONS =over =item * C<-f> I, C<--frames> I - the total number of frames. This is always rounded up to the next even number. Default: 20 =item * C<-d> I, C<--delay> I - the delay in 1/100 second between frames. Default: 10. =item * C<-p> I, C<--lowpct> I - the lowest coverage of the image. Default: 30 =item * C<-b> I, C<--back> I - the background color to fade to. Default: #FFFFFF. =item * C<-v>, C<--verbose> - produce progress information. =back =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/samples/README0000644000175000017500000000643212263740601020113 0ustar gregoagregoaThis directory includes example code for Imager. If you have sample code to contribute, please contact the maintainer. The notes here just provide a basic description and the functions used. anaglyph.pl Produce a color, grey or pure anaglyph image given left and right images of a stereoscopic pair. Uses transform2() and convert(). replace_color.pl Example using Imager::transform2() to replace one color with another in an image. http://www.perlmonks.org/?node_id=497355 inline_replace_color.pl Example using Inline::C and the Imager API to replace one color with another in an image. interleave.pl Produce an interleaved image given the left and right images of a stereoscopic pair. Note that the source images must be pre-scaled. This includes 3 different implementations, first using transform2(), the second using the internal i_copyto() function and the third using the internal i_glin() and i_plin() functions. samp-form.cgi samp-image.cgi Example that demonstrates generating an image linked from a HTML form. The POD for this sample discusses alternate approaches and security considerations. samp-scale.html samp-scale.cgi Example that demonstrates reading an image uploaded via a HTML form. Produces an output image scaled to fit inside 200x200. samp-tags.html samp-tags.cgi Example that demonstrates reading an image uploaded via a HTML form. Produces a text/plain report of the tags that Imager defined for the image. This and the previous sample are very similar, the intent is to show the common elements and to demonstrate that the output is independent of the input. See the section "Parsing an image posted via CGI" in Imager::Cookbook for cautions and details on reading uploaded images. border.pl Example of adding a border to an image. slant_text.pl Example of drawing transformed text. Draws slanted or rotated text to a new image and saves it to a file. As part of this it demonstrates calculating the transformed bounding box of the text. tk-photo.pl Simple example of making a Tk::Photo object using Imager data. align-string.pl Simple demonstration of the align_string() method. Usage: perl align-string.pl fontfile size outputfile text... eg. perl align-string.pl fontfiles/ImUgly.ttf 60 test.ppm .A. This demonstrates how the various values of halign and valign behave. inline_capture2image.pl Demonstrates using Inline and Imager's API to convert captured BGR image data into an Imager image. flasher.pl Animate an image fading down to a background color and back again. Demonstrates setting an alpha channel with convert(), rubthrough(), and writing animated GIFs. gifscale.pl Scales an animated GIF image, preserving GIF animation information and adjusting the image screen positions to account for the scale factor. quad_to_square.pl Sample from Richard Fairhurst demonstrating the use of the transform2() det() function. Transforms an arbitrary quadrilateral in the input into a square on the output. wiggle.pl Produce an animated GIF that blends back and forth between the two supplied images. If the input images form a stereo pair the GIF can be used for wiggle stereoscopy. drop_shadow.pl Produce a drop shadow based on the source image alpha channel. libimager-perl-1.004+dfsg.orig/samples/interleave.pl0000644000175000017500000000636012263740601021726 0ustar gregoagregoa#!perl -w use strict; use Imager; my $in0_name = shift; my $in1_name = shift; my $out_name = shift or usage(); my $in0 = Imager->new; $in0->read(file=>$in0_name) or die "Cannot load $in0_name: ", $in0->errstr, "\n"; my $in1 = Imager->new; $in1->read(file=>$in1_name) or die "Cannot load $in1_name: ", $in1->errstr, "\n"; $in0->getwidth == $in1->getwidth && $in0->getheight == $in1->getheight or die "Images must be the same width and height\n"; $in0->getwidth == $in1->getwidth or die "Images must have the same number of channels\n"; my $out = interleave_images3($in0, $in1); $out->write(file=>$out_name) or die "Cannot write $out_name: ", $out->errstr, "\n"; sub usage { print <getwidth; my $height = 2 * $even->getheight; my $expr = <$expr, width =>$width, height=>$height }, $even, $odd) or die Imager->errstr; $out; } # i_copyto() # this should really have been possible through the paste method too, # but the paste() interface is too limited for this # so we call i_copyto() directly # http://rt.cpan.org/NoAuth/Bug.html?id=11858 # the code as written here does work though sub interleave_images2 { my ($even, $odd) = @_; my $width = $even->getwidth; my $out = Imager->new(xsize=>$width, ysize=>2 * $even->getheight, channels => $even->getchannels); for my $y (0 .. $even->getheight-1) { Imager::i_copyto($out->{IMG}, $even->{IMG}, 0, $y, $width, $y+1, 0, $y*2); Imager::i_copyto($out->{IMG}, $odd->{IMG}, 0, $y, $width, $y+1, 0, 1+$y*2); } $out; } # this version uses the internal i_glin() and i_plin() functions # as of 0.44 the XS for i_glin() has a bug in that it doesn't copy # the returned colors into the returned color objects # http://rt.cpan.org/NoAuth/Bug.html?id=11860 sub interleave_images3 { my ($even, $odd) = @_; my $width = $even->getwidth; my $out = Imager->new(xsize=>$width, ysize=>2 * $even->getheight, channels => $even->getchannels); for my $y (0 .. $even->getheight-1) { my @row = Imager::i_glin($even->{IMG}, 0, $width, $y); Imager::i_plin($out->{IMG}, 0, $y*2, @row); @row = Imager::i_glin($odd->{IMG}, 0, $width, $y); Imager::i_plin($out->{IMG}, 0, 1+$y*2, @row); } $out; } =head1 NAME interleave.pl - given two identically sized images create an image twice the height with interleaved rows from the source images. =head1 SYNOPSIS perl interleave.pl even_input odd_input output =head1 DESCRIPTION This sample produces an output image with interleaved rows from the two input images. Multiple implementations are included, including two that revealed bugs or limitations in Imager, to demonstrate some different approaches. See http://www.3dexpo.com/interleaved.htm for an example where this might be useful. =head1 AUTHOR Tony Cook =for stopwords Oppenheim Thanks to Dan Oppenheim, who provided the impetus for this sample. =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/samples/inline_replace_color.pl0000644000175000017500000000404712031434615023735 0ustar gregoagregoa#!perl -w use strict; use Imager; =head1 NAME =for stopwords Inline inline_replace_color.pl - replace one color with another in an image, using Inline =head1 SYNOPSIS perl inline_replace_color.pl fromcolor tocolor inimage outimage perl inline_replace_color.pl white 808080 foo.jpg bar.png =head1 DESCRIPTION This is a simple demonstration of using Imager with Inline::C to replace one color in an image with another. Most of the work is done in the inline_replace_color() function. =over =cut # extract parameters my $from = shift; my $to = shift; my $in = shift; my $out = shift or die "Usage: $0 fromcolor tocolor inimage outimage\n"; # convert the colors into objects my $from_color = Imager::Color->new($from) or die "Cannot convert fromcolor $from into a color: ", Imager->errstr, "\n"; my $to_color = Imager::Color->new($to) or die "Cannot convert tocolor $to into a color: ", Imager->errstr, "\n"; # do the work my $img = Imager->new; $img->read(file=>$in) or die "Cannot read image $in: ", $img->errstr, "\n"; # unlike the transform2() version this works in place inline_replace_color($img, $from_color, $to_color); $img->write(file=>$out) or die "Cannot write image $out: ", $img->errstr, "\n"; =item inline_replace_color Called: inline_replace_color($in_image, $from_color, $to_color); Returns a new image object with colors replaced. =cut use Inline C => <<'EOS' => WITH => 'Imager'; void inline_replace_color(Imager::ImgRaw img, Imager::Color from, Imager::Color to) { int x, y, ch; i_color c; for (x = 0; x < img->xsize; ++x) { for (y = 0; y < img->ysize; ++y) { int match = 1; i_gpix(img, x, y, &c); for (ch = 0; ch < img->channels; ++ch) { if (c.channel[ch] != from->channel[ch]) { match = 0; break; } } if (match) i_ppix(img, x, y, to); } } } EOS __END__ =back =head1 REVISION $Revision: 816 $ =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Inline, Imager::API, Imager::Color, Imager::Files =cut libimager-perl-1.004+dfsg.orig/samples/drop_shadow.pl0000644000175000017500000000633512263740601022103 0ustar gregoagregoa#!perl use strict; use Imager; use Getopt::Long; my $bg; my $shadow_size = "10%"; my $offset = "0x0"; my $shadow_color = "#404040"; GetOptions( "bg=s" => \$bg, "size|s=s" => \$shadow_size, "o|offset=s" => \$offset, "s|shadow=s" => \$shadow_color, ); my $infile = shift; my $outfile = shift or die <x - offset of the original image within the shadow -shadow color - color of the shadow EOS my $src = Imager->new(file => $infile) or die "Cannot read image file '$infile': ", Imager->errstr, "\n"; # simplify things by always working in RGB rather than grey $src = $src->convert(preset => "rgb"); if ($shadow_size =~ /^([0-9]+)%$/) { my $dim = $src->getwidth < $src->getheight ? $src->getwidth : $src->getheight; $shadow_size = int($1 * $dim / 100 + 0.5); } my ($x_offset, $y_offset) = $offset =~ /^([+-]?[0-9]+)x([+-]?[0-9]+)$/ or die "$0: invalid offset\n"; my $shc = Imager::Color->new($shadow_color) or die "$0: invalid shadow color: ", Imager->errstr, "\n"; my ($red, $green, $blue) = $shc->rgba; # First create a new image, either with an alpha channel (if you want # transparency behind the shadow) or without, if you want a background # colour: my $out = Imager->new ( xsize => $shadow_size * 2 + $src->getwidth, ysize => $shadow_size * 2 + $src->getheight, channels => 4, ); if ($bg) { # fill it with your background color, if you want one my $bgc = Imager::Color->new($bg) or die "$0: invalid color '$bg'\n"; $out->box(filled => 1, color => $bgc); } # Make a work image to render the shadow on: my $shadow_work = Imager->new ( xsize => $out->getwidth, ysize => $out->getheight, channels => 1, ); if ($src->getchannels == 4) { # Extract the alpha channel from the source image, if the image has no # alpha, then a solid box then it's simpler, first the alpha version: my $alpha = $src->convert(preset => "alpha"); # and draw that on the work shadow: $shadow_work->paste ( src => $alpha, left => $shadow_size, top => $shadow_size, ); } else { # otherwise just draw a box for the non-alpha source: $shadow_work->box ( filled => 1, color => [ 255 ], xmin => $shadow_size, ymin => $shadow_size, xmax => $shadow_size + $src->getwidth() - 1, ymax => $shadow_size + $src->getheight() - 1, ); } # Blur the work shadow: $shadow_work->filter(type => "gaussian", stddev => $shadow_size); # Convert it to an RGB image with alpha: $shadow_work = $shadow_work->convert ( matrix => [ [ 0, $red / 255 ], [ 0, $green / 255 ], [ 0, $blue / 255 ], [ 1 ] ] ) or die $shadow_work->errstr; # Draw that on the output image: $out->rubthrough(src => $shadow_work); # Draw our original image on the output image, perhaps with an offset: $out->rubthrough ( src => $src, tx => $shadow_size + $x_offset, ty => $shadow_size + $y_offset, ); $out->write(file => $outfile) or die "Cannot write to '$outfile': ", $out->errstr, "\n"; libimager-perl-1.004+dfsg.orig/samples/slant_text.pl0000644000175000017500000001203212263740601021746 0ustar gregoagregoa#!perl -w use strict; use Imager; use Imager::Matrix2d; use Getopt::Long; use constant PI => 4 * atan2(1,1); # this sample requires Freetype 2.x $Imager::formats{"ft2"} or die "This sample require Freetype 2.x to be configured in Imager\n"; Getopt::Long::Configure("bundling"); my $angle = 30; my $fg = 'white'; my $bg = 'black'; my $size = 20; my $rotate; GetOptions('angle|a=f' => \$angle, 'size|s=i' => \$size, 'foreground|fg|f=s' => \$fg, 'background|bg|b=s' => \$bg, 'rotate|r' => \$rotate) or usage(); # check for sanity if ($angle < -45 or $angle > 45) { # while values outside this range are valid, the text would be hard # to read die "--angle is limited to the range -45 through +45\n"; } elsif ($size < 10) { die "--size must be 10 or greater\n"; } my $fontfile = shift; my $outfile = shift; @ARGV or usage(); my $text = "@ARGV"; my $angle_rads = $angle * (PI / 180); my $trans; # this is the only difference between rotation and shearing: the # transformation matrix if ($rotate) { $trans = Imager::Matrix2d->rotate(radians => $angle_rads); } else { $trans = Imager::Matrix2d->shear(x=>sin($angle_rads)/cos($angle_rads)); } # only the Freetype 2.x driver supports transformations for now my $font = Imager::Font->new(file=>$fontfile, type=>'ft2') or die "Cannot load font $fontfile: ", Imager->errstr, "\n"; $font->transform(matrix=>$trans); my $bbox = $font->bounding_box(string=>$text, size=>$size); # these are in font co-ordinates, so y is flipped my ($left, $miny, $right, $maxy) = transformed_bounds($bbox, $trans); # convert to image relative co-ordinates my ($top, $bottom) = (-$maxy, -$miny); my ($width, $height) = ($right - $left, $bottom - $top); my $img = Imager->new(xsize=>$width, ysize=>$height); # fill with the background $img->box(filled=>1, color=>$bg); # and draw our string in the right place $img->string(text => $text, color => Imager::Color->new('white'), x => -$left, y => -$top, color => $fg, font => $font, size => $size); $img->write(file=>$outfile) or die "Cannot save $outfile: ",$img->errstr,"\n"; sub transformed_bounds { my ($bbox, $matrix) = @_; my $bounds; for my $point ([ $bbox->start_offset, $bbox->ascent ], [ $bbox->start_offset, $bbox->descent ], [ $bbox->end_offset, $bbox->ascent ], [ $bbox->end_offset, $bbox->descent ]) { $bounds = add_bound($bounds, transform_point(@$point, $matrix)); } @$bounds; } sub transform_point { my ($x, $y, $matrix) = @_; return ( $x * $matrix->[0] + $y * $matrix->[1] + $matrix->[2], $x * $matrix->[3] + $y * $matrix->[4] + $matrix->[5] ); } sub add_bound { my ($bounds, $x, $y) = @_; $bounds or return [ $x, $y, $x, $y ]; $x < $bounds->[0] and $bounds->[0] = $x; $y < $bounds->[1] and $bounds->[1] = $y; $x > $bounds->[2] and $bounds->[2] = $x; $y > $bounds->[3] and $bounds->[3] = $y; $bounds; } sub usage { print < | -a Set the slant angle in degrees, limited to -45 to +45. Default 30. --size | -s Set the text size in pixels. Must be 10 or greater. Default: 20. --foreground | --fg | -f Set the text foreground color. Default: white. --background | --bg | -b Set the image background color. Default: black --rotate | -r Rotate instead of shearing. Default: shear eg. # shear $0 -a 45 fontfiles/ImUgly.ttf output.ppm "something to say" # rotate at 100 pixel font size, blue foregroune, white background $0 -rs 100 -b white -f blue fontfiles/ImUgly.ttf output.ppm Imager EOS exit 1; } =head1 NAME slant_text.pl - sample for drawing transformed text =head1 SYNOPSIS perl slant_text.pl [options] fontfile output text Run without arguments for option details. =head1 DESCRIPTION This is a sample for drawing transformed text. It's complicated by the need to create an image to put the text into, if you have text, a font, and a good idea where it belongs, it's simple to create the transformation matrix: use Imager::Matrix2d; # or call another method for shearing, etc my $matrix = Imager::Matrix2d->rotate(radians=>$some_angle); Feed the transformation matrix to the font: $font->transform(matrix=>$font); then draw the text as normal: $image->string(string=>$some_text, x => $where_x, y => $where_y, font => $font, size => $size); But if you do need the bounds, the code above does show you how to do it. =head1 FUNCTIONS =over =item transformed_bounds Returns a list of bounds: (minx, miny, maxx, maxy) These are offsets from the text's starting point in font co-ordinates - so positive y is I. Note: this returns the bounds of the transformed bounding box, in most cases the actual text will not be touching these boundaries. =cut =back =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =head1 SEE ALSO Imager(1), Imager::Cookbook, Imager::Matrix2d =cut libimager-perl-1.004+dfsg.orig/samples/replace_color.pl0000644000175000017500000000450612031434615022377 0ustar gregoagregoa#!perl -w use strict; use Imager; =head1 NAME replace_color - replace one color with another in an image =head1 SYNOPSIS perl replace_color fromcolor tocolor inimage outimage =head1 DESCRIPTION This is a simple demonstration of Imager::transform2 that replaces one color with another in an image. Note: this works with full color images, and always produces a 3 channel output image - the alpha channel (if any) is not preserved. Most of the work is done in the replace_color() function. =over =cut # extract parameters my $from = shift; my $to = shift; my $in = shift; my $out = shift or die "Usage: $0 fromcolor tocolor inimage outimage\n"; # convert the colors into objects my $from_color = Imager::Color->new($from) or die "Cannot convert fromcolor $from into a color: ", Imager->errstr, "\n"; my $to_color = Imager::Color->new($to) or die "Cannot convert tocolor $to into a color: ", Imager->errstr, "\n"; # do the work my $img = Imager->new; $img->read(file=>$in) or die "Cannot read image $in: ", $img->errstr, "\n"; my $result = replace_color($img, $from_color, $to_color) or die "Cannot replace colors: ", Imager->errstr, "\n"; $result->write(file=>$out) or die "Cannot write image $out: ", $result->errstr, "\n"; =item replace_color Called: my $result = replace_color($in_image, $from_color, $to_color); Returns a new image object with colors replaced. =cut sub replace_color { my ($img, $from_color, $to_color) = @_; my ($from_red, $from_green, $from_blue) = $from_color->rgba; my ($to_red, $to_green, $to_blue) = $to_color->rgba; my $rpnexpr = <<'EOS'; # get the pixel x y getp1 !pix # check against the from_color @pix red from_red eq @pix green from_green eq @pix blue from_blue eq and and # pick a result to_red to_green to_blue rgb @pix ifp EOS # rpnexpr doesn't really support comments - remove them $rpnexpr =~ s/^#.*\n//mg; my %constants = ( from_red => $from_red, from_green => $from_green, from_blue => $from_blue, to_red => $to_red, to_green => $to_green, to_blue => $to_blue, ); return Imager::transform2({ rpnexpr => $rpnexpr, constants => \%constants }, $img); } __END__ =back =head1 REVISION $Revision$ =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager, Imager::Engines, Imager::Color, Imager::Files =cut libimager-perl-1.004+dfsg.orig/samples/wiggle.pl0000644000175000017500000000300212031434615021032 0ustar gregoagregoa#!perl -w use strict; use Imager; my $left_name = shift; my $right_name = shift; my $out_name = shift or die "Usage: $0 left right out\n"; my $left = Imager->new(file => $left_name) or die "Cannot read $left_name: ", Imager->errstr, "\n"; my $right = Imager->new(file => $right_name) or die "Cannot read $right_name: ", Imager->errstr, "\n"; $left = $left->scale; $right = $right->scale; my $steps = 5; my @cycle; push @cycle, $left; my @down; my @delays = ( 50, ( 10 ) x ($steps-1), 50, ( 10 ) x ($steps-1) ); for my $pos (1 .. $steps-1) { my $work = $left->copy; $work->compose(src => $right, opacity => $pos/$steps); push @cycle, $work; unshift @down, $work; } push @cycle, $right, @down; Imager->write_multi({ file => $out_name, gif_delay => \@delays, gif_loop => 0, make_colors => "mediancut", translate => "errdiff" }, @cycle) or die "Cannot write $out_name: ", Imager->errstr, "\n"; =head1 NAME wiggle.pl - wiggle stereoscopy =head1 SYNOPSIS perl wiggle.pl left.jpg right.jpg out.gif =head1 DESCRIPTION Produces an animated GIF that displays left, then a blend of four images leading to right then back again. The left and right images are displayed a little longer. If the left and right images form a stereo pair (and the order doesn't really matter) the output animated GIF is useful for wiggle stereoscopy. =head1 CREDITS =for stopwords Oppenheim Dan Oppenheim described the effect and asked how to implement it. =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/samples/samp-tags.cgi0000755000175000017500000000275312263740601021620 0ustar gregoagregoa#!/usr/bin/perl -w =head1 NAME samp-tags.cgi - sample CGI that takes an uploaded image to produce a report =head1 SYNOPSIS Copy samp-tags.html to your document tree. Copy samp-tags.cgi to your /cgi-bin Browse to samp-tags.html in your browser Select an image file Click on "Report Image Tags" =cut use strict; use Imager; use CGI; my $cgi = CGI->new; my $filename = $cgi->param('image'); if ($filename) { my $fh = $cgi->upload('image'); if ($fh) { binmode $fh; my $image = Imager->new; if ($image->read(fh=>$fh)) { print "Content-Type: text/plain\n\n"; print "File: $filename\n"; my @tags = $image->tags; for my $tag (sort { $a->[0] cmp $b->[0] } @tags) { my $name = shift @$tag; print " $name: @$tag\n"; } } else { error("Cannot read image: ".$image->errstr); } } else { error("Incorrect form or input tag - check enctype and that the file upload field is type file"); } } else { error("No image was supplied"); } # simple error handler, ideally you'd display the form again with # an error in the right place, but this is a sample sub error { my ($msg) = @_; print "Content-Type: text/plain\n\nError processing form:\n$msg\n"; exit; } =head1 DESCRIPTION This is a sample CGI program that accepts an image file from the browser. Please read L for cautions and explanations. =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/samples/quad_to_square.pl0000644000175000017500000000266712031434615022610 0ustar gregoagregoa#!/usr/bin/perl -w use strict; # Convert quadrilateral to square use Imager; my $src=Imager->new(); $src->open(file=>"oldmap_200px.jpg"); # example co-ordinates of quadrilateral my $x0=12; my $y0=4; # top left my $x1=157; my $y1=0; # top right my $x2=140; my $y2=150; # bottom right my $x3=27; my $y3=159; # bottom left my $code=<$code, width=>200, height=>200, constants=>{x0=>$x0,y0=>$y0, x1=>$x1,y1=>$y1, x2=>$x2,y2=>$y2, x3=>$x3,y3=>$y3}}, ($src)); $newimg->write(file=>"output_imager.jpg"); =head1 NAME quad_to_square.pl - transform an arbitrary quadrilateral to a square. =head1 SYNOPSIS perl quad_to_square.pl =head1 DESCRIPTION =for stopwords Fairhurst resized Courtesy Richard Fairhurst: I've been using it to rectify ("square up") a load of roughly scanned maps, so that an arbitrary quadrilateral is resized into a square. The transform2 function is ideal for that. Thought you might be interested to see what people are doing with Imager - feel free to include this in the sample code. =head1 AUTHOR Richard Fairhurst =cut libimager-perl-1.004+dfsg.orig/samples/border.pl0000644000175000017500000001347112031434615021044 0ustar gregoagregoa#!perl -w use strict; use Imager; use Imager::Fountain; use Getopt::Long; Getopt::Long::Configure("bundling"); # see usage() for a description of the parameters we accept my $border_width = 10; my $border_height = 10; my $border_thickness; # sets width and height and overrides them my $fountain; my $color = 'red'; GetOptions('width|w=i' => \$border_width, 'height|h=i' => \$border_height, 'thickness|t=i' => \$border_thickness, 'fountain|f=s' => \$fountain, 'color|c=s' => \$color) or usage(); # make sure we got sane values if (defined $border_thickness) { if ($border_thickness <= 0) { die "--thickness must be positive\n"; } $border_width = $border_height = $border_thickness; } elsif ($border_width < 0) { die "--width must non-negative\n"; } elsif ($border_height < 0) { die "--height must be non-negative\n"; } elsif ($border_width == 0 && $border_height == 0) { # not much point if both are zero die "One of --width or --height must be positive\n"; } my $src_name = shift; my $out_name = shift or usage(); # treat extras as an error @ARGV and usage(); # load the source, let Imager work out the name my $src_image = Imager->new; $src_image->read(file=>$src_name) or die "Cannot read source image $src_name: ", $src_image->errstr, "\n"; my $out_image; if ($fountain) { # add a fountain fill border my ($out_color, $in_color) = split /,/, $fountain, 2; $in_color or die "--fountain '$fountain' invalid\n"; $out_image = fountain_border($src_image, $out_color, $in_color, $border_width, $border_height); } else { $out_image = solid_border($src_image, $color, $border_width, $border_height); } # write it out, and let Imager work out the output format from the # filename $out_image->write(file=>$out_name) or die "Cannot save $out_name: ", $out_image->errstr, "\n"; sub fountain_border { my ($src_image, $out_color_name, $in_color_name, $border_width, $border_height) = @_; my $out_color = Imager::Color->new($out_color_name) or die "Cannot translate color $out_color_name: ", Imager->errstr, "\n"; my $in_color = Imager::Color->new($in_color_name) or die "Cannot translate color $in_color_name: ", Imager->errstr, "\n"; my $fountain = Imager::Fountain->new; $fountain->add ( c0 => $out_color, c1 => $in_color, ); my $out = Imager->new(xsize => $src_image->getwidth() + 2 * $border_width, ysize => $src_image->getheight() + 2 * $border_height, bits => $src_image->bits, channels => $src_image->getchannels); my $width = $out->getwidth; my $height = $out->getheight; # these mark the corners of the inside rectangle, done here # to reduce the redundancy below my $in_left = $border_width - 1; my $in_right = $width - $border_width; my $in_top = $border_height - 1; my $in_bottom = $height - $border_height; # four linear fountain fills, one for each side # Note: we overlap the sides with the top and bottom to avoid # having them both anti-alias against the black background where x==y # (and the other corners) # top $out->polygon(x => [ 0, $width-1, $width-1, 0 ], y => [ 0, 0, $in_top, $in_top ], fill => { fountain => 'linear', segments => $fountain, xa => 0, ya => 0, xb => 0, yb => $border_height }); # bottom $out->polygon(x => [ 0, $width-1, $width-1, 0 ], y => [ $height-1, $height-1, $in_bottom, $in_bottom ], fill => { fountain => 'linear', segments => $fountain, xa => 0, ya => $height-1, xb => 0, yb => $height-$border_height }); # left $out->polygon(x => [ 0, 0, $in_left, $in_left ], y => [ 0, $height-1, $in_bottom, $in_top ], fill => { fountain => 'linear', segments => $fountain, xa => 0, ya => 0, xb => $border_width, yb => 0 }); # right $out->polygon(x => [ $width-1, $width-1, $in_right, $in_right ], y => [ 0, $height-1, $in_bottom, $in_top ], fill => { fountain => 'linear', segments => $fountain, xa => $width-1, ya => 0, xb => $width-$border_width, yb => 0 }); # and put the source in $out->paste(left => $border_width, top => $border_height, img => $src_image); return $out; } sub solid_border { my ($source, $color, $border_width, $border_height) = @_; my $out = Imager->new(xsize => $source->getwidth() + 2 * $border_width, ysize => $source->getheight() + 2 * $border_height, bits => $source->bits, channels => $source->getchannels); # we can do it the lazy way for a solid border - just fill the whole image $out->box(filled => 1, color=>$color) or die "Invalid color '$color':", $out->errstr, "\n"; $out->paste(left => $border_width, top => $border_height, img => $source); return $out; } sub usage { print < | -w Set width of border (default 10) eg. --width 25 --height | -h Set height of border (default 10) eg. --height 30 --thickness | -t Sets width and height of border, overrides -w and -h eg. --thickness 20 --fountain , | -f outcolor,incolor Creates a border that's a linear fountain fill with outcolor at the outside and incolor at the inside. eg. --fountain red,black --color Sets the color of the default solid border. Ignored if --fountain is supplied. (default red) eg. --color blue EOS exit 1; } =head1 NAME border.pl - sample to add borders to an image =head1 SYNOPSIS perl border.pl [options] input output =head1 DESCRIPTION Simple sample of adding borders to an image. =head1 AUTHOR Tony Cook =head1 REVISION $Revision$ =cut libimager-perl-1.004+dfsg.orig/samples/samp-scale.html0000644000175000017500000000052112031434615022135 0ustar gregoagregoa Sample form for Imager handling of uploaded images

File:

libimager-perl-1.004+dfsg.orig/samples/tk-photo.pl0000644000175000017500000000225212263740601021331 0ustar gregoagregoa#!perl -w use strict; use Tk; use Tk::Photo; use MIME::Base64; use Tk::PNG; use Imager; my $image = Imager->new(xsize=>100, ysize=>100); # draw something simple here, you'll probably do something more complex $image->box(filled=>1, color=>'blue'); $image->box(filled=>1, color=>'red', xmin=>20, ymin=>20, xmax=>79, ymax=>79); my $image_data; $image->write(data =>\$image_data, type=>'png') or die "Cannot save image: ", $image->errstr; # supplying binary data didn't work, so we base64 encode it $image_data = encode_base64($image_data); my $main = MainWindow->new; my $tk_image = $main->Photo(-data => $image_data); $main->Label(-image=>$tk_image)->pack; MainLoop; =head1 NAME =for stopwords tk-photo.pl tk-photo.pl - display an Imager image under Tk =head1 SYNOPSIS $ perl tk-photo.pl =head1 DESCRIPTION Simple code to make a Tk::Photo object from an Imager image. This works by: =over =item 1. write the image data to a scalar in PNG format =item 2. Base64 decode the data =item 3. read() it into the photo object, supplying the Base64 encoded data to the C<-data> parameter. =back =head1 REVISION $Revision$ =head1 AUTHOR Tony Cook =cut libimager-perl-1.004+dfsg.orig/imperlio.h0000644000175000017500000000017212263740601017553 0ustar gregoagregoa#ifndef IMAGER_IMPERLIO_H #define IMAGER_IMPERLIO_H extern i_io_glue_t * im_io_new_perlio(pTHX_ PerlIO *handle); #endif libimager-perl-1.004+dfsg.orig/T1/0000755000175000017500000000000012617614576016064 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/T1/typemap0000644000175000017500000000003412263740600017444 0ustar gregoagregoaImager::Font::T1xs T_PTROBJ libimager-perl-1.004+dfsg.orig/T1/imt1.c0000644000175000017500000005012412263740600017065 0ustar gregoagregoa#include "imext.h" #include "imt1.h" #include #include static int t1_get_flags(char const *flags); static char *t1_from_utf8(char const *in, size_t len, int *outlen); static undef_int i_init_t1_low(int t1log); static void t1_push_error(void); static void i_t1_set_aa(int st); static int t1_active_fonts = 0; static int t1_initialized = 0; static int t1_aa = -1; struct i_t1_font_tag { int font_id; }; static i_mutex_t mutex; /* =item i_t1_start() Initialize the font driver. This does not actually initialize T1Lib, it just allocates the mutex we use to gate access to it. =cut */ void i_t1_start(void) { mutex = i_mutex_new(); } /* =item i_init_t1(t1log) Initializes the t1lib font rendering engine. =cut */ undef_int i_init_t1(int t1log) { undef_int result; i_mutex_lock(mutex); result = i_init_t1_low(t1log); i_mutex_unlock(mutex); return result; } static undef_int i_init_t1_low(int t1log) { int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE; mm_log((1,"init_t1(%d)\n", t1log)); i_clear_error(); if (t1_active_fonts) { mm_log((1, "Cannot re-initialize T1 - active fonts\n")); i_push_error(0, "Cannot re-initialize T1 - active fonts"); return 1; } if (t1_initialized) { T1_CloseLib(); t1_initialized = 0; } if (t1log) init_flags |= LOGFILE; if ((T1_InitLib(init_flags) == NULL)){ mm_log((1,"Initialization of t1lib failed\n")); i_push_error(0, "T1_InitLib failed"); return(1); } T1_SetLogLevel(T1LOG_DEBUG); ++t1_initialized; return(0); } /* =item i_close_t1() Shuts the t1lib font rendering engine down. This it seems that this function is never used. =cut */ void i_close_t1(void) { i_mutex_lock(mutex); T1_CloseLib(); t1_initialized = 0; i_mutex_unlock(mutex); } /* =item i_t1_new(pfb, afm) Loads the fonts with the given filenames, returns its font id pfb - path to pfb file for font afm - path to afm file for font =cut */ i_t1_font_t i_t1_new(char *pfb,char *afm) { int font_id; i_t1_font_t font; i_mutex_lock(mutex); i_clear_error(); if (!t1_initialized && i_init_t1_low(0)) { i_mutex_unlock(mutex); return NULL; } mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL"))); font_id = T1_AddFont(pfb); if (font_id<0) { mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id)); t1_push_error(); i_mutex_unlock(mutex); return NULL; } if (afm != NULL) { mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm)); if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm)); } if (T1_LoadFont(font_id)) { mm_log((1, "i_t1_new() -> -1 - T1_LoadFont failed (%d)\n", T1_errno)); t1_push_error(); i_push_error(0, "loading font"); T1_DeleteFont(font_id); i_mutex_unlock(mutex); return NULL; } ++t1_active_fonts; i_mutex_unlock(mutex); font = mymalloc(sizeof(*font)); font->font_id = font_id; mm_log((1, "i_t1_new() -> %p (%d)\n", font, font_id)); return font; } /* =item i_t1_destroy(font) Frees resources for a t1 font with given font id. font - font to free =cut */ int i_t1_destroy(i_t1_font_t font) { int result; i_mutex_lock(mutex); mm_log((1,"i_t1_destroy(font %p (%d))\n", font, font->font_id)); --t1_active_fonts; result = T1_DeleteFont(font->font_id); myfree(font); i_mutex_unlock(mutex); return result; } /* =item i_t1_set_aa(st) Sets the antialiasing level of the t1 library. st - 0 = NONE, 1 = LOW, 2 = HIGH. Must be called with the mutex locked. =cut */ static void i_t1_set_aa(int st) { int i; unsigned long cst[17]; mm_log((1, "i_t1_set_aa(%d)\n", st)); if (t1_aa == st) return; switch(st) { case 0: T1_AASetBitsPerPixel( 8 ); T1_AASetLevel( T1_AA_NONE ); T1_AANSetGrayValues( 0, 255 ); mm_log((1,"setting T1 antialias to none\n")); break; case 1: T1_AASetBitsPerPixel( 8 ); T1_AASetLevel( T1_AA_LOW ); T1_AASetGrayValues( 0,65,127,191,255 ); mm_log((1,"setting T1 antialias to low\n")); break; case 2: T1_AASetBitsPerPixel(8); T1_AASetLevel(T1_AA_HIGH); for(i=0;i<17;i++) cst[i]=(i*255)/16; T1_AAHSetGrayValues( cst ); mm_log((1,"setting T1 antialias to high\n")); } t1_aa = st; } /* =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align,aa) Interface to text rendering into a single channel in an image im pointer to image structure xb x coordinate of start of string yb y coordinate of start of string ( see align ) channel - destination channel fontnum - t1 library font id points - number of points in fontheight str - string to render len - string length align - (0 - top of font glyph | 1 - baseline ) aa - anti-aliasing level =cut */ undef_int i_t1_cp(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char* str,size_t len,int align, int utf8, char const *flags, int aa) { GLYPH *glyph; int xsize,ysize,x,y; i_color val; int mod_flags = t1_get_flags(flags); int fontnum = font->font_id; unsigned int ch_mask_store; i_clear_error(); mm_log((1, "i_t1_cp(font %p (%d), im %p, (xb,yb)=" i_DFp ", channel %d, points %g, str %p, len %u, align %d, utf8 %d, flags '%s', aa %d)\n", font, fontnum, im, i_DFcp(xb, yb), channel, points, str, (unsigned)len, align, utf8, flags, aa)); if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); i_push_error(0, "null image"); return(0); } i_mutex_lock(mutex); i_t1_set_aa(aa); if (utf8) { int worklen; char *work = t1_from_utf8(str, len, &worklen); if (work == NULL) { i_mutex_unlock(mutex); return 0; } glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL); myfree(work); } else { glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL); } if (glyph == NULL) { t1_push_error(); i_push_error(0, "i_t1_cp: T1_AASetString failed"); i_mutex_unlock(mutex); return 0; } mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent)); mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing)); mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY)); mm_log((1,"bpp: %lu\n", (unsigned long)glyph->bpp)); xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing; ysize=glyph->metrics.ascent-glyph->metrics.descent; mm_log((1,"width: %d height: %d\n",xsize,ysize)); ch_mask_store=im->ch_mask; im->ch_mask=1<metrics.leftSideBearing; yb-=glyph->metrics.ascent; } for(y=0;ybits[y*xsize+x]; i_ppix(im,x+xb,y+yb,&val); } im->ch_mask=ch_mask_store; i_mutex_unlock(mutex); return 1; } static void t1_fix_bbox(BBox *bbox, const char *str, size_t len, int advance, int space_position) { /* never called with len == 0 */ if (str[0] == space_position && bbox->llx > 0) bbox->llx = 0; if (str[len-1] == space_position && bbox->urx < advance) bbox->urx = advance; if (bbox->lly > bbox->ury) bbox->lly = bbox->ury = 0; } /* =item i_t1_bbox(handle, fontnum, points, str, len, cords) function to get a strings bounding box given the font id and sizes handle - pointer to font handle fontnum - t1 library font id points - number of points in fontheight str - string to measure len - string length cords - the bounding box (modified in place) =cut */ int i_t1_bbox(i_t1_font_t font, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) { BBox bbox; BBox gbbox; int mod_flags = t1_get_flags(flags); i_img_dim advance; int fontnum = font->font_id; int space_position; i_clear_error(); i_mutex_lock(mutex); space_position = T1_GetEncodingIndex(fontnum, "space"); mm_log((1,"i_t1_bbox(font %p (%d),points %.2f,str '%.*s', len %u)\n", font, fontnum,points,(int)len,str,(unsigned)len)); if (T1_LoadFont(fontnum) == -1) { t1_push_error(); i_mutex_unlock(mutex); return 0; } if (len == 0) { /* len == 0 has special meaning to T1lib, but it means there's nothing to draw, so return that */ bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0; advance = 0; } else { if (utf8) { int worklen; char *work = t1_from_utf8(str, len, &worklen); if (!work) { i_mutex_unlock(mutex); return 0; } advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags); bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags); t1_fix_bbox(&bbox, work, worklen, advance, space_position); myfree(work); } else { advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags); bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags); t1_fix_bbox(&bbox, str, len, advance, space_position); } } gbbox = T1_GetFontBBox(fontnum); mm_log((1,"bbox: (%d, %d, %d, %d, %d, %d)\n", (int)(bbox.llx*points/1000), (int)(gbbox.lly*points/1000), (int)(bbox.urx*points/1000), (int)(gbbox.ury*points/1000), (int)(bbox.lly*points/1000), (int)(bbox.ury*points/1000) )); cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000; cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000; cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000; cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000; cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000; cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000; cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000; cords[BBOX_RIGHT_BEARING] = cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH]; i_mutex_unlock(mutex); return BBOX_RIGHT_BEARING+1; } /* =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, utf8, flags, aa) Interface to text rendering in a single color onto an image im - pointer to image structure xb - x coordinate of start of string yb - y coordinate of start of string ( see align ) cl - color to draw the text in fontnum - t1 library font id points - number of points in fontheight str - char pointer to string to render len - string length align - (0 - top of font glyph | 1 - baseline ) utf8 - str is utf8 flags - formatting flags aa - anti-aliasing level =cut */ undef_int i_t1_text(i_t1_font_t font, i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl, double points,const char* str,size_t len,int align, int utf8, char const *flags, int aa) { GLYPH *glyph; int xsize,ysize,y; int mod_flags = t1_get_flags(flags); i_render *r; int fontnum = font->font_id; mm_log((1, "i_t1_text(font %p (%d), im %p, (xb,yb)=" i_DFp ", cl (%d,%d,%d,%d), points %g, str %p, len %u, align %d, utf8 %d, flags '%s', aa %d)\n", font, fontnum, im, i_DFcp(xb, yb), cl->rgba.r, cl->rgba.g, cl->rgba.b, cl->rgba.a, points, str, (unsigned)len, align, utf8, flags, aa)); i_clear_error(); if (im == NULL) { i_push_error(0, "null image"); mm_log((1,"i_t1_text: Null image in input\n")); return(0); } i_mutex_lock(mutex); i_t1_set_aa(aa); if (utf8) { int worklen; char *work = t1_from_utf8(str, len, &worklen); if (!work) { i_mutex_unlock(mutex); return 0; } glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL); myfree(work); } else { /* T1_AASetString() accepts a char * not a const char */ glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL); } if (glyph == NULL) { mm_log((1, "T1_AASetString failed\n")); t1_push_error(); i_push_error(0, "i_t1_text(): T1_AASetString failed"); i_mutex_unlock(mutex); return 0; } mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent)); mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing)); mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY)); mm_log((1,"bpp: %lu\n",(unsigned long)glyph->bpp)); xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing; ysize=glyph->metrics.ascent-glyph->metrics.descent; mm_log((1,"width: %d height: %d\n",xsize,ysize)); if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; } r = i_render_new(im, xsize); for(y=0;ybits+y*xsize, cl); } i_render_delete(r); i_mutex_unlock(mutex); return 1; } /* =item t1_get_flags(flags) Processes the characters in I to create a mod_flags value used by some T1Lib functions. =cut */ static int t1_get_flags(char const *flags) { int mod_flags = T1_KERNING; while (*flags) { switch (*flags++) { case 'u': case 'U': mod_flags |= T1_UNDERLINE; break; case 'o': case 'O': mod_flags |= T1_OVERLINE; break; case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break; /* ignore anything we don't recognize */ } } return mod_flags; } /* =item t1_from_utf8(char const *in, size_t len, int *outlen) Produces an unencoded version of I by dropping any Unicode character over 255. Returns a newly allocated buffer which should be freed with myfree(). Sets *outlen to the number of bytes used in the output string. =cut */ static char * t1_from_utf8(char const *in, size_t len, int *outlen) { /* at this point len is from a STRLEN which should be size_t and can't be too big for mymalloc */ char *out = mymalloc(len+1); /* rechecked 29jul11 tonyc */ char *p = out; unsigned long c; while (len) { c = i_utf8_advance(&in, &len); if (c == ~0UL) { myfree(out); i_push_error(0, "invalid UTF8 character"); return 0; } /* yeah, just drop them */ if (c < 0x100) { *p++ = (char)c; } } *p = '\0'; *outlen = p - out; return out; } /* =item i_t1_has_chars(font_num, text, len, utf8, out) Check if the given characters are defined by the font. Note that len is the number of bytes, not the number of characters (when utf8 is non-zero). out[char index] will be true if the character exists. Accepts UTF-8, but since T1 can only have 256 characters, any chars with values over 255 will simply be returned as false. Returns the number of characters that were checked. =cut */ int i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8, char *out) { int count = 0; int font_num = font->font_id; i_mutex_lock(mutex); mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %u, utf8 %d)\n", font_num, text, (unsigned)len, utf8)); i_clear_error(); if (T1_LoadFont(font_num)) { t1_push_error(); i_mutex_unlock(mutex); return 0; } while (len) { unsigned long c; if (utf8) { c = i_utf8_advance(&text, &len); if (c == ~0UL) { i_push_error(0, "invalid UTF8 character"); i_mutex_unlock(mutex); return 0; } } else { c = (unsigned char)*text++; --len; } if (c >= 0x100) { /* limit of 256 characters for T1 */ *out++ = 0; } else { char const * name = T1_GetCharName(font_num, (unsigned char)c); if (name) { *out++ = strcmp(name, ".notdef") != 0; } else { mm_log((2, " No name found for character %lx\n", c)); *out++ = 0; } } ++count; } i_mutex_unlock(mutex); return count; } /* =item i_t1_face_name(font, name_buf, name_buf_size) Copies the face name of the given C to C. Returns the number of characters required to store the name (which can be larger than C, including the space required to store the terminating NUL). If name_buf is too small (as specified by name_buf_size) then the name will be truncated. name_buf will always be NUL termintaed. =cut */ int i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) { char *name; int font_num = font->font_id; i_mutex_lock(mutex); T1_errno = 0; if (T1_LoadFont(font_num)) { t1_push_error(); i_mutex_unlock(mutex); return 0; } name = T1_GetFontName(font_num); if (name) { size_t len = strlen(name); strncpy(name_buf, name, name_buf_size); name_buf[name_buf_size-1] = '\0'; i_mutex_unlock(mutex); return len + 1; } else { t1_push_error(); i_mutex_unlock(mutex); return 0; } } int i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf, size_t name_buf_size) { char *name; int font_num = font->font_id; i_clear_error(); if (ch > 0xFF) { return 0; } i_mutex_lock(mutex); if (T1_LoadFont(font_num)) { t1_push_error(); i_mutex_unlock(mutex); return 0; } name = T1_GetCharName(font_num, (unsigned char)ch); if (name) { if (strcmp(name, ".notdef")) { size_t len = strlen(name); strncpy(name_buf, name, name_buf_size); name_buf[name_buf_size-1] = '\0'; i_mutex_unlock(mutex); return len + 1; } else { i_mutex_unlock(mutex); return 0; } } else { t1_push_error(); i_mutex_unlock(mutex); return 0; } } static void t1_push_error(void) { #if T1LIB_VERSION > 5 || T1LIB_VERSION == 5 && T1LIB_VERSION >= 1 /* I don't know when T1_StrError() was introduced, be conservative */ i_push_error(T1_errno, T1_StrError(T1_errno)); #else switch (T1_errno) { case 0: i_push_error(0, "No error"); break; #ifdef T1ERR_SCAN_FONT_FORMAT case T1ERR_SCAN_FONT_FORMAT: i_push_error(T1ERR_SCAN_FONT_FORMAT, "Attempt to Load Multiple Master Font"); break; #endif #ifdef T1ERR_SCAN_FILE_OPEN_ERR case T1ERR_SCAN_FILE_OPEN_ERR: i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "Type 1 Font File Open Error"); break; #endif #ifdef T1ERR_SCAN_OUT_OF_MEMORY case T1ERR_SCAN_OUT_OF_MEMORY: i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "Virtual Memory Exceeded"); break; #endif #ifdef T1ERR_SCAN_ERROR case T1ERR_SCAN_ERROR: i_push_error(T1ERR_SCAN_ERROR, "Syntactical Error Scanning Font File"); break; #endif #ifdef T1ERR_SCAN_FILE_EOF case T1ERR_SCAN_FILE_EOF: i_push_error(T1ERR_SCAN_FILE_EOF, "Premature End of Font File Encountered"); break; #endif #ifdef T1ERR_PATH_ERROR case T1ERR_PATH_ERROR: i_push_error(T1ERR_PATH_ERROR, "Path Construction Error"); break; #endif #ifdef T1ERR_PARSE_ERROR case T1ERR_PARSE_ERROR: i_push_error(T1ERR_PARSE_ERROR, "Font is Corrupt"); break; #endif #ifdef T1ERR_TYPE1_ABORT case T1ERR_TYPE1_ABORT: i_push_error(T1ERR_TYPE1_ABORT, "Rasterization Aborted"); break; #endif #ifdef T1ERR_INVALID_FONTID case T1ERR_INVALID_FONTID: i_push_error(T1ERR_INVALID_FONTID, "Font ID Invalid in this Context"); break; #endif #ifdef T1ERR_INVALID_PARAMETER case T1ERR_INVALID_PARAMETER: i_push_error(T1ERR_INVALID_PARAMETER, "Invalid Argument in Function Call"); break; #endif #ifdef T1ERR_OP_NOT_PERMITTED case T1ERR_OP_NOT_PERMITTED: i_push_error(T1ERR_OP_NOT_PERMITTED, "Operation not Permitted"); break; #endif #ifdef T1ERR_ALLOC_MEM case T1ERR_ALLOC_MEM: i_push_error(T1ERR_ALLOC_MEM, "Memory Allocation Error"); break; #endif #ifdef T1ERR_FILE_OPEN_ERR case T1ERR_FILE_OPEN_ERR: i_push_error(T1ERR_FILE_OPEN_ERR, "Error Opening File"); break; #endif #ifdef T1ERR_UNSPECIFIED case T1ERR_UNSPECIFIED: i_push_error(T1ERR_UNSPECIFIED, "Unspecified T1Lib Error"); break; #endif #ifdef T1ERR_NO_AFM_DATA case T1ERR_NO_AFM_DATA: i_push_error(T1ERR_NO_AFM_DATA, "Missing AFM Data"); break; #endif #ifdef T1ERR_X11 case T1ERR_X11: i_push_error(T1ERR_X11, "X11 Interface Error"); break; #endif #ifdef T1ERR_COMPOSITE_CHAR case T1ERR_COMPOSITE_CHAR: i_push_error(T1ERR_COMPOSITE_CHAR, "Missing Component of Composite Character"); break; #endif #ifdef T1ERR_SCAN_ENCODING case T1ERR_SCAN_ENCODING: i_push_error(T1ERR_SCAN_ENCODING, "Error Scanning Encoding File"); break; #endif default: i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno); } #endif } libimager-perl-1.004+dfsg.orig/T1/README0000644000175000017500000000115012263740600016722 0ustar gregoagregoaImager::Font::T1 provides Type 1 font support for Imager via T1Lib. http://imager.perl.org/ http://www.t1lib.org/ This requires that t1lib is installed, including any development files. For Linux distributions this typically requires installation of the associated -dev or -devel package. See Imager::Install for more information. Imager::Font::T1 is shipped as part of Imager, but if the libraries required aren't found it won't be installed. If you require T1 support via libt1 then add a dependency on Imager::Font::T1. Imager::Font::FT2 provides most of the functionality of Imager::Font::T1 and more.libimager-perl-1.004+dfsg.orig/T1/imt1.h0000644000175000017500000000213112263740600017065 0ustar gregoagregoa#ifndef IMAGER_IMT1_H #define IMAGER_IMT1_H #include "imdatatypes.h" typedef struct i_t1_font_tag *i_t1_font_t; extern void i_t1_start(void); extern undef_int i_init_t1(int t1log); extern void i_close_t1(void); extern i_t1_font_t i_t1_new(char *pfb,char *afm); extern int i_t1_destroy(i_t1_font_t font); extern undef_int i_t1_cp(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char* str,size_t len,int align, int utf8, char const *flags, int aa); extern int i_t1_bbox(i_t1_font_t font,double points,const char *str,size_t len,i_img_dim *cords, int utf8,char const *flags); extern undef_int i_t1_text(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,const i_color *cl,double points,const char* str,size_t len,int align, int utf8, char const *flags, int aa); extern int i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8, char *out); extern int i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size); extern int i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf, size_t name_buf_size); #endif libimager-perl-1.004+dfsg.orig/T1/t/0000755000175000017500000000000012617614576016327 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/T1/t/t10type1.t0000644000175000017500000003647412263740600020102 0ustar gregoagregoa#!perl -w use strict; use Test::More; use Imager ':all'; use Imager::Test qw(diff_text_with_nul is_color3 is_image isnt_image); use Imager::Font::T1; use Cwd qw(getcwd abs_path); #$Imager::DEBUG=1; plan tests => 110; ok($Imager::formats{t1}, "must have t1"); -d "testout" or mkdir "testout"; ok(-d "testout", "make output directory"); init_log("testout/t10type1.log",1); my $deffont = 'fontfiles/dcr10.pfb'; my $fontname_pfb=$ENV{'T1FONTTESTPFB'}||$deffont; my $fontname_afm=$ENV{'T1FONTTESTAFM'}||'./fontfiles/dcr10.afm'; -f $fontname_pfb or skip_all("cannot find fontfile for type 1 test $fontname_pfb"); -f $fontname_afm or skip_all("cannot find fontfile for type 1 test $fontname_afm"); SKIP: { print "# has t1\n"; #i_t1_set_aa(1); unlink "t1lib.log"; # lose it if it exists init(t1log=>0); ok(!-e("t1lib.log"), "disable t1log"); init(t1log=>1); ok(-e("t1lib.log"), "enable t1log"); init(t1log=>0); unlink "t1lib.log"; my $fnum=Imager::Font::T1xs->new($fontname_pfb,$fontname_afm); # this will load the pfb font unless (ok($fnum >= 0, "load font $fontname_pfb")) { skip("without the font I can't do a thing", 90); } my $bgcolor=Imager::Color->new(255,0,0,255); my $overlay=Imager::ImgRaw::new(200,70,3); ok($fnum->cp($overlay,5,50,1,50.0,'XMCLH',1), "i_t1_cp"); i_line($overlay,0,50,100,50,$bgcolor,1); my @bbox=$fnum->bbox(50.0,'XMCLH'); is(@bbox, 8, "i_t1_bbox"); print "# bbox: ($bbox[0], $bbox[1]) - ($bbox[2], $bbox[3])\n"; open(FH,">testout/t30t1font.ppm") || die "cannot open testout/t35t1font.ppm\n"; binmode(FH); # for os2 my $IO = Imager::io_new_fd( fileno(FH) ); i_writeppm_wiol($overlay,$IO); close(FH); $bgcolor=Imager::Color::set($bgcolor,200,200,200,255); my $backgr=Imager::ImgRaw::new(280,300,3); ok($fnum->text($backgr,10,100,$bgcolor,150.0,'test',1,2), "i_t1_text"); # "UTF8" tests # for perl < 5.6 we can hand-encode text # since T1 doesn't support over 256 chars in an encoding we just drop # chars over \xFF # the following is "A\xA1\x{2010}A" # my $text = pack("C*", 0x41, 0xC2, 0xA1, 0xE2, 0x80, 0x90, 0x41); my $alttext = "A\xA1A"; my @utf8box = $fnum->bbox(50.0, $text, 1); is(@utf8box, 8, "utf8 bbox element count"); my @base = $fnum->bbox(50.0, $alttext, 0); is(@base, 8, "alt bbox element count"); my $maxdiff = $fontname_pfb eq $deffont ? 0 : $base[2] / 3; print "# (@utf8box vs @base)\n"; ok(abs($utf8box[2] - $base[2]) <= $maxdiff, "compare box sizes $utf8box[2] vs $base[2] (maxerror $maxdiff)"); # hand-encoded UTF8 drawing ok($fnum->text($backgr, 10, 140, $bgcolor, 32, $text, 1,1), "draw hand-encoded UTF8"); ok($fnum->cp($backgr, 80, 140, 1, 32, $text, 1, 1), "cp hand-encoded UTF8"); { # invalid utf8 my $text = pack("C", 0xC0); ok(!$fnum->text($backgr, 10, 140, $bgcolor, 32, $text, 1, 1), "attempt to draw invalid utf8"); is(Imager->_error_as_msg, "invalid UTF8 character", "check message"); } # ok, try native perl UTF8 if available SKIP: { $] >= 5.006 or skip("perl too old to test native UTF8 support", 5); my $text; # we need to do this in eval to prevent compile time errors in older # versions eval q{$text = "A\xA1\x{2010}A"}; # A, a with ogonek, HYPHEN, A in our test font #$text = "A".chr(0xA1).chr(0x2010)."A"; # this one works too Imager->log("draw UTF8\n"); ok($fnum->text($backgr, 10, 180, $bgcolor, 32, $text, 1), "draw UTF8"); ok($fnum->cp($backgr, 80, 180, 1, 32, $text, 1), "cp UTF8"); @utf8box = $fnum->bbox(50.0, $text, 0); is(@utf8box, 8, "native utf8 bbox element count"); ok(abs($utf8box[2] - $base[2]) <= $maxdiff, "compare box sizes native $utf8box[2] vs $base[2] (maxerror $maxdiff)"); eval q{$text = "A\xA1\xA2\x01\x1F\x{0100}A"}; ok($fnum->text($backgr, 10, 220, $bgcolor, 32, $text, 0, 1, "uso"), "more complex output"); } open(FH,">testout/t30t1font2.ppm") || die "cannot open testout/t35t1font.ppm\n"; binmode(FH); $IO = Imager::io_new_fd( fileno(FH) ); i_writeppm_wiol($backgr, $IO); close(FH); undef $fnum; # character existance tests - uses the special ExistenceTest font my $exists_font = 'fontfiles/ExistenceTest.pfb'; my $exists_afm = 'fontfiles/ExistenceText.afm'; -e $exists_font or die "$exists_font not found"; my $font_num = Imager::Font::T1xs->new($exists_font, $exists_afm); SKIP: { ok($font_num >= 0, 'loading test font') or skip('Could not load test font', 6); # first the list interface my @exists = $font_num->has_chars("!A"); is(@exists, 2, "return count from has_chars"); ok($exists[0], "we have an exclamation mark"); ok(!$exists[1], "we have no uppercase A"); # then the scalar interface my $exists = $font_num->has_chars("!A"); is(length($exists), 2, "return scalar length"); ok(ord(substr($exists, 0, 1)), "we have an exclamation mark"); ok(!ord(substr($exists, 1, 1)), "we have no upper-case A"); undef $font_num; } my $font = Imager::Font->new(file=>$exists_font, type=>'t1'); SKIP: { ok($font, "loaded OO font") or skip("Could not load test font", 24); my @exists = $font->has_chars(string=>"!A"); is(@exists, 2, "return count from has_chars"); ok($exists[0], "we have an exclamation mark"); ok(!$exists[1], "we have no uppercase A"); # then the scalar interface my $exists = $font->has_chars(string=>"!A"); is(length($exists), 2, "return scalar length"); ok(ord(substr($exists, 0, 1)), "we have an exclamation mark"); ok(!ord(substr($exists, 1, 1)), "we have no upper-case A"); # check the advance width my @bbox = $font->bounding_box(string=>'/', size=>100); print "# @bbox\n"; isnt($bbox[2], $bbox[5], "different advance to pos_width"); # names my $face_name = $font->{t1font}->face_name(); print "# face $face_name\n"; is($face_name, 'ExistenceTest', "face name"); $face_name = $font->face_name; is($face_name, 'ExistenceTest', "face name"); my @glyph_names = $font->glyph_names(string=>"!J/"); is($glyph_names[0], 'exclam', "check exclam name OO"); ok(!defined($glyph_names[1]), "check for no J name OO"); is($glyph_names[2], 'slash', "check slash name OO"); # this character chosen since when it's truncated to one byte it # becomes 0x21 or '!' which the font does define my $text = pack("C*", 0xE2, 0x80, 0xA1); # "\x{2021}" as utf-8 @glyph_names = $font->glyph_names(string=>$text, utf8=>1); is($glyph_names[0], undef, "expect no glyph_name for \\x{20A1}"); # make sure a missing string parameter is handled correctly eval { $font->glyph_names(); }; is($@, "", "correct error handling"); cmp_ok(Imager->errstr, '=~', qr/no string parameter/, "error message"); # test extended bounding box results # the test font is known to have a shorter advance width for that char @bbox = $font->bounding_box(string=>"/", size=>100); is(@bbox, 8, "should be 8 entries"); isnt($bbox[6], $bbox[2], "different advance width"); my $bbox = $font->bounding_box(string=>"/", size=>100); cmp_ok($bbox->pos_width, '>', $bbox->advance_width, "OO check"); cmp_ok($bbox->right_bearing, '<', 0, "check right bearing"); cmp_ok($bbox->display_width, '>', $bbox->advance_width, "check display width (roughly)"); # check with a char that fits inside the box $bbox = $font->bounding_box(string=>"!", size=>100); print "# pos width ", $bbox->pos_width, "\n"; # they aren't the same historically for the type 1 driver isnt($bbox->pos_width, $bbox->advance_width, "check backwards compatibility"); cmp_ok($bbox->left_bearing, '>', 0, "left bearing positive"); cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive"); cmp_ok($bbox->display_width, '<', $bbox->advance_width, "display smaller than advance"); } SKIP: { print "# alignment tests\n"; my $font = Imager::Font->new(file=>$deffont, type=>'t1'); ok($font, "loaded deffont OO") or skip("could not load font:".Imager->errstr, 4); my $im = Imager->new(xsize=>140, ysize=>150); my %common = ( font=>$font, size=>40, aa=>1, ); $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue'); $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue'); $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); for my $args ([ x=>5, text=>"A", color=>"white" ], [ x=>40, text=>"y", color=>"white" ], [ x=>75, text=>"A", channel=>1 ], [ x=>110, text=>"y", channel=>1 ]) { ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); } ok($im->write(file=>'testout/t30align.ppm'), "save align image"); } SKIP: { # see http://rt.cpan.org/Ticket/Display.html?id=20555 print "# bounding box around spaces\n"; # SpaceTest contains 3 characters, space, ! and .undef # only characters that define character zero seem to illustrate # the problem we had with spaces my $space_fontfile = "fontfiles/SpaceTest.pfb"; my $font = Imager::Font->new(file => $space_fontfile, type => 't1'); ok($font, "loaded $space_fontfile") or skip("failed to load $space_fontfile" . Imager->errstr, 13); my $bbox = $font->bounding_box(string => "", size => 36); print "# empty string bbox: @$bbox\n"; is($bbox->start_offset, 0, "empty string start_offset"); is($bbox->end_offset, 0, "empty string end_offset"); is($bbox->advance_width, 0, "empty string advance_width"); is($bbox->ascent, 0, "empty string ascent"); is($bbox->descent, 0, "empty string descent"); # a single space my $bbox_space = $font->bounding_box(string => " ", size => 36); print "# space bbox: @$bbox_space\n"; is($bbox_space->start_offset, 0, "single space start_offset"); is($bbox_space->end_offset, $bbox_space->advance_width, "single space end_offset"); cmp_ok($bbox_space->ascent, '>=', $bbox_space->descent, "single space ascent/descent"); my $bbox_bang = $font->bounding_box(string => "!", size => 36); print "# '!' bbox: @$bbox_bang\n"; # space ! space my $bbox_spbangsp = $font->bounding_box(string => " ! ", size => 36); print "# ' ! ' bbox: @$bbox_spbangsp\n"; my $exp_advance = $bbox_bang->advance_width + 2 * $bbox_space->advance_width; is($bbox_spbangsp->advance_width, $exp_advance, "sp ! sp advance_width"); is($bbox_spbangsp->start_offset, 0, "sp ! sp start_offset"); is($bbox_spbangsp->end_offset, $exp_advance, "sp ! sp end_offset"); } SKIP: { # http://rt.cpan.org/Ticket/Display.html?id=20554 # this is "A\xA1\x{2010}A" # the t1 driver is meant to ignore any UTF8 characters over 0xff print "# issue 20554\n"; my $text = pack("C*", 0x41, 0xC2, 0xA1, 0xE2, 0x80, 0x90, 0x41); my $tran_text = "A\xA1A"; my $font = Imager::Font->new(file => 'fontfiles/dcr10.pfb', type => 't1'); $font or skip("cannot load font fontfiles/fcr10.pfb:".Imager->errstr, 1); my $bbox_utf8 = $font->bounding_box(string => $text, utf8 => 1, size => 36); my $bbox_tran = $font->bounding_box(string => $tran_text, size => 36); is($bbox_utf8->advance_width, $bbox_tran->advance_width, "advance widths should match"); } { # string output cut off at NUL ('\0') # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd my $font = Imager::Font->new(file => 'fontfiles/dcr10.pfb', type => 't1'); ok($font, "loaded dcr10.pfb"); diff_text_with_nul("a\\0b vs a", "a\0b", "a", font => $font, color => '#FFFFFF'); diff_text_with_nul("a\\0b vs a", "a\0b", "a", font => $font, channel => 1); # UTF8 encoded \xBF my $pound = pack("C*", 0xC2, 0xBF); diff_text_with_nul("utf8 pound\0pound vs pound", "$pound\0$pound", $pound, font => $font, color => '#FFFFFF', utf8 => 1); diff_text_with_nul("utf8 dash\0dash vs dash", "$pound\0$pound", $pound, font => $font, channel => 1, utf8 => 1); } { # RT 11972 # when rendering to a transparent image the coverage should be # expressed in terms of the alpha channel rather than the color my $font = Imager::Font->new(file=>'fontfiles/dcr10.pfb', type=>'t1'); my $im = Imager->new(xsize => 40, ysize => 20, channels => 4); ok($im->string(string => "AB", size => 20, aa => 2, color => '#F00', x => 0, y => 15, font => $font), "draw to transparent image"); my $im_noalpha = $im->convert(preset => 'noalpha'); my $im_pal = $im->to_paletted(make_colors => 'mediancut'); my @colors = $im_pal->getcolors; is(@colors, 2, "should be only 2 colors"); @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors; is_color3($colors[0], 0, 0, 0, "check we got black"); is_color3($colors[1], 255, 0, 0, "and red"); } SKIP: { # RT 60509 # checks that a c:foo or c:\foo path is handled correctly on win32 my $type = "t1"; $^O eq "MSWin32" || $^O eq "cygwin" or skip("only for win32", 2); my $dir = getcwd or skip("Cannot get cwd", 2); if ($^O eq "cygwin") { $dir = Cygwin::posix_to_win_path($dir); } my $abs_path = abs_path($deffont); my $font = Imager::Font->new(file => $abs_path, type => $type); ok($font, "found font by absolute path") or print "# path $abs_path\n"; undef $font; $^O eq "cygwin" and skip("cygwin doesn't support drive relative DOSsish paths", 1); my ($drive) = $dir =~ /^([a-z]:)/i or skip("cwd has no drive letter", 2); my $drive_path = $drive . $deffont; $font = Imager::Font->new(file => $drive_path, type => $type); ok($font, "found font by drive relative path") or print "# path $drive_path\n"; } { Imager->log("Testing aa levels", 1); my $f1 = Imager::Font->new(file => $deffont, type => "t1"); is($f1->{t1aa}, 2, "should have default aa level"); my $imbase = Imager->new(xsize => 100, ysize => 20); ok($imbase->string(text => "test", size => 18, x => 5, y => 18, color => "#FFF", font => $f1, aa => 1), "draw text with def aa level"); ok(Imager::Font::T1->set_aa_level(1), "set aa level to 1"); my $f2 = Imager::Font->new(file => $deffont, type => "t1"); is($f2->{t1aa}, 1, "new font has new aa level"); my $imaa1 = Imager->new(xsize => 100, ysize => 20); ok($imaa1->string(text => "test", size => 18, x => 5, y => 18, color => "#FFF", font => $f2, aa => 1), "draw text with non-def aa level"); isnt_image($imbase, $imaa1, "images should differ"); ok($f2->set_aa_level(2), "set aa level of font"); is($f2->{t1aa}, 2, "check new aa level"); my $imaa2 = Imager->new(xsize => 100, ysize => 20); ok($imaa2->string(text => "test", size => 18, x => 5, y => 18, color => "#FFF", font => $f2, aa => 1), "draw text with non-def but 2 aa level"); is_image($imbase, $imaa2, "check images match"); } { # error handling check my $im = Imager->new(xsize => 100, ysize => 20); my $fnum = Imager::Font->new(file => $deffont, type => "t1"); ok(!$im->string(font => $fnum, string => "text", size => -10), "set invalid size"); is($im->errstr, "i_t1_text(): T1_AASetString failed: Invalid Argument in Function Call", "check error message"); } } #malloc_state(); libimager-perl-1.004+dfsg.orig/T1/t/t20oo.t0000644000175000017500000000522612263740600017445 0ustar gregoagregoa#!/usr/bin/perl -w use strict; use Imager; use Imager::Test qw(isnt_image); use Test::More tests => 14; # extracted from t/t36oofont.t my $fontname_pfb = "fontfiles/dcr10.pfb"; my $green=Imager::Color->new(92,205,92,128); die $Imager::ERRSTR unless $green; my $red=Imager::Color->new(205, 92, 92, 255); die $Imager::ERRSTR unless $red; -d "testout" or mkdir "testout"; ok(-d "testout", "make output directory"); Imager::init_log("testout/t20oo.log", 1); my $img=Imager->new(xsize=>300, ysize=>100) or die "$Imager::ERRSTR\n"; my $font=Imager::Font->new(file=>$fontname_pfb,size=>25, type => "t1") or die $img->{ERRSTR}; ok(1, "created font"); ok($img->string(font=>$font, text=>"XMCLH", 'x'=>100, 'y'=>100), "draw text"); $img->line(x1=>0, x2=>300, y1=>50, y2=>50, color=>$green); my $text="LLySja"; my @bbox=$font->bounding_box(string=>$text, 'x'=>0, 'y'=>50); is(@bbox, 8, "bounding box list length"); $img->box(box=>\@bbox, color=>$green); # "utf8" support $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41); ok($img->string(font=>$font, text=>$text, 'x'=>100, 'y'=>50, utf8=>1, overline=>1), "draw 'utf8' hand-encoded text"); ok($img->string(font=>$font, text=>$text, 'x'=>140, 'y'=>50, utf8=>1, underline=>1, channel=>2), "channel 'utf8' hand-encoded text"); SKIP: { $] >= 5.006 or skip("perl too old for native utf8", 2); eval q{$text = "A\x{2010}A"}; ok($img->string(font=>$font, text=>$text, 'x'=>180, 'y'=>50, strikethrough=>1), "draw native UTF8 text"); ok($img->string(font=>$font, text=>$text, 'x'=>220, 'y'=>50, channel=>1), "channel native UTF8 text"); } ok($img->write(file=>"testout/t36oofont1.ppm", type=>'pnm'), "write t36oofont1.ppm") or print "# ",$img->errstr,"\n"; { # RT 71469 my $font1 = Imager::Font->new(file => $fontname_pfb, type => "t1"); my $font2 = Imager::Font::T1->new(file => $fontname_pfb); for my $font ($font1, $font2) { print "# ", join(",", $font->{color}->rgba), "\n"; my $im = Imager->new(xsize => 20, ysize => 20, channels => 4); ok($im->string(text => "T", font => $font, y => 15), "draw with default color") or print "# ", $im->errstr, "\n"; my $work = Imager->new(xsize => 20, ysize => 20); my $cmp = $work->copy; $work->rubthrough(src => $im); isnt_image($work, $cmp, "make sure something was drawn"); } } { # open a non-font as a font (test open failure) local $ENV{LANG} = "C"; local $ENV{LC_ALL} = "C"; my $font = Imager::Font->new(file => "t/t20oo.t", type => "t1"); ok(!$font, "should fail to open test script as a font"); print "# ", Imager->errstr, "\n"; } unless ($ENV{IMAGER_KEEP_FILES}) { unlink "testout/t36oofont1.ppm"; } libimager-perl-1.004+dfsg.orig/T1/t/t90std.t0000644000175000017500000000066612263740600017634 0ustar gregoagregoa#!perl -w use strict; use Imager::Test qw(std_font_tests std_font_test_count); use Imager::Font; use Test::More tests => std_font_test_count(); Imager->open_log(log => "testout/t90std.log"); my $font = Imager::Font->new(file => "fontfiles/dcr10.pfb", type => "t1"); SKIP: { $font or skip "Cannot load font", std_font_test_count(); std_font_tests({ font => $font, has_chars => [ 1, '', 1 ]}); } Imager->close_log; libimager-perl-1.004+dfsg.orig/T1/t/t30thread.t0000644000175000017500000000277212263740600020303 0ustar gregoagregoa#!perl -w use strict; use Imager; use Config; my $loaded_threads; BEGIN { if ($Config{useithreads} && $] > 5.008007) { $loaded_threads = eval { require threads; threads->import; 1; }; } } use Test::More; $Config{useithreads} or plan skip_all => "can't test Imager's threads support with no threads"; $] > 5.008007 or plan skip_all => "require a perl with CLONE_SKIP to test Imager's threads support"; $loaded_threads or plan skip_all => "couldn't load threads"; $INC{"Devel/Cover.pm"} and plan skip_all => "threads and Devel::Cover don't get along"; # https://rt.cpan.org/Ticket/Display.html?id=65812 # https://github.com/schwern/test-more/issues/labels/Test-Builder2#issue/100 $Test::More::VERSION =~ /^2\.00_/ and plan skip_all => "threads are hosed in 2.00_06 and presumably all 2.00_*"; plan tests => 8; Imager->open_log(log => "testout/t30thread.log"); my $ft1 = Imager::Font->new(file => "fontfiles/dcr10.pfb", type => "t1"); ok($ft1, "make a font"); ok($ft1->_valid, "and it's valid"); my $ft2; my $thr = threads->create ( sub { ok(!$ft1->_valid, "first font no longer valid"); $ft2 = Imager::Font->new(file => "fontfiles/dcr10.pfb", type => "t1"); ok($ft2, "make a new font in thread"); ok($ft2->_valid, "and it's valid"); 1; }, ); ok($thr->join, "join the thread"); ok($ft1->_valid, "original font still valid in main thread"); is($ft2, undef, "font created in thread shouldn't be set in main thread"); Imager->close_log(); libimager-perl-1.004+dfsg.orig/T1/Makefile.PL0000644000175000017500000000466312567572530020044 0ustar gregoagregoa#!perl -w use strict; use ExtUtils::MakeMaker; use Getopt::Long; use Config; my $verbose = $ENV{IM_VERBOSE}; my @libpaths; my @incpaths; GetOptions("incpath=s", \@incpaths, "libpath=s" => \@libpaths, "verbose|v" => \$verbose); our $BUILDING_IMAGER; our %IMAGER_LIBS; my $MM_ver = eval $ExtUtils::MakeMaker::VERSION; my %opts = ( NAME => 'Imager::Font::T1', VERSION_FROM => 'T1.pm', OBJECT => 'T1.o imt1.o', clean => { FILES => 'testout' }, ); my @inc; if ($BUILDING_IMAGER) { push @inc, "-I.."; unshift @INC, "../lib"; } else { unshift @INC, "inc"; print "T1Lib: building independently\n"; require Imager::ExtUtils; push @inc, Imager::ExtUtils->includes; $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ]; # Imager required configure through use my @Imager_req = ( Imager => "0.95" ); if ($MM_ver >= 6.46) { $opts{META_MERGE} = { configure_requires => { @Imager_req, }, build_requires => { @Imager_req, "Test::More" => "0.47", }, resources => { homepage => "http://imager.perl.org/", repository => "git://git.imager.perl.org/imager.git", bugtracker => "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Imager", }, }; $opts{PREREQ_PM} = { @Imager_req, XSLoader => 0, }; } } require Imager::Probe; my %probe = ( name => "T1Lib", inccheck => sub { -e File::Spec->catfile($_[0], "t1lib.h") }, libbase => "t1", testcode => _t1_test_code(), testcodeheaders => [ "stdio.h", "string.h", "t1lib.h" ], incpath => \@incpaths, libpath => \@libpaths, verbose => $verbose, ); my $probe_res = Imager::Probe->probe(\%probe); if ($probe_res) { $IMAGER_LIBS{T1} = 1; push @inc, $probe_res->{INC}; $opts{LIBS} = $probe_res->{LIBS}; $opts{DEFINE} = $probe_res->{DEFINE}; $opts{INC} = "@inc"; if ($MM_ver > 6.06) { $opts{AUTHOR} = 'Tony Cook '; $opts{ABSTRACT} = 'T1Lib font driver for Imager'; } WriteMakefile(%opts); } else { $IMAGER_LIBS{T1} = 0; if ($BUILDING_IMAGER) { ExtUtils::MakeMaker::WriteEmptyMakefile(%opts); } else { # fail in good way die "OS unsupported: T1Lib headers/libraries not found\n"; } } sub _t1_test_code { return <<'CODE'; int font_id; if (T1_InitLib(IGNORE_CONFIGFILE|IGNORE_FONTDATABASE) == NULL) { fprintf(stderr, "T1Lib: Cannot initialize\n"); return 1; } T1_CloseLib(); return 0; CODE } libimager-perl-1.004+dfsg.orig/T1/fontfiles/0000755000175000017500000000000012617670351020046 5ustar gregoagregoalibimager-perl-1.004+dfsg.orig/T1/fontfiles/SpaceTest.afm0000644000175000017500000000110712263740600022415 0ustar gregoagregoaStartFontMetrics 2.0 Comment Generated by pfaedit Comment Creation Date: Thu Jul 20 21:51:08 2006 FontName SpaceTest FullName SpaceTest FamilyName SpaceTest Weight Medium Notice (Created by Tony Cook,,, with FontForge 1.0 (http://fontforge.sf.net)) ItalicAngle 0 IsFixedPitch false UnderlinePosition -100 UnderlineThickness 50 Version 001.000 EncodingScheme AdobeStandardEncoding FontBBox 72 -24 414 684 StartCharMetrics 3 C 0 ; WX 487 ; N uniFFFD ; B 72 87 414 396 ; C 32 ; WX 500 ; N space ; B 0 0 0 0 ; C 33 ; WX 451 ; N exclam ; B 156 -24 312 684 ; EndCharMetrics EndFontMetrics libimager-perl-1.004+dfsg.orig/T1/fontfiles/SpaceTest.pfb0000644000175000017500000000601312263740600022422 0ustar gregoagregoa€>%!PS-AdobeFont-1.0: SpaceTest 001.000 %%DocumentSuppliedResources: font SpaceTest %%Title: SpaceTest %%Version: 001.000 %%CreationDate: Thu Jul 20 21:51:08 2006 %%Creator: Tony Cook,,, %Copyright: Created by Tony Cook,,, with FontForge 1.0 %Copyright: (http://fontforge.sf.net) % 2006-7-20: Created. % Generated by FontForge 20041218 (http://fontforge.sf.net/) %%EndComments FontDirectory/SpaceTest known{/SpaceTest findfont dup/UniqueID known{dup /UniqueID get 4120929 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 12 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /SpaceTest def /FontBBox {72 -24 414 684 }readonly def /UniqueID 4120929 def /XUID [1021 918 1786090884 13370659] def /PaintType 0 def /FontInfo 10 dict dup begin /version (001.000) readonly def /Notice (Created by Tony Cook,,, with FontForge 1.0 \050http://fontforge.sf.net\051) readonly def /FullName (SpaceTest) readonly def /FamilyName (SpaceTest) readonly def /Weight (Medium) readonly def /FSType 8 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding 256 array 0 1 255 { 1 index exch /.notdef put} for dup 0/uniFFFD put dup 32/space put dup 33/exclam put readonly def currentdict end currentfile eexec €™j0òü(´Ú]ãJÍî’ìH0u&š‰©¶$¼[5-­UÏË÷Úcší¸ßô‹·!ÑrÖÿVPò UÌÖC¢“ÏOT_‡Ê¾Í~Ö¿‚ 2«)‘ª ùhÚaC o—7P2L¶ÊEø¾=ö+†ˆ{L ¦ÒÓ!Fš4Vš4Êâ)úÆhíÄìT˜€XÇÈmCP®h—ˆŸÒ„<…Õƒ}Ÿ+Ÿ»ö$`Xw[£œá zÄ—räµ ×„ >OÍv¦6PÔKx¤Íϸafc!ØÙ<  ôi óëUíò»ˆ2;´Å#©*¤kK›¡]¥9”Ús~ü¤Ž76i‹ì'z¹rPhŒ°r¤ÊÚœEðÑ‘(ÆÍÀa㲃䈹êãeö«TN’#(ÅÄ£DTã_ê$ÔÛ£Ò öt4«Rž©IèF%–%ÝõÛ´¹Ð¡ç=!ó0ã5gâÊ“}ÚnÝ‹Y6†&îjrˆ ÙïÔ?Øù%õñ·‰åe8¿Bç €|§…ö*žò}%DIs¾æñ?ÀÎYúéWèlÛ½Ÿ;ZVŠ'ø•SÕ©øE|"®V¢8ùŒìË‘¯²éÝóÓ0Úo--ÆqˆT„ûz/˜¨æ„/® d(»¥]nO,“ÞVûZ:SVï<ÕÿNQ RÿÙiÛÇÚ½ö0ÍçNî‚1†áÝ]@á´NÚa°Ïl&:„¥ZÖ ý›EE\˜yÍ >”j(ÿ¦…Jמ ‚jÖï<¿ئÛÖÊ(‰@q˜äxW»ø8y¡ù¹ËÛçMé;ÛéU‡îè¾|‰EÖ òRO;zòKÜÃ3n.'r%þˆN\&¦?kôü–ÎiáaêìûŸËEˆoÝ8(„¹˜Ni!²ëU^9¶6ô“ Éä†Ûš6$¯Lϵ;÷GÃê¯%çpùÀ6 ƒjÕ KÏ ¹Ç²YܯþNþ¦Ýw;H}ÎùކÛþäÌ;ðÞμGCiîà­â…oaÅœüÀAŠ“O½¤³ïiÖðzÒÎ=ÍøÈ i?¿­C„œÎž-!¤oFÙ+ùÅ”Z¿tò„º±ÜµÇ2á‰ù2¶µT'Ÿ%ÓTDÆõ¼éta,›; S¼ÏŒbr0_ÄÆTÔÐR "`F{£Ó|Çê„é߀>)2ÎÓˆë¾ÄãÖZ–á þüy6öê·†Š©ãÄ½èøˆäxÚ9pO¬×E0Sd­ªïÍW½^XÏ.Ç?L>Ý­=)x›a‘]È'Ž™Ô)«®©…剋üÖ¿Dk1*éöŸÝÎñKðV1&¢<{’/Æ~” &œ;i¶«"¾Ïspº®´kBç°¾4GNÁnƒWèIö&ÈG)¼\Ø!¼¡Ïp‘¡Ï;yÒÜ“¯jàlLñÐÉÓVïxÇ”ŸËfï»»ÜßÕo÷H-*v7‹»l 1ว›‚X„ »<úB£Åá»+ùù2…Q¨´´‚ü(ïÀ)€  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}if€libimager-perl-1.004+dfsg.orig/T1/fontfiles/ExistenceTest.pfb0000644000175000017500000000616212263740600023323 0ustar gregoagregoa€0%!PS-AdobeFont-1.0: ExistenceTest 001.000 %%DocumentSuppliedResources: font ExistenceTest %%Title: ExistenceTest %%Version: 001.000 %%CreationDate: Thu Jul 20 21:57:23 2006 %%Creator: Tony Cook,,, %Copyright: Created by Tony Cook,,, with PfaEdit 1.0 %Copyright: (http://pfaedit.sf.net) % 2002-12-23: Created. % Generated by FontForge 20041218 (http://fontforge.sf.net/) %%EndComments FontDirectory/ExistenceTest known{/ExistenceTest findfont dup/UniqueID known{dup /UniqueID get 4225394 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /ExistenceTest def /FontBBox {-60 -55 819 775 }readonly def /UniqueID 4225394 def /PaintType 0 def /FontInfo 10 dict dup begin /version (001.000) readonly def /Notice (Created by Tony Cook,,, with PfaEdit 1.0 \050http://pfaedit.sf.net\051) readonly def /FullName (ExistenceTest) readonly def /FamilyName (ExistenceTest) readonly def /Weight (Medium) readonly def /FSType 12 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding 256 array 0 1 255 { 1 index exch /.notdef put} for dup 0/uniFFFD put dup 33/exclam put dup 47/slash put readonly def currentdict end currentfile eexec €o4…>£ö‰à‡Ã¬`0˜šFôü%ž¿msµþËÌÐxœò™aV…­ïC`TäÖÐ%«:¼p‚Ö}]Éèvks~ ¦«êÜçmGÆ€dVF"µÁk——æ¬iyó‘vhæ[e6 \1õ£ŽŸg¡æïIðøÈ¡š%¸2ÉK û:Òd)…äÿ}èT>—àfcä5z«T€èùÿ»´ógèèi|”"ågµbÇPè.)?GîðJiú`ˆ‰Êg‰‚ìXÃAÉ´ße~‹C/ ö€•ô¶‘¼]+Åí몕ñeW‚:×Õœ!’ëܺÄÙêé€~°˜t;ÂfiAþ£~¡QHº'à1 XàE¿AämÖ‹Ì®6ÖÓ¤TA®bÄÚò’W©ŒÇ™Häw>= 2úm˜+à­z5kwZvrJ@-\¬ù¿n.³ŽfN¹ôãú ¥”©:–=ö9ãig[ö”ÛM†è¡Á$V mº líµtIB3š¯ØŒQ¾ ·×ä´â—wÒ†LIUË­`ø‹"wW[¡ËîãþÏNóšz ôÇ–ÖôR¸Ô†`Ìp&ó*:»CæG÷"Ê5%¢F|guæÜ•“<·óçÁ¥žMÎ-2ÂhoÑâ¹­ÛûÍWÌ'W»kMußÀK{"É…Ì¹ÚøŸŸr0+Xí¸Um5©Ï›¿Ù7‘LÊi]5—’®Ì¬ nŠƒP­ççdgZ_>L^˜_EI žÞRÓª1/Aà…bÏ!°I€bCNBçåáPi©2±ûò®xõ’ªÝuW™þT¦7¸=®qÙTS±eæxìBâ±ó$ÆÁbËÏ~8t"a;‹=U4ޝ—b¯ò#ÎÌ•L Ѫ¼ö!{ ,ä: ¡ÙÓͳ¬ ]%¯m]Z?è§xŸ>ñ¯;lZ/fÈ ”I9•;òª8Õâ¢Õ X’Îj-&ÐSrtVã‹Å[ÖÇ ÌŽs_´øƒD=¥_áœ|Žû,§6ÎÐkrÖaÎt,Ê¿;<žT ˆ<åþ¯£ƒä¬íH9ê£á]nüx¸ìxõš,­Kns]éZ3QóL‹qh*¶õ6Iª @Ñ×EìØH‡bìŸ-càÌPå: X´!û[¢@IÃoÍ<0'e5 0) { EXTEND(SP, rc); for (i = 0; i < rc; ++i) PUSHs(sv_2mortal(newSViv(cords[i]))); } undef_int i_t1_text(font,im,xb,yb,cl,points,str_sv,align,utf8=0,flags="",aa=1) Imager::Font::T1xs font Imager::ImgRaw im i_img_dim xb i_img_dim yb Imager::Color cl double points SV* str_sv int align int utf8 const char* flags int aa PREINIT: char *str; STRLEN len; CODE: str = SvPV(str_sv, len); #ifdef SvUTF8 if (SvUTF8(str_sv)) utf8 = 1; #endif RETVAL = i_t1_text(font,im, xb,yb,cl,points,str,len,align, utf8,flags,aa); OUTPUT: RETVAL void i_t1_has_chars(font, text_sv, utf8 = 0) Imager::Font::T1xs font SV *text_sv int utf8 PREINIT: char const *text; STRLEN len; char *work; int count; int i; PPCODE: text = SvPV(text_sv, len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif work = mymalloc(len); count = i_t1_has_chars(font, text, len, utf8, work); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) { PUSHs(boolSV(work[i])); } } else { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(work, count))); } myfree(work); void i_t1_face_name(font) Imager::Font::T1xs font PREINIT: char name[255]; int len; PPCODE: len = i_t1_face_name(font, name, sizeof(name)); if (len) { EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv(name, strlen(name)))); } void i_t1_glyph_names(font, text_sv, utf8 = 0) Imager::Font::T1xs font SV *text_sv int utf8 PREINIT: char const *text; STRLEN work_len; size_t len; char name[255]; SSize_t count = 0; PPCODE: text = SvPV(text_sv, work_len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif i_clear_error(); len = work_len; while (len) { unsigned long ch; if (utf8) { ch = i_utf8_advance(&text, &len); if (ch == ~0UL) { i_push_error(0, "invalid UTF8 character"); XSRETURN(0); } } else { ch = *text++; --len; } EXTEND(SP, count+1); if (i_t1_glyph_name(font, ch, name, sizeof(name))) { ST(count) = sv_2mortal(newSVpv(name, 0)); } else { ST(count) = &PL_sv_undef; } ++count; } XSRETURN(count); int i_t1_CLONE_SKIP(...) CODE: (void)items; /* avoid unused warning */ RETVAL = 1; OUTPUT: RETVAL BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; i_t1_start();libimager-perl-1.004+dfsg.orig/T1/T1.pm0000644000175000017500000001406112460670607016701 0ustar gregoagregoapackage Imager::Font::T1; use strict; use Imager::Color; use vars qw(@ISA $VERSION); @ISA = qw(Imager::Font); use Scalar::Util (); BEGIN { $VERSION = "1.024"; require XSLoader; XSLoader::load('Imager::Font::T1', $VERSION); } *_first = \&Imager::Font::_first; my $t1aa = 2; sub new { my $class = shift; my %hsh=(color=>Imager::Color->new(255,0,0,255), size=>15, @_); unless ($hsh{file}) { $Imager::ERRSTR = "No font file specified"; return; } unless (-e $hsh{file}) { $Imager::ERRSTR = "Font file $hsh{file} not found"; return; } unless ($Imager::formats{t1}) { $Imager::ERRSTR = "Type 1 fonts not supported in this build"; return; } # we want to avoid T1Lib's file search mechanism unless ($hsh{file} =~ m!^/! || $hsh{file} =~ m!^\.\/?/! || $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) { $hsh{file} = './' . $hsh{file}; } if($hsh{afm}) { unless (-e $hsh{afm}) { $Imager::ERRSTR = "Afm file $hsh{afm} not found"; return; } unless ($hsh{afm} =~ m!^/! || $hsh{afm} =~ m!^\./! || $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) { $hsh{file} = './' . $hsh{file}; } } else { $hsh{afm} = 0; } my $font = Imager::Font::T1xs->new($hsh{file},$hsh{afm}); unless ($font) { # the low-level code may miss some error handling Imager->_set_error(Imager->_error_as_msg); return; } return bless { t1font => $font, aa => $hsh{aa} || 0, file => $hsh{file}, type => 't1', size => $hsh{size}, color => $hsh{color}, t1aa => $t1aa, }, $class; } sub _draw { my $self = shift; $self->_valid or return; my %input = @_; my $flags = ''; $flags .= 'u' if $input{underline}; $flags .= 's' if $input{strikethrough}; $flags .= 'o' if $input{overline}; my $aa = $input{aa} ? $self->{t1aa} : 0; if (exists $input{channel}) { $self->{t1font}->cp($input{image}{IMG}, $input{'x'}, $input{'y'}, $input{channel}, $input{size}, $input{string}, $input{align}, $input{utf8}, $flags, $aa) or return; } else { $self->{t1font}->text($input{image}{IMG}, $input{'x'}, $input{'y'}, $input{color}, $input{size}, $input{string}, $input{align}, $input{utf8}, $flags, $aa) or return; } return $self; } sub _bounding_box { my $self = shift; $self->_valid or return; my %input = @_; my $flags = ''; $flags .= 'u' if $input{underline}; $flags .= 's' if $input{strikethrough}; $flags .= 'o' if $input{overline}; my @bbox = $self->{t1font}->bbox($input{size}, $input{string}, $input{utf8}, $flags); unless (@bbox) { Imager->_set_error(Imager->_error_as_msg); return; } return @bbox; } # check if the font has the characters in the given string sub has_chars { my ($self, %hsh) = @_; $self->_valid or return; unless (defined $hsh{string}) { $Imager::ERRSTR = "No string supplied to \$font->has_chars()"; return; } if (wantarray) { my @result = $self->{t1font} ->has_chars($hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0)); unless (@result) { Imager->_set_error(Imager->_error_as_msg); return; } return @result; } else { my $result = $self->{t1font} ->has_chars($hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0)); unless (defined $result) { Imager->_set_error(Imager->_error_as_msg); return; } return $result; } } sub utf8 { 1; } sub can_glyph_names { 1; } sub face_name { my ($self) = @_; $self->_valid or return; return $self->{t1font}->face_name(); } sub glyph_names { my ($self, %input) = @_; $self->_valid or return; my $string = $input{string}; defined $string or return Imager->_set_error("no string parameter passed to glyph_names"); my $utf8 = _first($input{utf8} || 0); my @result = $self->{t1font}->glyph_names($string, $utf8); unless (@result) { Imager->_set_error(Imager->_error_as_msg); return; } return @result; } sub set_aa_level { my ($self, $new_t1aa) = @_; if (!defined $new_t1aa || ($new_t1aa != 1 && $new_t1aa != 2)) { Imager->_set_error("set_aa_level: parameter must be 1 or 2"); return; } if (ref $self) { $self->_valid or return; $self->{t1aa} = $new_t1aa; } else { $t1aa = $new_t1aa; } return 1; } sub _valid { my $self = shift; unless ($self->{t1font} && Scalar::Util::blessed($self->{t1font})) { Imager->_set_error("font object was created in another thread"); return; } return 1; } 1; __END__ =head1 NAME Imager::Font::Type1 - low-level functions for Type1 fonts =head1 DESCRIPTION Imager::Font creates a Imager::Font::Type1 object when asked to create a font object based on a C<.pfb> file. See Imager::Font to see how to use this type. This class provides low-level functions that require the caller to perform data validation By default Imager no longer creates the F log file. You can re-enable that by calling Imager::init() with the C option: Imager::init(t1log=>1); This must be called before creating any fonts. Currently specific to Imager::Font::Type1, you can use the following flags when drawing text or calculating a bounding box: =for stopwords overline strikethrough =over =item * C - Draw the text with an underline. =item * C - Draw the text with an overline. =item * C - Draw the text with a strikethrough. =back Obviously, if you're calculating the bounding box the size of the line is included in the box, and the line isn't drawn :) =head2 Anti-aliasing T1Lib supports multiple levels of anti-aliasing, by default, if you request anti-aliased output, Imager::Font::T1 will use the maximum level. You can override this with the set_t1_aa() method: =over =item set_aa_level() Usage: $font->set_aa_level(1); Imager::Font::T1->set_aa_level(2); Sets the T1Lib anti-aliasing level either for the specified font, or for new font objects. The only parameter must be 1 or 2. Returns true on success. =back =head1 AUTHOR Addi, Tony =cut libimager-perl-1.004+dfsg.orig/fills.c0000644000175000017500000005710712263740600017050 0ustar gregoagregoa#define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" /* =head1 NAME fills.c - implements the basic general fills =head1 SYNOPSIS i_fill_t *fill; i_color c1, c2; i_fcolor fc1, fc2; int combine; fill = i_new_fill_solidf(&fc1, combine); fill = i_new_fill_solid(&c1, combine); fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy); fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy); fill = i_new_fill_image(im, matrix, xoff, yoff, combine); fill = i_new_fill_opacity(fill, alpha_mult); i_fill_destroy(fill); =head1 DESCRIPTION Implements the basic general fills, which can be used for filling some shapes and for flood fills. Each fill can implement up to 3 functions: =over =item fill_with_color called for fills on 8-bit images. This can be NULL in which case the fill_with_colorf function is called. =item fill_with_fcolor called for fills on non-8-bit images or when fill_with_color is NULL. =item destroy called by i_fill_destroy() if non-NULL, to release any extra resources that the fill may need. =back fill_with_color and fill_with_fcolor are basically the same function except that the first works with lines of i_color and the second with lines of i_fcolor. If the combines member if non-zero the line data is populated from the target image before calling fill_with_*color. fill_with_color needs to fill the I parameter with the fill pixels. If combines is non-zero it the fill pixels should be combined with the existing data. The current fills are: =over =item * solid fill =item * hatched fill =item * fountain fill =back Fountain fill is implemented by L. Other fills that could be implemented include: =over =item * image - an image tiled over the fill area, with an offset either horizontally or vertically. =item * checkerboard - combine 2 fills in a checkerboard =item * combine - combine the levels of 2 other fills based in the levels of an image =item * regmach - use the register machine to generate colors =back =over =cut */ static i_color fcolor_to_color(const i_fcolor *c) { int ch; i_color out; for (ch = 0; ch < MAXCHANNELS; ++ch) out.channel[ch] = SampleFTo8(c->channel[ch]); return out; } static i_fcolor color_to_fcolor(const i_color *c) { int ch; i_fcolor out; for (ch = 0; ch < MAXCHANNELS; ++ch) out.channel[ch] = Sample8ToF(c->channel[ch]); return out; } /* alpha combine in with out */ #define COMBINE(out, in, channels) \ { \ int ch; \ for (ch = 0; ch < (channels); ++ch) { \ (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \ + (in).channel[ch] * (in).channel[3]) / 255; \ } \ } /* alpha combine in with out, in this case in is a simple array of samples, potentially not integers - the mult combiner uses doubles for accuracy */ #define COMBINEA(out, in, channels) \ { \ int ch; \ for (ch = 0; ch < (channels); ++ch) { \ (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \ + (in)[ch] * (in)[3]) / 255; \ } \ } #define COMBINEF(out, in, channels) \ { \ int ch; \ for (ch = 0; ch < (channels); ++ch) { \ (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \ + (in).channel[ch] * (in).channel[3]; \ } \ } typedef struct { i_fill_t base; i_color c; i_fcolor fc; } i_fill_solid_t; static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *); static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *); static i_fill_solid_t base_solid_fill = { { fill_solid, fill_solidf, NULL, NULL, NULL, }, }; /* =item i_fill_destroy(fill) =order 90 =category Fills =synopsis i_fill_destroy(fill); Call to destroy any fill object. =cut */ void i_fill_destroy(i_fill_t *fill) { if (fill->destroy) (fill->destroy)(fill); myfree(fill); } /* =item i_new_fill_solidf(color, combine) =category Fills =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine); Create a solid fill based on a float color. If combine is non-zero then alpha values will be combined. =cut */ i_fill_t * i_new_fill_solidf(const i_fcolor *c, int combine) { int ch; i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */ *fill = base_solid_fill; if (combine) { i_get_combine(combine, &fill->base.combine, &fill->base.combinef); } fill->fc = *c; for (ch = 0; ch < MAXCHANNELS; ++ch) { fill->c.channel[ch] = SampleFTo8(c->channel[ch]); } return &fill->base; } /* =item i_new_fill_solid(color, combine) =category Fills =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine); Create a solid fill based on an 8-bit color. If combine is non-zero then alpha values will be combined. =cut */ i_fill_t * i_new_fill_solid(const i_color *c, int combine) { int ch; i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */ *fill = base_solid_fill; if (combine) { i_get_combine(combine, &fill->base.combine, &fill->base.combinef); } fill->c = *c; for (ch = 0; ch < MAXCHANNELS; ++ch) { fill->fc.channel[ch] = Sample8ToF(c->channel[ch]); } return &fill->base; } static unsigned char builtin_hatches[][8] = { { /* 1x1 checkerboard */ 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, }, { /* 2x2 checkerboard */ 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, }, { /* 4 x 4 checkerboard */ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, }, { /* single vertical lines */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, }, { /* double vertical lines */ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, }, { /* quad vertical lines */ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, }, { /* single hlines */ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, { /* double hlines */ 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, }, { /* quad hlines */ 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, }, { /* single / */ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, }, { /* single \ */ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, }, { /* double / */ 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, }, { /* double \ */ 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, }, { /* single grid */ 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }, { /* double grid */ 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88, }, { /* quad grid */ 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, }, { /* single dots */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, { /* 4 dots */ 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, }, { /* 16 dots */ 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, }, { /* simple stipple */ 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00, }, { /* weave */ 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF, }, { /* single cross hatch */ 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01, }, { /* double cross hatch */ 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11, }, { /* vertical lozenge */ 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA, }, { /* horizontal lozenge */ 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07, }, { /* scales overlapping downwards */ 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3, }, { /* scales overlapping upwards */ 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01, }, { /* scales overlapping leftwards */ 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84, }, { /* scales overlapping rightwards */ 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1, }, { /* denser stipple */ 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11, }, { /* L-shaped tiles */ 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90, }, { /* wider stipple */ 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00, }, }; typedef struct { i_fill_t base; i_color fg, bg; i_fcolor ffg, fbg; unsigned char hatch[8]; i_img_dim dx, dy; } i_fill_hatch_t; static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data); static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data); static i_fill_t * i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy); /* =item i_new_fill_hatch(C, C, C, C, C, C, C) =category Fills =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy); Creates a new hatched fill with the C color used for the 1 bits in the hatch and C for the 0 bits. If C is non-zero alpha values will be combined. If C is non-NULL it should be a pointer to 8 bytes of the hash definition, with the high-bits to the left. If C is NULL then one of the standard hatches is used. (C, C) are an offset into the hatch which can be used to hatch adjoining areas out of alignment, or to align the origin of a hatch with the side of a filled area. =cut */ i_fill_t * i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) { return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch, dx, dy); } /* =item i_new_fill_hatchf(C, C, C, C, C, C, C) =category Fills =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy); Creates a new hatched fill with the C color used for the 1 bits in the hatch and C for the 0 bits. If C is non-zero alpha values will be combined. If C is non-NULL it should be a pointer to 8 bytes of the hash definition, with the high-bits to the left. If C is NULL then one of the standard hatches is used. (C, C) are an offset into the hatch which can be used to hatch adjoining areas out of alignment, or to align the origin of a hatch with the side of a filled area. =cut */ i_fill_t * i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) { return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch, dx, dy); } static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data); static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data); struct i_fill_image_t { i_fill_t base; i_img *src; i_img_dim xoff, yoff; int has_matrix; double matrix[9]; }; static struct i_fill_image_t image_fill_proto = { { fill_image, fill_imagef, NULL } }; /* =item i_new_fill_image(C, C, C, C, C) =category Fills =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine); Create an image based fill. matrix is an array of 9 doubles representing a transformation matrix. C and C are the offset into the image to start filling from. =cut */ i_fill_t * i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine) { struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */ *fill = image_fill_proto; if (combine) { i_get_combine(combine, &fill->base.combine, &fill->base.combinef); } else { fill->base.combine = NULL; fill->base.combinef = NULL; } fill->src = im; if (xoff < 0) xoff += im->xsize; fill->xoff = xoff; if (yoff < 0) yoff += im->ysize; fill->yoff = yoff; if (matrix) { fill->has_matrix = 1; memcpy(fill->matrix, matrix, sizeof(fill->matrix)); } else fill->has_matrix = 0; return &fill->base; } static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data); static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data); struct i_fill_opacity_t { i_fill_t base; i_fill_t *other_fill; double alpha_mult; }; static struct i_fill_opacity_t opacity_fill_proto = { { fill_opacity, fill_opacityf, NULL } }; i_fill_t * i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) { struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill)); *fill = opacity_fill_proto; fill->base.combine = base_fill->combine; fill->base.combinef = base_fill->combinef; fill->other_fill = base_fill; fill->alpha_mult = alpha_mult; if (!base_fill->f_fill_with_color) { /* base fill only does floating, so we only do that too */ fill->base.f_fill_with_color = NULL; } return &fill->base; } #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill)) /* =back =head1 INTERNAL FUNCTIONS =over =item fill_solid(fill, x, y, width, channels, data) The 8-bit sample fill function for non-combining solid fills. =cut */ static void fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data) { i_color c = T_SOLID_FILL(fill)->c; i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1); while (width-- > 0) { *data++ = c; } } /* =item fill_solid(fill, x, y, width, channels, data) The floating sample fill function for non-combining solid fills. =cut */ static void fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data) { i_fcolor c = T_SOLID_FILL(fill)->fc; i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1); while (width-- > 0) { *data++ = c; } } static i_fill_hatch_t hatch_fill_proto = { { fill_hatch, fill_hatchf, NULL } }; /* =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy) Implements creation of hatch fill objects. =cut */ static i_fill_t * i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg, int combine, int hatch, const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) { i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */ *fill = hatch_fill_proto; /* Some Sun C didn't like the condition expressions that were here. See https://rt.cpan.org/Ticket/Display.html?id=21944 */ if (fg) fill->fg = *fg; else fill->fg = fcolor_to_color(ffg); if (bg) fill->bg = *bg; else fill->bg = fcolor_to_color(fbg); if (ffg) fill->ffg = *ffg; else fill->ffg = color_to_fcolor(fg); if (fbg) fill->fbg = *fbg; else fill->fbg = color_to_fcolor(bg); if (combine) { i_get_combine(combine, &fill->base.combine, &fill->base.combinef); } else { fill->base.combine = NULL; fill->base.combinef = NULL; } if (cust_hatch) { memcpy(fill->hatch, cust_hatch, 8); } else { if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches)) hatch = 0; memcpy(fill->hatch, builtin_hatches[hatch], 8); } fill->dx = dx & 7; fill->dy = dy & 7; return &fill->base; } /* =item fill_hatch(fill, x, y, width, channels, data) The 8-bit sample fill function for hatched fills. =cut */ static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data) { i_fill_hatch_t *f = (i_fill_hatch_t *)fill; int byte = f->hatch[(y + f->dy) & 7]; int xpos = (x + f->dx) & 7; int mask = 128 >> xpos; i_color fg = f->fg; i_color bg = f->bg; if (channels < 3) { i_adapt_colors(2, 4, &fg, 1); i_adapt_colors(2, 4, &bg, 1); } while (width-- > 0) { if (byte & mask) *data++ = fg; else *data++ = bg; if ((mask >>= 1) == 0) mask = 128; } } /* =item fill_hatchf(fill, x, y, width, channels, data) The floating sample fill function for hatched fills. =cut */ static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data) { i_fill_hatch_t *f = (i_fill_hatch_t *)fill; int byte = f->hatch[(y + f->dy) & 7]; int xpos = (x + f->dx) & 7; int mask = 128 >> xpos; i_fcolor fg = f->ffg; i_fcolor bg = f->fbg; if (channels < 3) { i_adapt_fcolors(2, 4, &fg, 1); i_adapt_fcolors(2, 4, &bg, 1); } while (width-- > 0) { if (byte & mask) *data++ = fg; else *data++ = bg; if ((mask >>= 1) == 0) mask = 128; } } /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */ /* linear interpolation */ static i_color interp_i_color(i_color before, i_color after, double pos, int channels) { i_color out; int ch; pos -= floor(pos); for (ch = 0; ch < channels; ++ch) out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch]; if (channels > 3 && out.channel[3]) for (ch = 0; ch < channels; ++ch) if (ch != 3) { int temp = out.channel[ch] * 255 / out.channel[3]; if (temp > 255) temp = 255; out.channel[ch] = temp; } return out; } /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */ /* linear interpolation */ static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos, int channels) { i_fcolor out; int ch; pos -= floor(pos); for (ch = 0; ch < channels; ++ch) out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch]; if (out.channel[3]) for (ch = 0; ch < channels; ++ch) if (ch != 3) { int temp = out.channel[ch] / out.channel[3]; if (temp > 1.0) temp = 1.0; out.channel[ch] = temp; } return out; } /* =item fill_image(fill, x, y, width, channels, data, work) =cut */ static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data) { struct i_fill_image_t *f = (struct i_fill_image_t *)fill; i_img_dim i = 0; i_color *out = data; int want_channels = channels > 2 ? 4 : 2; if (f->has_matrix) { /* the hard way */ while (i < width) { double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2]; double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5]; double ix = floor(rx / f->src->xsize); double iy = floor(ry / f->src->ysize); i_color c[2][2]; i_color c2[2]; i_img_dim dy; if (f->xoff) { rx += iy * f->xoff; ix = floor(rx / f->src->xsize); } else if (f->yoff) { ry += ix * f->yoff; iy = floor(ry / f->src->ysize); } rx -= ix * f->src->xsize; ry -= iy * f->src->ysize; for (dy = 0; dy < 2; ++dy) { if ((i_img_dim)rx == f->src->xsize-1) { i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]); i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]); } else { i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize, c[dy]); } c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels); } *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels); ++i; } } else { /* the easy way */ /* this should be possible to optimize to use i_glin() */ while (i < width) { i_img_dim rx = x+i; i_img_dim ry = y; i_img_dim ix = rx / f->src->xsize; i_img_dim iy = ry / f->src->ysize; if (f->xoff) { rx += iy * f->xoff; ix = rx / f->src->xsize; } else if (f->yoff) { ry += ix * f->yoff; iy = ry / f->src->ysize; } rx -= ix * f->src->xsize; ry -= iy * f->src->ysize; i_gpix(f->src, rx, ry, out); ++out; ++i; } } if (f->src->channels != want_channels) i_adapt_colors(want_channels, f->src->channels, data, width); } /* =item fill_imagef(fill, x, y, width, channels, data, work) =cut */ static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data) { struct i_fill_image_t *f = (struct i_fill_image_t *)fill; i_img_dim i = 0; int want_channels = channels > 2 ? 4 : 2; if (f->has_matrix) { i_fcolor *work_data = data; /* the hard way */ while (i < width) { double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2]; double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5]; double ix = floor(rx / f->src->xsize); double iy = floor(ry / f->src->ysize); i_fcolor c[2][2]; i_fcolor c2[2]; i_img_dim dy; if (f->xoff) { rx += iy * f->xoff; ix = floor(rx / f->src->xsize); } else if (f->yoff) { ry += ix * f->yoff; iy = floor(ry / f->src->ysize); } rx -= ix * f->src->xsize; ry -= iy * f->src->ysize; for (dy = 0; dy < 2; ++dy) { if ((i_img_dim)rx == f->src->xsize-1) { i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]); i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]); } else { i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize, c[dy]); } c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels); } *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels); ++i; } } else { i_fcolor *work_data = data; /* the easy way */ /* this should be possible to optimize to use i_glin() */ while (i < width) { i_img_dim rx = x+i; i_img_dim ry = y; i_img_dim ix = rx / f->src->xsize; i_img_dim iy = ry / f->src->ysize; if (f->xoff) { rx += iy * f->xoff; ix = rx / f->src->xsize; } else if (f->yoff) { ry += ix * f->yoff; iy = ry / f->src->xsize; } rx -= ix * f->src->xsize; ry -= iy * f->src->ysize; i_gpixf(f->src, rx, ry, work_data); ++work_data; ++i; } } if (f->src->channels != want_channels) i_adapt_fcolors(want_channels, f->src->channels, data, width); } static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_color *data) { struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill; int alpha_chan = channels > 2 ? 3 : 1; i_color *datap = data; (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data); while (width--) { double new_alpha = datap->channel[alpha_chan] * f->alpha_mult; if (new_alpha < 0) datap->channel[alpha_chan] = 0; else if (new_alpha > 255) datap->channel[alpha_chan] = 255; else datap->channel[alpha_chan] = (int)(new_alpha + 0.5); ++datap; } } static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, i_fcolor *data) { struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill; int alpha_chan = channels > 2 ? 3 : 1; i_fcolor *datap = data; (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data); while (width--) { double new_alpha = datap->channel[alpha_chan] * f->alpha_mult; if (new_alpha < 0) datap->channel[alpha_chan] = 0; else if (new_alpha > 1.0) datap->channel[alpha_chan] = 1.0; else datap->channel[alpha_chan] = new_alpha; ++datap; } } /* =back =head1 AUTHOR Tony Cook =head1 SEE ALSO Imager(3) =cut */ libimager-perl-1.004+dfsg.orig/limits.c0000644000175000017500000001232012263740601017225 0ustar gregoagregoa/* =head1 NAME limits.c - manages data/functions for limiting the sizes of images read from files. =head1 SYNOPSIS // user code if (!i_set_image_file_limits(max_width, max_height, max_bytes)) { // error } i_get_image_file_limits(&max_width, &max_height, &max_bytes); // file reader implementations if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) { // error handling } =head1 DESCRIPTION Manage limits for image files read by Imager. Setting a value of zero means that limit will be ignored. =over =cut */ #define IMAGER_NO_CONTEXT #include "imageri.h" /* =item im_set_image_file_limits(ctx, width, height, bytes) XX =category Files =synopsis im_set_image_file_limits(aIMCTX, 500, 500, 1000000); =synopsis i_set_image_file_limits(500, 500, 1000000); Set limits on the sizes of images read by Imager. Setting a limit to 0 means that limit is ignored. Negative limits result in failure. Parameters: =over =item * i_img_dim width, height - maximum width and height. =item * size_t bytes - maximum size in memory in bytes. A value of zero sets this limit to one gigabyte. =back Returns non-zero on success. Also callable as C. =cut */ int im_set_image_file_limits(pIMCTX, i_img_dim width, i_img_dim height, size_t bytes) { i_clear_error(); if (width < 0) { i_push_error(0, "width must be non-negative"); return 0; } if (height < 0) { i_push_error(0, "height must be non-negative"); return 0; } if (bytes < 0) { i_push_error(0, "bytes must be non-negative"); return 0; } aIMCTX->max_width = width; aIMCTX->max_height = height; aIMCTX->max_bytes = bytes ? bytes : DEF_BYTES_LIMIT; return 1; } /* =item im_get_image_file_limits(ctx, &width, &height, &bytes) XX =category Files =synopsis im_get_image_file_limits(aIMCTX, &width, &height, &bytes) =synopsis i_get_image_file_limits(&width, &height, &bytes) Retrieves the file limits set by i_set_image_file_limits(). =over =item * i_img_dim *width, *height - the maximum width and height of the image. =item * size_t *bytes - size in memory of the image in bytes. =back Also callable as C. =cut */ int im_get_image_file_limits(pIMCTX, i_img_dim *width, i_img_dim *height, size_t *bytes) { im_clear_error(aIMCTX); *width = aIMCTX->max_width; *height = aIMCTX->max_height; *bytes = aIMCTX->max_bytes; return 1; } /* =item im_int_check_image_file_limits(width, height, channels, sample_size) XX =category Files =synopsis im_int_check_image_file_limits(aIMCTX, width, height, channels, sizeof(i_sample_t)) =synopsis i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t)) Checks the size of a file in memory against the configured image file limits. This also range checks the values to those permitted by Imager and checks for overflows in calculating the size. Returns non-zero if the file is within limits. This function is intended to be called by image file read functions. Also callable as C. =cut */ int im_int_check_image_file_limits(pIMCTX, i_img_dim width, i_img_dim height, int channels, size_t sample_size) { size_t bytes; im_clear_error(aIMCTX); if (width <= 0) { im_push_errorf(aIMCTX, 0, "file size limit - image width of %" i_DF " is not positive", i_DFc(width)); return 0; } if (aIMCTX->max_width && width > aIMCTX->max_width) { im_push_errorf(aIMCTX, 0, "file size limit - image width of %" i_DF " exceeds limit of %" i_DF, i_DFc(width), i_DFc(aIMCTX->max_width)); return 0; } if (height <= 0) { im_push_errorf(aIMCTX, 0, "file size limit - image height of %" i_DF " is not positive", i_DFc(height)); return 0; } if (aIMCTX->max_height && height > aIMCTX->max_height) { im_push_errorf(aIMCTX, 0, "file size limit - image height of %" i_DF " exceeds limit of %" i_DF, i_DFc(height), i_DFc(aIMCTX->max_height)); return 0; } if (channels < 1 || channels > MAXCHANNELS) { im_push_errorf(aIMCTX, 0, "file size limit - channels %d out of range", channels); return 0; } if (sample_size < 1 || sample_size > sizeof(long double)) { im_push_errorf(aIMCTX, 0, "file size limit - sample_size %ld out of range", (long)sample_size); return 0; } /* This overflow check is a bit more paranoid than usual. We don't protect it under max_bytes since we always want to check for overflow. */ bytes = width * height * channels * sample_size; if (bytes / width != height * channels * sample_size || bytes / height != width * channels * sample_size) { im_push_error(aIMCTX, 0, "file size limit - integer overflow calculating storage"); return 0; } if (aIMCTX->max_bytes) { if (bytes > aIMCTX->max_bytes) { im_push_errorf(aIMCTX, 0, "file size limit - storage size of %lu " "exceeds limit of %lu", (unsigned long)bytes, (unsigned long)aIMCTX->max_bytes); return 0; } } return 1; } libimager-perl-1.004+dfsg.orig/combine.im0000644000175000017500000000345112031434614017525 0ustar gregoagregoa/* =head1 NAME combine.im - combining channels into an image =head1 SYNOPSIS out = i_combine(imgs, channels, count); =head1 DESCRIPTION Combines channels from the input images into an output image. =over =cut */ #include "imager.h" i_img * i_combine(i_img **imgs, const int *channels, int in_count) { i_img *out = NULL; int maxbits = 0; i_img *maximg = NULL; int i; i_img_dim width, height; i_img_dim x, y; i_clear_error(); if (in_count <= 0) { i_push_error(0, "At least one image must be supplied"); return NULL; } if (in_count > MAXCHANNELS) { i_push_errorf(0, "Maximum of %d channels, you supplied %d", MAXCHANNELS, in_count); return NULL; } width = imgs[0]->xsize; height = imgs[0]->ysize; for (i = 0; i < in_count; ++i) { if (imgs[i]->bits > maxbits) { maximg = imgs[i]; maxbits = maximg->bits; } if (imgs[i]->xsize < width) width = imgs[i]->xsize; if (imgs[i]->ysize < height) height = imgs[i]->ysize; if (channels[i] < 0) { i_push_error(0, "Channel numbers must be zero or positive"); return NULL; } if (channels[i] >= imgs[i]->channels) { i_push_errorf(0, "Channel %d for image %d is too high (%d channels)", channels[i], i, imgs[i]->channels); return NULL; } } out = i_sametype_chans(maximg, width, height, in_count); if (!out) return NULL; #code maxbits <= i_8_bits IM_SAMPLE_T *in_row = mymalloc(sizeof(IM_SAMPLE_T) * width); IM_COLOR *out_row = mymalloc(sizeof(IM_COLOR) * width); for (y = 0; y < height; ++y) { for (i = 0; i < in_count; ++i) { IM_GSAMP(imgs[i], 0, width, y, in_row, channels + i, 1); for (x = 0; x < width; ++x) out_row[x].channel[i] = in_row[x]; } IM_PLIN(out, 0, width, y, out_row); } #/code return out; } libimager-perl-1.004+dfsg.orig/scale.im0000644000175000017500000002276112263740601017210 0ustar gregoagregoa#include "imager.h" #include "imageri.h" /* * i_scale_mixing() is based on code contained in pnmscale.c, part of * the netpbm distribution. No code was copied from pnmscale but * the algorthm was and for this I thank the netpbm crew. * * Tony */ /* pnmscale.c - read a portable anymap and scale it ** ** Copyright (C) 1989, 1991 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. ** */ static void zero_row(i_fcolor *row, i_img_dim width, int channels); #code static void IM_SUFFIX(accum_output_row)(i_fcolor *accum, double fraction, IM_COLOR const *in, i_img_dim width, int channels); static void IM_SUFFIX(horizontal_scale)(IM_COLOR *out, i_img_dim out_width, i_fcolor const *in, i_img_dim in_width, int channels); #/code /* =item i_scale_mixing Returns a new image scaled to the given size. Unlike i_scale_axis() this does a simple coverage of pixels from source to target and doesn't resample. Adapted from pnmscale. =cut */ i_img * i_scale_mixing(i_img *src, i_img_dim x_out, i_img_dim y_out) { i_img *result; i_fcolor *accum_row = NULL; i_img_dim x, y; int ch; size_t accum_row_bytes; double rowsleft, fracrowtofill; i_img_dim rowsread; double y_scale; mm_log((1, "i_scale_mixing(src %p, out(" i_DFp "))\n", src, i_DFcp(x_out, y_out))); i_clear_error(); if (x_out <= 0) { i_push_errorf(0, "output width %" i_DF " invalid", i_DFc(x_out)); return NULL; } if (y_out <= 0) { i_push_errorf(0, "output height %" i_DF " invalid", i_DFc(y_out)); return NULL; } if (x_out == src->xsize && y_out == src->ysize) { return i_copy(src); } y_scale = y_out / (double)src->ysize; result = i_sametype_chans(src, x_out, y_out, src->channels); if (!result) return NULL; accum_row_bytes = sizeof(i_fcolor) * src->xsize; if (accum_row_bytes / sizeof(i_fcolor) != src->xsize) { i_push_error(0, "integer overflow allocating accumulator row buffer"); return NULL; } accum_row = mymalloc(accum_row_bytes); #code src->bits <= 8 IM_COLOR *in_row = NULL; IM_COLOR *xscale_row = NULL; size_t in_row_bytes, out_row_bytes; in_row_bytes = sizeof(IM_COLOR) * src->xsize; if (in_row_bytes / sizeof(IM_COLOR) != src->xsize) { i_push_error(0, "integer overflow allocating input row buffer"); return NULL; } out_row_bytes = sizeof(IM_COLOR) * x_out; if (out_row_bytes / sizeof(IM_COLOR) != x_out) { i_push_error(0, "integer overflow allocating output row buffer"); return NULL; } in_row = mymalloc(in_row_bytes); xscale_row = mymalloc(out_row_bytes); rowsread = 0; rowsleft = 0.0; for (y = 0; y < y_out; ++y) { if (y_out == src->ysize) { /* no vertical scaling, just load it */ #ifdef IM_EIGHT_BIT i_img_dim x; int ch; /* load and convert to doubles */ IM_GLIN(src, 0, src->xsize, y, in_row); for (x = 0; x < src->xsize; ++x) { for (ch = 0; ch < src->channels; ++ch) { accum_row[x].channel[ch] = in_row[x].channel[ch]; } } #else IM_GLIN(src, 0, src->xsize, y, accum_row); #endif /* alpha adjust if needed */ if (src->channels == 2 || src->channels == 4) { for (x = 0; x < src->xsize; ++x) { for (ch = 0; ch < src->channels-1; ++ch) { accum_row[x].channel[ch] *= accum_row[x].channel[src->channels-1] / IM_SAMPLE_MAX; } } } } else { fracrowtofill = 1.0; zero_row(accum_row, src->xsize, src->channels); while (fracrowtofill > 0) { if (rowsleft <= 0) { if (rowsread < src->ysize) { IM_GLIN(src, 0, src->xsize, rowsread, in_row); ++rowsread; } /* else just use the last row read */ rowsleft = y_scale; } if (rowsleft < fracrowtofill) { IM_SUFFIX(accum_output_row)(accum_row, rowsleft, in_row, src->xsize, src->channels); fracrowtofill -= rowsleft; rowsleft = 0; } else { IM_SUFFIX(accum_output_row)(accum_row, fracrowtofill, in_row, src->xsize, src->channels); rowsleft -= fracrowtofill; fracrowtofill = 0; } } } /* we've accumulated a vertically scaled row */ if (x_out == src->xsize) { #if IM_EIGHT_BIT i_img_dim x; int ch; /* no need to scale, but we need to convert it */ if (result->channels == 2 || result->channels == 4) { int alpha_chan = result->channels - 1; for (x = 0; x < x_out; ++x) { double alpha = accum_row[x].channel[alpha_chan] / IM_SAMPLE_MAX; if (alpha) { for (ch = 0; ch < alpha_chan; ++ch) { int val = accum_row[x].channel[ch] / alpha + 0.5; xscale_row[x].channel[ch] = IM_LIMIT(val); } } else { /* rather than leaving any color data as whatever was originally in the buffer, set it to black. This isn't any more correct, but it gives us more compressible image data. RT #32324 */ for (ch = 0; ch < alpha_chan; ++ch) { xscale_row[x].channel[ch] = 0; } } xscale_row[x].channel[alpha_chan] = IM_LIMIT(accum_row[x].channel[alpha_chan]+0.5); } } else { for (x = 0; x < x_out; ++x) { for (ch = 0; ch < result->channels; ++ch) xscale_row[x].channel[ch] = IM_LIMIT(accum_row[x].channel[ch]+0.5); } } IM_PLIN(result, 0, x_out, y, xscale_row); #else IM_PLIN(result, 0, x_out, y, accum_row); #endif } else { IM_SUFFIX(horizontal_scale)(xscale_row, x_out, accum_row, src->xsize, src->channels); IM_PLIN(result, 0, x_out, y, xscale_row); } } myfree(in_row); myfree(xscale_row); #/code myfree(accum_row); return result; } static void zero_row(i_fcolor *row, i_img_dim width, int channels) { i_img_dim x; int ch; /* with IEEE floats we could just use memset() but that's not safe in general under ANSI C. memset() is slightly faster. */ for (x = 0; x < width; ++x) { for (ch = 0; ch < channels; ++ch) row[x].channel[ch] = 0.0; } } #code static void IM_SUFFIX(accum_output_row)(i_fcolor *accum, double fraction, IM_COLOR const *in, i_img_dim width, int channels) { i_img_dim x; int ch; /* it's tempting to change this into a pointer iteration loop but modern CPUs do the indexing as part of the instruction */ if (channels == 2 || channels == 4) { for (x = 0; x < width; ++x) { for (ch = 0; ch < channels-1; ++ch) { accum[x].channel[ch] += in[x].channel[ch] * fraction * in[x].channel[channels-1] / IM_SAMPLE_MAX; } accum[x].channel[channels-1] += in[x].channel[channels-1] * fraction; } } else { for (x = 0; x < width; ++x) { for (ch = 0; ch < channels; ++ch) { accum[x].channel[ch] += in[x].channel[ch] * fraction; } } } } static void IM_SUFFIX(horizontal_scale)(IM_COLOR *out, i_img_dim out_width, i_fcolor const *in, i_img_dim in_width, int channels) { double frac_col_to_fill, frac_col_left; i_img_dim in_x; i_img_dim out_x; double x_scale = (double)out_width / in_width; int ch; double accum[MAXCHANNELS] = { 0 }; frac_col_to_fill = 1.0; out_x = 0; for (in_x = 0; in_x < in_width; ++in_x) { frac_col_left = x_scale; while (frac_col_left >= frac_col_to_fill) { for (ch = 0; ch < channels; ++ch) accum[ch] += frac_col_to_fill * in[in_x].channel[ch]; if (channels == 2 || channels == 4) { int alpha_chan = channels - 1; double alpha = accum[alpha_chan] / IM_SAMPLE_MAX; if (alpha) { for (ch = 0; ch < alpha_chan; ++ch) { IM_WORK_T val = IM_ROUND(accum[ch] / alpha); out[out_x].channel[ch] = IM_LIMIT(val); } } else { for (ch = 0; ch < alpha_chan; ++ch) { /* See RT #32324 (and mention above) */ out[out_x].channel[ch] = 0; } } out[out_x].channel[alpha_chan] = IM_LIMIT(IM_ROUND(accum[alpha_chan])); } else { for (ch = 0; ch < channels; ++ch) { IM_WORK_T val = IM_ROUND(accum[ch]); out[out_x].channel[ch] = IM_LIMIT(val); } } for (ch = 0; ch < channels; ++ch) accum[ch] = 0; frac_col_left -= frac_col_to_fill; frac_col_to_fill = 1.0; ++out_x; } if (frac_col_left > 0) { for (ch = 0; ch < channels; ++ch) { accum[ch] += frac_col_left * in[in_x].channel[ch]; } frac_col_to_fill -= frac_col_left; } } if (out_x < out_width-1 || out_x > out_width) { i_fatal(3, "Internal error: out_x %d out of range (width %d)", out_x, out_width); } if (out_x < out_width) { for (ch = 0; ch < channels; ++ch) { accum[ch] += frac_col_to_fill * in[in_width-1].channel[ch]; } if (channels == 2 || channels == 4) { int alpha_chan = channels - 1; double alpha = accum[alpha_chan] / IM_SAMPLE_MAX; if (alpha) { for (ch = 0; ch < alpha_chan; ++ch) { IM_WORK_T val = IM_ROUND(accum[ch] / alpha); out[out_x].channel[ch] = IM_LIMIT(val); } } else { for (ch = 0; ch < alpha_chan; ++ch) { /* See RT #32324 (and mention above) */ out[out_x].channel[ch] = 0; } } out[out_x].channel[alpha_chan] = IM_LIMIT(IM_ROUND(accum[alpha_chan])); } else { for (ch = 0; ch < channels; ++ch) { IM_WORK_T val = IM_ROUND(accum[ch]); out[out_x].channel[ch] = IM_LIMIT(val); } } } } #/code