Пример #1
0
/*
 * Compute the adjustment matrix for scaling and/or rotating the page
 * to match the medium.  If the medium is completely flexible in a given
 * dimension (e.g., roll media in one dimension, or displays in both),
 * we must adjust its size in that dimension to match the request.
 * We recognize this by an unreasonably small medium->p.{x,y}.
 */
static void 
make_adjustment_matrix(const gs_point * request, const gs_rect * medium,
		       gs_matrix * pmat, bool scale, int rotate)
{
    double rx = request->x, ry = request->y;
    double mx = medium->q.x, my = medium->q.y;

    /* Rotate the request if necessary. */ 
    if (rotate & 1) {
	double temp = rx;

	rx = ry, ry = temp;
    }
    /* If 'medium' is flexible, adjust 'mx' and 'my' towards 'rx' and 'ry',
       respectively. Note that 'mx' and 'my' have just acquired the largest
       permissible value, medium->q. */
    if (medium->p.x < mx) {	/* non-empty width range */
	if (rx < medium->p.x)
	    mx = medium->p.x;	/* use minimum of the range */
	else if (rx < mx)
	    mx = rx;		/* fits */
		/* else leave mx == medium->q.x, i.e., the maximum */
    }
    if (medium->p.y < my) {	/* non-empty height range */
	if (ry < medium->p.y)
	    my = medium->p.y;	/* use minimum of the range */
	else if (ry < my)
	    my = ry;		/* fits */
	    /* else leave my == medium->q.y, i.e., the maximum */
    }

    /* Translate to align the centers. */ 
    gs_make_translation(mx / 2, my / 2, pmat);

    /* Rotate if needed. */ 
    if (rotate)
	gs_matrix_rotate(pmat, 90.0 * rotate, pmat);

    /* Scale if needed. */ 
    if (scale) {
	double xfactor = mx / rx;
	double yfactor = my / ry;
	double factor = min(xfactor, yfactor);

	if (factor < 1)
	    gs_matrix_scale(pmat, factor, factor, pmat);
    }
    /* Now translate the origin back, */ 
    /* using the original, unswapped request. */ 
    gs_matrix_translate(pmat, -request->x / 2, -request->y / 2, pmat);
}
Пример #2
0
static int
vu_begin_image(px_state_t * pxs)
{
    px_vendor_state_t *v_state = pxs->vendor_state;
    gs_image_t image = v_state->image;
    px_bitmap_params_t params;
    gs_point origin;
    int code;

    if (v_state->color_space == eGraySub)
	params.color_space = eGray;
    else
	params.color_space = eSRGB;
    params.width = params.dest_width = v_state->SourceWidth;
    params.height = params.dest_height = v_state->BlockHeight;
    params.depth = 8;
    params.indexed = false;
    code = px_image_color_space(&image, &params,
				(const gs_string *)&pxs->pxgs->palette,
				pxs->pgs);
    if (code < 0) {
	return code;
    }

    /* Set up the image parameters. */
    if (gs_currentpoint(pxs->pgs, &origin) < 0)
	return_error(errorCurrentCursorUndefined);
    image.Width = v_state->SourceWidth;
    image.Height = v_state->BlockHeight;
    {
	gs_matrix imat, dmat;

	gs_make_scaling(image.Width, image.Height, &imat);
	gs_make_translation(origin.x, origin.y + v_state->StartLine, &dmat);
	gs_matrix_scale(&dmat, image.Width, image.Height, &dmat);
	/* The ImageMatrix is dmat' * imat. */
	gs_matrix_invert(&dmat, &dmat);
	gs_matrix_multiply(&dmat, &imat, &image.ImageMatrix);
    }
    image.CombineWithColor = true;
    image.Interpolate = pxs->interpolate;
    code = pl_begin_image(pxs->pgs, &image, &v_state->info);
    if (code < 0)
	return code;
    return 0;
}
Пример #3
0
/* Initialize for writing a path using the default implementation. */
void
gdev_vector_dopath_init(gdev_vector_dopath_state_t *state,
                        gx_device_vector *vdev, gx_path_type_t type,
                        const gs_matrix *pmat)
{
    state->vdev = vdev;
    state->type = type;
    if (pmat) {
        state->scale_mat = *pmat;
        /*
         * The path element writing procedures all divide the coordinates
         * by the scale, so we must compensate for that here.
         */
        gs_matrix_scale(&state->scale_mat, 1.0 / vdev->scale.x,
                        1.0 / vdev->scale.y, &state->scale_mat);
    } else {
        gs_make_scaling(vdev->scale.x, vdev->scale.y, &state->scale_mat);
    }
    state->first = true;
}
Пример #4
0
/*
 * Form the transformation matrix required to render a pattern.
 */
  void
pcl_xfm_get_pat_xfm(
    const pcl_state_t *     pcs,
    pcl_pattern_t *         pptrn,
    gs_matrix *             pmat
)
{
    const pcl_xfm_state_t * pxfmst = &(pcs->xfm_state);
    int                     rot = (pcs->pat_orient - pxfmst->lp_orient) & 0x3;

    *pmat = pxfmst->lp2dev_mtx;
    pmat->tx = pcs->pat_ref_pt.x;
    pmat->ty = pcs->pat_ref_pt.y;

    /* record the referenc point used in the rendering structure */
    pptrn->ref_pt = pcs->pat_ref_pt;

    /* rotate as necessar */
    if (rot != 0)
        gs_matrix_multiply(&(rot_mtx[rot]), pmat, pmat);

    /* scale to the appropriate resolution (before print direction rotation) */
    gs_matrix_scale( pmat,
                     inch2coord(1.0 / (floatp)pptrn->ppat_data->xres),
                     inch2coord(1.0 / (floatp)pptrn->ppat_data->yres),
                     pmat
                     );

    /* avoid parameters that are slightly different from integers */
    pmat->xx = adjust_param(pmat->xx);
    pmat->xy = adjust_param(pmat->xy);
    pmat->yx = adjust_param(pmat->yx);
    pmat->yy = adjust_param(pmat->yy);

    /* record the rotation used for rendering */
    pptrn->orient = pcs->pat_orient;
}
Пример #5
0
/*
 * Reset all parameters which must be reset whenever the page size changes.
 *
 * The third operand indicates if this routine is being called as part of
 * an initial reset. In that case, done't call HPGL's reset - the reset
 * will do that later.
 */
  static void
new_page_size(
    pcl_state_t *               pcs,
    const pcl_paper_size_t *    psize,
    bool                        reset_initial,
    bool                        for_passthrough
)
{
    floatp                      width_pts = psize->width * 0.01;
    floatp                      height_pts = psize->height * 0.01;
    float                       page_size[2];
    static float                old_page_size[2] = { 0, 0 };
    gs_state *                  pgs = pcs->pgs;
    gs_matrix                   mat;
    bool                        changed_page_size;

    page_size[0] = width_pts;
    page_size[1] = height_pts;

    old_page_size[0] = pcs->xfm_state.paper_size ? pcs->xfm_state.paper_size->width : 0;
    old_page_size[1] = pcs->xfm_state.paper_size ? pcs->xfm_state.paper_size->height : 0;

    put_param1_float_array(pcs, "PageSize", page_size);

    /*
     * Reset the default transformation.
     *
     * The graphic library provides a coordinate system in points, with the
     * origin at the lower left corner of the page. The PCL code uses a
     * coordinate system in centi-points, with the origin at the upper left
     * corner of the page.
     */
    gs_setdefaultmatrix(pgs, NULL);
    gs_initmatrix(pgs);
    gs_currentmatrix(pgs, &mat);
    gs_matrix_translate(&mat, 0.0, height_pts, &mat);
    gs_matrix_scale(&mat, 0.01, -0.01, &mat);
    gs_setdefaultmatrix(pgs, &mat);

    pcs->xfm_state.paper_size = psize;
    pcs->overlay_enabled = false;
    update_xfm_state(pcs, reset_initial);
    reset_margins(pcs, for_passthrough);

    /* check if update_xfm_state changed the page size */
    changed_page_size = !(old_page_size[0] == pcs->xfm_state.paper_size->width &&
                          old_page_size[1] == pcs->xfm_state.paper_size->height);


    /*
     * make sure underlining is disabled (homing the cursor may cause
     * an underline to be put out.
     */
    pcs->underline_enabled = false;
    pcl_home_cursor(pcs);

    pcl_xfm_reset_pcl_pat_ref_pt(pcs);

    if (!reset_initial)
        hpgl_do_reset(pcs, pcl_reset_page_params);

    if ( pcs->end_page == pcl_end_page_top ) {  /* don't erase in snippet mode */
        if (pcs->page_marked || changed_page_size) {
            gs_erasepage(pcs->pgs);
            pcs->page_marked = false;
        }
    }
}
Пример #6
0
/* Compute the FontDescriptor metrics for a font. */
int
pdf_compute_font_descriptor(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd)
{
    gs_font_base *bfont = pdf_base_font_font(pfd->base_font, false);
    gs_glyph glyph, notdef;
    int index;
    int wmode = bfont->WMode;
    int members = (GLYPH_INFO_WIDTH0 << wmode) |
        GLYPH_INFO_BBOX | GLYPH_INFO_NUM_PIECES;
    pdf_font_descriptor_values_t desc;
    gs_matrix smat;
    gs_matrix *pmat = NULL;
    int fixed_width = 0;
    int small_descent = 0, small_height = 0;
    bool small_present = false;
    int x_height = 0;
    int cap_height = 0;
    gs_rect bbox_colon, bbox_period, bbox_I;
    bool is_cid = (bfont->FontType == ft_CID_encrypted ||
                   bfont->FontType == ft_CID_TrueType);
    bool have_colon = false, have_period = false, have_I = false;
    int code;

    memset(&bbox_colon, 0, sizeof(bbox_colon)); /* quiet gcc warnings. */
    memset(&bbox_period, 0, sizeof(bbox_period)); /* quiet gcc warnings. */
    memset(&bbox_I, 0, sizeof(bbox_I)); /* quiet gcc warnings. */
    memset(&desc, 0, sizeof(desc));
    if (is_cid && bfont->FontBBox.p.x != bfont->FontBBox.q.x &&
                  bfont->FontBBox.p.y != bfont->FontBBox.q.y) {
        int scale = (bfont->FontType == ft_TrueType || bfont->FontType == ft_CID_TrueType ? 1000 : 1);

        desc.FontBBox.p.x = (int)(bfont->FontBBox.p.x * scale);
        desc.FontBBox.p.y = (int)(bfont->FontBBox.p.y * scale);
        desc.FontBBox.q.x = (int)(bfont->FontBBox.q.x * scale);
        desc.FontBBox.q.y = (int)(bfont->FontBBox.q.y * scale);
        desc.Ascent = desc.FontBBox.q.y;
        members &= ~GLYPH_INFO_BBOX;
    } else {
        desc.FontBBox.p.x = desc.FontBBox.p.y = max_int;
        desc.FontBBox.q.x = desc.FontBBox.q.y = min_int;
    }
    /*
     * Embedded TrueType fonts use a 1000-unit character space, but the
     * font itself uses a 1-unit space.  Compensate for this here.
     */
    switch (bfont->FontType) {
    case ft_TrueType:
    case ft_CID_TrueType:
        gs_make_scaling(1000.0, 1000.0, &smat);
        pmat = &smat;
        /* Type 3 fonts may use a FontMatrix in PDF, so we don't
         * need to deal with non-standard matrices
         */
    case ft_GL2_531:
    case ft_PCL_user_defined:
    case ft_GL2_stick_user_defined:
    case ft_MicroType:
    case ft_user_defined:
        break;
        /* Other font types may use a non-standard (not 1000x1000) design grid
         * The FontMatrix is used to map to the unit square. However PDF files
         * don't allow FontMatrix entries, all fonts are nominally 1000x1000.
         * If we have a font with a non-standard matrix we must account for that
         * here by scaling the font outline.
         */
    default:
        gs_matrix_scale(&bfont->FontMatrix, 1000.0, 1000.0, &smat);
        pmat = &smat;
        break;
    }

    /*
     * Scan the entire glyph space to compute Ascent, Descent, FontBBox, and
     * the fixed width if any.  For non-symbolic fonts, also note the
     * bounding boxes for Latin letters and a couple of other characters,
     * for computing the remaining descriptor values (CapHeight,
     * ItalicAngle, StemV, XHeight, and flags SERIF, SCRIPT, ITALIC,
     * ALL_CAPS, and SMALL_CAPS).  (The algorithms are pretty crude.)
     */
    notdef = GS_NO_GLYPH;
    for (index = 0;
         (bfont->procs.enumerate_glyph((gs_font *)bfont, &index,
                (is_cid ? GLYPH_SPACE_INDEX : GLYPH_SPACE_NAME), &glyph)) >= 0 &&
             index != 0;
         ) {
        gs_glyph_info_t info;
        gs_const_string gname;
        gs_glyph glyph_known_enc;
        gs_char position=0;

        code = bfont->procs.glyph_info((gs_font *)bfont, glyph, pmat, members, &info);
        if (code == gs_error_VMerror)
            return code;
        if (code < 0) {
            /*
             * Since this function may be indirtectly called from gx_device_finalize,
             * we are unable to propagate error code to the interpreter.
             * Therefore we skip it here hoping that few errors can be
             * recovered by the integration through entire glyph set.
             */
            continue;
        }
        if (members & GLYPH_INFO_BBOX) {
            /* rect_merge(desc.FontBBox, info.bbox); Expanding due to type cast :*/
            if (info.bbox.p.x < desc.FontBBox.p.x) desc.FontBBox.p.x = (int)info.bbox.p.x;
            if (info.bbox.q.x > desc.FontBBox.q.x) desc.FontBBox.q.x = (int)info.bbox.q.x;
            if (info.bbox.p.y < desc.FontBBox.p.y) desc.FontBBox.p.y = (int)info.bbox.p.y;
            if (info.bbox.q.y > desc.FontBBox.q.y) desc.FontBBox.q.y = (int)info.bbox.q.y;
            if (!info.num_pieces)
                desc.Ascent = max(desc.Ascent, (int)info.bbox.q.y);
        }
        if (notdef == GS_NO_GLYPH && gs_font_glyph_is_notdef(bfont, glyph)) {
            notdef = glyph;
            desc.MissingWidth = (int)info.width[wmode].x;
        }
        if (info.width[wmode].y != 0)
            fixed_width = min_int;
        else if (fixed_width == 0)
            fixed_width = (int)info.width[wmode].x;
        else if (info.width[wmode].x != fixed_width)
            fixed_width = min_int;
        if (desc.Flags & FONT_IS_SYMBOLIC)
            continue;		/* skip Roman-only computation */
        if (is_cid)
            continue;
        code = bfont->procs.glyph_name((gs_font *)bfont, glyph, &gname);
        if (code < 0) {
            /* If we fail to get the glyph name, best assume this is a symbolic font */
            desc.Flags |= FONT_IS_SYMBOLIC;
            continue;
        }
        /* See if the glyph name is in any of the known encodings */
        glyph_known_enc = gs_c_name_glyph(gname.data, gname.size);
        if (glyph_known_enc == gs_no_glyph) {
            desc.Flags |= FONT_IS_SYMBOLIC;
            continue;
        }
        /* Finally check if the encoded glyph is in Standard Encoding */
        /* gs_c_decode always fails to find .notdef, its always present so
         * don't worry about it
         */
        if(strncmp(".notdef", (const char *)gname.data, gname.size)) {
            position = gs_c_decode(glyph_known_enc, 0);
            if (position == GS_NO_CHAR) {
                desc.Flags |= FONT_IS_SYMBOLIC;
                continue;
            }
        }
        switch (gname.size) {
        case 5:
            if (!memcmp(gname.data, "colon", 5))
                bbox_colon = info.bbox, have_colon = true;
            continue;
        case 6:
            if (!memcmp(gname.data, "period", 6))
                bbox_period = info.bbox, have_period = true;
            continue;
        case 1:
            break;
        default:
            continue;
        }

        if (gname.data[0] >= 'A' && gname.data[0] <= 'Z') {
            cap_height = max(cap_height, (int)info.bbox.q.y);
            if (gname.data[0] == 'I')
                bbox_I = info.bbox, have_I = true;
        } else if (gname.data[0] >= 'a' && gname.data[0] <= 'z') {
            int y0 = (int)(info.bbox.p.y), y1 = (int)(info.bbox.q.y);

            small_present = true;
            switch (gname.data[0]) {
            case 'b': case 'd': case 'f': case 'h':
            case 'k': case 'l': case 't': /* ascender */
                small_height = max(small_height, y1);
            case 'i':		/* anomalous ascent */
                break;
            case 'j':		/* descender with anomalous ascent */
                small_descent = min(small_descent, y0);
                break;
            case 'g': case 'p': case 'q': case 'y': /* descender */
                small_descent = min(small_descent, y0);
            default:		/* no ascender or descender */
                x_height = max(x_height, y1);
            }
        }
    }
    if (!(desc.Flags & FONT_IS_SYMBOLIC)) {
        desc.Flags |= FONT_IS_ADOBE_ROMAN; /* required if not symbolic */
        desc.XHeight = (int)x_height;
        if (!small_present && (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType))
            desc.Flags |= FONT_IS_ALL_CAPS;
        desc.CapHeight = cap_height;
        /*
         * Look at various glyphs to determine ItalicAngle, StemV,
         * SERIF, SCRIPT, and ITALIC.
         */
        if (have_colon && have_period) {
            /* Calculate the dominant angle. */
            int angle =
                (int)(atan2((bbox_colon.q.y - bbox_colon.p.y) -
                              (bbox_period.q.y - bbox_period.p.y),
                            (bbox_colon.q.x - bbox_colon.p.x) -
                              (bbox_period.q.x - bbox_period.p.x)) *
                      radians_to_degrees) - 90;

            /* Normalize to [-90..90]. */
            while (angle > 90)
                angle -= 180;
            while (angle < -90)
                angle += 180;
            if (angle < -30)
                angle = -30;
            else if (angle > 30)
                angle = 30;
            /*
             * For script or embellished fonts, we can get an angle that is
             * slightly off from zero even for non-italic fonts.
             * Compensate for this now.
             */
            if (angle <= 2 && angle >= -2)
                angle = 0;
            desc.ItalicAngle = angle;
        }
        if (desc.ItalicAngle)
            desc.Flags |= FONT_IS_ITALIC;
        if (have_I) {
            double wdot = bbox_period.q.x - bbox_period.p.x;
            double wcolon = bbox_I.q.x - bbox_I.p.x;
            double wI = bbox_period.q.x - bbox_period.p.x;

            desc.StemV = (int)wdot;
            if (wI > wcolon * 2.5 || wI > (bbox_period.q.y - bbox_period.p.y) * 0.25)
                desc.Flags |= FONT_IS_SERIF;
        }
    }
    if (desc.Ascent == 0)
        desc.Ascent = desc.FontBBox.q.y;
    desc.Descent = desc.FontBBox.p.y;
    if (!(desc.Flags & (FONT_IS_SYMBOLIC | FONT_IS_ALL_CAPS)) &&
        (small_descent > desc.Descent / 3 || desc.XHeight > small_height * 0.9) &&
        (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType)
        )
        desc.Flags |= FONT_IS_SMALL_CAPS;
    if (fixed_width > 0 && (!pdev->PDFA != 0 || bfont->FontType != ft_TrueType)) {
        desc.Flags |= FONT_IS_FIXED_WIDTH;
        desc.AvgWidth = desc.MaxWidth = desc.MissingWidth = fixed_width;
    }
    if (desc.CapHeight == 0)
        desc.CapHeight = desc.Ascent;
    if (desc.StemV == 0)
        desc.StemV = (int)(desc.FontBBox.q.x * 0.15);
    pfd->common.values = desc;
    return 0;
}
Пример #7
0
int
xps_parse_tiling_brush(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, xps_item_t *root,
    int (*func)(xps_context_t*, char*, xps_resource_t*, xps_item_t*, void*), void *user)
{
    xps_item_t *node;
    int code;

    char *opacity_att;
    char *transform_att;
    char *viewbox_att;
    char *viewport_att;
    char *tile_mode_att;
    /*char *viewbox_units_att;*/
    /*char *viewport_units_att;*/

    xps_item_t *transform_tag = NULL;

    gs_matrix transform;
    gs_rect viewbox;
    gs_rect viewport;
    float scalex, scaley;
    int tile_mode;

    opacity_att = xps_att(root, "Opacity");
    transform_att = xps_att(root, "Transform");
    viewbox_att = xps_att(root, "Viewbox");
    viewport_att = xps_att(root, "Viewport");
    tile_mode_att = xps_att(root, "TileMode");
    /*viewbox_units_att = xps_att(root, "ViewboxUnits");*/
    /*viewport_units_att = xps_att(root, "ViewportUnits");*/

    for (node = xps_down(root); node; node = xps_next(node))
    {
        if (!strcmp(xps_tag(node), "ImageBrush.Transform"))
            transform_tag = xps_down(node);
        if (!strcmp(xps_tag(node), "VisualBrush.Transform"))
            transform_tag = xps_down(node);
    }

    xps_resolve_resource_reference(ctx, dict, &transform_att, &transform_tag, NULL);

    gs_make_identity(&transform);
    if (transform_att)
        xps_parse_render_transform(ctx, transform_att, &transform);
    if (transform_tag)
        xps_parse_matrix_transform(ctx, transform_tag, &transform);

    viewbox.p.x = 0.0; viewbox.p.y = 0.0;
    viewbox.q.x = 1.0; viewbox.q.y = 1.0;
    if (viewbox_att)
        xps_parse_rectangle(ctx, viewbox_att, &viewbox);

    viewport.p.x = 0.0; viewport.p.y = 0.0;
    viewport.q.x = 1.0; viewport.q.y = 1.0;
    if (viewport_att)
        xps_parse_rectangle(ctx, viewport_att, &viewport);

    /* some sanity checks on the viewport/viewbox size */
    if (fabs(viewport.q.x - viewport.p.x) < 0.01) { gs_warn("skipping tile with zero width view port"); return 0; }
    if (fabs(viewport.q.y - viewport.p.y) < 0.01) { gs_warn("skipping tile with zero height view port"); return 0; }
    if (fabs(viewbox.q.x - viewbox.p.x) < 0.01) { gs_warn("skipping tile with zero width view box"); return 0; }
    if (fabs(viewbox.q.y - viewbox.p.y) < 0.01) { gs_warn("skipping tile with zero height view box"); return 0; }

    scalex = (viewport.q.x - viewport.p.x) / (viewbox.q.x - viewbox.p.x);
    scaley = (viewport.q.y - viewport.p.y) / (viewbox.q.y - viewbox.p.y);

    tile_mode = TILE_NONE;
    if (tile_mode_att)
    {
        if (!strcmp(tile_mode_att, "None"))
            tile_mode = TILE_NONE;
        if (!strcmp(tile_mode_att, "Tile"))
            tile_mode = TILE_TILE;
        if (!strcmp(tile_mode_att, "FlipX"))
            tile_mode = TILE_FLIP_X;
        if (!strcmp(tile_mode_att, "FlipY"))
            tile_mode = TILE_FLIP_Y;
        if (!strcmp(tile_mode_att, "FlipXY"))
            tile_mode = TILE_FLIP_X_Y;
    }

    gs_gsave(ctx->pgs);

    code = xps_begin_opacity(ctx, base_uri, dict, opacity_att, NULL, false, false);
    if (code)
    {
        gs_grestore(ctx->pgs);
        return gs_rethrow(code, "cannot create transparency group");
    }

    /* TODO(tor): check viewport and tiling to see if we can set it to TILE_NONE */

    if (tile_mode != TILE_NONE)
    {
        struct tile_closure_s closure;

        gs_client_pattern gspat;
        gs_client_color gscolor;
        gs_color_space *cs;
        bool sa;

        closure.ctx = ctx;
        closure.base_uri = base_uri;
        closure.dict = dict;
        closure.tag = root;
        closure.tile_mode = tile_mode;
        closure.user = user;
        closure.func = func;

        closure.viewbox.p.x = viewbox.p.x;
        closure.viewbox.p.y = viewbox.p.y;
        closure.viewbox.q.x = viewbox.q.x;
        closure.viewbox.q.y = viewbox.q.y;

        gs_pattern1_init(&gspat);
        uid_set_UniqueID(&gspat.uid, gs_next_ids(ctx->memory, 1));
        gspat.PaintType = 1;
        gspat.TilingType = 2;
        gspat.PaintProc = xps_remap_pattern;
        gspat.client_data = &closure;

        /* We need to know if this tiling brush includes transparency.
           We could do a proper scan, but for now we'll be lazy and just look
           at the flag from scanning the page. */
        gspat.uses_transparency = ctx->has_transparency;

        gspat.XStep = viewbox.q.x - viewbox.p.x;
        gspat.YStep = viewbox.q.y - viewbox.p.y;
        gspat.BBox.p.x = viewbox.p.x;
        gspat.BBox.p.y = viewbox.p.y;
        gspat.BBox.q.x = viewbox.q.x;
        gspat.BBox.q.y = viewbox.q.y;

        if (tile_mode == TILE_FLIP_X || tile_mode == TILE_FLIP_X_Y)
        {
            gspat.BBox.q.x += gspat.XStep;
            gspat.XStep *= 2;
        }

        if (tile_mode == TILE_FLIP_Y || tile_mode == TILE_FLIP_X_Y)
        {
            gspat.BBox.q.y += gspat.YStep;
            gspat.YStep *= 2;
        }

        gs_matrix_translate(&transform, viewport.p.x, viewport.p.y, &transform);
        gs_matrix_scale(&transform, scalex, scaley, &transform);
        gs_matrix_translate(&transform, -viewbox.p.x, -viewbox.p.y, &transform);

        cs = ctx->srgb;
        gs_setcolorspace(ctx->pgs, cs);
        gsicc_profile_reference(cs->cmm_icc_profile_data, 1);

        sa = gs_currentstrokeadjust(ctx->pgs);
        gs_setstrokeadjust(ctx->pgs, false);
        gs_makepattern(&gscolor, &gspat, &transform, ctx->pgs, NULL);
        gs_setpattern(ctx->pgs, &gscolor);
        xps_fill(ctx);
        gs_setstrokeadjust(ctx->pgs, sa);
        gsicc_profile_reference(cs->cmm_icc_profile_data, -1);

        /* gs_makepattern increments the pattern count stored in the color
         * structure. We will discard the color struct (its on the stack)
         * so we need to decrement the reference before we throw away
         * the structure.
         */
        gs_pattern_reference(&gscolor, -1);
    }
    else
    {
        xps_clip(ctx);

        gs_concat(ctx->pgs, &transform);

        gs_translate(ctx->pgs, viewport.p.x, viewport.p.y);
        gs_scale(ctx->pgs, scalex, scaley);
        gs_translate(ctx->pgs, -viewbox.p.x, -viewbox.p.y);

        gs_moveto(ctx->pgs, viewbox.p.x, viewbox.p.y);
        gs_lineto(ctx->pgs, viewbox.p.x, viewbox.q.y);
        gs_lineto(ctx->pgs, viewbox.q.x, viewbox.q.y);
        gs_lineto(ctx->pgs, viewbox.q.x, viewbox.p.y);
        gs_closepath(ctx->pgs);
        gs_clip(ctx->pgs);
        gs_newpath(ctx->pgs);

        code = func(ctx, base_uri, dict, root, user);
        if (code < 0)
        {
            xps_end_opacity(ctx, base_uri, dict, opacity_att, NULL);
            gs_grestore(ctx->pgs);
            return gs_rethrow(code, "cannot draw tile");
        }
    }

    xps_end_opacity(ctx, base_uri, dict, opacity_att, NULL);

    gs_grestore(ctx->pgs);

    return 0;
}
Пример #8
0
/*
 * 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;
}