static void fz_test_color(fz_context *ctx, fz_test_device *t, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params) { if (!*t->is_color && colorspace && fz_colorspace_type(ctx, colorspace) != FZ_COLORSPACE_GRAY) { if (colorspace == fz_device_rgb(ctx)) { if (is_rgb_color(t->threshold, color[0], color[1], color[2])) { *t->is_color = 2; t->resolved = 1; if (t->passthrough == NULL) fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } } else { float rgb[3]; fz_convert_color(ctx, color_params, NULL, fz_device_rgb(ctx), rgb, colorspace, color); if (is_rgb_color(t->threshold, rgb[0], rgb[1], rgb[2])) { *t->is_color = 2; t->resolved = 1; if (t->passthrough == NULL) { fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } } } } }
static void fz_test_color(fz_context *ctx, fz_device *dev, fz_colorspace *colorspace, const float *color) { fz_test_device *t = (fz_test_device*)dev; if (!*t->is_color && colorspace && colorspace != fz_device_gray(ctx)) { if (colorspace == fz_device_rgb(ctx)) { if (is_rgb_color(t->threshold, color[0], color[1], color[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } } else { float rgb[3]; fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, color); if (is_rgb_color(t->threshold, rgb[0], rgb[1], rgb[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } } } }
static void fz_test_color(fz_device *dev, fz_colorspace *colorspace, const float *color) { fz_context *ctx = dev->ctx; struct test *t = dev->user; if (!*t->is_color && colorspace && colorspace != fz_device_gray(ctx)) { if (colorspace == fz_device_rgb(ctx)) { if (is_rgb_color(t->threshold, color[0], color[1], color[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; } } else { float rgb[3]; fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, color); if (is_rgb_color(t->threshold, rgb[0], rgb[1], rgb[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; } } } }
static void fz_draw_fill_path(void *user, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_bbox bbox; int i; fz_reset_gel(dev->gel, dev->scissor); fz_flatten_fill_path(dev->gel, path, ctm, flatness); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (fz_is_empty_rect(bbox)) return; fz_convert_color(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, even_odd, bbox, dev->dest, colorbv); }
static void fz_draw_stroke_path(fz_device *devp, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_bbox bbox; int i; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; if (model == NULL) model = fz_device_gray; if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, state->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, state->scissor); if (fz_is_empty_rect(bbox)) return; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, 0, bbox, state->dest, colorbv); if (state->shape) { fz_reset_gel(dev->gel, state->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); colorbv[0] = 255; fz_scan_convert(dev->gel, 0, bbox, state->shape, colorbv); } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void fz_draw_begin_mask(fz_context *ctx, void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv) { fz_draw_device *dev = user; fz_pixmap *dest; fz_pixmap *shape = dev->shape; fz_bbox bbox; if (dev->top == dev->stack_max) fz_grow_stack(dev); bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(ctx, fz_device_gray, bbox); if (dev->shape) { /* FIXME: If we ever want to support AIS true, then we * probably want to create a shape pixmap here, using: * shape = fz_new_pixmap_with_rect(NULL, bbox); * then, in the end_mask code, we create the mask from this * rather than dest. */ shape = NULL; } if (luminosity) { float bc; if (!colorspace) colorspace = fz_device_gray; fz_convert_color(ctx, colorspace, colorfv, fz_device_gray, &bc); fz_clear_pixmap_with_color(dest, bc * 255); if (shape) fz_clear_pixmap_with_color(shape, 255); } else { fz_clear_pixmap(dest); if (shape) fz_clear_pixmap(shape); } dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].luminosity = luminosity; dev->stack[dev->top].shape = dev->shape; dev->stack[dev->top].blendmode = dev->blendmode; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Mask begin\n"); #endif dev->top++; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; }
void fz_paint_shade(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) { unsigned char clut[256][FZ_MAX_COLORS]; fz_pixmap *temp, *conv; float color[FZ_MAX_COLORS]; int i, k; ctm = fz_concat(shade->matrix, ctm); if (shade->use_function) { for (i = 0; i < 256; i++) { fz_convert_color(shade->colorspace, shade->function[i], dest->colorspace, color); for (k = 0; k < dest->colorspace->n; k++) clut[i][k] = color[k] * 255; clut[i][k] = shade->function[i][shade->colorspace->n] * 255; } conv = fz_new_pixmap_with_rect(dest->colorspace, bbox); temp = fz_new_pixmap_with_rect(fz_device_gray, bbox); fz_clear_pixmap(temp); } else { temp = dest; } switch (shade->type) { case FZ_LINEAR: fz_paint_linear(shade, ctm, temp, bbox); break; case FZ_RADIAL: fz_paint_radial(shade, ctm, temp, bbox); break; case FZ_MESH: fz_paint_mesh(shade, ctm, temp, bbox); break; } if (shade->use_function) { unsigned char *s = temp->samples; unsigned char *d = conv->samples; int len = temp->w * temp->h; while (len--) { int v = *s++; int a = fz_mul255(*s++, clut[v][conv->n - 1]); for (k = 0; k < conv->n - 1; k++) *d++ = fz_mul255(clut[v][k], a); *d++ = a; } fz_paint_pixmap(dest, conv, 255); fz_drop_pixmap(conv); fz_drop_pixmap(temp); } }
static void fz_draw_fill_image_mask(fz_context *ctx, void *user, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_pixmap *scaled = NULL; int dx, dy; int i; if (image->w == 0 || image->h == 0) return; if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(ctx, image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } fz_convert_color(ctx, colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_paint_image_with_color(dev->dest, dev->scissor, dev->shape, image, ctm, colorbv); if (scaled) fz_drop_pixmap(ctx, scaled); if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); }
static void fz_draw_stroke_text(fz_context *ctx, void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); fz_convert_color(ctx, colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_stroked_glyph(ctx, dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); if (dev->shape) draw_glyph(colorbv, dev->shape, glyph, x, y, dev->scissor); fz_drop_pixmap(ctx, glyph); } } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_begin_mask(fz_device *devp, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv) { fz_draw_device *dev = devp->user; fz_pixmap *dest; fz_bbox bbox; fz_draw_state *state = push_stack(dev); fz_pixmap *shape = state->shape; bbox = fz_bbox_covering_rect(rect); bbox = fz_intersect_bbox(bbox, state->scissor); dest = fz_new_pixmap_with_bbox(dev->ctx, fz_device_gray, bbox); if (state->shape) { /* FIXME: If we ever want to support AIS true, then we * probably want to create a shape pixmap here, using: * shape = fz_new_pixmap_with_bbox(NULL, bbox); * then, in the end_mask code, we create the mask from this * rather than dest. */ shape = NULL; } if (luminosity) { float bc; if (!colorspace) colorspace = fz_device_gray; fz_convert_color(dev->ctx, fz_device_gray, &bc, colorspace, colorfv); fz_clear_pixmap_with_value(dev->ctx, dest, bc * 255); if (shape) fz_clear_pixmap_with_value(dev->ctx, shape, 255); } else { fz_clear_pixmap(dev->ctx, dest); if (shape) fz_clear_pixmap(dev->ctx, shape); } #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top-1, "Mask begin\n"); #endif state[1].scissor = bbox; state[1].dest = dest; state[1].shape = shape; state[1].luminosity = luminosity; }
static void fz_draw_fill_path(fz_device *devp, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_bbox bbox; int i; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; fz_reset_gel(dev->gel, state->scissor); fz_flatten_fill_path(dev->gel, path, ctm, flatness); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, state->scissor); if (fz_is_empty_rect(bbox)) return; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, even_odd, bbox, state->dest, colorbv); if (state->shape) { fz_reset_gel(dev->gel, state->scissor); fz_flatten_fill_path(dev->gel, path, ctm, flatness); fz_sort_gel(dev->gel); colorbv[0] = alpha * 255; fz_scan_convert(dev->gel, even_odd, bbox, state->shape, colorbv); } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void fz_draw_fill_image_mask(void *user, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_pixmap *scaled = NULL; int dx, dy; int i; if (image->w == 0 || image->h == 0) return; dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { scaled = fz_transform_pixmap(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_scale_pixmap(image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } fz_convert_color(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_paint_image_with_color(dev->dest, dev->scissor, image, ctm, colorbv); if (scaled) fz_drop_pixmap(scaled); }
static void fz_draw_fill_text(void *user, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; fz_convert_color(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_glyph(dev->cache, text->font, gid, trm); if (glyph) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); fz_drop_pixmap(glyph); } } }
static void fz_paint_mesh(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) { float tri[3][MAXN]; fz_point p; float *mesh; int ntris; int i, k; mesh = shade->mesh; if (shade->use_function) ntris = shade->mesh_len / 9; else ntris = shade->mesh_len / ((2 + shade->colorspace->n) * 3); while (ntris--) { for (k = 0; k < 3; k++) { p.x = *mesh++; p.y = *mesh++; p = fz_transform_point(ctm, p); tri[k][0] = p.x; tri[k][1] = p.y; if (shade->use_function) tri[k][2] = *mesh++ * 255; else { fz_convert_color(shade->colorspace, mesh, dest->colorspace, tri[k] + 2); for (i = 0; i < dest->colorspace->n; i++) tri[k][i + 2] *= 255; mesh += shade->colorspace->n; } } fz_paint_triangle(dest, tri[0], tri[1], tri[2], 2 + dest->colorspace->n, bbox); } }
static void fz_draw_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_bbox bbox; int i; if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, dev->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (fz_is_empty_rect(bbox)) return; fz_convert_color(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, 0, bbox, dev->dest, colorbv); }
static void do_paint_tri(void *arg, fz_vertex *av, fz_vertex *bv, fz_vertex *cv) { struct paint_tri_data *ptd = (struct paint_tri_data *)arg; int i, k; fz_vertex *vertices[3]; fz_vertex *v; float *ltri; fz_context *ctx; fz_shade *shade; fz_pixmap *dest; float local[3][MAXN]; vertices[0] = av; vertices[1] = bv; vertices[2] = cv; dest = ptd->dest; ctx = ptd->ctx; shade = ptd->shade; for (k = 0; k < 3; k++) { v = vertices[k]; ltri = &local[k][0]; ltri[0] = v->p.x; ltri[1] = v->p.y; if (shade->use_function) ltri[2] = v->c[0] * 255; else { fz_convert_color(ctx, dest->colorspace, <ri[2], shade->colorspace, v->c); for (i = 0; i < dest->colorspace->n; i++) ltri[i + 2] *= 255; } } fz_paint_triangle(dest, local, 2 + dest->colorspace->n, ptd->bbox); }
static void fz_draw_begin_mask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv) { fz_draw_device *dev = user; fz_pixmap *dest; fz_bbox bbox; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(fz_device_gray, bbox); if (luminosity) { float bc; if (!colorspace) colorspace = fz_device_gray; fz_convert_color(colorspace, colorfv, fz_device_gray, &bc); fz_clear_pixmap_with_color(dest, bc * 255); } else fz_clear_pixmap(dest); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].luminosity = luminosity; dev->top++; dev->scissor = bbox; dev->dest = dest; }
static void fz_draw_fill_text(fz_context *ctx, void *user, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; unsigned char shapebv; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); fz_convert_color(ctx, colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; shapebv = 255; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_glyph(ctx, dev->cache, text->font, gid, trm, model); if (glyph) { /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1746 */ if (glyph->n > 1 && text->font->t3procs) { float light; fz_convert_color(ctx, colorspace, color, fz_device_gray, &light); if (light != 0) { fz_pixmap *gray = fz_new_pixmap_with_rect(ctx, fz_device_gray, fz_bound_pixmap(glyph)); fz_convert_pixmap(ctx, glyph, gray); fz_drop_pixmap(ctx, glyph); glyph = fz_alpha_from_gray(ctx, gray, 0); fz_drop_pixmap(ctx, gray); } } if (glyph->n == 1) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); if (dev->shape) draw_glyph(&shapebv, dev->shape, glyph, x, y, dev->scissor); } else { fz_matrix ctm = {glyph->w, 0.0, 0.0, -glyph->h, x + glyph->x, y + glyph->y + glyph->h}; fz_paint_image(dev->dest, dev->scissor, dev->shape, glyph, ctm, alpha * 255); } fz_drop_pixmap(ctx, glyph); } } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src) { float srcv[FZ_MAX_COLORS]; float dstv[FZ_MAX_COLORS]; int srcn, dstn; int y, x, k, i; fz_colorspace *ss = src->colorspace; fz_colorspace *ds = dst->colorspace; unsigned char *s = src->samples; unsigned char *d = dst->samples; assert(src->w == dst->w && src->h == dst->h); assert(src->n == ss->n + 1); assert(dst->n == ds->n + 1); srcn = ss->n; dstn = ds->n; /* Special case for Lab colorspace (scaling of components to float) */ if (!strcmp(ss->name, "Lab") && srcn == 3) { for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { srcv[0] = *s++ / 255.0f * 100; srcv[1] = *s++ - 128; srcv[2] = *s++ - 128; fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) *d++ = dstv[k] * 255; *d++ = *s++; } } } /* Brute-force for small images */ else if (src->w * src->h < 256) { for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { for (k = 0; k < srcn; k++) srcv[k] = *s++ / 255.0f; fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) *d++ = dstv[k] * 255; *d++ = *s++; } } } /* 1-d lookup table for separation and similar colorspaces */ else if (srcn == 1) { unsigned char lookup[FZ_MAX_COLORS * 256]; for (i = 0; i < 256; i++) { srcv[0] = i / 255.0f; fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) lookup[i * dstn + k] = dstv[k] * 255; } for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { i = *s++; for (k = 0; k < dstn; k++) *d++ = lookup[i * dstn + k]; *d++ = *s++; } } } /* Memoize colors using a hash table for the general case */ else { fz_hash_table *lookup; unsigned char *color; lookup = fz_new_hash_table(ctx, 509, srcn, -1); for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { color = fz_hash_find(ctx, lookup, s); if (color) { memcpy(d, color, dstn); s += srcn; d += dstn; *d++ = *s++; } else { for (k = 0; k < srcn; k++) srcv[k] = *s++ / 255.0f; fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) *d++ = dstv[k] * 255; fz_hash_insert(ctx, lookup, s - srcn, d - dstn); *d++ = *s++; } } } fz_free_hash(ctx, lookup); } }
static void fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm, trunc_trm; fz_pixmap *glyph; int i, x, y, gid; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; fz_bbox scissor = state->scissor; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trunc_trm = trm; trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); scissor.x0 -= x; scissor.x1 -= x; scissor.y0 -= y; scissor.y1 -= y; glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trunc_trm, ctm, stroke, scissor); if (glyph) { draw_glyph(colorbv, state->dest, glyph, x, y, state->scissor); if (state->shape) draw_glyph(colorbv, state->shape, glyph, x, y, state->scissor); fz_drop_pixmap(dev->ctx, glyph); } else { fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm); if (path) { fz_draw_stroke_path(devp, path, stroke, fz_identity, colorspace, color, alpha); fz_free_path(dev->ctx, path); } else { fz_warn(dev->ctx, "cannot render glyph"); } } } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void pdf_dev_color(fz_context *ctx, pdf_device *pdev, fz_colorspace *colorspace, const float *color, int stroke, const fz_color_params *color_params) { int diff = 0; int i; int cspace = 0; float rgb[FZ_MAX_COLORS]; gstate *gs = CURRENT_GSTATE(pdev); if (colorspace == fz_device_gray(ctx)) cspace = 1; else if (colorspace == fz_device_rgb(ctx)) cspace = 3; else if (colorspace == fz_device_cmyk(ctx)) cspace = 4; if (cspace == 0) { /* If it's an unknown colorspace, fallback to rgb */ fz_convert_color(ctx, color_params, NULL, fz_device_rgb(ctx), rgb, colorspace, color); color = rgb; colorspace = fz_device_rgb(ctx); cspace = 3; } if (gs->colorspace[stroke] != colorspace) { gs->colorspace[stroke] = colorspace; diff = 1; } for (i=0; i < cspace; i++) if (gs->color[stroke][i] != color[i]) { gs->color[stroke][i] = color[i]; diff = 1; } if (diff == 0) return; switch (cspace + stroke*8) { case 1: fz_append_printf(ctx, gs->buf, "%g g\n", color[0]); break; case 3: fz_append_printf(ctx, gs->buf, "%g %g %g rg\n", color[0], color[1], color[2]); break; case 4: fz_append_printf(ctx, gs->buf, "%g %g %g %g k\n", color[0], color[1], color[2], color[3]); break; case 1+8: fz_append_printf(ctx, gs->buf, "%g G\n", color[0]); break; case 3+8: fz_append_printf(ctx, gs->buf, "%g %g %g RG\n", color[0], color[1], color[2]); break; case 4+8: fz_append_printf(ctx, gs->buf, "%g %g %g %g K\n", color[0], color[1], color[2], color[3]); break; } }
static void fz_draw_fill_image_mask(fz_device *devp, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_pixmap *scaled = NULL; fz_pixmap *pixmap; fz_pixmap *orig_pixmap; int dx, dy; int i; fz_context *ctx = dev->ctx; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; fz_bbox clip = fz_pixmap_bbox(ctx, state->dest); clip = fz_intersect_bbox(clip, state->scissor); if (image->w == 0 || image->h == 0) return; dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); pixmap = fz_image_to_pixmap(ctx, image, dx, dy); orig_pixmap = pixmap; fz_try(ctx) { if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); if (dx < pixmap->w && dy < pixmap->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(dev->ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); if (!scaled) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); } if (scaled) pixmap = scaled; } fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_paint_image_with_color(state->dest, state->scissor, state->shape, pixmap, ctm, colorbv); if (scaled) fz_drop_pixmap(dev->ctx, scaled); if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); } fz_always(ctx) { fz_drop_pixmap(dev->ctx, orig_pixmap); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void fz_draw_fill_shade(fz_context *ctx, void *user, fz_shade *shade, fz_matrix ctm, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest = dev->dest; fz_rect bounds; fz_bbox bbox, scissor; float colorfv[FZ_MAX_COLORS]; unsigned char colorbv[FZ_MAX_COLORS + 1]; bounds = fz_bound_shade(shade, ctm); bbox = fz_intersect_bbox(fz_round_rect(bounds), dev->scissor); scissor = dev->scissor; // TODO: proper clip by shade->bbox if (fz_is_empty_rect(bbox)) return; if (!model) { fz_warn(ctx, "cannot render shading directly to an alpha mask"); return; } if (alpha < 1) { dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox); fz_clear_pixmap(dest); } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); if (shade->use_background) { unsigned char *s; int x, y, n, i; fz_convert_color(ctx, shade->colorspace, shade->background, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = scissor.y0; y < scissor.y1; y++) { s = dest->samples + ((scissor.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n; for (x = scissor.x0; x < scissor.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } if (dev->shape) { for (y = scissor.y0; y < scissor.y1; y++) { s = dev->shape->samples + (scissor.x0 - dev->shape->x) + (y - dev->shape->y) * dev->shape->w; for (x = scissor.x0; x < scissor.x1; x++) { *s++ = 255; } } } } fz_paint_shade(ctx, shade, ctm, dest, bbox); if (dev->shape) fz_clear_pixmap_rect_with_color(dev->shape, 255, bbox); if (alpha < 1) { fz_paint_pixmap(dev->dest, dest, alpha * 255); fz_drop_pixmap(ctx, dest); } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static int xps_parse_gradient_stops(fz_context *ctx, xps_document *doc, char *base_uri, fz_xml *node, struct stop *stops, int maxcount) { fz_colorspace *colorspace; float sample[FZ_MAX_COLORS]; float rgb[3]; int before, after; int count; int i; /* We may have to insert 2 extra stops when postprocessing */ maxcount -= 2; count = 0; while (node && count < maxcount) { if (fz_xml_is_tag(node, "GradientStop")) { char *offset = fz_xml_att(node, "Offset"); char *color = fz_xml_att(node, "Color"); if (offset && color) { stops[count].offset = fz_atof(offset); stops[count].index = count; xps_parse_color(ctx, doc, base_uri, color, &colorspace, sample); fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, sample + 1); stops[count].r = rgb[0]; stops[count].g = rgb[1]; stops[count].b = rgb[2]; stops[count].a = sample[0]; count ++; } } node = fz_xml_next(node); } if (count == 0) { fz_warn(ctx, "gradient brush has no gradient stops"); stops[0].offset = 0; stops[0].r = 0; stops[0].g = 0; stops[0].b = 0; stops[0].a = 1; stops[1].offset = 1; stops[1].r = 1; stops[1].g = 1; stops[1].b = 1; stops[1].a = 1; return 2; } if (count == maxcount) fz_warn(ctx, "gradient brush exceeded maximum number of gradient stops"); /* Postprocess to make sure the range of offsets is 0.0 to 1.0 */ qsort(stops, count, sizeof(struct stop), cmp_stop); before = -1; after = -1; for (i = 0; i < count; i++) { if (stops[i].offset < 0) before = i; if (stops[i].offset > 1) { after = i; break; } } /* Remove all stops < 0 except the largest one */ if (before > 0) { memmove(stops, stops + before, (count - before) * sizeof(struct stop)); count -= before; } /* Remove all stops > 1 except the smallest one */ if (after >= 0) count = after + 1; /* Expand single stop to 0 .. 1 */ if (count == 1) { stops[1] = stops[0]; stops[0].offset = 0; stops[1].offset = 1; return 2; } /* First stop < 0 -- interpolate value to 0 */ if (stops[0].offset < 0) { float d = -stops[0].offset / (stops[1].offset - stops[0].offset); stops[0].offset = 0; stops[0].r = lerp(stops[0].r, stops[1].r, d); stops[0].g = lerp(stops[0].g, stops[1].g, d); stops[0].b = lerp(stops[0].b, stops[1].b, d); stops[0].a = lerp(stops[0].a, stops[1].a, d); } /* Last stop > 1 -- interpolate value to 1 */ if (stops[count-1].offset > 1) { float d = (1 - stops[count-2].offset) / (stops[count-1].offset - stops[count-2].offset); stops[count-1].offset = 1; stops[count-1].r = lerp(stops[count-2].r, stops[count-1].r, d); stops[count-1].g = lerp(stops[count-2].g, stops[count-1].g, d); stops[count-1].b = lerp(stops[count-2].b, stops[count-1].b, d); stops[count-1].a = lerp(stops[count-2].a, stops[count-1].a, d); } /* First stop > 0 -- insert a duplicate at 0 */ if (stops[0].offset > 0) { memmove(stops + 1, stops, count * sizeof(struct stop)); stops[0] = stops[1]; stops[0].offset = 0; count++; } /* Last stop < 1 -- insert a duplicate at 1 */ if (stops[count-1].offset < 1) { stops[count] = stops[count-1]; stops[count].offset = 1; count++; } return count; }
static void fz_draw_fill_shade(fz_device *devp, fz_shade *shade, fz_matrix ctm, float alpha) { fz_draw_device *dev = devp->user; fz_rect bounds; fz_bbox bbox, scissor; fz_pixmap *dest, *shape; float colorfv[FZ_MAX_COLORS]; unsigned char colorbv[FZ_MAX_COLORS + 1]; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; bounds = fz_bound_shade(dev->ctx, shade, ctm); scissor = state->scissor; bbox = fz_intersect_bbox(fz_bbox_covering_rect(bounds), scissor); if (fz_is_empty_rect(bbox)) return; if (!model) { fz_warn(dev->ctx, "cannot render shading directly to an alpha mask"); return; } if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); dest = state->dest; shape = state->shape; if (alpha < 1) { dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, bbox); fz_clear_pixmap(dev->ctx, dest); if (shape) { shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } } if (shade->use_background) { unsigned char *s; int x, y, n, i; fz_convert_color(dev->ctx, model, colorfv, shade->colorspace, shade->background); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = scissor.y0; y < scissor.y1; y++) { s = dest->samples + (unsigned int)(((scissor.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n); for (x = scissor.x0; x < scissor.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } if (shape) { for (y = scissor.y0; y < scissor.y1; y++) { s = shape->samples + (unsigned int)((scissor.x0 - shape->x) + (y - shape->y) * shape->w); for (x = scissor.x0; x < scissor.x1; x++) { *s++ = 255; } } } } fz_paint_shade(dev->ctx, shade, ctm, dest, bbox); if (shape) fz_clear_pixmap_rect_with_value(dev->ctx, shape, 255, bbox); if (alpha < 1) { fz_paint_pixmap(state->dest, dest, alpha * 255); fz_drop_pixmap(dev->ctx, dest); if (shape) { fz_paint_pixmap(state->shape, shape, alpha * 255); fz_drop_pixmap(dev->ctx, shape); } } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }