From 93701ab27b4d50f5d27da43f34d432e1963ce337 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Tue, 26 Jul 2011 16:09:55 +0100 Subject: Fix bug 692354: Horizontal white lines in images. The problem is due to abutting images showing gaps between them. These gaps are due to a combination of rounding errors, and anti-aliasing effects on the edge of images. The solution is to selectively 'grid fit' images. If an image is part of a type 3 font, we do NOT want to grid fit it, as this is where the sub pixel positioning makes a huge difference. If an image is displayed with alpha, then we don't want to grid fit it (as grid fitting will tend to make the edges of images overlap by 1 pixel, and will hence produce nasty effects). Otherwise, we will grid fit; Grid fit in this sense is where we expand an image to completely fill the pixel grid that it touches (i.e. the extents for the image are expanded to pixel boundaries; no half full pixels are left around the edges). The only real change of note here is in how we detect that we are in a type 3 charproc; we add a new draw device creation function that we call in the type3 charproc case that sets a flag that the drawing functions can check. --- draw/draw_device.c | 32 +++++++++++++++++++++++------ draw/draw_scale.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 6 deletions(-) (limited to 'draw') diff --git a/draw/draw_device.c b/draw/draw_device.c index 46a3fa2b..52393081 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -8,6 +8,10 @@ typedef struct fz_draw_device_s fz_draw_device; +enum { + FZ_DRAWDEV_FLAGS_TYPE3 = 1, +}; + struct fz_draw_device_s { fz_glyph_cache *cache; @@ -17,6 +21,7 @@ struct fz_draw_device_s fz_pixmap *shape; fz_bbox scissor; + int flags; int top; int blendmode; struct { @@ -737,14 +742,14 @@ fz_draw_fill_shade(void *user, fz_shade *shade, fz_matrix ctm, float alpha) } static fz_pixmap * -fz_transform_pixmap(fz_pixmap *image, fz_matrix *ctm, int x, int y, int dx, int dy) +fz_transform_pixmap(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 Yflip or XYflip */ - scaled = fz_scale_pixmap(image, ctm->e, ctm->f, ctm->a, ctm->d); + scaled = fz_scale_pixmap_gridfit(image, ctm->e, ctm->f, ctm->a, ctm->d, gridfit); if (scaled == NULL) return NULL; ctm->a = scaled->w; @@ -756,7 +761,7 @@ fz_transform_pixmap(fz_pixmap *image, fz_matrix *ctm, int x, int y, int dx, int if (ctm->a == 0 && ctm->b != 0 && ctm->c != 0 && ctm->d == 0) { /* Other orthogonal flip/rotation cases */ - scaled = fz_scale_pixmap(image, ctm->f, ctm->e, ctm->b, ctm->c); + scaled = fz_scale_pixmap_gridfit(image, ctm->f, ctm->e, ctm->b, ctm->c, gridfit); if (scaled == NULL) return NULL; ctm->b = scaled->w; @@ -815,7 +820,7 @@ fz_draw_fill_image(void *user, fz_pixmap *image, fz_matrix ctm, float alpha) 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); + scaled = fz_transform_pixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy, (alpha == 1.0f) && ((dev->flags & FZ_DRAWDEV_FLAGS_TYPE3) == 0)); if (scaled == NULL) { if (dx < 1) @@ -876,7 +881,7 @@ fz_draw_fill_image_mask(void *user, fz_pixmap *image, fz_matrix ctm, 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); + scaled = fz_transform_pixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy, (alpha == 1.0f) && ((dev->flags & FZ_DRAWDEV_FLAGS_TYPE3) == 0)); if (scaled == NULL) { if (dx < 1) @@ -951,7 +956,7 @@ fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix c 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); + scaled = fz_transform_pixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy, (dev->flags & FZ_DRAWDEV_FLAGS_TYPE3) == 0); if (scaled == NULL) { if (dx < 1) @@ -1307,6 +1312,7 @@ fz_new_draw_device(fz_glyph_cache *cache, fz_pixmap *dest) ddev->shape = NULL; ddev->top = 0; ddev->blendmode = 0; + ddev->flags = 0; ddev->scissor.x0 = dest->x; ddev->scissor.y0 = dest->y; @@ -1344,3 +1350,17 @@ fz_new_draw_device(fz_glyph_cache *cache, fz_pixmap *dest) return dev; } + +fz_device * +fz_new_draw_device_type3(fz_glyph_cache *cache, fz_pixmap *dest) +{ + fz_device *dev = fz_new_draw_device(cache, dest); + + if (dev) + { + fz_draw_device *ddev = (fz_draw_device *)dev->user; + + ddev->flags |= FZ_DRAWDEV_FLAGS_TYPE3; + } + return dev; +} diff --git a/draw/draw_scale.c b/draw/draw_scale.c index 9b94702e..40a5deff 100644 --- a/draw/draw_scale.c +++ b/draw/draw_scale.c @@ -988,6 +988,65 @@ scale_single_col(unsigned char *dst, unsigned char *src, fz_weights *weights, in } #endif /* SINGLE_PIXEL_SPECIALS */ +fz_pixmap * +fz_scale_pixmap_gridfit(fz_pixmap *src, float x, float y, float w, float h, int gridfit) +{ + if (gridfit) { + float n; + if (w > 0) { + /* Adjust the left hand edge, leftwards to a pixel boundary */ + n = (float)(int)x; /* n is now on a pixel boundary */ + if (n > x) /* Ensure it's the pixel boundary BELOW x */ + n -= 1.0f; + w += x-n; /* width gets wider as x >= n */ + x = n; + /* Adjust the right hand edge rightwards to a pixel boundary */ + n = (float)(int)w; /* n is now the integer width <= w */ + if (n != w) /* If w isn't an integer already, bump it */ + w = 1.0f + n;/* up to the next integer. */ + } else { + /* Adjust the right hand edge, rightwards to a pixel boundary */ + n = (float)(int)x; /* n is now on a pixel boundary */ + if (n > x) /* Ensure it's the pixel boundary <= x */ + n -= 1.0f; + if (n != x) /* If x isn't on a pixel boundary already, */ + n += 1.0f; /* make n be the pixel boundary above x. */ + w -= n-x; /* Expand width (more negative!) as n >= x */ + x = n; + /* Adjust the left hand edge leftwards to a pixel boundary */ + n = (float)(int)w; + if (n != w) + w = n - 1.0f; + } + if (h > 0) { + /* Adjust the bottom edge, downwards to a pixel boundary */ + n = (float)(int)y; /* n is now on a pixel boundary */ + if (n > y) /* Ensure it's the pixel boundary BELOW y */ + n -= 1.0f; + h += y-n; /* height gets larger as y >= n */ + y = n; + /* Adjust the top edge upwards to a pixel boundary */ + n = (float)(int)h; /* n is now the integer height <= h */ + if (n != h) /* If h isn't an integer already, bump it */ + h = 1.0f + n;/* up to the next integer. */ + } else { + /* Adjust the top edge, upwards to a pixel boundary */ + n = (float)(int)y; /* n is now on a pixel boundary */ + if (n > y) /* Ensure it's the pixel boundary <= y */ + n -= 1.0f; + if (n != y) /* If y isn't on a pixel boundary already, */ + n += 1.0f; /* make n be the pixel boundary above y. */ + h -= n-y; /* Expand height (more negative!) as n >= y */ + y = n; + /* Adjust the bottom edge downwards to a pixel boundary */ + n = (float)(int)h; + if (n != h) + h = n - 1.0f; + } + } + return fz_scale_pixmap(src, x, y, w, h); +} + fz_pixmap * fz_scale_pixmap(fz_pixmap *src, float x, float y, float w, float h) { -- cgit v1.2.3