Пример #1
0
/* <tx> <ty> <matrix> translate <matrix> */
static int
ztranslate(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    int code;
    double trans[2];

    if ((code = num_params(op, 2, trans)) >= 0) {
        code = gs_translate(igs, trans[0], trans[1]);
        if (code < 0)
            return code;
    } else {			/* matrix operand */
        gs_matrix mat;

        /* The num_params failure might be a stack underflow. */
        check_op(2);
        if ((code = num_params(op - 1, 2, trans)) < 0 ||
            (code = gs_make_translation(trans[0], trans[1], &mat)) < 0 ||
            (code = write_matrix(op, &mat)) < 0
            ) {			/* Might be a stack underflow. */
            check_op(3);
            return code;
        }
        op[-2] = *op;
    }
    pop(2);
    return code;
}
Пример #2
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);
}
Пример #3
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;
}
Пример #4
0
void eprn_get_initial_matrix(gx_device *device, gs_matrix *mptr)
{
  eprn_Device *dev = (eprn_Device *)device;
  float
    /*  The following two arrays are oriented w.r.t. pixmap device space, i.e.,
        the index 0 refers to the x coordinate (horizontal) and the index 1 to
        the y coordinate (vertical) in pixmap device space. */
    extension[2],       /* media extension in pixels */
    pixels_per_bp[2];   /* resolution */
  int
    j,
    quarters;

#ifdef EPRN_TRACE
  if_debug0(EPRN_TRACE_CHAR, "! eprn_get_initial_matrix()...\n");
#endif

  /* We need 'default_orientation' and also the margins. */
  if (dev->eprn.code == ms_none) {
#ifdef EPRN_TRACE
    if_debug0(EPRN_TRACE_CHAR,
      "! eprn_get_initial_matrix(): code is still ms_none.\n");
#endif
    if (eprn_set_page_layout(dev) != 0)
      eprintf("  Processing can't be stopped at this point although this error "
        "occurred.\n");
      /* The current function has a signature without the ability to signal
         an error condition. */
  }

  quarters = dev->eprn.default_orientation +
    (dev->MediaSize[0] <= dev->MediaSize[1]? 0: 1);
     /* Number of quarter-circle rotations by +90 degrees necessary to obtain
        default user space starting with the y axis upwards in pixmap device
        space.
        It's not documented, but 'MediaSize' is the requested "PageSize" page
        device parameter value and hence is to be interpreted in default (not
        default default!) user space. The condition above therefore tests
        whether landscape orientation has been requested.
      */

  /* Soft tumble option: rotate default user space by 180 degrees on every
     second page */
  if (dev->eprn.soft_tumble && dev->ShowpageCount % 2 != 0) quarters += 2;

  /* Prepare auxiliary data */
  for (j = 0; j < 2; j++) pixels_per_bp[j] = dev->HWResolution[j]/BP_PER_IN;
  /*  'HWResolution[]' contains the standard PostScript page device parameter
      'HWResolution' which is defined in pixels per inch with respect to
       device space. */
  if (quarters % 2 == 0) {
    /* Default user space and pixmap device space agree in what is "horizontal"
       and what is "vertical". */
    extension[0] = dev->MediaSize[0];
    extension[1] = dev->MediaSize[1];
  }
  else {
    extension[0] = dev->MediaSize[1];
    extension[1] = dev->MediaSize[0];
  }
  /* Convert from bp to pixels: */
  for (j = 0; j < 2; j++) extension[j] *= pixels_per_bp[j];
   /* Note that we are using the user-specified extension of the sheet, not the
      "official" one we could obtain in most cases from 'size'. */

  switch (quarters % 4) {
  case 0:
    /*  The y axis of default user space points upwards in pixmap device space.
        The CTM is uniquely characterized by the following mappings from
        default user space to pixmap device space:
          (0, 0)                -> (0, height in pixels)
          (width in bp, 0)      -> (width in pixels, height in pixels)
          (0, height in bp)     -> (0, 0)
        'width' and 'height' refer to the sheet's extension as seen from pixmap
        device space, i.e., width in pixels == extension[0] and
        height in pixels == extension[1].

        From the PLR we find that the CTM is a PostScript matrix
        [a b c d tx ty] used for mapping user space coordinates (x, y) to
        device space coordinates (x', y') as follows:
          x' = a*x + c*y + tx
          y' = b*x + d*y + ty
        Ghostscript's matrix type 'gs_matrix' writes its structure components
        'xx' etc. in storage layout order into a PostScript matrix (see
        write_matrix() in iutil.c), hence we obtain by comparison with
        gsmatrix.h the PostScript matrix [ xx xy yx yy tx ty ].
        The correspondence can also be seen by comparison of the equations
        above with the code in gs_point_transform() in gsmatrix.c.
        It would, however, still be reassuring to have a corresponding
        statement in ghostscript's documentation.
    */
    gx_default_get_initial_matrix(device, mptr);
    /*  Of course, I could also set this directly:
          mptr->xx = pixels_per_bp[0];
          mptr->xy = 0;
          mptr->yx = 0;
          mptr->yy = -pixels_per_bp[1];
          mptr->tx = 0;
          mptr->ty = extension[1];
        Doing it in this way is, however, more stable against dramatic changes
        in ghostscript.
    */
    break;
  case 1:
    /*  The y axis of default user space points to the left in pixmap device
        space. The CTM is uniquely characterized by the following mappings from
        default user space to pixmap device space:
          (0, 0)                -> (width in pixels, height in pixels)
          (height in bp, 0)     -> (width in pixels, 0)
          (0, width in bp)      -> (0, height in pixels)
    */
    mptr->xx = 0;
    mptr->xy = -pixels_per_bp[1];
    mptr->yx = -pixels_per_bp[0];
    mptr->yy = 0;
    mptr->tx = extension[0];
    mptr->ty = extension[1];
    break;
  case 2:
    /*  The y axis of default user space points downwards in pixmap device
        space. The CTM is uniquely characterized by the following mappings from
        default user space to pixmap device space:
          (0, 0)                -> (width in pixels, 0)
          (width in bp, 0)      -> (0, 0)
          (0, height in bp)     -> (width in pixels, height in pixels)
    */
    mptr->xx = -pixels_per_bp[0];
    mptr->xy = 0;
    mptr->yx = 0;
    mptr->yy = pixels_per_bp[1];
    mptr->tx = extension[0];
    mptr->ty = 0;
    break;
  case 3:
    /*  The y axis of default user space points to the right in pixmap device
        space. The CTM is uniquely characterized by the following mappings from
        default user space to pixmap device space:
          (0, 0)                -> (0, 0)
          (height in bp, 0)     -> (0, height in pixels)
          (0, width in bp)      -> (width in pixels, 0)
    */
    mptr->xx = 0;
    mptr->xy = pixels_per_bp[1];
    mptr->yx = pixels_per_bp[0];
    mptr->yy = 0;
    mptr->tx = 0;
    mptr->ty = 0;
    break;
  }

  /*  Finally, shift the device space origin to the top-left corner of the
      printable area. I am deliberately not using the corresponding shift
      feature in gx_device_set_margins() because it achieves its effect by
      using the 'Margins' array which should remain at the user's disposal for
      correcting misadjustments. In addition, gx_device_set_margins() will not
      work correctly for quarters % 4 != 0 anyway.
  */
  {
    gs_matrix translation;

    /*  Translation of pixmap device space origin by top and left margins in
        pixmap device space */
    gs_make_translation(
      -dev->eprn.right_shift*pixels_per_bp[0],
      -dev->eprn.down_shift *pixels_per_bp[1],
      &translation);

    /* Multiply the initial matrix from the right with the translation matrix,
       i.e., in going from user to device space the translation will be applied
       last. */
    gs_matrix_multiply(mptr, &translation, mptr);
  }

#ifdef EPRN_TRACE
  if_debug6(EPRN_TRACE_CHAR, "  Returning [%g %g %g %g %g %g].\n",
    mptr->xx, mptr->xy, mptr->yx, mptr->yy, mptr->tx, mptr->ty);
#endif
  return;
}