fz_error *
fz_newpixmapwithrect(fz_pixmap **pixp, fz_irect r, int n, int a)
{
	return fz_newpixmap(pixp,
				r.x0, r.y0,
				r.x1 - r.x0,
				r.y1 - r.y0, n, a);
}
Beispiel #2
0
static void
fz_drawfillimage(void *user, fz_pixmap *image, fz_matrix ctm, float alpha)
{
	fz_drawdevice *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_pixmap *converted = nil;
	fz_pixmap *scaled = nil;
	int dx, dy;

	if (!model)
	{
		fz_warn("cannot render image directly to an alpha mask");
		return;
	}

	if (image->w == 0 || image->h == 0)
		return;

	if (image->colorspace != model)
	{
		converted = fz_newpixmap(model, image->x, image->y, image->w, image->h);
		fz_convertpixmap(image, converted);
		image = converted;
	}

#ifdef SMOOTHSCALE
	dx = sqrtf(ctm.a * ctm.a + ctm.c * ctm.c);
	dy = sqrtf(ctm.b * ctm.b + ctm.d * ctm.d);
	if (dx < image->w && dy < image->h)
	{
		scaled = fz_smoothtransformpixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy);
		if (scaled == NULL)
		{
			if (dx < 1)
				dx = 1;
			if (dy < 1)
				dy = 1;
			scaled = fz_smoothscalepixmap(image, image->x, image->y, dx, dy);
		}
		if (scaled != NULL)
			image = scaled;
	}
#else
	if (fz_calcimagescale(image, ctm, &dx, &dy))
	{
		scaled = fz_scalepixmap(image, dx, dy);
		image = scaled;
	}
#endif

	fz_paintimage(dev->dest, dev->scissor, image, ctm, alpha * 255);

	if (scaled)
		fz_droppixmap(scaled);
	if (converted)
		fz_droppixmap(converted);
}
fz_error *
fz_newpixmapcopy(fz_pixmap **pixp, fz_pixmap *old)
{
	fz_error *error;
	error = fz_newpixmap(pixp, old->x, old->y, old->w, old->h, old->n, old->a);
	if (error)
		return error;
	memcpy((*pixp)->p, old->p, old->w * old->h * (old->n + old->a));
	return nil;
}
Beispiel #4
0
fz_error *
fz_newpixmapcopy(fz_pixmap **pixp, fz_pixmap *old)
{
	fz_error *error;
	error = fz_newpixmap(pixp, old->x, old->y, old->w, old->h, old->n);
	if (error)
		return error;
	memcpy((*pixp)->samples, old->samples, old->w * old->h * old->n);
	return nil;
}
fz_pixmap *
fz_rendert3glyph(fz_font *font, int gid, fz_matrix trm)
{
	fz_error error;
	fz_matrix ctm;
	fz_buffer *contents;
	fz_bbox bbox;
	fz_device *dev;
	fz_glyphcache *cache;
	fz_pixmap *glyph;
	fz_pixmap *result;

	if (gid < 0 || gid > 255)
		return NULL;

	contents = font->t3procs[gid];
	if (!contents)
		return NULL;

	ctm = fz_concat(font->t3matrix, trm);
	dev = fz_newbboxdevice(&bbox);
	error = font->t3run(font->t3xref, font->t3resources, contents, dev, ctm);
	if (error)
		fz_catch(error, "cannot draw type3 glyph");
	fz_freedevice(dev);

	glyph = fz_newpixmap(fz_devicegray, bbox.x0-1, bbox.y0-1, bbox.x1 - bbox.x0 + 1, bbox.y1 - bbox.y0 + 1);
	fz_clearpixmap(glyph, 0);

	cache = fz_newglyphcache();
	dev = fz_newdrawdevice(cache, glyph);
	error = font->t3run(font->t3xref, font->t3resources, contents, dev, ctm);
	if (error)
		fz_catch(error, "cannot draw type3 glyph");
	fz_freedevice(dev);
	fz_freeglyphcache(cache);

	result = fz_alphafromgray(glyph, 0);
	fz_droppixmap(glyph);

	return result;
}
Beispiel #6
0
static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark *drawtimes)
{
	fz_error error;
	fz_matrix ctm;
	fz_irect bbox;
	fz_pixmap *pix;
	char name[256];
	char pnmhdr[256];
	int i, x, y, w, h, b, bh;
	int fd = -1;
	long start;
	long end;
	long elapsed;
	fz_md5 digest;

	if (!drawpattern)
		fz_md5init(&digest);

	drawloadpage(pagenum, loadtimes);

	if (benchmark)
		gettime(&start);

	ctm = fz_identity();
	ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1));
	ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom));
	ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate));

	bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox));
	w = bbox.x1 - bbox.x0;
	h = bbox.y1 - bbox.y0;
	bh = h / drawbands;

	if (drawpattern)
	{
		sprintf(name, drawpattern, drawcount++);
		fd = open(name, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
		if (fd < 0)
			die(fz_throw("ioerror: could not open file '%s'", name));

		sprintf(pnmhdr, "P6\n%d %d\n255\n", w, h);
		write(fd, pnmhdr, strlen(pnmhdr));
	}

	error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4);
	if (error)
		die(error);

	memset(pix->samples, 0xff, pix->h * pix->w * pix->n);

	for (b = 0; b < drawbands; b++)
	{
		if (drawbands > 1)
			fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands);

		error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm);
		if (error)
			die(error);

		if (drawpattern)
		{
			for (y = 0; y < pix->h; y++)
			{
				unsigned char *src = pix->samples + y * pix->w * 4;
				unsigned char *dst = src;

				for (x = 0; x < pix->w; x++)
				{
					dst[x * 3 + 0] = src[x * 4 + 1];
					dst[x * 3 + 1] = src[x * 4 + 2];
					dst[x * 3 + 2] = src[x * 4 + 3];
				}

				write(fd, dst, pix->w * 3);

				memset(src, 0xff, pix->w * 4);
			}
		}

		if (!drawpattern)
			fz_md5update(&digest, pix->samples, pix->h * pix->w * 4);

		pix->y += bh;
		if (pix->y + pix->h > bbox.y1)
			pix->h = bbox.y1 - pix->y;
	}

	fz_droppixmap(pix);

	if (!drawpattern) {
		unsigned char buf[16];
		fz_md5final(&digest, buf);
		for (i = 0; i < 16; i++)
			fprintf(stderr, "%02x", buf[i]);
	}

	if (drawpattern)
		close(fd);

	drawfreepage();

	if (benchmark)
	{
		gettime(&end);
		elapsed = end - start;

		if (elapsed < drawtimes->min)
		{
			drawtimes->min = elapsed;
			drawtimes->minpage = pagenum;
		}
		if (elapsed > drawtimes->max)
		{
			drawtimes->max = elapsed;
			drawtimes->maxpage = pagenum;
		}
		drawtimes->avg += elapsed;
		drawtimes->pages++;

		fprintf(stderr, " time %.3fs",
			elapsed / 1000000.0);
	}

	fprintf(stderr, "\n");
}
Beispiel #7
0
static fz_error *
renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm)
{
	fz_error *error;
	fz_image *image = node->image;
	fz_irect bbox;
	fz_irect clip;
	int dx, dy;
	fz_pixmap *tile;
	fz_pixmap *temp;
	fz_matrix imgmat;
	fz_matrix invmat;
	int fa, fb, fc, fd;
	int u0, v0;
	int x0, y0;
	int w, h;
	int tileheight;

DEBUG("image %dx%d %d+%d %s\n{\n", image->w, image->h, image->n, image->a, image->cs?image->cs->name:"(nil)");

	bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm));
	clip = fz_intersectirects(gc->clip, bbox);

	if (fz_isemptyrect(clip))
		return fz_okay;
        if (image->w == 0 || image->h == 0)
                return fz_okay;

	if (image->n + image->a == 0)
		return fz_okay;

	calcimagescale(ctm, image->w, image->h, &dx, &dy);

	/* try to fit tile into a typical L2 cachce */
	tileheight = 512 * 1024 / (image->w * (image->n + image->a));
	/* tileheight must be an even multiple of dy, except for last band */
	tileheight = (tileheight + dy - 1) / dy * dy;

	if ((dx != 1 || dy != 1) && image->h > tileheight) {
		int y = 0;

		DEBUG("  load image tile size = %dx%d\n", image->w, tileheight);
		error = fz_newpixmap(&tile, 0, 0, image->w,
				     tileheight, image->n + 1);
		if (error)
			return error;

		error = fz_newscaledpixmap(&temp, image->w, image->h, image->n + 1, dx, dy);
		if (error)
			goto cleanup;

		do {
			if (y + tileheight > image->h)
				tileheight = image->h - y;
			tile->y = y;
			tile->h = tileheight;
			DEBUG("  tile xywh=%d %d %d %d sxsy=1/%d 1/%d\n",
			      0, y, image->w, tileheight, dx, dy);
			error = image->loadtile(image, tile);
			if (error)
				goto cleanup1;

			error = fz_scalepixmaptile(temp, 0, y, tile, dx, dy);
			if (error)
				goto cleanup1;

			y += tileheight;
		} while (y < image->h);

		fz_droppixmap(tile);
		tile = temp;
	}
	else {


DEBUG("  load image\n");
		error = fz_newpixmap(&tile, 0, 0, image->w, image->h, image->n + 1);
		if (error)
			return error;

		error = image->loadtile(image, tile);
		if (error)
			goto cleanup;

		if (dx != 1 || dy != 1)
		{
DEBUG("  scale image 1/%d 1/%d\n", dx, dy);
			error = fz_scalepixmap(&temp, tile, dx, dy);
			if (error)
				goto cleanup;
			fz_droppixmap(tile);
			tile = temp;
		}
	}

	if (image->cs && image->cs != gc->model)
	{
DEBUG("  convert from %s to %s\n", image->cs->name, gc->model->name);
		error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, gc->model->n + 1);
		if (error)
			goto cleanup;
		fz_convertpixmap(image->cs, tile, gc->model, temp);
		fz_droppixmap(tile);
		tile = temp;
	}

	imgmat.a = 1.0 / tile->w;
	imgmat.b = 0.0;
	imgmat.c = 0.0;
	imgmat.d = -1.0 / tile->h;
	imgmat.e = 0.0;
	imgmat.f = 1.0;
	invmat = fz_invertmatrix(fz_concat(imgmat, ctm));

	w = clip.x1 - clip.x0;
	h = clip.y1 - clip.y0;
	x0 = clip.x0;
	y0 = clip.y0;
	u0 = (invmat.a * (x0+0.5) + invmat.c * (y0+0.5) + invmat.e) * 65536;
	v0 = (invmat.b * (x0+0.5) + invmat.d * (y0+0.5) + invmat.f) * 65536;
	fa = invmat.a * 65536;
	fb = invmat.b * 65536;
	fc = invmat.c * 65536;
	fd = invmat.d * 65536;

#define PSRC tile->samples, tile->w, tile->h
#define PDST(p) p->samples + ((y0-p->y) * p->w + (x0-p->x)) * p->n, p->w * p->n
#define PCTM u0, v0, fa, fb, fc, fd, w, h

	switch (gc->flag)
	{
	case FNONE:
		{
DEBUG("  fnone %d x %d\n", w, h);
			if (image->cs)
				error = fz_newpixmapwithrect(&gc->dest, clip, gc->model->n + 1);
			else
				error = fz_newpixmapwithrect(&gc->dest, clip, 1);
			if (error)
				goto cleanup;

			if (image->cs)
				fz_img_4c4(PSRC, PDST(gc->dest), PCTM);
			else
				fz_img_1c1(PSRC, PDST(gc->dest), PCTM);
		}
		break;

	case FOVER:
		{
DEBUG("  fover %d x %d\n", w, h);
			if (image->cs)
				fz_img_4o4(PSRC, PDST(gc->over), PCTM);
			else
				fz_img_1o1(PSRC, PDST(gc->over), PCTM);
		}
		break;

	case FOVER | FRGB:
DEBUG("  fover+rgb %d x %d\n", w, h);
		fz_img_w4i1o4(gc->argb, PSRC, PDST(gc->over), PCTM);
		break;

	default:
		assert(!"impossible flag in image span function");
	}

DEBUG("}\n");

	fz_droppixmap(tile);
	return fz_okay;

cleanup1:
	fz_droppixmap(temp);
cleanup:
	fz_droppixmap(tile);
	return error;
}
static void saveimage(fz_obj *obj, int num, int gen)
{
    pdf_image *img = nil;
    fz_obj *ref;
    fz_error error;
    fz_pixmap *pix;
    char name[1024];
    FILE *f;
    int bpc;
    int w;
    int h;
    int n;
    int x;
    int y;

    error = fz_newindirect(&ref, num, gen, xref);
    if (error)
        die(error);

    error = pdf_newstore(&xref->store);
    if (error)
        die(error);

    error = pdf_loadimage(&img, xref, ref);
    if (error)
        die(error);

    n = img->super.n;
    w = img->super.w;
    h = img->super.h;
    bpc = img->bpc;

    error = fz_newpixmap(&pix, 0, 0, w, h, n + 1);
    if (error)
        die(error);

    error = img->super.loadtile(&img->super, pix);
    if (error)
        die(error);

    if (bpc == 1 && n == 0)
    {
        fz_pixmap *temp;

        error = fz_newpixmap(&temp, pix->x, pix->y, pix->w, pix->h, pdf_devicergb->n + 1);
        if (error)
            die(error);

        for (y = 0; y < pix->h; y++)
            for (x = 0; x < pix->w; x++)
            {
                int pixel = y * pix->w + x;
                temp->samples[pixel * temp->n + 0] = 255;
                temp->samples[pixel * temp->n + 1] = pix->samples[pixel];
                temp->samples[pixel * temp->n + 2] = pix->samples[pixel];
                temp->samples[pixel * temp->n + 3] = pix->samples[pixel];
            }

        fz_droppixmap(pix);
        pix = temp;
    }

    if (img->super.cs && strcmp(img->super.cs->name, "DeviceRGB"))
    {
        fz_pixmap *temp;

        error = fz_newpixmap(&temp, pix->x, pix->y, pix->w, pix->h, pdf_devicergb->n + 1);
        if (error)
            die(error);

        fz_convertpixmap(img->super.cs, pix, pdf_devicergb, temp);
        fz_droppixmap(pix);
        pix = temp;
    }

    sprintf(name, "img-%04d.pnm", num);

    f = fopen(name, "wb");
    if (f == NULL)
        die(fz_throw("Error creating image file"));

    fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);

    for (y = 0; y < pix->h; y++)
        for (x = 0; x < pix->w; x++)
        {
            fz_sample *sample = &pix->samples[(y * pix->w + x) * (pdf_devicergb->n + 1)];
            unsigned char r = sample[1];
            unsigned char g = sample[2];
            unsigned char b = sample[3];
            fprintf(f, "%c%c%c", r, g, b);
        }

    if (fclose(f) < 0)
        die(fz_throw("Error closing image file"));

    fz_droppixmap(pix);

    pdf_dropstore(xref->store);
    xref->store = nil;

    fz_dropimage(&img->super);

    fz_dropobj(ref);
}
Beispiel #9
0
static fz_error
pdf_loadimageimp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask)
{
	fz_stream *stm;
	fz_pixmap *tile;
	fz_obj *obj, *res;
	fz_error error;

	int w, h, bpc, n;
	int imagemask;
	int interpolate;
	int indexed;
	fz_colorspace *colorspace;
	fz_pixmap *mask; /* explicit mask/softmask image */
	int usecolorkey;
	int colorkey[FZ_MAXCOLORS * 2];
	float decode[FZ_MAXCOLORS * 2];

	int scale;
	int stride;
	unsigned char *samples;
	int i, len;

	/* special case for JPEG2000 images */
	if (pdf_isjpximage(dict))
	{
		tile = nil;
		error = pdf_loadjpximage(&tile, xref, dict);
		if (error)
			return fz_rethrow(error, "cannot load jpx image");
		if (forcemask)
		{
			if (tile->n != 2)
			{
				fz_droppixmap(tile);
				return fz_throw("softmask must be grayscale");
			}
			mask = fz_alphafromgray(tile, 1);
			fz_droppixmap(tile);
			*imgp = mask;
			return fz_okay;
		}
		*imgp = tile;
		return fz_okay;
	}

	w = fz_toint(fz_dictgetsa(dict, "Width", "W"));
	h = fz_toint(fz_dictgetsa(dict, "Height", "H"));
	bpc = fz_toint(fz_dictgetsa(dict, "BitsPerComponent", "BPC"));
	imagemask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM"));
	interpolate = fz_tobool(fz_dictgetsa(dict, "Interpolate", "I"));

	indexed = 0;
	usecolorkey = 0;
	colorspace = nil;
	mask = nil;

	if (imagemask)
		bpc = 1;

	if (w == 0)
		return fz_throw("image width is zero");
	if (h == 0)
		return fz_throw("image height is zero");
	if (bpc == 0)
		return fz_throw("image depth is zero");
	if (w > (1 << 16))
		return fz_throw("image is too wide");
	if (h > (1 << 16))
		return fz_throw("image is too high");

	obj = fz_dictgetsa(dict, "ColorSpace", "CS");
	if (obj && !imagemask && !forcemask)
	{
		/* colorspace resource lookup is only done for inline images */
		if (fz_isname(obj))
		{
			res = fz_dictget(fz_dictgets(rdb, "ColorSpace"), obj);
			if (res)
				obj = res;
		}

		error = pdf_loadcolorspace(&colorspace, xref, obj);
		if (error)
			return fz_rethrow(error, "cannot load image colorspace");

		if (!strcmp(colorspace->name, "Indexed"))
			indexed = 1;

		n = colorspace->n;
	}
	else
	{
		n = 1;
	}

	obj = fz_dictgetsa(dict, "Decode", "D");
	if (obj)
	{
		for (i = 0; i < n * 2; i++)
			decode[i] = fz_toreal(fz_arrayget(obj, i));
	}
	else
	{
		float maxval = indexed ? (1 << bpc) - 1 : 1;
		for (i = 0; i < n * 2; i++)
			decode[i] = i & 1 ? maxval : 0;
	}

	obj = fz_dictgetsa(dict, "SMask", "Mask");
	if (fz_isdict(obj))
	{
		/* Not allowed for inline images */
		if (!cstm)
		{
			error = pdf_loadimageimp(&mask, xref, rdb, obj, nil, 1);
			if (error)
			{
				if (colorspace)
					fz_dropcolorspace(colorspace);
				return fz_rethrow(error, "cannot load image mask/softmask");
			}
		}
	}
	else if (fz_isarray(obj))
	{
		usecolorkey = 1;
		for (i = 0; i < n * 2; i++)
			colorkey[i] = fz_toint(fz_arrayget(obj, i));
	}

	stride = (w * n * bpc + 7) / 8;
	samples = fz_calloc(h, stride);

	if (cstm)
	{
		stm = pdf_openinlinestream(cstm, xref, dict, stride * h);
	}
	else
	{
		error = pdf_openstream(&stm, xref, fz_tonum(dict), fz_togen(dict));
		if (error)
		{
			if (colorspace)
				fz_dropcolorspace(colorspace);
			if (mask)
				fz_droppixmap(mask);
			return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_tonum(dict));
		}
	}

	len = fz_read(stm, samples, h * stride);
	if (len < 0)
	{
		fz_close(stm);
		if (colorspace)
			fz_dropcolorspace(colorspace);
		if (mask)
			fz_droppixmap(mask);
		return fz_rethrow(len, "cannot read image data");
	}

	/* Make sure we read the EOF marker (for inline images only) */
	if (cstm)
	{
		unsigned char tbuf[512];
		int tlen = fz_read(stm, tbuf, sizeof tbuf);
		if (tlen < 0)
			fz_catch(tlen, "ignoring error at end of image");
		if (tlen > 0)
			fz_warn("ignoring garbage at end of image");
	}

	fz_close(stm);

	/* Pad truncated images */
	if (len < stride * h)
	{
		fz_warn("padding truncated image (%d 0 R)", fz_tonum(dict));
		memset(samples + len, 0, stride * h - len);
	}

	/* Invert 1-bit image masks */
	if (imagemask)
	{
		/* 0=opaque and 1=transparent so we need to invert */
		unsigned char *p = samples;
		len = h * stride;
		for (i = 0; i < len; i++)
			p[i] = ~p[i];
	}

	pdf_logimage("size %dx%d n=%d bpc=%d imagemask=%d indexed=%d\n", w, h, n, bpc, imagemask, indexed);

	/* Unpack samples into pixmap */

	tile = fz_newpixmap(colorspace, 0, 0, w, h);

	scale = 1;
	if (!indexed)
	{
		switch (bpc)
		{
		case 1: scale = 255; break;
		case 2: scale = 85; break;
		case 4: scale = 17; break;
		}
	}

	fz_unpacktile(tile, samples, n, bpc, stride, scale);

	if (usecolorkey)
		pdf_maskcolorkey(tile, n, colorkey);

	if (indexed)
	{
		fz_pixmap *conv;

		fz_decodeindexedtile(tile, decode, (1 << bpc) - 1);

		conv = pdf_expandindexedpixmap(tile);
		fz_droppixmap(tile);
		tile = conv;
	}
	else
	{
		fz_decodetile(tile, decode);
	}

	if (colorspace)
		fz_dropcolorspace(colorspace);

	tile->mask = mask;
	tile->interpolate = interpolate;

	fz_free(samples);

	*imgp = tile;
	return fz_okay;
}
static fz_error gettile(fz_lazytile *l, int y0)
{
	fz_error error;
	fz_image *image = l->image;
	int dx = l->dx;
	int dy = l->dy;
	fz_pixmap *tile;
	fz_pixmap *temp;
	int tileheight = l->tileheight;

	if(y0 < 0)
		y0 = 0;

	int y = y0 * dy;

	if (y + tileheight > image->h)
		tileheight = image->h - y;

	if (tileheight < 0)
		return fz_okay;

	if (l->tile)
	{
		fz_droppixmap(l->tile);
		l->tile = NULL;
	}

	error = fz_newpixmap(&tile, 0, y, image->w, tileheight, image->n + 1);
	if (error)
		return error;

	error = image->loadtile(image, tile);
	if (error)
		goto cleanup;

	if (dx > 1 || dy > 1)
	{
		error = fz_scalepixmap(&temp, tile, dx, dy);
		if (error)
			goto cleanup;

		fz_droppixmap(tile);
		tile = temp;
	}

	if (image->cs && image->cs != l->target_cs)
	{
		error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, l->target_cs->n + 1);
		if (error)
			goto cleanup;

		fz_convertpixmap(image->cs, tile, l->target_cs, temp);
		fz_droppixmap(tile);
		tile = temp;
	}

	tile->y = y0;
	l->tile = tile;

	return fz_okay;

cleanup:
	if (tile)
		fz_droppixmap(tile);

	return error;
}
fz_pixmap *
fz_renderftstrokedglyph(fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_strokestate *state)
{
	FT_Face face = font->ftface;
	float expansion = fz_matrixexpansion(ctm);
	int linewidth = state->linewidth * expansion * 64 / 2;
	FT_Matrix m;
	FT_Vector v;
	FT_Error fterr;
	FT_Stroker stroker;
	FT_Glyph glyph;
	FT_BitmapGlyph bitmap;
	fz_pixmap *pix;
	int y;

	m.xx = trm.a * 64; /* should be 65536 */
	m.yx = trm.b * 64;
	m.xy = trm.c * 64;
	m.yy = trm.d * 64;
	v.x = trm.e * 64;
	v.y = trm.f * 64;

	fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
	if (fterr)
	{
		fz_warn("FT_Set_Char_Size: %s", ft_errorstring(fterr));
		return nil;
	}

	FT_Set_Transform(face, &m, &v);

	fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
	if (fterr)
	{
		fz_warn("FT_Load_Glyph(gid %d): %s", gid, ft_errorstring(fterr));
		return nil;
	}

	fterr = FT_Stroker_New(fz_ftlib, &stroker);
	if (fterr)
	{
		fz_warn("FT_Stroker_New: %s", ft_errorstring(fterr));
		return nil;
	}

	FT_Stroker_Set(stroker, linewidth, state->linecap, state->linejoin, state->miterlimit * 65536);

	fterr = FT_Get_Glyph(face->glyph, &glyph);
	if (fterr)
	{
		fz_warn("FT_Get_Glyph: %s", ft_errorstring(fterr));
		FT_Stroker_Done(stroker);
		return nil;
	}

	fterr = FT_Glyph_Stroke(&glyph, stroker, 1);
	if (fterr)
	{
		fz_warn("FT_Glyph_Stroke: %s", ft_errorstring(fterr));
		FT_Done_Glyph(glyph);
		FT_Stroker_Done(stroker);
		return nil;
	}

	fterr = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
	if (fterr)
	{
		fz_warn("FT_Glyph_To_Bitmap: %s", ft_errorstring(fterr));
		FT_Done_Glyph(glyph);
		FT_Stroker_Done(stroker);
		return nil;
	}

	bitmap = (FT_BitmapGlyph)glyph;
	pix = fz_newpixmap(NULL,
		bitmap->left,
		bitmap->top - bitmap->bitmap.rows,
		bitmap->bitmap.width,
		bitmap->bitmap.rows);

	for (y = 0; y < pix->h; y++)
	{
		memcpy(pix->samples + y * pix->w,
			bitmap->bitmap.buffer + (pix->h - y - 1) * bitmap->bitmap.pitch,
			pix->w);
	}

	FT_Done_Glyph(glyph);
	FT_Stroker_Done(stroker);

	return pix;
}
fz_pixmap *
fz_renderftglyph(fz_font *font, int gid, fz_matrix trm)
{
	FT_Face face = font->ftface;
	FT_Matrix m;
	FT_Vector v;
	FT_Error fterr;
	fz_pixmap *glyph;
	int y;

	/* Fudge the font matrix to stretch the glyph if we've substituted the font. */
	if (font->ftsubstitute && gid < font->widthcount)
	{
		int subw;
		int realw;
		float scale;

		/* TODO: use FT_Get_Advance */
		fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72);
		if (fterr)
			fz_warn("freetype setting character size: %s", ft_errorstring(fterr));

		fterr = FT_Load_Glyph(font->ftface, gid,
			FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
		if (fterr)
			fz_warn("freetype failed to load glyph: %s", ft_errorstring(fterr));

		realw = ((FT_Face)font->ftface)->glyph->metrics.horiAdvance;
		subw = font->widthtable[gid];
		if (realw)
			scale = (float) subw / realw;
		else
			scale = 1;

		trm = fz_concat(fz_scale(scale, 1), trm);
	}

	/*
	Freetype mutilates complex glyphs if they are loaded
	with FT_Set_Char_Size 1.0. it rounds the coordinates
	before applying transformation. to get more precision in
	freetype, we shift part of the scale in the matrix
	into FT_Set_Char_Size instead
	*/

	m.xx = trm.a * 64; /* should be 65536 */
	m.yx = trm.b * 64;
	m.xy = trm.c * 64;
	m.yy = trm.d * 64;
	v.x = trm.e * 64;
	v.y = trm.f * 64;

	fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
	if (fterr)
		fz_warn("freetype setting character size: %s", ft_errorstring(fterr));
	FT_Set_Transform(face, &m, &v);

	if (font->fthint)
	{
		/*
		Enable hinting, but keep the huge char size so that
		it is hinted for a character. This will in effect nullify
		the effect of grid fitting. This form of hinting should
		only be used for DynaLab and similar tricky TrueType fonts,
		so that we get the correct outline shape.
		*/
#ifdef GRIDFIT
		/* If you really want grid fitting, enable this code. */
		float scale = fz_matrixexpansion(trm);
		m.xx = trm.a * 65536 / scale;
		m.xy = trm.b * 65536 / scale;
		m.yx = trm.c * 65536 / scale;
		m.yy = trm.d * 65536 / scale;
		v.x = 0;
		v.y = 0;

		fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72);
		if (fterr)
			fz_warn("freetype setting character size: %s", ft_errorstring(fterr));
		FT_Set_Transform(face, &m, &v);
#endif
		fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP);
		if (fterr)
			fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr));
	}
	else
	{
		fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
		if (fterr)
		{
			fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr));
			return nil;
		}
	}

	fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal);
	if (fterr)
	{
		fz_warn("freetype render glyph (gid %d): %s", gid, ft_errorstring(fterr));
		return nil;
	}

	glyph = fz_newpixmap(NULL,
		face->glyph->bitmap_left,
		face->glyph->bitmap_top - face->glyph->bitmap.rows,
		face->glyph->bitmap.width,
		face->glyph->bitmap.rows);

	for (y = 0; y < glyph->h; y++)
	{
		memcpy(glyph->samples + y * glyph->w,
			face->glyph->bitmap.buffer + (glyph->h - y - 1) * face->glyph->bitmap.pitch,
			glyph->w);
	}

	return glyph;
}
Beispiel #13
0
fz_error
fz_rendershade(fz_shade *shade, fz_matrix ctm, fz_colorspace *destcs, fz_pixmap *dest)
{
	unsigned char clut[256][3];
	unsigned char *s, *d;
	fz_error error;
	fz_pixmap *temp;
	float rgb[3];
	float tri[3][MAXN];
	fz_point p;
	int i, j, k, n;

	assert(dest->n == 4);

	ctm = fz_concat(shade->matrix, ctm);

	if (shade->usefunction)
	{
		n = 3;
		error = fz_newpixmap(&temp, dest->x, dest->y, dest->w, dest->h, 2);
		if (error)
			return error;
	}
	else if (shade->cs != destcs)
	{
		n = 2 + shade->cs->n;
		error = fz_newpixmap(&temp, dest->x, dest->y, dest->w, dest->h,
			shade->cs->n + 1);
		if (error)
			return error;
	}
	else
	{
		n = 2 + shade->cs->n;
		temp = dest;
	}

	fz_clearpixmap(temp);

	for (i = 0; i < shade->meshlen; i++)
	{
		for (k = 0; k < 3; k++)
		{
			p.x = shade->mesh[(i * 3 + k) * n + 0];
			p.y = shade->mesh[(i * 3 + k) * n + 1];
			p = fz_transformpoint(ctm, p);
			if (isnan(p.y) || isnan(p.x)) // How is this happening?
			goto baddata;
			tri[k][0] = p.x;
			tri[k][1] = p.y;
			for (j = 2; j < n; j++)
				tri[k][j] = shade->mesh[( i * 3 + k) * n + j] * 255;
		}
		fz_drawtriangle(temp, tri[0], tri[1], tri[2], n);
baddata:
		;
	}

	if (shade->usefunction)
	{
		for (i = 0; i < 256; i++)
		{
			fz_convertcolor(shade->cs, shade->function[i], destcs, rgb);
			clut[i][0] = rgb[0] * 255;
			clut[i][1] = rgb[1] * 255;
			clut[i][2] = rgb[2] * 255;
		}

		n = temp->w * temp->h;
		s = temp->samples;
		d = dest->samples;

		while (n--)
		{
			d[0] = s[0];
			d[1] = fz_mul255(s[0], clut[s[1]][0]);
			d[2] = fz_mul255(s[0], clut[s[1]][1]);
			d[3] = fz_mul255(s[0], clut[s[1]][2]);
			s += 2;
			d += 4;
		}

		fz_droppixmap(temp);
	}

	else if (shade->cs != destcs)
	{
		fz_convertpixmap(shade->cs, temp, destcs, dest);
		fz_droppixmap(temp);
	}

	return fz_okay;
}
Beispiel #14
0
void
drawpnm(int pagenum)
{
    fz_error *error;
    fz_matrix ctm;
    fz_irect bbox;
    fz_pixmap *pix;
    char namebuf[256];
    char buf[256];
    int x, y, w, h, b, bh;
    int fd;

    drawloadpage(pagenum);

    ctm = fz_identity();
    ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1));
    ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom));
    ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate));

    bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox));
    w = bbox.x1 - bbox.x0;
    h = bbox.y1 - bbox.y0;
    bh = h / drawbands;

    if (drawpattern)
    {
        sprintf(namebuf, drawpattern, drawcount++);
        fd = open(namebuf, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
        if (fd < 0)
            die(fz_throw("ioerror: could not open file '%s'", namebuf));
    }
    else
        fd = 1;

    sprintf(buf, "P6\n%d %d\n255\n", w, h);
    write(fd, buf, strlen(buf));

    error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4);
    if (error)
        die(error);

    memset(pix->samples, 0xff, pix->h * pix->w * pix->n);

    for (b = 0; b < drawbands; b++)
    {
        if (drawbands > 1)
            fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands);

        error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm);
        if (error)
            die(error);

        for (y = 0; y < pix->h; y++)
        {
            unsigned char *src = pix->samples + y * pix->w * 4;
            unsigned char *dst = src;

            for (x = 0; x < pix->w; x++)
            {
                dst[x * 3 + 0] = src[x * 4 + 1];
                dst[x * 3 + 1] = src[x * 4 + 2];
                dst[x * 3 + 2] = src[x * 4 + 3];
            }

            write(fd, dst, pix->w * 3);

            memset(src, 0xff, pix->w * 4);
        }

        pix->y += bh;
        if (pix->y + pix->h > bbox.y1)
            pix->h = bbox.y1 - pix->y;
    }

    fz_droppixmap(pix);

    if (drawpattern)
        close(fd);

    drawfreepage();
}
Beispiel #15
0
fz_error *
pdf_loadtile(fz_image *img, fz_pixmap *tile)
{
	pdf_image *src = (pdf_image*)img;
	void (*tilefunc)(unsigned char*,int,unsigned char*, int, int, int, int);
	fz_error *error;

	assert(tile->n == img->n + 1);
	assert(tile->x >= 0);
	assert(tile->y >= 0);
	assert(tile->x + tile->w <= img->w);
	assert(tile->y + tile->h <= img->h);

	switch (src->bpc)
	{
	case 1: tilefunc = fz_loadtile1; break;
	case 2: tilefunc = fz_loadtile2; break;
	case 4: tilefunc = fz_loadtile4; break;
	case 8: tilefunc = fz_loadtile8; break;
	default:
		return fz_throw("rangecheck: unsupported bit depth: %d", src->bpc);
	}

	if (src->indexed)
	{
		fz_pixmap *tmp;
		int x, y, k, i;
		int bpcfact = 1;

		error = fz_newpixmap(&tmp, tile->x, tile->y, tile->w, tile->h, 1);
		if (error)
			return error;

		switch (src->bpc)
		{
		case 1: bpcfact = 255; break;
		case 2: bpcfact = 85; break;
		case 4: bpcfact = 17; break;
		case 8: bpcfact = 1; break;
		}

		tilefunc(src->samples->rp, src->stride,
				tmp->samples, tmp->w,
				tmp->w, tmp->h, 0);

		for (y = 0; y < tile->h; y++)
		{
			for (x = 0; x < tile->w; x++)
			{
				tile->samples[(y * tile->w + x) * tile->n] = 255;
				i = tmp->samples[y * tile->w + x] / bpcfact;
				i = CLAMP(i, 0, src->indexed->high);
				for (k = 0; k < src->indexed->base->n; k++)
				{
					tile->samples[(y * tile->w + x) * tile->n + k + 1] =
						src->indexed->lookup[i * src->indexed->base->n + k];
				}
			}
		}

		if (src->usecolorkey)
			maskcolorkeyindexed(tmp, tile, src->colorkey);

		fz_droppixmap(tmp);
	}

	else
	{
		tilefunc(src->samples->rp, src->stride,
				tile->samples, tile->w * tile->n,
				img->w * (img->n + img->a), img->h, img->a ? 0 : img->n);
		if (src->usecolorkey)
			maskcolorkey(tile, src->colorkey);
		fz_decodetile(tile, !img->a, src->decode);
	}

	return nil;
}
Beispiel #16
0
static fz_error *
renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm)
{
	fz_error *error;
	fz_image *image = node->image;
	fz_irect bbox;
	fz_irect clip;
	int dx, dy;
	fz_pixmap *tile;
	fz_pixmap *temp;
	fz_matrix imgmat;
	fz_matrix invmat;
	int fa, fb, fc, fd;
	int u0, v0;
	int x0, y0;
	int w, h;

DEBUG("image %dx%d %d+%d %s\n{\n", image->w, image->h, image->n, image->a, image->cs?image->cs->name:"(nil)");

	bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm));
	clip = fz_intersectirects(gc->clip, bbox);

	if (fz_isemptyrect(clip))
		return nil;

	calcimagescale(ctm, image->w, image->h, &dx, &dy);

DEBUG("  load image\n");
	error = fz_newpixmap(&tile, 0, 0, image->w, image->h, image->n + 1);
	if (error)
		return error;

	error = image->loadtile(image, tile);
	if (error)
		goto cleanup;

	if (dx != 1 || dy != 1)
	{
DEBUG("  scale image 1/%d 1/%d\n", dx, dy);
		error = fz_scalepixmap(&temp, tile, dx, dy);
		if (error)
			goto cleanup;
		fz_droppixmap(tile);
		tile = temp;
	}

	if (image->cs && image->cs != gc->model)
	{
DEBUG("  convert from %s to %s\n", image->cs->name, gc->model->name);
		error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, gc->model->n + 1);
		if (error)
			goto cleanup;
		fz_convertpixmap(image->cs, tile, gc->model, temp);
		fz_droppixmap(tile);
		tile = temp;
	}

	imgmat.a = 1.0 / tile->w;
	imgmat.b = 0.0;
	imgmat.c = 0.0;
	imgmat.d = -1.0 / tile->h;
	imgmat.e = 0.0;
	imgmat.f = 1.0;
	invmat = fz_invertmatrix(fz_concat(imgmat, ctm));

	w = clip.x1 - clip.x0;
	h = clip.y1 - clip.y0;
	x0 = clip.x0;
	y0 = clip.y0;
	u0 = (invmat.a * (x0+0.5) + invmat.c * (y0+0.5) + invmat.e) * 65536;
	v0 = (invmat.b * (x0+0.5) + invmat.d * (y0+0.5) + invmat.f) * 65536;
	fa = invmat.a * 65536;
	fb = invmat.b * 65536;
	fc = invmat.c * 65536;
	fd = invmat.d * 65536;

#define PSRC tile->samples, tile->w, tile->h
#define PDST(p) p->samples + ((y0-p->y) * p->w + (x0-p->x)) * p->n, p->w * p->n
#define PCTM u0, v0, fa, fb, fc, fd, w, h

	switch (gc->flag)
	{
	case FNONE:
		{
DEBUG("  fnone %d x %d\n", w, h);
			if (image->cs)
				error = fz_newpixmapwithrect(&gc->dest, clip, gc->model->n + 1);
			else
				error = fz_newpixmapwithrect(&gc->dest, clip, 1);
			if (error)
				goto cleanup;

			if (image->cs)
				fz_img_4c4(PSRC, PDST(gc->dest), PCTM);
			else
				fz_img_1c1(PSRC, PDST(gc->dest), PCTM);
		}
		break;

	case FOVER:
		{
DEBUG("  fover %d x %d\n", w, h);
			if (image->cs)
				fz_img_4o4(PSRC, PDST(gc->over), PCTM);
			else
				fz_img_1o1(PSRC, PDST(gc->over), PCTM);
		}
		break;

	case FOVER | FRGB:
DEBUG("  fover+rgb %d x %d\n", w, h);
		fz_img_w3i1o4(gc->rgb, PSRC, PDST(gc->over), PCTM);
		break;

	default:
		assert(!"impossible flag in image span function");
	}

DEBUG("}\n");

	fz_droppixmap(tile);
	return nil;

cleanup:
	fz_droppixmap(tile);
	return error;
}