/* Set up a clipping path and device for insideness testing. */ static int in_path(os_ptr oppath, i_ctx_t *i_ctx_p, gx_device * phdev) { int code = gs_gsave(igs); int npop; double uxy[2]; if (code < 0) return code; code = num_params(oppath, 2, uxy); if (code >= 0) { /* Aperture is a single pixel. */ gs_point dxy; gs_fixed_rect fr; gs_transform(igs, uxy[0], uxy[1], &dxy); fr.p.x = fixed_floor(float2fixed(dxy.x)); fr.p.y = fixed_floor(float2fixed(dxy.y)); fr.q.x = fr.p.x + fixed_1; fr.q.y = fr.p.y + fixed_1; code = gx_clip_to_rectangle(igs, &fr); npop = 2; } else if (code == e_stackunderflow) { /* If 0 elements, definitely a stackunderflow; otherwise, */ /* only 1 number, also a stackunderflow. */ npop = code; } else { /* Aperture is a user path. */ /* We have to set the clipping path without disturbing */ /* the current path. */ gx_path *ipath = igs->path; gx_path save; gx_path_init_local(&save, imemory); gx_path_assign_preserve(&save, ipath); gs_newpath(igs); code = upath_append(oppath, i_ctx_p, false); if (code >= 0) code = gx_clip_to_path(igs); gx_path_assign_free(igs->path, &save); npop = 1; } if (code < 0) { gs_grestore(igs); return code; } /* Install the hit detection device. */ gx_set_device_color_1(igs); gx_device_init((gx_device *) phdev, (const gx_device *)&gs_hit_device, NULL, true); phdev->width = phdev->height = max_int; gx_device_fill_in_procs(phdev); gx_set_device_only(igs, phdev); return npop; }
static int margin_boundary(line_list * ll, margin_set * set, active_line * alp, fixed xx0, fixed xx1, fixed yy0, fixed yy1, int dir, fixed y0, fixed y1) { section *sect = set->sect; fixed x0, x1, xmin, xmax; int xp0, xp; int i0, i; # if !CHECK_SPOT_CONTIGUITY int i1; # endif if (yy0 > yy1) return 0; /* enumerate integral x's in [yy0,yy1] : */ if (alp == 0) x0 = xx0, x1 = xx1; else { x0 = (yy0 == y0 ? alp->x_current : AL_X_AT_Y(alp, yy0)); x1 = (yy1 == y1 ? alp->x_next : AL_X_AT_Y(alp, yy1)); } xmin = min(x0, x1); xmax = max(x0, x1); # if !CHECK_SPOT_CONTIGUITY xp0 = fixed_floor(xmin) + fixed_half; i0 = fixed2int(xp0) - ll->bbox_left; if (xp0 < xmin) { xp0 += fixed_1; i0++; } if (i0 < 0) return_error(gs_error_unregistered); /* Must not happen. */ for (i = i0, xp = xp0; xp < xmax && i < ll->bbox_width; xp += fixed_1, i++) { fixed y = (alp == 0 ? yy0 : Y_AT_X(alp, xp)); fixed dy = y - set->y; bool ud; short *b, h; section *s = §[i]; if (dy < 0) dy = 0; /* fix rounding errors in Y_AT_X */ if (dy >= fixed_1) dy = fixed_1; /* safety */ vd_circle(xp, y, 2, 0); ud = (alp == 0 ? (dir > 0) : ((alp->start.x - alp->end.x) * dir > 0)); b = (ud ? &s->y0 : &s->y1); h = (short)dy; if (*b == -1 || (*b != -2 && ( ud ? *b > h : *b < h))) *b = h; } # else xp0 = fixed_floor(xmin) + fixed_half; i0 = fixed2int(xp0) - ll->bbox_left; if (xp0 < xmin) { i0++; xp0 += fixed_1; } for (i = i0, xp = xp0; xp < xmax; xp += fixed_1, i++) { section *s = §[i]; fixed y = (alp==0 ? yy0 : Y_AT_X(alp, xp)); fixed dy = y - set->y; bool ud; short *b, h; if (dy < 0) dy = 0; /* fix rounding errors in Y_AT_X */ if (dy >= fixed_1) dy = fixed_1; /* safety */ vd_circle(xp, y, 2, 0); ud = (alp == 0 ? (dir > 0) : ((alp->start.x - alp->end.x) * dir > 0)); b = (ud ? &s->y0 : &s->y1); h = (short)dy; if (*b == -1 || (*b != -2 && ( ud ? *b > h : *b < h))) *b = h; } if (i0 < 0 || i > ll->bbox_width) return_error(gs_error_unregistered); /* Must not happen. */ # endif if (i > i0) return store_margin(ll, set, i0, i); return 0; }
void image_downsize_gd_fixed_point(image *im) { int x, y; fixed_t sy1, sy2, sx1, sx2; int dstX = 0, dstY = 0, srcX = 0, srcY = 0; fixed_t width_scale, height_scale; int dstW = im->target_width; int dstH = im->target_height; int srcW = im->width; int srcH = im->height; if (im->height_padding) { dstY = im->height_padding; dstH = im->height_inner; } if (im->width_padding) { dstX = im->width_padding; dstW = im->width_inner; } width_scale = fixed_div(int_to_fixed(srcW), int_to_fixed(dstW)); height_scale = fixed_div(int_to_fixed(srcH), int_to_fixed(dstH)); for (y = dstY; (y < dstY + dstH); y++) { sy1 = fixed_mul(int_to_fixed(y - dstY), height_scale); sy2 = fixed_mul(int_to_fixed((y + 1) - dstY), height_scale); for (x = dstX; (x < dstX + dstW); x++) { fixed_t sx, sy; fixed_t spixels = 0; fixed_t red = 0, green = 0, blue = 0, alpha = 0; if (!im->has_alpha) alpha = FIXED_255; sx1 = fixed_mul(int_to_fixed(x - dstX), width_scale); sx2 = fixed_mul(int_to_fixed((x + 1) - dstX), width_scale); sy = sy1; /* DEBUG_TRACE("sx1 %f, sx2 %f, sy1 %f, sy2 %f\n", fixed_to_float(sx1), fixed_to_float(sx2), fixed_to_float(sy1), fixed_to_float(sy2)); */ do { fixed_t yportion; //DEBUG_TRACE(" yportion(sy %f, sy1 %f, sy2 %f) = ", fixed_to_float(sy), fixed_to_float(sy1), fixed_to_float(sy2)); if (fixed_floor(sy) == fixed_floor(sy1)) { yportion = FIXED_1 - (sy - fixed_floor(sy)); if (yportion > sy2 - sy1) { yportion = sy2 - sy1; } sy = fixed_floor(sy); } else if (sy == fixed_floor(sy2)) { yportion = sy2 - fixed_floor(sy2); } else { yportion = FIXED_1; } //DEBUG_TRACE("%f\n", fixed_to_float(yportion)); sx = sx1; do { fixed_t xportion; fixed_t pcontribution; pix p; //DEBUG_TRACE(" xportion(sx %f, sx1 %f, sx2 %f) = ", fixed_to_float(sx), fixed_to_float(sx1), fixed_to_float(sx2)); if (fixed_floor(sx) == fixed_floor(sx1)) { xportion = FIXED_1 - (sx - fixed_floor(sx)); if (xportion > sx2 - sx1) { xportion = sx2 - sx1; } sx = fixed_floor(sx); } else if (sx == fixed_floor(sx2)) { xportion = sx2 - fixed_floor(sx2); } else { xportion = FIXED_1; } //DEBUG_TRACE("%f\n", fixed_to_float(xportion)); pcontribution = fixed_mul(xportion, yportion); p = get_pix(im, fixed_to_int(sx + srcX), fixed_to_int(sy + srcY)); /* DEBUG_TRACE(" merging with pix %d, %d: src %x (%d %d %d %d), pcontribution %f\n", fixed_to_int(sx + srcX), fixed_to_int(sy + srcY), p, COL_RED(p), COL_GREEN(p), COL_BLUE(p), COL_ALPHA(p), fixed_to_float(pcontribution)); */ red += fixed_mul(int_to_fixed(COL_RED(p)), pcontribution); green += fixed_mul(int_to_fixed(COL_GREEN(p)), pcontribution); blue += fixed_mul(int_to_fixed(COL_BLUE(p)), pcontribution); if (im->has_alpha) alpha += fixed_mul(int_to_fixed(COL_ALPHA(p)), pcontribution); spixels += pcontribution; sx += FIXED_1; } while (sx < sx2); sy += FIXED_1; } while (sy < sy2); // If rgba get too large for the fixed-point representation, fallback to the floating point routine // This should only happen with very large images if (red < 0 || green < 0 || blue < 0 || alpha < 0) { warn("fixed-point overflow: %d %d %d %d\n", red, green, blue, alpha); return image_downsize_gd(im); } if (spixels != 0) { /* DEBUG_TRACE(" rgba (%f %f %f %f) spixels %f\n", fixed_to_float(red), fixed_to_float(green), fixed_to_float(blue), fixed_to_float(alpha), fixed_to_float(spixels)); */ spixels = fixed_div(FIXED_1, spixels); red = fixed_mul(red, spixels); green = fixed_mul(green, spixels); blue = fixed_mul(blue, spixels); if (im->has_alpha) alpha = fixed_mul(alpha, spixels); } /* Clamping to allow for rounding errors above */ if (red > FIXED_255) red = FIXED_255; if (green > FIXED_255) green = FIXED_255; if (blue > FIXED_255) blue = FIXED_255; if (im->has_alpha && alpha > FIXED_255) alpha = FIXED_255; /* DEBUG_TRACE(" -> %d, %d %x (%d %d %d %d)\n", x, y, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)), fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)); */ if (im->orientation != ORIENTATION_NORMAL) { int ox, oy; // new destination pixel coordinates after rotating image_get_rotated_coords(im, x, y, &ox, &oy); if (im->orientation >= 5) { // 90 and 270 rotations, width/height are swapped so we have to use alternate put_pix method put_pix_rotated( im, ox, oy, im->target_height, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)) ); } else { put_pix( im, ox, oy, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)) ); } } else { put_pix( im, x, y, COL_FULL(fixed_to_int(red), fixed_to_int(green), fixed_to_int(blue), fixed_to_int(alpha)) ); } } } }
/* We take the trouble to do this efficiently in the simple cases. */ int gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count) { const gs_rect *rlist = pr; gx_clip_path *pcpath; uint rcount = count; int code; gx_device * pdev = pgs->device; gx_device_color *pdc = gs_currentdevicecolor_inline(pgs); const gs_imager_state *pis = (const gs_imager_state *)pgs; bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc); bool hl_color = (hl_color_available && dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_hlcolor, NULL, 0)); bool center_of_pixel = (pgs->fill_adjust.x == 0 && pgs->fill_adjust.y == 0); /* Processing a fill object operation */ dev_proc(pgs->device, set_graphics_type_tag)(pgs->device, GS_PATH_TAG); code = gx_set_dev_color(pgs); if (code != 0) return code; if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) || is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) && gx_effective_clip_path(pgs, &pcpath) >= 0 && clip_list_is_rectangle(gx_cpath_list(pcpath)) && (hl_color || pdc->type == gx_dc_type_pure || pdc->type == gx_dc_type_ht_binary || pdc->type == gx_dc_type_ht_colored) && gs_state_color_load(pgs) >= 0 && (*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics) <= 1 && (!pgs->overprint || !pgs->effective_overprint_mode) ) { uint i; gs_fixed_rect clip_rect; gx_cpath_inner_box(pcpath, &clip_rect); /* We should never plot anything for an empty clip rectangle */ if ((clip_rect.p.x >= clip_rect.q.x) && (clip_rect.p.y >= clip_rect.q.y)) return 0; for (i = 0; i < count; ++i) { gs_fixed_point p, q; gs_fixed_rect draw_rect; if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 || gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0 ) { /* Switch to the slow algorithm. */ goto slow; } draw_rect.p.x = min(p.x, q.x); draw_rect.p.y = min(p.y, q.y); draw_rect.q.x = max(p.x, q.x); draw_rect.q.y = max(p.y, q.y); if (hl_color) { rect_intersect(draw_rect, clip_rect); /* We do pass on 0 extant rectangles to high level devices. It isn't clear how a client and an output device should interact if one uses a center of pixel algorithm and the other uses any part of pixel. For now we punt and just pass the high level rectangle on without adjustment. */ if (draw_rect.p.x <= draw_rect.q.x && draw_rect.p.y <= draw_rect.q.y) { code = dev_proc(pdev, fill_rectangle_hl_color)(pdev, &draw_rect, pis, pdc, pcpath); if (code < 0) return code; } } else { int x, y, w, h; rect_intersect(draw_rect, clip_rect); if (center_of_pixel) { draw_rect.p.x = fixed_rounded(draw_rect.p.x); draw_rect.p.y = fixed_rounded(draw_rect.p.y); draw_rect.q.x = fixed_rounded(draw_rect.q.x); draw_rect.q.y = fixed_rounded(draw_rect.q.y); } else { /* any part of pixel rule - touched */ draw_rect.p.x = fixed_floor(draw_rect.p.x); draw_rect.p.y = fixed_floor(draw_rect.p.y); draw_rect.q.x = fixed_ceiling(draw_rect.q.x); draw_rect.q.y = fixed_ceiling(draw_rect.q.y); } x = fixed2int(draw_rect.p.x); y = fixed2int(draw_rect.p.y); w = fixed2int(draw_rect.q.x) - x; h = fixed2int(draw_rect.q.y) - y; /* clients that use the "any part of pixel" rule also fill 0 areas. This is true of current graphics library clients but not a general rule. */ if (!center_of_pixel) { if (w == 0) w = 1; /* yes Adobe Acrobat 8, seems to back up the y coordinate when the width is 0, sigh. */ if (h == 0) { y--; h = 1; } } if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0) goto slow; } } return 0; slow:rlist = pr + i; rcount = count - i; } { bool do_save = !gx_path_is_null(pgs->path); if (do_save) { if ((code = gs_gsave(pgs)) < 0) return code; gs_newpath(pgs); } if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 || (code = gs_fill(pgs)) < 0 ) DO_NOTHING; if (do_save) gs_grestore(pgs); else if (code < 0) gs_newpath(pgs); } return code; }