Esempio n. 1
0
/* 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);
    }
}
Esempio n. 2
0
/*
 * Compute the scale for transforming the line width and dash pattern for a
 * stroke operation, and, if necessary to handle anisotropic scaling, a full
 * transformation matrix to be inverse-applied to the path elements as well.
 * Return 0 if only scaling, 1 if a full matrix is needed.
 */
int
gdev_vector_stroke_scaling(const gx_device_vector *vdev,
                           const gs_imager_state *pis,
                           double *pscale, gs_matrix *pmat)
{
    bool set_ctm = true;
    double scale = 1;

    /*
     * If the CTM is not uniform, stroke width depends on angle.
     * We'd like to avoid resetting the CTM, so we check for uniform
     * CTMs explicitly.  Note that in PDF, unlike PostScript, it is
     * the CTM at the time of the stroke operation, not the CTM at
     * the time the path was constructed, that is used for transforming
     * the points of the path; so if we have to reset the CTM, we must
     * do it before constructing the path, and inverse-transform all
     * the coordinates.
     */
    if (is_xxyy(&pis->ctm)) {
        scale = fabs(pis->ctm.xx);
        set_ctm = fabs(pis->ctm.yy) != scale;
    } else if (is_xyyx(&pis->ctm)) {
        scale = fabs(pis->ctm.xy);
        set_ctm = fabs(pis->ctm.yx) != scale;
    } else if ((pis->ctm.xx == pis->ctm.yy && pis->ctm.xy == -pis->ctm.yx) ||
               (pis->ctm.xx == -pis->ctm.yy && pis->ctm.xy == pis->ctm.yx)
        ) {
        scale = hypot(pis->ctm.xx, pis->ctm.xy);
        set_ctm = false;
    }
    if (set_ctm) {
        /*
         * Adobe Acrobat Reader has limitations on the maximum user
         * coordinate value.  If we scale the matrix down too far, the
         * coordinates will get too big: limit the scale factor to prevent
         * this from happening.  (This does no harm for other output
         * formats.)
         */
        double
            mxx = pis->ctm.xx / vdev->scale.x,
            mxy = pis->ctm.xy / vdev->scale.y,
            myx = pis->ctm.yx / vdev->scale.x,
            myy = pis->ctm.yy / vdev->scale.y;

        scale = 0.5 * (fabs(mxx) + fabs(mxy) + fabs(myx) + fabs(myy));
        pmat->xx = mxx / scale, pmat->xy = mxy / scale;
        pmat->yx = myx / scale, pmat->yy = myy / scale;
        pmat->tx = pmat->ty = 0;
    }
    *pscale = scale;
    return (int)set_ctm;
}
Esempio n. 3
0
/* Return gs_error_undefinedresult if the matrix is not invertible. */
int
gs_distance_transform_inverse(floatp dx, floatp dy,
                              const gs_matrix * pmat, gs_point * pdpt)
{
    if (is_xxyy(pmat)) {
        if (is_fzero(pmat->xx) || is_fzero(pmat->yy))
            return_error(gs_error_undefinedresult);
        pdpt->x = dx / pmat->xx;
        pdpt->y = dy / pmat->yy;
    } else if (is_xyyx(pmat)) {
        if (is_fzero(pmat->xy) || is_fzero(pmat->yx))
            return_error(gs_error_undefinedresult);
        pdpt->x = dy / pmat->xy;
        pdpt->y = dx / pmat->yx;
    } else {
        double det = pmat->xx * pmat->yy - pmat->xy * pmat->yx;

        if (det == 0)
            return_error(gs_error_undefinedresult);
        pdpt->x = (dx * pmat->yy - dy * pmat->yx) / det;
        pdpt->y = (dy * pmat->xx - dx * pmat->xy) / det;
    }
    return 0;
}
Esempio n. 4
0
int
gdev_vector_dopath(gx_device_vector *vdev, const gx_path * ppath,
                   gx_path_type_t type, const gs_matrix *pmat)
{
    bool do_close =
        (type & (gx_path_type_stroke | gx_path_type_always_close)) != 0;
    gs_fixed_rect rbox;
    gx_path_rectangular_type rtype = gx_path_is_rectangular(ppath, &rbox);
    gs_path_enum cenum;
    gdev_vector_dopath_state_t state;
    gs_fixed_point line_start, line_end;
    bool incomplete_line = false;
    bool need_moveto = false;
    int code;

    gdev_vector_dopath_init(&state, vdev, type, pmat);
    /*
     * if the path type is stroke, we only recognize closed
     * rectangles; otherwise, we recognize all rectangles.
     * Note that for stroking with a transformation, we can't use dorect,
     * which requires (untransformed) device coordinates.
     */
    if (rtype != prt_none &&
        (!(type & gx_path_type_stroke) || rtype == prt_closed) &&
        (pmat == 0 || is_xxyy(pmat) || is_xyyx(pmat)) &&
        (state.scale_mat.xx == 1.0 && state.scale_mat.yy == 1.0 &&
         is_xxyy(&state.scale_mat) &&
         is_fzero2(state.scale_mat.tx, state.scale_mat.ty))
        ) {
        gs_point p, q;

        gs_point_transform_inverse((double)rbox.p.x, (double)rbox.p.y,
                                   &state.scale_mat, &p);
        gs_point_transform_inverse((double)rbox.q.x, (double)rbox.q.y,
                                   &state.scale_mat, &q);
        code = vdev_proc(vdev, dorect)(vdev, (fixed)p.x, (fixed)p.y,
                                       (fixed)q.x, (fixed)q.y, type);
        if (code >= 0)
            return code;
        /* If the dorect proc failed, use a general path. */
    }
    code = vdev_proc(vdev, beginpath)(vdev, type);
    if (code < 0)
        return code;
    gx_path_enum_init(&cenum, ppath);
    for (;;) {
        gs_fixed_point vs[3];
        int pe_op = gx_path_enum_next(&cenum, vs);

    sw:
        if (type & gx_path_type_optimize) {
        opt:
            /* RJW: We fail to optimize gaptos */
            if (pe_op == gs_pe_lineto) {
                if (!incomplete_line) {
                    line_end = vs[0];
                    incomplete_line = true;
                    continue;
                }
                /*
                 * Merge collinear horizontal or vertical line segments
                 * going in the same direction.
                 */
                if (vs[0].x == line_end.x) {
                    if (vs[0].x == line_start.x &&
                        coord_between(line_start.y, line_end.y, vs[0].y)
                        ) {
                        line_end.y = vs[0].y;
                        continue;
                    }
                } else if (vs[0].y == line_end.y) {
                    if (vs[0].y == line_start.y &&
                        coord_between(line_start.x, line_end.x, vs[0].x)
                        ) {
                        line_end.x = vs[0].x;
                        continue;
                    }
                }
            }
            if (incomplete_line) {
                if (need_moveto) {	/* see gs_pe_moveto case */
                    code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
                                                      &line_start);
                    if (code < 0)
                        return code;
                    need_moveto = false;
                }
                code = gdev_vector_dopath_segment(&state, gs_pe_lineto,
                                                  &line_end);
                if (code < 0)
                    return code;
                line_start = line_end;
                incomplete_line = false;
                goto opt;
            }
        }
        switch (pe_op) {
        case 0:		/* done */
        done:
            code = vdev_proc(vdev, endpath)(vdev, type);
            return (code < 0 ? code : 0);
        case gs_pe_curveto:
            if (need_moveto) {	/* see gs_pe_moveto case */
                code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
                                                  &line_start);
                if (code < 0)
                    return code;
                need_moveto = false;
            }
            line_start = vs[2];
            goto draw;
        case gs_pe_moveto:
            /*
             * A bug in Acrobat Reader 4 causes it to draw a single pixel
             * for a fill with an isolated moveto.  If we're doing a fill
             * without a stroke, defer emitting a moveto until we know that
             * the subpath has more elements.
             */
            line_start = vs[0];
            if (!(type & gx_path_type_stroke) && (type & gx_path_type_fill)) {
                need_moveto = true;
                continue;
            }
            goto draw;
        case gs_pe_lineto:
        case gs_pe_gapto:
            if (need_moveto) {	/* see gs_pe_moveto case */
                code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
                                                  &line_start);
                if (code < 0)
                    return code;
                need_moveto = false;
            }
            line_start = vs[0];
            goto draw;
        case gs_pe_closepath:
            if (need_moveto) {	/* see gs_pe_moveto case */
                need_moveto = false;
                continue;
            }
            if (!do_close) {
                pe_op = gx_path_enum_next(&cenum, vs);
                if (pe_op == 0)
                    goto done;
                code = gdev_vector_dopath_segment(&state, gs_pe_closepath, vs);
                if (code < 0)
                    return code;
                goto sw;
            }
            /* falls through */
        draw:
            code = gdev_vector_dopath_segment(&state, pe_op, vs);
            if (code < 0)
                return code;
        }
        incomplete_line = false; /* only needed if optimizing */
    }
}
Esempio n. 5
0
static int
pdf_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
	    const gx_color_tile *p_tile, const gx_color_tile *m_tile,
	    cos_stream_t *pcs_image, pdf_resource_t **ppres)
{
    pdf_resource_t *pres;
    int code = pdf_alloc_resource(pdev, resourcePattern, pdc->mask.id, ppres,
				  0L);
    cos_stream_t *pcos;
    cos_dict_t *pcd;
    cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)");
    const gx_color_tile *tile = (p_tile ? p_tile : m_tile);
    const gx_strip_bitmap *btile = (p_tile ? &p_tile->tbits : &m_tile->tmask);
    bool mask = p_tile == 0;
    gs_point step;
    gs_matrix smat;

    if (code < 0)
	return code;
    if (!tile_size_ok(pdev, p_tile, m_tile))
	return_error(gs_error_limitcheck);
    /*
     * We currently can't handle Patterns whose X/Y step isn't parallel
     * to the coordinate axes.
     */
    if (is_xxyy(&tile->step_matrix))
	step.x = tile->step_matrix.xx, step.y = tile->step_matrix.yy;
    else if (is_xyyx(&tile->step_matrix))
	step.x = tile->step_matrix.yx, step.y = tile->step_matrix.xy;
    else
	return_error(gs_error_rangecheck);
    if (pcd_Resources == 0)
	return_error(gs_error_VMerror);
    gs_make_identity(&smat);
    smat.xx = btile->rep_width / (pdev->HWResolution[0] / 72.0);
    smat.yy = btile->rep_height / (pdev->HWResolution[1] / 72.0);
    smat.tx = tile->step_matrix.tx / (pdev->HWResolution[0] / 72.0);
    smat.ty = tile->step_matrix.ty / (pdev->HWResolution[1] / 72.0);
    pres = *ppres;
    {
	cos_dict_t *pcd_XObject = cos_dict_alloc(pdev, "pdf_pattern(XObject)");
	char key[MAX_REF_CHARS + 3];
	cos_value_t v;

	if (pcd_XObject == 0)
	    return_error(gs_error_VMerror);
	sprintf(key, "/R%ld", pcs_image->id);
	COS_OBJECT_VALUE(&v, pcs_image);
	if ((code = cos_dict_put(pcd_XObject, (byte *)key, strlen(key), &v)) < 0 ||
	    (code = cos_dict_put_c_key_object(pcd_Resources, "/XObject",
					      COS_OBJECT(pcd_XObject))) < 0
	    )
	    return code;
    }
    if ((code = cos_dict_put_c_strings(pcd_Resources, "/ProcSet",
				       (mask ? "[/PDF/ImageB]" :
					"[/PDF/ImageC]"))) < 0)
	return code;
    cos_become(pres->object, cos_type_stream);
    pcos = (cos_stream_t *)pres->object;
    pcd = cos_stream_dict(pcos);
    if ((code = cos_dict_put_c_key_int(pcd, "/PatternType", 1)) < 0 ||
	(code = cos_dict_put_c_key_int(pcd, "/PaintType",
				       (mask ? 2 : 1))) < 0 ||
	(code = cos_dict_put_c_key_int(pcd, "/TilingType",
				       tile->tiling_type)) < 0 ||
	(code = cos_dict_put_c_key_object(pcd, "/Resources",
					  COS_OBJECT(pcd_Resources))) < 0 ||
	(code = cos_dict_put_c_strings(pcd, "/BBox", "[0 0 1 1]")) < 0 ||
	(code = cos_dict_put_matrix(pcd, "/Matrix", &smat)) < 0 ||
	(code = cos_dict_put_c_key_real(pcd, "/XStep", step.x / btile->rep_width)) < 0 ||
	(code = cos_dict_put_c_key_real(pcd, "/YStep", step.y / btile->rep_height)) < 0
	) {
	return code;
    }

    {
	char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */

	sprintf(buf, "/R%ld Do\n", pcs_image->id);
	cos_stream_add_bytes(pcos, (const byte *)buf, strlen(buf));
    }

    return 0;
}