void fz_stdconvpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst) { float srcv[FZ_MAXCOLORS]; float dstv[FZ_MAXCOLORS]; int y, x, k; unsigned char *s = src->p; unsigned char *d = dst->p; printf("convert pixmap from %s to %s\n", srcs->name, dsts->name); assert(src->w == dst->w && src->h == dst->h); assert(src->n == srcs->n + 1); assert(dst->n == dsts->n + 1); for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { *d++ = *s++; for (k = 0; k < src->n - 1; k++) srcv[k] = *s++ / 255.0; fz_convertcolor(srcs, srcv, dsts, dstv); for (k = 0; k < dst->n - 1; k++) *d++ = dstv[k] * 255; } } }
static void fz_drawfillimagemask(void *user, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAXCOLORS + 1]; float colorfv[FZ_MAXCOLORS]; fz_pixmap *scaled = nil; int dx, dy; int i; if (image->w == 0 || image->h == 0) return; #ifdef SMOOTHSCALE 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_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_convertcolor(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_paintimagecolor(dev->dest, dev->scissor, image, ctm, colorbv); if (scaled) fz_droppixmap(scaled); }
static fz_error * rendersolid(fz_renderer *gc, fz_solidnode *solid, fz_matrix ctm) { fz_error *error; float rgb[3]; unsigned char *p; int n; if (gc->maskonly) return fz_throw("assert: mask only renderer"); if (gc->model->n != 3) return fz_throw("assert: non-rgb renderer"); fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); gc->rgb[0] = rgb[0] * 255; gc->rgb[1] = rgb[1] * 255; gc->rgb[2] = rgb[2] * 255; DEBUG("solid %s [%d %d %d];\n", solid->cs->name, gc->rgb[0], gc->rgb[1], gc->rgb[2]); if (gc->flag == FOVER) { p = gc->over->samples; n = gc->over->w * gc->over->h; } else { error = fz_newpixmapwithrect(&gc->dest, gc->clip, 4); if (error) return error; p = gc->dest->samples; n = gc->dest->w * gc->dest->h; } while (n--) { p[0] = 255; p[1] = gc->rgb[0]; p[2] = gc->rgb[1]; p[3] = gc->rgb[2]; p += 4; } return nil; }
static void fz_drawstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAXCOLORS + 1]; float colorfv[FZ_MAXCOLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; fz_convertcolor(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->els[i].gid; if (gid < 0) continue; tm.e = text->els[i].x; tm.f = text->els[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_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor); fz_droppixmap(glyph); } } }
static void fz_drawstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrixexpansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; unsigned char colorbv[FZ_MAXCOLORS + 1]; float colorfv[FZ_MAXCOLORS]; fz_bbox bbox; int i; if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_resetgel(dev->gel, dev->scissor); if (stroke->dashlen > 0) fz_dashpath(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_strokepath(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sortgel(dev->gel); bbox = fz_boundgel(dev->gel); bbox = fz_intersectbbox(bbox, dev->scissor); if (fz_isemptyrect(bbox)) return; fz_convertcolor(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scanconvert(dev->gel, dev->ael, 0, bbox, dev->dest, colorbv); }
static void fz_drawfillshade(void *user, fz_shade *shade, fz_matrix ctm, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest = dev->dest; fz_rect bounds; fz_bbox bbox; float colorfv[FZ_MAXCOLORS]; unsigned char colorbv[FZ_MAXCOLORS + 1]; bounds = fz_boundshade(shade, ctm); bbox = fz_intersectbbox(fz_roundrect(bounds), dev->scissor); // TODO: proper clip by shade->bbox if (!fz_isemptyrect(shade->bbox)) { bounds = fz_transformrect(fz_concat(shade->matrix, ctm), shade->bbox); bbox = fz_intersectbbox(fz_roundrect(bounds), bbox); } if (fz_isemptyrect(bbox)) return; if (!model) { fz_warn("cannot render shading directly to an alpha mask"); return; } if (alpha < 1) { dest = fz_newpixmapwithrect(dev->dest->colorspace, bbox); fz_clearpixmap(dest, 0); } if (shade->usebackground) { unsigned char *s; int x, y, n, i; fz_convertcolor(shade->cs, shade->background, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = bbox.y0; y < bbox.y1; y++) { s = dest->samples + ((bbox.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n; for (x = bbox.x0; x < bbox.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } } fz_rendershade(shade, ctm, dest, bbox); if (alpha < 1) { fz_paintpixmap(dev->dest, dest, alpha * 255); fz_droppixmap(dest); } }
static fz_error * rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm) { fz_error *error; int oldmaskonly; fz_pixmap *oldover; fz_irect oldclip; fz_irect bbox; fz_irect clip; fz_pixmap *shapepix = nil; fz_pixmap *colorpix = nil; fz_node *shape; fz_node *color; float rgb[3]; shape = mask->super.first; color = shape->next; /* special case black voodo */ if (gc->flag & FOVER) { if (fz_issolidnode(color)) { fz_solidnode *solid = (fz_solidnode*)color; fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); gc->argb[0] = solid->a * 255; gc->argb[1] = rgb[0] * solid->a * 255; gc->argb[2] = rgb[1] * solid->a * 255; gc->argb[3] = rgb[2] * solid->a * 255; gc->argb[4] = rgb[0] * 255; gc->argb[5] = rgb[1] * 255; gc->argb[6] = rgb[2] * 255; gc->flag |= FRGB; /* we know these can handle the FRGB shortcut */ if (fz_ispathnode(shape)) return renderpath(gc, (fz_pathnode*)shape, ctm); if (fz_istextnode(shape)) return rendertext(gc, (fz_textnode*)shape, ctm); if (fz_isimagenode(shape)) return renderimage(gc, (fz_imagenode*)shape, ctm); } } oldclip = gc->clip; oldover = gc->over; bbox = fz_roundrect(fz_boundnode(shape, ctm)); clip = fz_intersectirects(bbox, gc->clip); bbox = fz_roundrect(fz_boundnode(color, ctm)); clip = fz_intersectirects(bbox, clip); if (fz_isemptyrect(clip)) return fz_okay; DEBUG("mask [%d %d %d %d]\n{\n", clip.x0, clip.y0, clip.x1, clip.y1); { fz_irect sbox = fz_roundrect(fz_boundnode(shape, ctm)); fz_irect cbox = fz_roundrect(fz_boundnode(color, ctm)); if (cbox.x0 >= sbox.x0 && cbox.x1 <= sbox.x1) if (cbox.y0 >= sbox.y0 && cbox.y1 <= sbox.y1) DEBUG("potentially useless mask\n"); } gc->clip = clip; gc->over = nil; oldmaskonly = gc->maskonly; gc->maskonly = 1; error = rendernode(gc, shape, ctm); if (error) goto cleanup; shapepix = gc->dest; gc->dest = nil; gc->maskonly = oldmaskonly; error = rendernode(gc, color, ctm); if (error) goto cleanup; colorpix = gc->dest; gc->dest = nil; gc->clip = oldclip; gc->over = oldover; if (shapepix && colorpix) { if (gc->over) { blendmask(gc, colorpix, shapepix, gc->over, 1); } else { clip.x0 = MAX(colorpix->x, shapepix->x); clip.y0 = MAX(colorpix->y, shapepix->y); clip.x1 = MIN(colorpix->x+colorpix->w, shapepix->x+shapepix->w); clip.y1 = MIN(colorpix->y+colorpix->h, shapepix->y+shapepix->h); error = fz_newpixmapwithrect(&gc->dest, clip, colorpix->n); if (error) goto cleanup; blendmask(gc, colorpix, shapepix, gc->dest, 0); } } DEBUG("}\n"); if (shapepix) fz_droppixmap(shapepix); if (colorpix) fz_droppixmap(colorpix); return fz_okay; cleanup: if (shapepix) fz_droppixmap(shapepix); if (colorpix) fz_droppixmap(colorpix); return error; }
static fz_error * rendersolid(fz_renderer *gc, fz_solidnode *solid, fz_matrix ctm) { fz_error *error; float rgb[3]; unsigned char a, r, g, b; unsigned char *p; int n; if (gc->maskonly) return fz_throw("assert: mask only renderer"); if (gc->model->n != 3) return fz_throw("assert: non-rgb renderer"); fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); gc->argb[0] = solid->a * 255; gc->argb[1] = rgb[0] * solid->a * 255; gc->argb[2] = rgb[1] * solid->a * 255; gc->argb[3] = rgb[2] * solid->a * 255; gc->argb[4] = rgb[0] * 255; gc->argb[5] = rgb[1] * 255; gc->argb[6] = rgb[2] * 255; DEBUG("solid %s [%d %d %d %d];\n", solid->cs->name, gc->argb[0], gc->argb[1], gc->argb[2], gc->argb[3]); if (gc->flag == FOVER) { p = gc->over->samples; n = gc->over->w * gc->over->h; } else { error = fz_newpixmapwithrect(&gc->dest, gc->clip, 4); if (error) return error; p = gc->dest->samples; n = gc->dest->w * gc->dest->h; } a = gc->argb[0]; r = gc->argb[1]; g = gc->argb[2]; b = gc->argb[3]; if (((unsigned)p & 3)) { while (n--) { p[0] = a; p[1] = r; p[2] = g; p[3] = b; p += 4; } } else { unsigned *pw = (unsigned *)p; #if BYTE_ORDER == LITTLE_ENDIAN unsigned argb = a | (r << 8) | (g << 16) | (b << 24); #else unsigned argb = (a << 24) | (r << 16) | (g << 8) | b; #endif while (n--) { *pw++ = argb; } } return fz_okay; }
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; }
static void fz_stdconvpixmap(fz_pixmap *src, fz_pixmap *dst) { float srcv[FZ_MAXCOLORS]; float dstv[FZ_MAXCOLORS]; 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_convertcolor(ss, srcv, ds, dstv); 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_convertcolor(ss, srcv, ds, dstv); 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_MAXCOLORS * 256]; for (i = 0; i < 256; i++) { srcv[0] = i / 255.0f; fz_convertcolor(ss, srcv, ds, dstv); 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_hashtable *lookup; unsigned char *color; lookup = fz_newhash(509, srcn); for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { color = fz_hashfind(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_convertcolor(ss, srcv, ds, dstv); for (k = 0; k < dstn; k++) *d++ = dstv[k] * 255; fz_hashinsert(lookup, s - srcn, d - dstn); *d++ = *s++; } } } fz_freehash(lookup); } }