Index: poppler/CairoOutputDev.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/CairoOutputDev.cc,v retrieving revision 1.48 diff -u -r1.48 CairoOutputDev.cc --- poppler/CairoOutputDev.cc 21 Dec 2006 01:01:30 -0000 1.48 +++ poppler/CairoOutputDev.cc 24 Mar 2007 21:02:41 -0000 @@ -15,6 +15,7 @@ #include #include +#include #include #include "goo/gfile.h" @@ -30,7 +31,6 @@ #include #include "CairoOutputDev.h" #include "CairoFontEngine.h" - //------------------------------------------------------------------------ // #define LOG_CAIRO @@ -202,7 +202,7 @@ cairo_set_miter_limit (cairo, state->getMiterLimit()); } -#define MIN(a,b) (a) < (b) ? (a) : (b) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) void CairoOutputDev::updateLineWidth(GfxState *state) { LOG(printf ("line width: %f\n", state->getLineWidth())); @@ -491,6 +491,17 @@ } +static inline int splashRound(SplashCoord x) { + return (int)floor(x + 0.5); +} + +static inline int splashCeil(SplashCoord x) { + return (int)ceil(x); +} + +static inline int splashFloor(SplashCoord x) { + return (int)floor(x); +} void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, @@ -517,13 +528,58 @@ cairo_restore (cairo); return; } - - row_stride = (width + 3) & ~3; - buffer = (unsigned char *) malloc (height * row_stride); - if (buffer == NULL) { - error(-1, "Unable to allocate memory for image."); - return; - } + /*XXX BUGS: cannadoc 013 - the arrow should be filled in but it is not. */ + cairo_get_matrix(cairo, &matrix); + printf("[%f %f], [%f %f], %f %f\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0); + //{ + double xScale = matrix.xx; + double yScale = matrix.yy; + int tx, tx2, ty, ty2; + int scaledHeight = height; + int scaledWidth = width; + if (xScale >= 0) { + tx = splashRound(matrix.x0 - 0.01); + tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1; + } else { + tx = splashRound(matrix.x0 + 0.01) - 1; + tx2 = splashRound(matrix.x0 + xScale - 0.01); + } + scaledWidth = abs(tx2 - tx) + 1; + //scaledWidth = splashRound(fabs(xScale)); + if (scaledWidth == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledWidth = 1; + } + if (yScale >= 0) { + ty = splashFloor(matrix.y0 + 0.01); + ty2 = splashCeil(matrix.y0 + yScale - 0.01); + } else { + ty = splashCeil(matrix.y0 - 0.01); + ty2 = splashFloor(matrix.y0 + yScale + 0.01); + } + scaledHeight = abs(ty2 - ty); + int need_pad = 0; + int head_pad = 0; + int tail_pad = 0; + if (splashRound(fabs(yScale)) < splashCeil(fabs(yScale))) + need_pad = 1; + + printf("xscale: %g, yscale: %g\n", xScale, yScale); + printf("width: %d, height: %d\n", width, height); + printf("scaledWidth: %d, scaledHeight: %d\n", scaledWidth, scaledHeight); + /*XXX: URGENT PROBLEM: if yScale is very small these get very big, which is very bad + * They cause us to large allocations and lots of uneccessary work */ + tail_pad = (matrix.y0 - ty)*(height/yScale); + head_pad = (ty2 - (matrix.y0 + yScale))*(height/yScale); + printf("head_pad: %d tail_pad: %d\n", head_pad, tail_pad); + int origHeight = height; + height += tail_pad; + height += head_pad; + printf("origHeight: %d height: %d\n", origHeight, height); + printf("ty: %d, ty2: %d\n", ty, ty2); + //} /* TODO: Do we want to cache these? */ imgStr = new ImageStream(str, width, 1, 1); @@ -531,6 +587,14 @@ invert_bit = invert ? 1 : 0; + row_stride = (scaledWidth + 3) & ~3; + buffer = (unsigned char *) malloc (scaledHeight * row_stride); + if (buffer == NULL) { + error(-1, "Unable to allocate memory for image."); + return; + } + +#if 0 for (y = 0; y < height; y++) { pix = imgStr->getLine(); dest = buffer + y * row_stride; @@ -542,9 +606,120 @@ *dest++ = 255; } } +#else + int yp = height / scaledHeight; + int origYp = origHeight / scaledHeight; + int yq = height % scaledHeight; + int xp = width / scaledWidth; + int xq = width % scaledWidth; + int origHeight_c = origHeight; +// int p_position = 0; + int yt = 0; + unsigned char *pixBuf = (unsigned char *)malloc(MIN(yp+1, origHeight)*width); + int lastYStep = 1; + int total = 0; + for (int y = 0; y < scaledHeight; y++) { + // y scale Bresenham + int yStep = yp; + yt += yq; + + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + // read row (s) from image + { + int n = (yp > 0) ? yStep : lastYStep; + total += n; + if (n > 0) { + unsigned char *p = pixBuf; + int head_pad_count = head_pad; + int origHeight_count = origHeight; + int tail_pad_count = tail_pad; + for (int i=0; igetLine(); + for (int j=0; j 0 ? yStep : 1; + int origN = n; + int head_pad_size = MIN(n, head_pad); + n -= head_pad_size; + head_pad -= MIN(head_pad_size, yStep); + + int pix_size = MIN(n, origHeight); + n -= pix_size; + origHeight -= MIN(pix_size, yStep); + + int tail_pad_size = MIN(n, tail_pad); + n -= tail_pad_size; + tail_pad -= MIN(tail_pad_size, yStep); + if (n != 0) { + printf("n = %d (%d %d %d)\n", n, head_pad_size, pix_size, tail_pad_size); + assert(n == 0); + } + for (int x = 0; x < scaledWidth; ++x) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + int m = xStep > 0 ? xStep : 1; + float pixAcc0 = 0; + /* could m * head_pad_size * tail_pad_size overflow? */ + if (invert_bit) { + pixAcc0 += m * head_pad_size * tail_pad_size * 255; + } else { + pixAcc0 += m * head_pad_size * tail_pad_size * 0; + } + for (int i = 0; i < pix_size; ++i) { + /* use background color instead of always checking invert_bit */ + for (int j = 0; j< m; ++j) { + if (xSrc + i*width + j > MIN(yp + 1, origHeight_c)*width) { + printf("%d > %d (%d %d %d %d) (%d %d %d)\n", xSrc + i*width + j, MIN(yp + 1, origHeight_c)*width, xSrc, i , width, j, yp, origHeight_c, width); + printf("%d %d %d\n", head_pad_size, pix_size, tail_pad_size); + assert(0 && "bad access\n"); + } + pixAcc0 += pixBuf[xSrc + i*width + j]; + } + } + buffer[y * row_stride + x] = pixAcc0 / (origN*m); + xSrc += xStep; + x1 += 1; + } + + } + free(pixBuf); +#endif image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8, - width, height, row_stride); + scaledWidth, scaledHeight, row_stride); if (image == NULL) { delete imgStr; return; @@ -555,18 +730,28 @@ return; } - cairo_matrix_init_translate (&matrix, 0, height); - cairo_matrix_scale (&matrix, width, -height); + //cairo_matrix_init_translate (&matrix, 0, -scaledHeight); +// cairo_matrix_scale (&matrix, width, -height); - cairo_pattern_set_matrix (pattern, &matrix); + //cairo_pattern_set_matrix (pattern, &matrix); /* we should actually be using CAIRO_FILTER_NEAREST here. However, * cairo doesn't yet do minifaction filtering causing scaled down * images with CAIRO_FILTER_NEAREST to look really bad */ cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST); - - cairo_mask (cairo, pattern); - + { + cairo_get_matrix(cairo, &matrix); + cairo_save (cairo); + cairo_scale(cairo, 1.0/matrix.xx, 1.0/matrix.yy); + // get integer co-ords + cairo_translate (cairo, tx - matrix.x0, ty2 - matrix.y0); + if (yScale > 0) + cairo_scale(cairo, 1, -1); + cairo_mask (cairo, pattern); + cairo_get_matrix(cairo, &matrix); + printf("mask at: [%f %f], [%f %f], %f %f\n\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0); + cairo_restore(cairo); + } cairo_pattern_destroy (pattern); cairo_surface_destroy (image); free (buffer);