/* * ESC & f <pp_enum> S * * Contrary to what is indicated in the "PCL 5 Printer Language Technical * Reference Manual", October 1992 ed., p. 6-16, pushd cursors are stored * in logical page space, not device space. */ static int push_pop_cursor(pcl_args_t * pargs, pcl_state_t * pcs) { int type = uint_arg(pargs); if ((type == 0) && (pcs->cursor_stk_size < countof(pcs->cursor_stk))) { gs_point *ppt = &(pcs->cursor_stk[pcs->cursor_stk_size++]); ppt->x = (double)pcs->cap.x; ppt->y = (double)pcs->cap.y; gs_point_transform(ppt->x, ppt->y, &(pcs->xfm_state.pd2lp_mtx), ppt); } else if ((type == 1) && (pcs->cursor_stk_size > 0)) { gs_point *ppt = &(pcs->cursor_stk[--pcs->cursor_stk_size]); gs_matrix lp2pd; pcl_invert_mtx(&(pcs->xfm_state.pd2lp_mtx), &lp2pd); gs_point_transform(ppt->x, ppt->y, &lp2pd, ppt); pcl_set_cap_x(pcs, (coord) ppt->x, false, false); pcl_set_cap_y(pcs, (coord) ppt->y - pcs->margins.top, false, false, false, false); } return 0; }
/* Report current point for sampling */ int gs_screen_currentpoint(gs_screen_enum * penum, gs_point * ppt) { gs_point pt; int code; double sx, sy; /* spot center in spot coords (integers) */ gs_point spot_center; /* device coords */ if (penum->order.wse) { int code; code = gs_wts_screen_enum_currentpoint(penum->order.wse, ppt); return code; } if (penum->y >= penum->strip) { /* all done */ gx_ht_construct_spot_order(&penum->order); return 1; } /* We displace the sampled coordinates very slightly */ /* in order to reduce the likely number of points */ /* for which the spot function returns the same value. */ if ((code = gs_point_transform(penum->x + 0.501, penum->y + 0.498, &penum->mat, &pt)) < 0) return code; /* find the spot center in device coords : */ sx = ceil( pt.x / 2 ) * 2; sy = ceil( pt.y / 2 ) * 2; if ((code = gs_point_transform(sx, sy, &penum->mat_inv, &spot_center)) < 0) return code; /* shift the spot center to nearest pixel center : */ spot_center.x = floor(spot_center.x) + 0.5; spot_center.y = floor(spot_center.y) + 0.5; /* compute the spot function arguments for the shifted spot : */ if ((code = gs_distance_transform(penum->x - spot_center.x + 0.501, penum->y - spot_center.y + 0.498, &penum->mat, &pt)) < 0) return code; pt.x += 1; pt.y += 1; if (pt.x < -1.0) pt.x += ((int)(-ceil(pt.x)) + 1) & ~1; else if (pt.x >= 1.0) pt.x -= ((int)pt.x + 1) & ~1; if (pt.y < -1.0) pt.y += ((int)(-ceil(pt.y)) + 1) & ~1; else if (pt.y >= 1.0) pt.y -= ((int)pt.y + 1) & ~1; *ppt = pt; return 0; }
/* Calculate bonding box of a box transformed by a matrix. */ static int zbbox_transform(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_matrix m; float bbox[4]; gs_point aa, az, za, zz; double temp; int code; if ((code = read_matrix(imemory, op, &m)) < 0) return code; if (!r_is_array(op - 1)) return_op_typecheck(op - 1); check_read(op[-1]); if (r_size(op - 1) != 4) return_error(gs_error_rangecheck); if ((code = process_float_array(imemory, op - 1, 4, bbox) < 0)) return code; gs_point_transform(bbox[0], bbox[1], &m, &aa); gs_point_transform(bbox[0], bbox[3], &m, &az); gs_point_transform(bbox[2], bbox[1], &m, &za); gs_point_transform(bbox[2], bbox[3], &m, &zz); if ( aa.x > az.x) temp = aa.x, aa.x = az.x, az.x = temp; if ( za.x > zz.x) temp = za.x, za.x = zz.x, zz.x = temp; if ( za.x < aa.x) aa.x = za.x; /* min */ if ( az.x > zz.x) zz.x = az.x; /* max */ if ( aa.y > az.y) temp = aa.y, aa.y = az.y, az.y = temp; if ( za.y > zz.y) temp = za.y, za.y = zz.y, zz.y = temp; if ( za.y < aa.y) aa.y = za.y; /* min */ if ( az.y > zz.y) zz.y = az.y; /* max */ push(2); make_real(op - 3, (float)aa.x); make_real(op - 2, (float)aa.y); make_real(op - 1, (float)zz.x); make_real(op , (float)zz.y); return 0; }
/* * End (raster) graphics mode. This may be called explicitly by either of the * end graphics mode commands (<esc>*rB or <esc>*rC), or implicitly by any * commmand which is neither legal nor ignored in graphics mode. */ int pcl_end_graphics_mode( pcl_state_t * pcs ) { gs_point cur_pt; gs_matrix dev2pd; /* close the raster; exit graphics mode */ pcl_complete_raster(pcs); pcs->raster_state.graphics_mode = false; /* get the new current point; then restore the graphic state */ gs_transform(pcs->pgs, 0.0, 0.0, &cur_pt); pcl_grestore(pcs); /* transform the new point back to "pseudo print direction" space */ pcl_invert_mtx(&(pcs->xfm_state.pd2dev_mtx), &dev2pd); gs_point_transform(cur_pt.x, cur_pt.y, &dev2pd, &cur_pt); pcl_set_cap_x(pcs, (coord)(cur_pt.x + 0.5) - adjust_pres_mode(pcs), false, false); return pcl_set_cap_y( pcs, (coord)(cur_pt.y + 0.5) - pcs->margins.top, false, false, false, false ); }
/* Return gs_error_undefinedresult if the matrix is not invertible. */ int gs_point_transform_inverse(floatp x, floatp y, const gs_matrix * pmat, gs_point * ppt) { if (is_xxyy(pmat)) { if (is_fzero(pmat->xx) || is_fzero(pmat->yy)) return_error(gs_error_undefinedresult); ppt->x = (x - pmat->tx) / pmat->xx; ppt->y = (y - pmat->ty) / pmat->yy; return 0; } else if (is_xyyx(pmat)) { if (is_fzero(pmat->xy) || is_fzero(pmat->yx)) return_error(gs_error_undefinedresult); ppt->x = (y - pmat->ty) / pmat->xy; ppt->y = (x - pmat->tx) / pmat->yx; return 0; } else { /* There are faster ways to do this, */ /* but we won't implement one unless we have to. */ gs_matrix imat; int code = gs_matrix_invert(pmat, &imat); if (code < 0) return code; return gs_point_transform(x, y, &imat, ppt); } }
int gs_itransform(gs_state * pgs, floatp x, floatp y, gs_point * pt) { /* If the matrix isn't skewed, we get more accurate results */ /* by using transform_inverse than by using the inverse matrix. */ if (!is_skewed(&pgs->ctm)) { return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt); } else { ensure_inverse_valid(pgs); return gs_point_transform(x, y, &pgs->ctm_inverse, pt); } }
/* * Transform an aligned rectangle. Because all transformations in PCL are * diagonal, both the source and destination rectangles are aligned with the * coordinate axes, and hence may be represented by a pair of points. * * prect1 and prect2 may point to the same rectangle. */ void pcl_transform_rect(const gs_memory_t *mem, const gs_rect * prect1, gs_rect * prect2, const gs_matrix * pmtx ) { gs_point_transform(prect1->p.x, prect1->p.y, pmtx, &(prect2->p)); gs_point_transform(prect1->q.x, prect1->q.y, pmtx, &(prect2->q)); if (prect2->p.x > prect2->q.x) { double ftmp = prect2->p.x; prect2->p.x = prect2->q.x; prect2->q.x = ftmp; } if (prect2->p.y > prect2->q.y) { double ftmp = prect2->p.y; prect2->p.y = prect2->q.y; prect2->q.y = ftmp; } }
/* Used for the best precision of the current point, see comment in clamp_point_aux. */ int gs_point_transform2fixed_rounding(const gs_matrix_fixed * pmat, floatp x, floatp y, gs_fixed_point * ppt) { gs_point fpt; gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt); if (!(f_fits_in_fixed(fpt.x) && f_fits_in_fixed(fpt.y))) return_error(gs_error_limitcheck); ppt->x = float2fixed_rounded(fpt.x); ppt->y = float2fixed_rounded(fpt.y); return 0; }
/* * Preserve the current point and text margin set by transfroming them into * logical page space. */ static void preserve_cap_and_margins(const pcl_state_t * pcs, gs_point * pcur_pt, gs_rect * ptext_rect) { pcur_pt->x = (double)pcs->cap.x; pcur_pt->y = (double)pcs->cap.y; gs_point_transform(pcur_pt->x, pcur_pt->y, &(pcs->xfm_state.pd2lp_mtx), pcur_pt); ptext_rect->p.x = (double)pcs->margins.left; ptext_rect->p.y = (double)pcs->margins.top; ptext_rect->q.x = (double)pcs->margins.right; ptext_rect->q.y = (double)(pcs->margins.top + pcs->margins.length); pcl_transform_rect(pcs->memory, ptext_rect, ptext_rect, &(pcs->xfm_state.pd2lp_mtx)); }
static inline int gs_point_transform_compat(floatp x, floatp y, const gs_matrix_fixed *m, gs_point *pt) { #if !PRECISE_CURRENTPOINT gs_fixed_point p; int code = gs_point_transform2fixed(m, x, y, &p); if (code < 0) return code; pt->x = fixed2float(p.x); pt->y = fixed2float(p.y); return 0; #else return gs_point_transform(x, y, (const gs_matrix *)m, pt); #endif }
/* * Set up the pattern orientation and reference point for PCL. Note that PCL's * pattern reference point is kept in logical page space. */ void pcl_xfm_pcl_set_pat_ref_pt( pcl_state_t * pcs ) { pcl_xfm_state_t * pxfmst = &(pcs->xfm_state); gs_point_transform( pcs->pcl_pat_ref_pt.x, pcs->pcl_pat_ref_pt.y, &(pxfmst->lp2dev_mtx), &(pcs->pat_ref_pt) ); pcs->pat_ref_pt.x = floor(pcs->pat_ref_pt.x + 0.5); pcs->pat_ref_pt.y = floor(pcs->pat_ref_pt.y + 0.5); pcs->pat_orient = (pxfmst->lp_orient + (pcs->rotate_patterns ? pxfmst->print_dir : 0)) & 0x3; }
/* * Convert the current point and text margin set back into "pseudo print * direction" space. */ static void restore_cap_and_margins(pcl_state_t * pcs, const gs_point * pcur_pt, const gs_rect * ptext_rect) { gs_matrix lp2pd; gs_point tmp_pt; gs_rect tmp_rect; pcl_invert_mtx(&(pcs->xfm_state.pd2lp_mtx), &lp2pd); gs_point_transform(pcur_pt->x, pcur_pt->y, &lp2pd, &tmp_pt); pcs->cap.x = (coord) tmp_pt.x; pcs->cap.y = (coord) tmp_pt.y; pcl_transform_rect(pcs->memory, ptext_rect, &tmp_rect, &lp2pd); pcs->margins.left = (coord) tmp_rect.p.x; pcs->margins.top = (coord) tmp_rect.p.y; pcs->margins.right = (coord) tmp_rect.q.x; pcs->margins.length = (coord) tmp_rect.q.y - pcs->margins.top; }
static inline int gs_arc_add_inline(gs_state *pgs, bool cw, floatp xc, floatp yc, floatp rad, floatp a1, floatp a2, bool add) { gs_point p3; int code = gs_imager_arc_add(pgs->path, (gs_imager_state *)pgs, cw, xc, yc, rad, a1, a2, add, &p3); if (code < 0) return code; #if !PRECISE_CURRENTPOINT return gx_setcurrentpoint_from_path((gs_imager_state *)pgs, pgs->path); #else pgs->current_point_valid = true; return gs_point_transform(p3.x, p3.y, &ctm_only(pgs), &pgs->current_point); #endif }
/* * ESC * p # R * * Set pattern reference point. * */ static int set_pat_ref_pt( pcl_args_t * pargs, pcl_state_t * pcs ) { uint rotate = uint_arg(pargs); if (rotate <= 1) { pcl_break_underline(pcs); gs_point_transform( (floatp)pcs->cap.x, (floatp)pcs->cap.y, &(pcs->xfm_state.pd2lp_mtx), &(pcs->pcl_pat_ref_pt) ); pcs->rotate_patterns = (rotate == 0); } return 0; }
/* Transform a point with a fixed-point result. */ int gs_point_transform2fixed(const gs_matrix_fixed * pmat, floatp x, floatp y, gs_fixed_point * ppt) { fixed px, py, t; double xtemp, ytemp; int code; if (!pmat->txy_fixed_valid) { /* The translation is out of range. Do the */ /* computation in floating point, and convert to */ /* fixed at the end. */ gs_point fpt; gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt); if (!(f_fits_in_fixed(fpt.x) && f_fits_in_fixed(fpt.y))) return_error(gs_error_limitcheck); ppt->x = float2fixed(fpt.x); ppt->y = float2fixed(fpt.y); return 0; } if (!is_fzero(pmat->xy)) { /* Hope for 90 degree rotation */ if ((code = CHECK_DFMUL2FIXED_VARS(px, y, pmat->yx, xtemp)) < 0 || (code = CHECK_DFMUL2FIXED_VARS(py, x, pmat->xy, ytemp)) < 0 ) return code; FINISH_DFMUL2FIXED_VARS(px, xtemp); FINISH_DFMUL2FIXED_VARS(py, ytemp); if (!is_fzero(pmat->xx)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, x, pmat->xx, xtemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, xtemp); if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0) return code; } if (!is_fzero(pmat->yy)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, y, pmat->yy, ytemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, ytemp); if ((code = CHECK_SET_FIXED_SUM(py, py, t)) < 0) return code; } } else { if ((code = CHECK_DFMUL2FIXED_VARS(px, x, pmat->xx, xtemp)) < 0 || (code = CHECK_DFMUL2FIXED_VARS(py, y, pmat->yy, ytemp)) < 0 ) return code; FINISH_DFMUL2FIXED_VARS(px, xtemp); FINISH_DFMUL2FIXED_VARS(py, ytemp); if (!is_fzero(pmat->yx)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, y, pmat->yx, ytemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, ytemp); if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0) return code; } } if (((code = CHECK_SET_FIXED_SUM(ppt->x, px, pmat->tx_fixed)) < 0) || ((code = CHECK_SET_FIXED_SUM(ppt->y, py, pmat->ty_fixed)) < 0) ) return code; return 0; }
int gs_transform(gs_state * pgs, floatp x, floatp y, gs_point * pt) { return gs_point_transform(x, y, &ctm_only(pgs), pt); }
int gx_begin_image3_generic(gx_device * dev, const gs_imager_state *pis, const gs_matrix *pmat, const gs_image_common_t *pic, const gs_int_rect *prect, const gx_drawing_color *pdcolor, const gx_clip_path *pcpath, gs_memory_t *mem, image3_make_mid_proc_t make_mid, image3_make_mcde_proc_t make_mcde, gx_image_enum_common_t **pinfo) { const gs_image3_t *pim = (const gs_image3_t *)pic; gx_image3_enum_t *penum; gs_int_rect mask_rect, data_rect; gx_device *mdev = 0; gx_device *pcdev = 0; gs_image_t i_pixel, i_mask; gs_matrix mi_pixel, mi_mask, mat; gs_rect mrect; gs_int_point origin; int code; /* Validate the parameters. */ if (pim->Height <= 0 || pim->MaskDict.Height <= 0) return_error(gs_error_rangecheck); switch (pim->InterleaveType) { default: return_error(gs_error_rangecheck); case interleave_chunky: if (pim->MaskDict.Width != pim->Width || pim->MaskDict.Height != pim->Height || pim->MaskDict.BitsPerComponent != pim->BitsPerComponent || pim->format != gs_image_format_chunky ) return_error(gs_error_rangecheck); break; case interleave_scan_lines: if (pim->MaskDict.Height % pim->Height != 0 && pim->Height % pim->MaskDict.Height != 0 ) return_error(gs_error_rangecheck); /* falls through */ case interleave_separate_source: if (pim->MaskDict.BitsPerComponent != 1) return_error(gs_error_rangecheck); } if (!check_image3_extent(pim->ImageMatrix.xx, pim->MaskDict.ImageMatrix.xx) || !check_image3_extent(pim->ImageMatrix.xy, pim->MaskDict.ImageMatrix.xy) || !check_image3_extent(pim->ImageMatrix.yx, pim->MaskDict.ImageMatrix.yx) || !check_image3_extent(pim->ImageMatrix.yy, pim->MaskDict.ImageMatrix.yy) ) return_error(gs_error_rangecheck); if ((code = gs_matrix_invert(&pim->ImageMatrix, &mi_pixel)) < 0 || (code = gs_matrix_invert(&pim->MaskDict.ImageMatrix, &mi_mask)) < 0 ) return code; if (fabs(mi_pixel.tx - mi_mask.tx) >= 0.5 || fabs(mi_pixel.ty - mi_mask.ty) >= 0.5 ) return_error(gs_error_rangecheck); #ifdef DEBUG { /* Although the PLRM says that the Mask and Image *must* be the same size, */ /* Adobe CPSI (and other RIPS) ignore this and process anyway. Note that we */ /* are not compatible if the Mask Height than the Data (pixel) Height. CPSI */ /* de-interleaves the mask from the data image and stops at the Mask Height */ /* Problem detected with Genoa 468-03 (part of file 468-01.ps) */ /***** fixme: When Data Image Height > Mask Height *****/ gs_point ep, em; if ((code = gs_point_transform(pim->Width, pim->Height, &mi_pixel, &ep)) < 0 || (code = gs_point_transform(pim->MaskDict.Width, pim->MaskDict.Height, &mi_mask, &em)) < 0 ) return code; if (fabs(ep.x - em.x) >= 0.5 || fabs(ep.y - em.y) >= 0.5) code = gs_error_rangecheck; /* leave the check in for debug breakpoint */ } #endif /* DEBUG */ penum = gs_alloc_struct(mem, gx_image3_enum_t, &st_image3_enum, "gx_begin_image3"); if (penum == 0) return_error(gs_error_VMerror); penum->num_components = gs_color_space_num_components(pim->ColorSpace); gx_image_enum_common_init((gx_image_enum_common_t *) penum, (const gs_data_image_t *)pim, &image3_enum_procs, dev, 1 + penum->num_components, pim->format); /* Initialize pointers now in case we bail out. */ penum->mask_data = 0; penum->pixel_data = 0; if (prect) { long lmw = pim->MaskDict.Width, lmh = pim->MaskDict.Height; data_rect = *prect; mask_rect.p.x = (int)(data_rect.p.x * lmw / pim->Width); mask_rect.p.y = (int)(data_rect.p.y * lmh / pim->Height); mask_rect.q.x = (int)((data_rect.q.x + pim->Width - 1) * lmw / pim->Width); mask_rect.q.y = (int)((data_rect.q.y + pim->Height - 1) * lmh / pim->Height); } else { mask_rect.p.x = mask_rect.p.y = 0; mask_rect.q.x = pim->MaskDict.Width; mask_rect.q.y = pim->MaskDict.Height; data_rect.p.x = data_rect.p.y = 0; data_rect.q.x = pim->Width; data_rect.q.y = pim->Height; } penum->mask_width = mask_rect.q.x - mask_rect.p.x; penum->mask_height = mask_rect.q.y - mask_rect.p.y; penum->mask_full_height = pim->MaskDict.Height; penum->mask_y = 0; penum->mask_skip = 0; penum->pixel_width = data_rect.q.x - data_rect.p.x; penum->pixel_height = data_rect.q.y - data_rect.p.y; penum->pixel_full_height = pim->Height; penum->pixel_y = 0; penum->mask_info = 0; penum->pixel_info = 0; if (pim->InterleaveType == interleave_chunky) { /* Allocate row buffers for the mask and pixel data. */ penum->pixel_data = gs_alloc_bytes(mem, (penum->pixel_width * pim->BitsPerComponent * penum->num_components + 7) >> 3, "gx_begin_image3(pixel_data)"); penum->mask_data = gs_alloc_bytes(mem, (penum->mask_width + 7) >> 3, "gx_begin_image3(mask_data)"); if (penum->pixel_data == 0 || penum->mask_data == 0) { code = gs_note_error(gs_error_VMerror); goto out1; } }
/* Internal routine for adding an arc to the path. */ static int arc_add(const arc_curve_params_t * arc, bool is_quadrant) { gx_path *path = arc->ppath; gs_imager_state *pis = arc->pis; double x0 = arc->p0.x, y0 = arc->p0.y; double xt = arc->pt.x, yt = arc->pt.y; floatp fraction; gs_fixed_point p0, p2, p3, pt; int code; if ((arc->action != arc_nothing && #if !PRECISE_CURRENTPOINT (code = gs_point_transform2fixed(&pis->ctm, x0, y0, &p0)) < 0) || (code = gs_point_transform2fixed(&pis->ctm, xt, yt, &pt)) < 0 || (code = gs_point_transform2fixed(&pis->ctm, arc->p3.x, arc->p3.y, &p3)) < 0 #else (code = gs_point_transform2fixed_rounding(&pis->ctm, x0, y0, &p0)) < 0) || (code = gs_point_transform2fixed_rounding(&pis->ctm, xt, yt, &pt)) < 0 || (code = gs_point_transform2fixed_rounding(&pis->ctm, arc->p3.x, arc->p3.y, &p3)) < 0 #endif ) return code; #if PRECISE_CURRENTPOINT if (!path_position_valid(path)) gs_point_transform(arc->p0.x, arc->p0.y, &ctm_only(arc->pis), &pis->subpath_start); #endif code = (arc->action == arc_nothing ? (p0.x = path->position.x, p0.y = path->position.y, 0) : arc->action == arc_lineto && path_position_valid(path) ? gx_path_add_line(path, p0.x, p0.y) : /* action == arc_moveto, or lineto with no current point */ gx_path_add_point(path, p0.x, p0.y)); if (code < 0) return code; /* Compute the fraction coefficient for the curve. */ /* See gx_path_add_partial_arc for details. */ if (is_quadrant) { /* one of |dx| and |dy| is r, the other is zero */ fraction = quarter_arc_fraction; if (arc->fast_quadrant > 0) { /* * The CTM is well-behaved, and we have pre-calculated the delta * from the circumference points to the control points. */ fixed delta = arc->quadrant_delta; if (pt.x != p0.x) p0.x = (pt.x > p0.x ? p0.x + delta : p0.x - delta); if (pt.y != p0.y) p0.y = (pt.y > p0.y ? p0.y + delta : p0.y - delta); p2.x = (pt.x == p3.x ? p3.x : pt.x > p3.x ? p3.x + delta : p3.x - delta); p2.y = (pt.y == p3.y ? p3.y : pt.y > p3.y ? p3.y + delta : p3.y - delta); goto add; } } else { double r = arc->radius; floatp dx = xt - x0, dy = yt - y0; double dist = dx * dx + dy * dy; double r2 = r * r; if (dist >= r2 * 1.0e8) /* almost zero radius; */ /* the >= catches dist == r == 0 */ fraction = 0.0; else fraction = (4.0 / 3.0) / (1 + sqrt(1 + dist / r2)); } p0.x += (fixed)((pt.x - p0.x) * fraction); p0.y += (fixed)((pt.y - p0.y) * fraction); p2.x = p3.x + (fixed)((pt.x - p3.x) * fraction); p2.y = p3.y + (fixed)((pt.y - p3.y) * fraction); add: if_debug8('r', "[r]Arc f=%f p0=(%f,%f) pt=(%f,%f) p3=(%f,%f) action=%d\n", fraction, x0, y0, xt, yt, arc->p3.x, arc->p3.y, (int)arc->action); /* Open-code gx_path_add_partial_arc_notes */ return gx_path_add_curve_notes(path, p0.x, p0.y, p2.x, p2.y, p3.x, p3.y, arc->notes | sn_from_arc); }
/* * Enter raster graphics mode. * * The major function of this routine is to establish the raster to device * space transformations. This is rather involved: * * 1. The first feature to be established is the orientation of raster space * relative to page space. Three state parameters are involved in * determining this orientation: the logical page orientation, the current * print direction, and the raster presentation mode. These are combined * in the following manner: * * tr = (print_direction / 90) + logical_page_orientation * * raster_rotate = (presentation_mode == 0 ? tr : tr & 0x2) * * 2. The next step is to determine the location of the origin of the raster * to page transformation. Intially this origin is set at the appropriate * corner of the logical page, based on the orientation determined above. * The origin is then shift based on the manner in which graphics mode is * entered (the mode operand): * * If entry is IMPLICIT (i.e.: via a transfer data command rather than * an enter graphics mode command), translation by the existing left * graphics margin is used, in the orientation of raster space. * * If entry is via an enter graphics mode command which specifies moving * the origin to the logical page boundary (NO_SCALE_LEFT_MARG (0) or * SCALE_LEFT_MARG (2)), action depends on whether or not horizontal * access of print direction space and of raster space are the same: * * if there are the same, the origin is left unchanged * * if they are not the same, the origin is shifted 1/6" (1200 centi- * points) in the positive horizontal raster space axis. * * The latter correction is not documented by HP, and there is no clear * reason why it should apply, but it has been verified to be the case * for all HP products testd. * * If entry is via an enter graphics mode command with specifies use * of the current point (NO_SCALE_CUR_PT(1) or SCALE_CUR_PT(3)), the * current point is transformed to raster space and its "horizontal" * component is used as the new graphics margin. * * Irrespective of how the "horizontal" component of the raster image origin * is specified, the vertical component is always derived from the current * addressable point, by converting the point to raster space. * * 3. Next, the scale of the raster to page space transformation is established. * This depends on whether or not PCL raster scaling is to be employed. * For raster scaling to be used, all of the following must hold: * * the scale_raster flag in the PCL raster state must be set * the current palette must be writable * the raster source height and width must have been explicitly set * * The scale_raster flag in the PCL raster state is normally set by the * enter raster graphics command. Hence, if graphics mode is entered * explicitly, the first requirement follows the behavior of the HP Color * LaserJet 5/5M. The DeskJet 1600C/CM behaves differently: it will never * user raster scaling if graphics mode is entered implicitly. * * The reason for the second requirement is undoubtedly related to some * backwards compatibility requirement, but is otherwise obscure. The * restriction is, however, both document and uniformly applied by all * HP products that support raster scaling. * * If raster scaling is not used, the scale of raster space is determined * by the ratio of the graphics resolution (set by the graphics resolution * command) and unit of page space (centi-points). This factor is applied * in both scan directions. * * If scaling is employed, the situation is somewhat more complicated. It * is necessary, in this case, to know which of the raster destination * dimensions have been explicitly set: * * If both dimensions are specified, the ration of these dimensions * to the source raster width and height determine the raster scale. * * If only one destination dimension is specified, the ratio of this * dimension to the corresponding source dimension determins the * raster scale for both dimensions; With strange interactions with * the 1200centipoint margin and rotated pages (Bug emulation). * * If neither dimension is specified, the page printable region is * transformed to raster space, the intersection of this with the * positive quadrant is taken. The dimensions of the resulting region * are compared with the dimensions of the source raster. The smaller * of the two dest_dim / src_dim ratios is used as the ratio for * the raster scale in both dimensions (i.e.: select the largest * isotropic scaling that does not cause clipping). * * 4. Finally, the extent of raster space must be determined. This is done by * converting the page printable region to raster space and intersecting * the result with the positive quadrant. This region is used to determine * the useable source raster width and height. * */ int pcl_enter_graphics_mode( pcl_state_t * pcs, pcl_gmode_entry_t mode ) { floatp scale_x, scale_y; pcl_xfm_state_t * pxfmst = &(pcs->xfm_state); pcl_raster_state_t * prstate = &(pcs->raster_state); float gmargin_cp = (float)prstate->gmargin_cp; gs_point cur_pt; gs_matrix rst2lp, rst2dev, lp2rst; gs_rect print_rect; uint src_wid, src_hgt; int rot; int code = 0; double dwid, dhgt; int clip_x, clip_y; /* * Check if the raster is to be clipped fully; see rtrstst.h for details. * Since this is a discontinuous effect, the equality checks below * should be made while still in centipoints. */ prstate->clip_all = ( (pcs->cap.x == pxfmst->pd_size.x) || (pcs->cap.y == pxfmst->pd_size.y) ); /* create to raster space to logical page space transformation */ rot = pxfmst->lp_orient + pxfmst->print_dir; if (prstate->pres_mode_3) rot &= 0x2; rot = (rot - pxfmst->lp_orient) & 0x3; if (prstate->y_advance == -1) rot = (rot + 2) & 0x3; pcl_make_rotation(rot, pxfmst->lp_size.x, pxfmst->lp_size.y, &rst2lp); pcl_invert_mtx(&rst2lp, &lp2rst); /* convert the current point to raster space */ cur_pt.x = (double)pcs->cap.x + adjust_pres_mode(pcs); cur_pt.y = (double)pcs->cap.y; pcl_xfm_to_logical_page_space(pcs, &cur_pt); gs_point_transform(cur_pt.x, cur_pt.y, &lp2rst, &cur_pt); /* translate the origin of the forward transformation */ if (((int)mode & 0x1) != 0) gmargin_cp = cur_pt.x; gs_matrix_translate(&rst2lp, gmargin_cp, cur_pt.y, &rst2lp); prstate->gmargin_cp = gmargin_cp; /* isotropic scaling with missing parameter is based on clipped raster dimensions */ /* transform the clipping window to raster space */ get_raster_print_rect(pcs->memory, &(pxfmst->lp_print_rect), &print_rect, &rst2lp); dwid = print_rect.q.x - print_rect.p.x; dhgt = print_rect.q.y - print_rect.p.y; clip_x = pxfmst->lp_print_rect.p.x; /* if neg then: */ clip_y = pxfmst->lp_print_rect.p.y; /* = 1200centipoints */ /* set the matrix scale */ if ( !prstate->scale_raster || !prstate->src_width_set || !prstate->src_height_set || (pcs->ppalet->pindexed->pfixed && mode == IMPLICIT) ) { scale_x = 7200.0 / (floatp)prstate->resolution; scale_y = scale_x; } else if (prstate->dest_width_set) { scale_x = (floatp)prstate->dest_width_cp / (floatp)prstate->src_width; if ( clip_x < 0 && pxfmst->lp_orient == 3 ) { scale_y = (floatp)(prstate->dest_width_cp - clip_y ) / (floatp)prstate->src_width; if ( rot == 2 && scale_y <= 2* prstate->src_width) /* empirical test 1 */ scale_y = scale_x; } else if ( clip_x < 0 && pxfmst->lp_orient == 1 && rot == 3 ) { scale_y = (floatp)(prstate->dest_width_cp - clip_y) / (floatp)prstate->src_width; if ( prstate->dest_width_cp <= 7200 ) /* empirical test 2 */ scale_y = (floatp)(prstate->dest_width_cp + clip_y) / (floatp)prstate->src_width; } else scale_y = scale_x; if (prstate->dest_height_set) scale_y = (floatp)prstate->dest_height_cp / (floatp)prstate->src_height; } else if (prstate->dest_height_set) { scale_x = scale_y = (floatp)prstate->dest_height_cp / (floatp)prstate->src_height; } else { /* select isotropic scaling with no clipping */ scale_x = (floatp)dwid / (floatp)prstate->src_width; scale_y = (floatp)dhgt / (floatp)prstate->src_height; if (scale_x > scale_y) scale_x = scale_y; else scale_y = scale_x; } gs_matrix_scale(&rst2lp, scale_x, scale_y, &rst2lp); gs_matrix_multiply(&rst2lp, &(pxfmst->lp2dev_mtx), &rst2dev); rst2dev.tx = (double)((int)(rst2dev.tx + 0.5)); rst2dev.ty = (double)((int)(rst2dev.ty + 0.5)); /* * Set up the graphic stat for rasters. This turns out to be more difficult * than might first be imagined. * * One problem is that two halftones may be needed simultaneously: * * the foreground CRD and halftone, in case the current "texture" is a * a solid color or an uncolored pattern * * the palette CRD and halftone, to be used in rendering the raster * itself * * Since the graphic state can only hold one CRD and one halftone method * at a time, this presents a bit of a problem. * * To get around the problem, an extra graphic state is necessary. Patterns * in the graphic library are given their own graphic state. Hence, by * replacing a solid color with an uncolored pattern that takes the * foreground value everywhere, the desired effect can be achieved. Code * in pcpatrn.c handles these matters. * * The second problem is a limitation in the graphic library's support of * CIE color spaces. These spaces require a joint cache, which is only * created when the color space is installed in the graphic state. However, * the current color space at the time a raster is rendered may need to * be a pattern color space, so that the proper interaction between the * raster and the texture generated by the pattern. To work around this * problem, we install the raster's color space in the current graphic * state, perform a gsave, then place what may be a patterned color space * in the new graphic state. */ pcl_set_graphics_state(pcs); pcl_set_drawing_color(pcs, pcl_pattern_raster_cspace, 0, true); pcl_gsave(pcs); pcl_set_drawing_color(pcs, pcs->pattern_type, pcs->current_pattern_id, true); gs_setmatrix(pcs->pgs, &rst2dev); /* translate the origin of the forward transformation */ /* tansform the clipping window to raster space; udpate source dimensions */ get_raster_print_rect(pcs->memory, &(pxfmst->lp_print_rect), &print_rect, &rst2lp); /* min size is 1 pixel */ src_wid = max(1, (uint)(floor(print_rect.q.x) - floor(print_rect.p.x))); src_hgt = max(1, (uint)(floor(print_rect.q.y) - floor(print_rect.p.y))); if (prstate->src_width_set && (src_wid > prstate->src_width)) src_wid = prstate->src_width; if (prstate->src_height_set && (src_hgt > prstate->src_height)) src_hgt = prstate->src_height; if (src_wid <= 0 || src_hgt <= 0) { pcl_grestore(pcs); return 1; /* hack, we want to return a non critical warning */ } /* determine (conservatively) if the region of interest has been marked */ pcs->page_marked = true; if ((code = pcl_start_raster(src_wid, src_hgt, pcs)) >= 0) prstate->graphics_mode = true; else pcl_grestore(pcs); return code; }