static fz_pixmap * fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, int y, int dx, int dy, int gridfit, fz_bbox *clip) { fz_pixmap *scaled; if (ctm->a != 0 && ctm->b == 0 && ctm->c == 0 && ctm->d != 0) { /* Unrotated or X-flip or Y-flip or XY-flip */ fz_matrix m = *ctm; if (gridfit) fz_gridfit_matrix(&m); scaled = fz_scale_pixmap(ctx, image, m.e, m.f, m.a, m.d, clip); if (!scaled) return NULL; ctm->a = scaled->w; ctm->d = scaled->h; ctm->e = scaled->x; ctm->f = scaled->y; return scaled; } if (ctm->a == 0 && ctm->b != 0 && ctm->c != 0 && ctm->d == 0) { /* Other orthogonal flip/rotation cases */ fz_matrix m = *ctm; fz_bbox rclip; if (gridfit) fz_gridfit_matrix(&m); if (clip) { rclip.x0 = clip->y0; rclip.y0 = clip->x0; rclip.x1 = clip->y1; rclip.y1 = clip->x1; } scaled = fz_scale_pixmap(ctx, image, m.f, m.e, m.b, m.c, (clip ? &rclip : 0)); if (!scaled) return NULL; ctm->b = scaled->w; ctm->c = scaled->h; ctm->f = scaled->x; ctm->e = scaled->y; return scaled; } /* Downscale, non rectilinear case */ if (dx > 0 && dy > 0) { scaled = fz_scale_pixmap(ctx, image, 0, 0, (float)dx, (float)dy, NULL); return scaled; } return NULL; }
static fz_pixmap * fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, int y, int dx, int dy, int gridfit) { fz_pixmap *scaled; if (ctm->a != 0 && ctm->b == 0 && ctm->c == 0 && ctm->d != 0) { /* Unrotated or X-flip or Y-flip or XY-flip */ fz_matrix m = *ctm; if (gridfit) fz_gridfit_matrix(&m); scaled = fz_scale_pixmap(ctx, image, m.e, m.f, m.a, m.d); if (scaled == NULL) return NULL; ctm->a = scaled->w; ctm->d = scaled->h; ctm->e = scaled->x; ctm->f = scaled->y; return scaled; } if (ctm->a == 0 && ctm->b != 0 && ctm->c != 0 && ctm->d == 0) { /* Other orthogonal flip/rotation cases */ fz_matrix m = *ctm; if (gridfit) fz_gridfit_matrix(&m); scaled = fz_scale_pixmap(ctx, image, m.f, m.e, m.b, m.c); if (scaled == NULL) return NULL; ctm->b = scaled->w; ctm->c = scaled->h; ctm->f = scaled->x; ctm->e = scaled->y; return scaled; } /* Downscale, non rectilinear case */ if (dx > 0 && dy > 0) { scaled = fz_scale_pixmap(ctx, image, 0, 0, (float)dx, (float)dy); return scaled; } return NULL; }
static void fz_paint_image_imp(fz_pixmap *dst, const fz_irect *scissor, fz_pixmap *shape, fz_pixmap *img, const fz_matrix *ctm, byte *color, int alpha) { byte *dp, *sp, *hp; int u, v, fa, fb, fc, fd; int x, y, w, h; int sw, sh, n, hw; fz_irect bbox; int dolerp; void (*paintfn)(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color, byte *hp); fz_matrix local_ctm = *ctm; fz_rect rect; /* grid fit the image */ fz_gridfit_matrix(&local_ctm); /* turn on interpolation for upscaled and non-rectilinear transforms */ dolerp = 0; if (!fz_is_rectilinear(&local_ctm)) dolerp = 1; if (sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b) > img->w) dolerp = 1; if (sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d) > img->h) dolerp = 1; /* except when we shouldn't, at large magnifications */ if (!img->interpolate) { if (sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b) > img->w * 2) dolerp = 0; if (sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d) > img->h * 2) dolerp = 0; } rect = fz_unit_rect; fz_irect_from_rect(&bbox, fz_transform_rect(&rect, &local_ctm)); fz_intersect_irect(&bbox, scissor); x = bbox.x0; if (shape && shape->x > x) x = shape->x; y = bbox.y0; if (shape && shape->y > y) y = shape->y; w = bbox.x1; if (shape && shape->x + shape->w < w) w = shape->x + shape->w; w -= x; h = bbox.y1; if (shape && shape->y + shape->h < h) h = shape->y + shape->h; h -= y; if (w < 0 || h < 0) return; /* map from screen space (x,y) to image space (u,v) */ fz_pre_scale(&local_ctm, 1.0f / img->w, 1.0f / img->h); fz_invert_matrix(&local_ctm, &local_ctm); fa = (int)(local_ctm.a *= 65536.0f); fb = (int)(local_ctm.b *= 65536.0f); fc = (int)(local_ctm.c *= 65536.0f); fd = (int)(local_ctm.d *= 65536.0f); local_ctm.e *= 65536.0f; local_ctm.f *= 65536.0f; /* Calculate initial texture positions. Do a half step to start. */ /* Bug 693021: Keep calculation in float for as long as possible to * avoid overflow. */ u = (int)((local_ctm.a * x) + (local_ctm.c * y) + local_ctm.e + ((local_ctm.a + local_ctm.c) * .5f)); v = (int)((local_ctm.b * x) + (local_ctm.d * y) + local_ctm.f + ((local_ctm.b + local_ctm.d) * .5f)); /* RJW: The following is voodoo. No idea why it works, but it gives * the best match between scaled/unscaled/interpolated/non-interpolated * that we have found. */ if (dolerp) { u -= 32768; v -= 32768; } dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n); n = dst->n; sp = img->samples; sw = img->w; sh = img->h; if (shape) { hw = shape->w; hp = shape->samples + (unsigned int)(((y - shape->y) * hw) + x - shape->x); } else { hw = 0; hp = NULL; } /* TODO: if (fb == 0 && fa == 1) call fz_paint_span */ if (dst->n == 4 && img->n == 2) { assert(!color); if (dolerp) paintfn = fz_paint_affine_g2rgb_lerp; else paintfn = fz_paint_affine_g2rgb_near; } else { if (dolerp) { if (color) paintfn = fz_paint_affine_color_lerp; else paintfn = fz_paint_affine_lerp; } else { if (color) paintfn = fz_paint_affine_color_near; else paintfn = fz_paint_affine_near; } } while (h--) { paintfn(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, color, hp); dp += dst->w * n; hp += hw; u += fc; v += fd; } }