예제 #1
0
bool PdfCreator::AddImagePage(fz_image *image, float imgDpi)
{
    CrashIf(!ctx || !doc);
    if (!ctx || !doc) return false;

    pdf_page *page = nullptr;
    fz_device *dev = nullptr;
    fz_var(page);
    fz_var(dev);

    fz_try(ctx) {
        float zoom = imgDpi ? 72 / imgDpi : 1.0f;
        fz_matrix ctm = { image->w * zoom, 0, 0, image->h * zoom, 0, 0 };
        fz_rect bounds = fz_unit_rect;
        fz_transform_rect(&bounds, &ctm);
        page = pdf_create_page(doc, bounds, 72, 0);
        dev = pdf_page_write(doc, page);
        fz_fill_image(dev, image, &ctm, 1.0);
        fz_free_device(dev);
        dev = nullptr;
        pdf_insert_page(doc, page, INT_MAX);
    }
    fz_always(ctx) {
        fz_free_device(dev);
        pdf_free_page(doc, page);
    }
    fz_catch(ctx) {
        return false;
    }
    return true;
}
예제 #2
0
static void draw_flow_box(fz_context *ctx, fz_html *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm)
{
	fz_html_flow *node;
	fz_text *text;
	fz_matrix trm;
	const char *s;
	float color[3];
	float x, y;
	int c, g;

	for (node = box->flow_head; node; node = node->next)
	{
		if (node->type == FLOW_IMAGE)
		{
			if (node->y > page_bot || node->y + node->h < page_top)
				continue;
		}
		else
		{
			if (node->y > page_bot || node->y < page_top)
				continue;
		}

		if (node->type == FLOW_WORD)
		{
			fz_scale(&trm, node->em, -node->em);
			text = fz_new_text(ctx, node->style->font, &trm, 0);

			x = node->x;
			y = node->y;
			s = node->text;
			while (*s)
			{
				s += fz_chartorune(&c, s);
				g = fz_encode_character(ctx, node->style->font, c);
				fz_add_text(ctx, text, g, c, x, y);
				x += fz_advance_glyph(ctx, node->style->font, g) * node->em;
			}

			color[0] = node->style->color.r / 255.0f;
			color[1] = node->style->color.g / 255.0f;
			color[2] = node->style->color.b / 255.0f;

			fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1);

			fz_drop_text(ctx, text);
		}
		else if (node->type == FLOW_IMAGE)
		{
			fz_matrix local_ctm = *ctm;
			fz_pre_translate(&local_ctm, node->x, node->y);
			fz_pre_scale(&local_ctm, node->w, node->h);
			fz_fill_image(ctx, dev, node->image, &local_ctm, 1);
		}
	}
}
예제 #3
0
파일: mucbz.c 프로젝트: DBNinja/sumatrapdf
void
cbz_run_page(cbz_document *doc, cbz_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie)
{
	fz_matrix local_ctm = *ctm;
	fz_image *image = page->image;
	float w = image->w * DPI / image->xres;
	float h = image->h * DPI / image->yres;
	fz_pre_scale(&local_ctm, w, h);
	fz_fill_image(dev, image, &local_ctm, 1);
}
예제 #4
0
static void
fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, fz_matrix ctm, float alpha, const fz_color_params *color_params)
{
	fz_test_device *dev = (fz_test_device*)dev_;

	while (dev->resolved == 0) /* So we can break out */
	{
		fz_compressed_buffer *buffer;

		if (*dev->is_color || !image->colorspace || fz_colorspace_is_gray(ctx, image->colorspace))
			break;

		if ((dev->options & FZ_TEST_OPT_IMAGES) == 0)
		{
			/* Don't test every pixel. Upgrade us from "black and white" to "probably color" */
			if (*dev->is_color == 0)
				*dev->is_color = 1;
			dev->resolved = 1;
			if (dev->passthrough == NULL)
				fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation");
			break;
		}

		buffer = fz_compressed_image_buffer(ctx, image);
		if (buffer && image->bpc == 8)
		{
			fz_stream *stream = fz_open_compressed_buffer(ctx, buffer);
			fz_try(ctx)
				fz_test_fill_compressed_8bpc_image(ctx, dev, image, stream, color_params);
			fz_always(ctx)
				fz_drop_stream(ctx, stream);
			fz_catch(ctx)
				fz_rethrow(ctx);
		}
		else
		{
			fz_pixmap *pix = fz_get_pixmap_from_image(ctx, image, NULL, NULL, 0, 0);
			if (pix == NULL) /* Should never happen really, but... */
				break;

			fz_try(ctx)
				fz_test_fill_other_image(ctx, dev, pix, color_params);
			fz_always(ctx)
				fz_drop_pixmap(ctx, pix);
			fz_catch(ctx)
				fz_rethrow(ctx);
		}
		break;
	}
	if (dev->passthrough)
		fz_fill_image(ctx, dev->passthrough, image, ctm, alpha, color_params);
}
예제 #5
0
파일: muimg.c 프로젝트: murphy221/nPDF
static void
img_run_page(fz_context *ctx, img_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie)
{
	fz_matrix local_ctm = *ctm;
	fz_image *image = page->image;
	int xres, yres;
	float w, h;
	fz_image_resolution(image, &xres, &yres);
	w = image->w * DPI / xres;
	h = image->h * DPI / yres;
	fz_pre_scale(&local_ctm, w, h);
	fz_fill_image(ctx, dev, image, &local_ctm, 1);
}
예제 #6
0
파일: mucbz.c 프로젝트: JorjMcKie/mupdf
static void
cbz_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
{
	cbz_page *page = (cbz_page*)page_;
	fz_matrix local_ctm;
	fz_image *image = page->image;
	int xres, yres;
	float w, h;

	fz_image_resolution(image, &xres, &yres);
	w = image->w * DPI / xres;
	h = image->h * DPI / yres;
	local_ctm = fz_pre_scale(ctm, w, h);
	fz_fill_image(ctx, dev, image, local_ctm, 1, NULL);
}
예제 #7
0
static void draw_flow_box(fz_context *ctx, fz_html *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm)
{
    fz_font *font;
    fz_html_flow *node;
    fz_text *text;
    fz_matrix trm;
    const char *s;
    float color[3];
    int c, g;

    for (node = box->flow_head; node; node = node->next)
    {
        if (node->type == FLOW_IMAGE)
        {
            if (node->y >= page_bot || node->y + node->h <= page_top)
                continue;
        }
        else
        {
            if (node->y > page_bot || node->y < page_top)
                continue;
        }

        if (node->type == FLOW_WORD)
        {
            fz_scale(&trm, node->em, -node->em);

            color[0] = node->style->color.r / 255.0f;
            color[1] = node->style->color.g / 255.0f;
            color[2] = node->style->color.b / 255.0f;

            /* TODO: reuse text object if color is unchanged */
            text = fz_new_text(ctx);


            trm.e = node->x;
            trm.f = node->y;
            s = node->content.text;
            if (node->char_r2l)
            {
                float w = 0;
                const char *t = s;

                while (*t)
                {
                    t += fz_chartorune(&c, t);
                    if (node->mirror)
                        c = ucdn_mirror(c);
                    g = fz_encode_character_with_fallback(ctx, node->style->font, c, 0, &font);
                    w += fz_advance_glyph(ctx, font, g) * node->em;
                }

                trm.e += w;
                while (*s)
                {
                    s += fz_chartorune(&c, s);
                    if (node->mirror)
                        c = ucdn_mirror(c);
                    g = fz_encode_character_with_fallback(ctx, node->style->font, c, 0, &font);
                    trm.e -= fz_advance_glyph(ctx, font, g) * node->em;
                    if (node->style->visibility == V_VISIBLE)
                        fz_add_text(ctx, text, font, 0, &trm, g, c);
                }
                trm.e += w;
            }
            else
            {
                while (*s)
                {
                    s += fz_chartorune(&c, s);
                    g = fz_encode_character_with_fallback(ctx, node->style->font, c, 0, &font);
                    if (node->style->visibility == V_VISIBLE)
                        fz_add_text(ctx, text, font, 0, &trm, g, c);
                    trm.e += fz_advance_glyph(ctx, font, g) * node->em;
                }
            }

            if (text)
            {
                fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1);
                fz_drop_text(ctx, text);
            }
        }
        else if (node->type == FLOW_IMAGE)
        {
            if (node->style->visibility == V_VISIBLE)
            {
                fz_matrix local_ctm = *ctm;
                fz_pre_translate(&local_ctm, node->x, node->y);
                fz_pre_scale(&local_ctm, node->w, node->h);
                fz_fill_image(ctx, dev, node->content.image, &local_ctm, 1);
            }
        }
    }
}
예제 #8
0
파일: dev_list.c 프로젝트: scroco/mupdf
void
fz_execute_display_list(fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz_bbox scissor)
{
	fz_display_node *node;
	fz_matrix ctm;
	fz_rect rect;
	fz_bbox bbox;
	int clipped = 0;
	int tiled = 0;
	int empty;

	if (!fz_is_infinite_bbox(scissor))
	{
		/* add some fuzz at the edges, as especially glyph rects
		 * are sometimes not actually completely bounding the glyph */
		scissor.x0 -= 20; scissor.y0 -= 20;
		scissor.x1 += 20; scissor.y1 += 20;
	}

	for (node = list->first; node; node = node->next)
	{
		/* cull objects to draw using a quick visibility test */

		if (tiled || node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE)
		{
			empty = 0;
		}
		else
		{
			bbox = fz_round_rect(fz_transform_rect(top_ctm, node->rect));
			bbox = fz_intersect_bbox(bbox, scissor);
			empty = fz_is_empty_bbox(bbox);
		}

		if (clipped || empty)
		{
			switch (node->cmd)
			{
			case FZ_CMD_CLIP_PATH:
			case FZ_CMD_CLIP_STROKE_PATH:
			case FZ_CMD_CLIP_TEXT:
			case FZ_CMD_CLIP_STROKE_TEXT:
			case FZ_CMD_CLIP_IMAGE_MASK:
			case FZ_CMD_BEGIN_MASK:
			case FZ_CMD_BEGIN_GROUP:
				clipped++;
				continue;
			case FZ_CMD_POP_CLIP:
			case FZ_CMD_END_GROUP:
				if (!clipped)
					goto visible;
				clipped--;
				continue;
			case FZ_CMD_END_MASK:
				if (!clipped)
					goto visible;
				continue;
			default:
				continue;
			}
		}

visible:
		ctm = fz_concat(node->ctm, top_ctm);

		switch (node->cmd)
		{
		case FZ_CMD_FILL_PATH:
			fz_fill_path(dev, node->item.path, node->flag, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_STROKE_PATH:
			fz_stroke_path(dev, node->item.path, node->stroke, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_CLIP_PATH:
		{
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
			fz_clip_path(dev, node->item.path, &trect, node->flag, ctm);
			break;
		}
		case FZ_CMD_CLIP_STROKE_PATH:
		{
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
			fz_clip_stroke_path(dev, node->item.path, &trect, node->stroke, ctm);
			break;
		}
		case FZ_CMD_FILL_TEXT:
			fz_fill_text(dev, node->item.text, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_STROKE_TEXT:
			fz_stroke_text(dev, node->item.text, node->stroke, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_CLIP_TEXT:
			fz_clip_text(dev, node->item.text, ctm, node->flag);
			break;
		case FZ_CMD_CLIP_STROKE_TEXT:
			fz_clip_stroke_text(dev, node->item.text, node->stroke, ctm);
			break;
		case FZ_CMD_IGNORE_TEXT:
			fz_ignore_text(dev, node->item.text, ctm);
			break;
		case FZ_CMD_FILL_SHADE:
			fz_fill_shade(dev, node->item.shade, ctm, node->alpha);
			break;
		case FZ_CMD_FILL_IMAGE:
			fz_fill_image(dev, node->item.image, ctm, node->alpha);
			break;
		case FZ_CMD_FILL_IMAGE_MASK:
			fz_fill_image_mask(dev, node->item.image, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_CLIP_IMAGE_MASK:
		{
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
			fz_clip_image_mask(dev, node->item.image, &trect, ctm);
			break;
		}
		case FZ_CMD_POP_CLIP:
			fz_pop_clip(dev);
			break;
		case FZ_CMD_BEGIN_MASK:
			rect = fz_transform_rect(top_ctm, node->rect);
			fz_begin_mask(dev, rect, node->flag, node->colorspace, node->color);
			break;
		case FZ_CMD_END_MASK:
			fz_end_mask(dev);
			break;
		case FZ_CMD_BEGIN_GROUP:
			rect = fz_transform_rect(top_ctm, node->rect);
			fz_begin_group(dev, rect,
				node->flag & ISOLATED, node->flag & KNOCKOUT,
				node->item.blendmode, node->alpha);
			break;
		case FZ_CMD_END_GROUP:
			fz_end_group(dev);
			break;
		case FZ_CMD_BEGIN_TILE:
			tiled++;
			rect.x0 = node->color[2];
			rect.y0 = node->color[3];
			rect.x1 = node->color[4];
			rect.y1 = node->color[5];
			fz_begin_tile(dev, node->rect, rect,
				node->color[0], node->color[1], ctm);
			break;
		case FZ_CMD_END_TILE:
			tiled--;
			fz_end_tile(dev);
			break;
		}
	}
}
예제 #9
0
void
fz_run_display_list(fz_display_list *list, fz_device *dev, const fz_matrix *top_ctm, const fz_rect *scissor, fz_cookie *cookie)
{
	fz_display_node *node;
	fz_matrix ctm;
	int clipped = 0;
	int tiled = 0;
	int progress = 0;
	fz_context *ctx = dev->ctx;

	if (!scissor)
		scissor = &fz_infinite_rect;

	if (cookie)
	{
		cookie->progress_max = list->len;
		cookie->progress = 0;
	}

	for (node = list->first; node; node = node->next)
	{
		int empty;

		fz_rect node_rect = node->rect;
		fz_transform_rect(&node_rect, top_ctm);

		/* Check the cookie for aborting */
		if (cookie)
		{
			if (cookie->abort)
				break;
			cookie->progress = progress++;
		}

		/* cull objects to draw using a quick visibility test */

		if (tiled ||
			node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE ||
			node->cmd == FZ_CMD_BEGIN_PAGE || node->cmd == FZ_CMD_END_PAGE)
		{
			empty = 0;
		}
		else
		{
			fz_rect rect = node_rect;
			fz_intersect_rect(&rect, scissor);
			empty = fz_is_empty_rect(&rect);
		}

		if (clipped || empty)
		{
			switch (node->cmd)
			{
			case FZ_CMD_CLIP_PATH:
			case FZ_CMD_CLIP_STROKE_PATH:
			case FZ_CMD_CLIP_STROKE_TEXT:
			case FZ_CMD_CLIP_IMAGE_MASK:
			case FZ_CMD_BEGIN_MASK:
			case FZ_CMD_BEGIN_GROUP:
				clipped++;
				continue;
			case FZ_CMD_CLIP_TEXT:
				/* Accumulated text has no extra pops */
				if (node->flag != 2)
					clipped++;
				continue;
			case FZ_CMD_POP_CLIP:
			case FZ_CMD_END_GROUP:
				if (!clipped)
					goto visible;
				clipped--;
				continue;
			case FZ_CMD_END_MASK:
				if (!clipped)
					goto visible;
				continue;
			default:
				continue;
			}
		}

visible:
		fz_concat(&ctm, &node->ctm, top_ctm);

		fz_try(ctx)
		{
			switch (node->cmd)
			{
			case FZ_CMD_BEGIN_PAGE:
				fz_begin_page(dev, &node_rect, &ctm);
				break;
			case FZ_CMD_END_PAGE:
				fz_end_page(dev);
				break;
			case FZ_CMD_FILL_PATH:
				fz_fill_path(dev, node->item.path, node->flag, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_STROKE_PATH:
				fz_stroke_path(dev, node->item.path, node->stroke, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_PATH:
				fz_clip_path(dev, node->item.path, &node_rect, node->flag, &ctm);
				break;
			case FZ_CMD_CLIP_STROKE_PATH:
				fz_clip_stroke_path(dev, node->item.path, &node_rect, node->stroke, &ctm);
				break;
			case FZ_CMD_FILL_TEXT:
				fz_fill_text(dev, node->item.text, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_STROKE_TEXT:
				fz_stroke_text(dev, node->item.text, node->stroke, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_TEXT:
				fz_clip_text(dev, node->item.text, &ctm, node->flag);
				break;
			case FZ_CMD_CLIP_STROKE_TEXT:
				fz_clip_stroke_text(dev, node->item.text, node->stroke, &ctm);
				break;
			case FZ_CMD_IGNORE_TEXT:
				fz_ignore_text(dev, node->item.text, &ctm);
				break;
			case FZ_CMD_FILL_SHADE:
				if ((dev->hints & FZ_IGNORE_SHADE) == 0)
					fz_fill_shade(dev, node->item.shade, &ctm, node->alpha);
				break;
			case FZ_CMD_FILL_IMAGE:
				if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
					fz_fill_image(dev, node->item.image, &ctm, node->alpha);
				break;
			case FZ_CMD_FILL_IMAGE_MASK:
				if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
					fz_fill_image_mask(dev, node->item.image, &ctm,
						node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_IMAGE_MASK:
				if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
					fz_clip_image_mask(dev, node->item.image, &node_rect, &ctm);
				break;
			case FZ_CMD_POP_CLIP:
				fz_pop_clip(dev);
				break;
			case FZ_CMD_BEGIN_MASK:
				fz_begin_mask(dev, &node_rect, node->flag, node->colorspace, node->color);
				break;
			case FZ_CMD_END_MASK:
				fz_end_mask(dev);
				break;
			case FZ_CMD_BEGIN_GROUP:
				fz_begin_group(dev, &node_rect,
					(node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
					node->item.blendmode, node->alpha);
				break;
			case FZ_CMD_END_GROUP:
				fz_end_group(dev);
				break;
			case FZ_CMD_BEGIN_TILE:
			{
				int cached;
				fz_rect tile_rect;
				tiled++;
				tile_rect.x0 = node->color[2];
				tile_rect.y0 = node->color[3];
				tile_rect.x1 = node->color[4];
				tile_rect.y1 = node->color[5];
				cached = fz_begin_tile_id(dev, &node->rect, &tile_rect, node->color[0], node->color[1], &ctm, node->flag);
				if (cached)
					node = skip_to_end_tile(node, &progress);
				break;
			}
			case FZ_CMD_END_TILE:
				tiled--;
				fz_end_tile(dev);
				break;
			/* SumatraPDF: support transfer functions */
			case FZ_CMD_APPLY_TRANSFER_FUNCTION:
				fz_apply_transfer_function(dev, node->item.tr, node->flag);
				break;
			}
		}
		fz_catch(ctx)
		{
			/* Swallow the error */
			if (cookie)
				cookie->errors++;
			fz_warn(ctx, "Ignoring error during interpretation");
		}
	}
}
예제 #10
0
void
fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz_bbox scissor, fz_cookie *cookie)
{
	fz_display_node *node;
	fz_matrix ctm;
	fz_rect rect;
	fz_bbox bbox;
	int clipped = 0;
	int tiled = 0;
	int empty;
	int progress = 0;
	
	//LOGE("Count %d", count);
	if (cookie)
	{
		cookie->progress_max = list->last - list->first;
		cookie->progress = 0;
	}

	for (node = list->first; node; node = node->next)
	{
		/* Check the cookie for aborting */
		if (cookie)
		{
			if (cookie->abort)
				break;
			cookie->progress = progress++;
		}

		/* cull objects to draw using a quick visibility test */

		if (tiled || node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE)
		{
			empty = 0;
		}
		else
		{
			bbox = fz_bbox_covering_rect(fz_transform_rect(top_ctm, node->rect));
			bbox = fz_intersect_bbox(bbox, scissor);
			empty = fz_is_empty_bbox(bbox);
		}

		if (clipped || empty)
		{
			switch (node->cmd)
			{
			case FZ_CMD_CLIP_PATH:
			case FZ_CMD_CLIP_STROKE_PATH:
			case FZ_CMD_CLIP_STROKE_TEXT:
			case FZ_CMD_CLIP_IMAGE_MASK:
			case FZ_CMD_BEGIN_MASK:
			case FZ_CMD_BEGIN_GROUP:
				clipped++;
				continue;
			case FZ_CMD_CLIP_TEXT:
				/* Accumulated text has no extra pops */
				if (node->flag != 2)
					clipped++;
				continue;
			case FZ_CMD_POP_CLIP:
			case FZ_CMD_END_GROUP:
				if (!clipped)
					goto visible;
				clipped--;
				continue;
			case FZ_CMD_END_MASK:
				if (!clipped)
					goto visible;
				continue;
			default:
				continue;
			}
		}

visible:
		ctm = fz_concat(node->ctm, top_ctm);

		switch (node->cmd)
		{
		case FZ_CMD_FILL_PATH:
			fz_fill_path(dev, node->item.path, node->flag, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_STROKE_PATH:
			fz_stroke_path(dev, node->item.path, node->stroke, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_CLIP_PATH:
		{
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
			fz_clip_path(dev, node->item.path, &trect, node->flag, ctm);
			break;
		}
		case FZ_CMD_CLIP_STROKE_PATH:
		{
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
			fz_clip_stroke_path(dev, node->item.path, &trect, node->stroke, ctm);
			break;
		}
		case FZ_CMD_FILL_TEXT:
			fz_fill_text(dev, node->item.text, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_STROKE_TEXT:
			fz_stroke_text(dev, node->item.text, node->stroke, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_CLIP_TEXT:
			fz_clip_text(dev, node->item.text, ctm, node->flag);
			break;
		case FZ_CMD_CLIP_STROKE_TEXT:
			fz_clip_stroke_text(dev, node->item.text, node->stroke, ctm);
			break;
		case FZ_CMD_IGNORE_TEXT:
			fz_ignore_text(dev, node->item.text, ctm);
			break;
		case FZ_CMD_FILL_SHADE:
			fz_fill_shade(dev, node->item.shade, ctm, node->alpha);
			break;
		case FZ_CMD_FILL_IMAGE:
			fz_fill_image(dev, node->item.image, ctm, node->alpha);
			break;
		case FZ_CMD_FILL_IMAGE_MASK:
			fz_fill_image_mask(dev, node->item.image, ctm,
				node->colorspace, node->color, node->alpha);
			break;
		case FZ_CMD_CLIP_IMAGE_MASK:
		{
			fz_rect trect = fz_transform_rect(top_ctm, node->rect);
			fz_clip_image_mask(dev, node->item.image, &trect, ctm);
			break;
		}
		case FZ_CMD_POP_CLIP:
			fz_pop_clip(dev);
			break;
		case FZ_CMD_BEGIN_MASK:
			rect = fz_transform_rect(top_ctm, node->rect);
			fz_begin_mask(dev, rect, node->flag, node->colorspace, node->color);
			break;
		case FZ_CMD_END_MASK:
			fz_end_mask(dev);
			break;
		case FZ_CMD_BEGIN_GROUP:
			rect = fz_transform_rect(top_ctm, node->rect);
			fz_begin_group(dev, rect,
				(node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
				node->item.blendmode, node->alpha);
			break;
		case FZ_CMD_END_GROUP:
			fz_end_group(dev);
			break;
		case FZ_CMD_BEGIN_TILE:
			tiled++;
			rect.x0 = node->color[2];
			rect.y0 = node->color[3];
			rect.x1 = node->color[4];
			rect.y1 = node->color[5];
			fz_begin_tile(dev, node->rect, rect,
				node->color[0], node->color[1], ctm);
			break;
		case FZ_CMD_END_TILE:
			tiled--;
			fz_end_tile(dev);
			break;
		}
	}
	//free(node_array);
}