Example #1
0
/*
 * Fill with non-standard X and Y stepping.
 * ptile is pdevc->colors.pattern.{m,p}_tile.
 * tbits_or_tmask is whichever of tbits and tmask is supplying
 * the tile size.
 * This implementation could be sped up considerably!
 */
static int
tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0,
              const gx_color_tile * ptile,
              const gx_strip_bitmap * tbits_or_tmask,
              int (*fill_proc) (const tile_fill_state_t * ptfs,
                                int x, int y, int w, int h))
{
    int x1 = x0 + w0, y1 = y0 + h0;
    int i0, i1, j0, j1, i, j;
    gs_matrix step_matrix;      /* translated by phase */
    int code;

    ptfs->x0 = x0, ptfs->w0 = w0;
    ptfs->y0 = y0, ptfs->h0 = h0;
    step_matrix = ptile->step_matrix;
    step_matrix.tx -= ptfs->phase.x;
    step_matrix.ty -= ptfs->phase.y;
    {
        gs_rect bbox;           /* bounding box in device space */
        gs_rect ibbox;          /* bounding box in stepping space */
        double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
        double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
        double u0, v0, u1, v1;

        bbox.p.x = x0, bbox.p.y = y0;
        bbox.q.x = x1, bbox.q.y = y1;
        gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
        if_debug10('T',
          "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
                   x0, y0, w0, h0,
                   ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
                   step_matrix.tx, step_matrix.ty);
        /*
         * If the pattern is partly transparent and XStep/YStep is smaller
         * than the device space BBox, we need to ensure that we cover
         * each pixel of the rectangle being filled with *every* pattern
         * that overlaps it, not just *some* pattern copy.
         */
        u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001;
        v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001;
        u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001;
        v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001;
        if (!ptile->is_simple)
            u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh;
        i0 = (int)fastfloor(u0);
        j0 = (int)fastfloor(v0);
        i1 = (int)ceil(u1);
        j1 = (int)ceil(v1);
    }
    if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
    for (i = i0; i < i1; i++)
        for (j = j0; j < j1; j++) {
            int x = (int)fastfloor(step_matrix.xx * i +
                          step_matrix.yx * j + step_matrix.tx);
            int y = (int)fastfloor(step_matrix.xy * i +
                          step_matrix.yy * j + step_matrix.ty);
            int w = tbits_or_tmask->size.x;
            int h = tbits_or_tmask->size.y;
            int xoff, yoff;

            if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
            if (x < x0)
                xoff = x0 - x, x = x0, w -= xoff;
            else
                xoff = 0;
            if (y < y0)
                yoff = y0 - y, y = y0, h -= yoff;
            else
                yoff = 0;
            if (x + w > x1)
                w = x1 - x;
            if (y + h > y1)
                h = y1 - y;
            if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
                      x, y, w, h, xoff, yoff);
            if (w > 0 && h > 0) {
                if (ptfs->pcdev == (gx_device *) & ptfs->cdev)
                    tile_clip_set_phase(&ptfs->cdev,
                                imod(xoff - x, ptfs->tmask->rep_width),
                                imod(yoff - y, ptfs->tmask->rep_height));
                /* Set the offsets for colored pattern fills */
                ptfs->xoff = xoff;
                ptfs->yoff = yoff;
                code = (*fill_proc) (ptfs, x, y, w, h);
                if (code < 0)
                    return code;
            }
        }
    return 0;
}
Example #2
0
/*
 * This is somewhat a clone of the tile_by_steps function but one
 * that performs filling from and to pdf14dev (transparency) buffers.
 * At some point it may be desirable to do some optimization here.
 */
static int
tile_by_steps_trans(tile_fill_trans_state_t * ptfs, int x0, int y0, int w0, int h0,
              gx_pattern_trans_t *fill_trans_buffer, const gx_color_tile * ptile)
{
    int x1 = x0 + w0, y1 = y0 + h0;
    int i0, i1, j0, j1, i, j;
    gs_matrix step_matrix;      /* translated by phase */
    gx_pattern_trans_t *ptrans_pat = ptile->ttrans;

    ptfs->x0 = x0, ptfs->w0 = w0;
    ptfs->y0 = y0, ptfs->h0 = h0;
    step_matrix = ptile->step_matrix;
    step_matrix.tx -= ptfs->phase.x;
    step_matrix.ty -= ptfs->phase.y;
    {
        gs_rect bbox;           /* bounding box in device space */
        gs_rect ibbox;          /* bounding box in stepping space */
        double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
        double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
        double u0, v0, u1, v1;

        bbox.p.x = x0, bbox.p.y = y0;
        bbox.q.x = x1, bbox.q.y = y1;
        gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
        if_debug10('T',
          "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
                   x0, y0, w0, h0,
                   ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
                   step_matrix.tx, step_matrix.ty);
        /*
         * If the pattern is partly transparent and XStep/YStep is smaller
         * than the device space BBox, we need to ensure that we cover
         * each pixel of the rectangle being filled with *every* pattern
         * that overlaps it, not just *some* pattern copy.
         */
        u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001;
        v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001;
        u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001;
        v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001;
        if (!ptile->is_simple)
            u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh;
        i0 = (int)fastfloor(u0);
        j0 = (int)fastfloor(v0);
        i1 = (int)ceil(u1);
        j1 = (int)ceil(v1);
    }
    if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
    for (i = i0; i < i1; i++)
        for (j = j0; j < j1; j++) {
            int x = (int)fastfloor(step_matrix.xx * i +
                          step_matrix.yx * j + step_matrix.tx);
            int y = (int)fastfloor(step_matrix.xy * i +
                          step_matrix.yy * j + step_matrix.ty);
            int w = ptrans_pat->width;
            int h = ptrans_pat->height;
            int xoff, yoff;
            int px, py;

            if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
            if (x < x0)
                xoff = x0 - x, x = x0, w -= xoff;
            else
                xoff = 0;
            if (y < y0)
                yoff = y0 - y, y = y0, h -= yoff;
            else
                yoff = 0;
            if (x + w > x1)
                w = x1 - x;
            if (y + h > y1)
                h = y1 - y;
            if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
                      x, y, w, h, xoff, yoff);
            if (w > 0 && h > 0) {

                px = imod(xoff - x, ptile->ttrans->width);
                py = imod(yoff - y, ptile->ttrans->height);

                /* Set the offsets for colored pattern fills */
                ptfs->xoff = xoff;
                ptfs->yoff = yoff;

                /* We only go through blending during tiling, if
                   there was overlap as defined by the step matrix
                   and the bounding box */

                ptile->ttrans->pat_trans_fill(x, y, x+w, y+h, px, py, ptile,
                        fill_trans_buffer);
            }
        }
    return 0;
}
Example #3
0
/* the routine sets ph->actual_frequency and ph->actual_angle. */
static int
pick_cell_size(gs_screen_halftone * ph, const gs_matrix * pmat, ulong max_size,
               uint min_levels, bool accurate, gx_ht_cell_params_t * phcp)
{
    const bool landscape = (pmat->xy != 0.0 || pmat->yx != 0.0);

    /* Account for a possibly reflected coordinate system. */
    /* See gxstroke.c for the algorithm. */
    const bool reflected = pmat->xy * pmat->yx > pmat->xx * pmat->yy;
    const int reflection = (reflected ? -1 : 1);
    const int rotation =
    (landscape ? (pmat->yx < 0 ? 90 : -90) : pmat->xx < 0 ? 180 : 0);
    const double f0 = ph->frequency, a0 = ph->angle;
    const double T =
    fabs((landscape ? pmat->yx / pmat->xy : pmat->xx / pmat->yy));
    gs_point uv0;

#define u0 uv0.x
#define v0 uv0.y
    int rt = 1;
    double f = 0, a = 0;
    double e_best = 1000;
    bool better;

    /*
     * We need to find a vector in device space whose length is
     * 1 inch / ph->frequency and whose angle is ph->angle.
     * Because device pixels may not be square, we can't simply
     * map the length to device space and then rotate it;
     * instead, since we know that user space is uniform in X and Y,
     * we calculate the correct angle in user space before rotation.
     */

    /* Compute trial values of u and v. */

    {
        gs_matrix rmat;

        gs_make_rotation(a0 * reflection + rotation, &rmat);
        gs_distance_transform(72.0 / f0, 0.0, &rmat, &uv0);
        gs_distance_transform(u0, v0, pmat, &uv0);
        if_debug10('h', "[h]Requested: f=%g a=%g mat=[%g %g %g %g] max_size=%lu min_levels=%u =>\n     u=%g v=%g\n",
                   ph->frequency, ph->angle,
                   pmat->xx, pmat->xy, pmat->yx, pmat->yy,
                   max_size, min_levels, u0, v0);
    }

    /* Adjust u and v to reasonable values. */

    if (u0 == 0 && v0 == 0)
        return_error(gs_error_rangecheck);
    while ((fabs(u0) + fabs(v0)) * rt < 4)
        ++rt;
  try_size:
    better = false;
    {
        double fm0 = u0 * rt;
        double fn0 = v0 * rt;
        int m0 = (int)floor(u0 * rt + 0.0001);
        int n0 = (int)floor(v0 * rt + 0.0001);
        gx_ht_cell_params_t p;

        p.R = p.R1 = rt;
        for (p.M = m0 + 1; p.M >= m0; p.M--)
            for (p.N = n0 + 1; p.N >= n0; p.N--) {
                long raster, wt, wt_size;
                double fr, ar, ft, at, f_diff, a_diff, f_err, a_err;

                p.M1 = (int)floor(p.M / T + 0.5);
                p.N1 = (int)floor(p.N * T + 0.5);
                gx_compute_cell_values(&p);
                if_debug3('h', "[h]trying m=%d, n=%d, r=%d\n", p.M, p.N, rt);
                wt = p.W;
                if (wt >= max_short)
                    continue;
                /* Check the strip size, not the full tile size, */
                /* against max_size. */
                raster = bitmap_raster(wt);
                if (raster > max_size / p.D || raster > max_long / wt)
                    continue;
                wt_size = raster * wt;

                /* Compute the corresponding values of F and A. */

                if (landscape)
                    ar = atan2(p.M * pmat->xy, p.N * pmat->yx),
                        fr = 72.0 * (p.M == 0 ? pmat->xy / p.N * cos(ar) :
                                     pmat->yx / p.M * sin(ar));
                else
                    ar = atan2(p.N * pmat->xx, p.M * pmat->yy),
                        fr = 72.0 * (p.M == 0 ? pmat->yy / p.N * sin(ar) :
                                     pmat->xx / p.M * cos(ar));
                ft = fabs(fr) * rt;
                /* Normalize the angle to the requested quadrant. */
                at = (ar * radians_to_degrees - rotation) * reflection;
                at -= floor(at / 180.0) * 180.0;
                at += floor(a0 / 180.0) * 180.0;
                f_diff = fabs(ft - f0);
                a_diff = fabs(at - a0);
                f_err = f_diff / fabs(f0);
                /*
                 * We used to compute the percentage difference here:
                 *      a_err = (a0 == 0 ? a_diff : a_diff / fabs(a0));
                 * but using the angle difference makes more sense:
                 */
                a_err = a_diff;

                if_debug5('h', " ==> d=%d, wt=%ld, wt_size=%ld, f=%g, a=%g\n",
                          p.D, wt, bitmap_raster(wt) * wt, ft, at);

                {
                    /*
                     * Compute the error in position between ideal location.
                     * and the current integer location.
                     */

                    double error =
                        (fn0 - p.N) * (fn0 - p.N) + (fm0 - p.M) * (fm0 - p.M);
                    /*
                     * Adjust the error by the length of the vector.  This gives
                     * a slight bias toward larger cell sizzes.
                     */
                    error /= p.N * p.N + p.M * p.M;
                    error = sqrt(error); /* The previous calcs. gave value squared */
                    if (error > e_best)
                        continue;
                    e_best = error;
                }
                *phcp = p;
                f = ft, a = at;
                better = true;
                if_debug3('h', "*** best wt_size=%ld, f_diff=%g, a_diff=%g\n",
                          wt_size, f_diff, a_diff);
                /*
                 * We want a maximum relative frequency error of 1% and a
                 * maximum angle error of 1% (of 90 degrees).
                 */
                if (f_err <= 0.01 && a_err <= 0.9 /*degrees*/)
                    goto done;
            }
    }
    if (phcp->C < min_levels) { /* We don't have enough levels yet.  Keep going. */
        ++rt;
        goto try_size;
    }
    if (better) {               /* If we want accurate screens, continue till we fail. */
        if (accurate) {
            ++rt;
            goto try_size;
        }
    } else {                    /*
                                 * We couldn't find an acceptable M and N.  If R > 1,
                                 * take what we've got; if R = 1, give up.
                                 */
        if (rt == 1)
            return_error(gs_error_rangecheck);
    }

    /* Deliver the results. */
  done:
    if_debug5('h', "[h]Chosen: f=%g a=%g M=%d N=%d R=%d\n",
              f, a, phcp->M, phcp->N, phcp->R);
    ph->actual_frequency = f;
    ph->actual_angle = a;
    return 0;
#undef u0
#undef v0
}