diff options
author | Robin Watts <robin.watts@artifex.com> | 2015-07-13 16:23:14 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2015-07-20 17:19:03 +0100 |
commit | 269fdfce2527cbba02e68d658af3f4b92ef40be0 (patch) | |
tree | c75e9e4abdae745c64f98eaafa86d572e747f536 /source/fitz/draw-device.c | |
parent | d8353609755104010afaf3e1967a36959f28c5dc (diff) | |
download | mupdf-269fdfce2527cbba02e68d658af3f4b92ef40be0.tar.xz |
Improve Grid fitting of images for .gproof files.
By default in MuPDF, when we render an axis aligned image, we
'gridfit' it. This is a heuristic used to improve the rendering
of tiled images, and avoid the background showing through on the
antialiased edges.
The general algorithm we use is to expand any image outwards so that
it completely covers any pixels that it touches any part of. This is
'safe' in that we never cause any pixels to not be covered that
should otherwise be so, and is important when we have images that are
aligned with (say) line art rectangles.
For gproof files though, this gives nasty results - because we have
multiple images tiled across the page all exactly abutting, in most
cases the edges will not be on exact integer coordinates. This means
we expand both images and 1 (destination) pixel is lost. This severely
hurts the rendering (in particular on text based pages).
We therefore introduce a new type of grid fitting, where we simply
align the edges of images to the closest integer pixel. This is safe
because we know that neighbouring images will be adjusted identically
and edges will stay coincident.
We enable/disable this behaviour through a new device flag, and make
the gproof interpreter set/clear this flag when generating the page -
thus normal rendering is unaffected.
We *could* have just poked the dev->flags fields directly, but that
would require magic in the display list device to check for them
being set/unset and to poke the dev->flags fields on playback, so
instead we introduce a new fz_render_flags function (that calls a
device function) to set/unset flags.
The other attraction of this is that if we ever have devices that
'filter', we can neatly handle passing flag changes on with those.
Currently the display list implementation only copes with set/clear
of the FZ_DEVFLAG_GRIDFIT_AS_TILED option. We only readily have 6
bits available to us, so we'll just extend this as required if we
add new render flags.
Diffstat (limited to 'source/fitz/draw-device.c')
-rw-r--r-- | source/fitz/draw-device.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c index a2499016..fdb631f4 100644 --- a/source/fitz/draw-device.c +++ b/source/fitz/draw-device.c @@ -610,7 +610,7 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, fz_text *text, const fz_matr fz_matrix mat; mat.a = pixmap->w; mat.b = mat.c = 0; mat.d = pixmap->h; mat.e = x + pixmap->x; mat.f = y + pixmap->y; - fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &mat, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES)); + fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &mat, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED); } fz_drop_glyph(ctx, glyph); } @@ -1040,7 +1040,9 @@ fz_transform_pixmap(fz_context *ctx, fz_draw_device *dev, fz_pixmap *image, fz_m /* Unrotated or X-flip or Y-flip or XY-flip */ fz_matrix m = *ctm; if (gridfit) - fz_gridfit_matrix(&m); + { + fz_gridfit_matrix(dev->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, &m); + } scaled = fz_scale_pixmap_cached(ctx, image, m.e, m.f, m.a, m.d, clip, dev->cache_x, dev->cache_y); if (!scaled) return NULL; @@ -1057,7 +1059,7 @@ fz_transform_pixmap(fz_context *ctx, fz_draw_device *dev, fz_pixmap *image, fz_m fz_matrix m = *ctm; fz_irect rclip; if (gridfit) - fz_gridfit_matrix(&m); + fz_gridfit_matrix(dev->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, &m); if (clip) { rclip.x0 = clip->y0; @@ -1174,7 +1176,7 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m } } - fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &local_ctm, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES)); + fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &local_ctm, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED); if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); @@ -1245,7 +1247,7 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; - fz_paint_image_with_color(state->dest, &state->scissor, state->shape, pixmap, &local_ctm, colorbv, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES)); + fz_paint_image_with_color(state->dest, &state->scissor, state->shape, pixmap, &local_ctm, colorbv, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED); if (scaled) fz_drop_pixmap(ctx, scaled); @@ -1351,7 +1353,7 @@ fz_draw_clip_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const if (scaled) pixmap = scaled; } - fz_paint_image(mask, &bbox, state->shape, pixmap, &local_ctm, 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES)); + fz_paint_image(mask, &bbox, state->shape, pixmap, &local_ctm, 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED); } fz_always(ctx) { @@ -2040,6 +2042,14 @@ fz_draw_drop_imp(fz_context *ctx, fz_device *devp) fz_drop_gel(ctx, gel); } +static void +fz_draw_render_flags(fz_context *ctx, fz_device *devp, int set, int clear) +{ + fz_draw_device *dev = (fz_draw_device*)devp; + + dev->flags = (dev->flags | set ) & ~clear; +} + fz_device * fz_new_draw_device(fz_context *ctx, fz_pixmap *dest) { @@ -2073,6 +2083,8 @@ fz_new_draw_device(fz_context *ctx, fz_pixmap *dest) dev->super.begin_tile = fz_draw_begin_tile; dev->super.end_tile = fz_draw_end_tile; + dev->super.render_flags = fz_draw_render_flags; + dev->flags = 0; dev->top = 0; dev->stack = &dev->init_stack[0]; |