예제 #1
0
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;x<x2+1;x++) {
    i_ppix(im,x,y1,val);
    i_ppix(im,x,y2,val);
  }
  for(y=y1;y<y2+1;y++) {
    i_ppix(im,x1,y,val);
    i_ppix(im,x2,y,val);
  }
}
예제 #2
0
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;
}
예제 #3
0
void
i_line_dda(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_color *val) {

  double dy;
  i_img_dim x;
  
  for(x=x1; x<=x2; x++) {
    dy = y1+ (x-x1)/(double)(x2-x1)*(y2-y1);
    i_ppix(im, x, (i_img_dim)(dy+0.5), val);
  }
}
예제 #4
0
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;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
      c = bmap[y*(bit->cols)+x];
      val.channel[channel] = c;
      i_ppix(im,x+xb,y+yb,&val);
    }
  } else {
    for(y=0;y<bit->rows;y++) {
      unsigned mask = 0x80;
      unsigned char *p = bmap + y * bit->cols;

      for(x=0;x<bit->width;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;
}
예제 #5
0
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;
}
예제 #6
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;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
    i_gpix(im,x,y,&rcolor);
    for(i=0;i<im->channels;i++) rcolor.channel[i]=saturate((255*(rcolor.channel[i]-a))/(b-a));    
    i_ppix(im,x,y,&rcolor);
  }

}
예제 #7
0
파일: mandelbrot.c 프로젝트: gitpan/Imager
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]); 
    }
  }
}
예제 #8
0
/*
=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<rad> with
color.

=cut
*/
void
i_circle_aa(i_img *im, double x, double y, double rad, const i_color *val) {
  i_mmarray dot;
  i_color temp;
  i_img_dim ly;
  dIMCTXim(im);

  im_log((aIMCTX, 1, "i_circle_aa(im %p, centre(" i_DFp "), rad %.2f, val %p)\n",
	  im, i_DFcp(x, y), rad, val));

  i_mmarray_cr(&dot,16*im->ysize);
  make_minmax_list(aIMCTX, &dot, x, y, rad);

  for(ly = 0; ly<im->ysize; ly++) {
    int ix, cy, minx = INT_MAX, maxx = INT_MIN;

    /* Find the left/rightmost set subpixels */
    for(cy = 0; cy<16; cy++) {
      frac tmin = dot.data[ly*16+cy].min;
      frac tmax = dot.data[ly*16+cy].max;
      if (tmax == -1) continue;

      if (minx > tmin) minx = tmin;
      if (maxx < tmax) maxx = tmax;
    }

    if (maxx == INT_MIN) continue; /* no work to be done for this row of pixels */

    minx /= 16;
    maxx /= 16;
    for(ix=minx; ix<=maxx; ix++) {
      int cnt = i_pixel_coverage(&dot, ix, ly);
      if (cnt>255) cnt = 255;
      if (cnt) { /* should never be true */
	int ch;
	float ratio = (float)cnt/255.0;
	i_gpix(im, ix, ly, &temp);
	for(ch=0;ch<im->channels; ch++) temp.channel[ch] = (unsigned char)((float)val->channel[ch]*ratio + (float)temp.channel[ch]*(1.0-ratio));
	i_ppix(im, ix, ly, &temp);
      }
    }
  }
  i_mmarray_dst(&dot);
}
예제 #9
0
파일: mandel.c 프로젝트: gitpan/Imager
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]); 
    }
  }
}
예제 #10
0
/* unused? */
void
i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val) {
  i_img_dim i,x;
  for(i=0;i<ar->lines;i++) if (ar->data[i].max!=-1) for(x=ar->data[i].min;x<ar->data[i].max;x++) i_ppix(im,x,i,val);
}
예제 #11
0
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; x<x2-1; x++) {
      int ch;
      i_color tval;
      double t = (dy) ? -(float)(p)/(float)(dx2) : 1;
      double t1, t2;

      if (t<0) t = 0;
      t1 = 1-t;
      t2 = t;

      i_gpix(im,x+1,y,&tval);
      for(ch=0;ch<im->channels;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;ch<im->channels;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; y<y2-1; y++) {
      int ch;
      i_color tval;
      double t = (dx) ? -(double)(p)/(double)(dy2) : 1;
      double t1, t2;
      
      if (t<0) t = 0;
      t1 = 1-t;
      t2 = t;

      i_gpix(im,x,y+1,&tval);
      for(ch=0;ch<im->channels;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;ch<im->channels;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);
  }
}
예제 #12
0
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<x2-1; x++) {
      if (p<0) {
        p += dy2;
      } else {
        y += cpy;
        p += dy2-dx2;
      }
      i_ppix(im, x+1, y, val);
    }
  } 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 - dy;

    x = x1;
    
    for(y=y1; y<y2-1; y++) {
      if (p<0) {
        p  += dx2;
      } else {
        x += cpx;
        p += dx2-dy2;
      }
      i_ppix(im, x, y+1, val);
    }
  }
  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);
  }
}
예제 #13
0
파일: imext.c 프로젝트: tonycoz/imager
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);
}
예제 #14
0
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;
}
예제 #15
0
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;
}
예제 #16
0
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;
}
예제 #17
0
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<<channel;

  if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
  
  for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
    val.channel[channel]=glyph->bits[y*xsize+x];
    i_ppix(im,x+xb,y+yb,&val);
  }
  
  im->ch_mask=ch_mask_store;

  i_mutex_unlock(mutex);

  return 1;
}