123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- /* Copyright (C) 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
- /*$Id: gximage2.c,v 1.2 2000/09/19 19:00:38 lpd Exp $ */
- /* ImageType 2 image implementation */
- #include "math_.h"
- #include "memory_.h"
- #include "gx.h"
- #include "gserrors.h"
- #include "gsmatrix.h" /* for gscoord.h */
- #include "gscoord.h"
- #include "gscspace.h"
- #include "gscpixel.h"
- #include "gsdevice.h"
- #include "gsiparm2.h"
- #include "gxgetbit.h"
- #include "gxiparam.h"
- #include "gxpath.h"
- /* Forward references */
- private dev_proc_begin_typed_image(gx_begin_image2);
- private image_proc_source_size(gx_image2_source_size);
- /* Structure descriptor */
- private_st_gs_image2();
- /* Define the image type for ImageType 2 images. */
- const gx_image_type_t gs_image_type_2 = {
- &st_gs_image2, gx_begin_image2, gx_image2_source_size,
- gx_image_no_sput, gx_image_no_sget, gx_image_default_release, 2
- };
- /* Initialize an ImageType 2 image. */
- void
- gs_image2_t_init(gs_image2_t * pim)
- {
- pim->type = &gs_image_type_2;
- pim->UnpaintedPath = 0;
- pim->PixelCopy = false;
- }
- /*
- * Compute the device space coordinates and source data size for an
- * ImageType 2 image. This procedure fills in
- * image.{Width,Height,ImageMatrix}.
- */
- typedef struct image2_data_s {
- gs_point origin;
- gs_int_rect bbox;
- gs_image1_t image;
- } image2_data_t;
- private int
- image2_set_data(const gs_image2_t * pim, image2_data_t * pid)
- {
- gs_state *pgs = pim->DataSource;
- gs_matrix smat;
- gs_rect sbox, dbox;
- gs_transform(pgs, pim->XOrigin, pim->YOrigin, &pid->origin);
- sbox.q.x = (sbox.p.x = pim->XOrigin) + pim->Width;
- sbox.q.y = (sbox.p.y = pim->YOrigin) + pim->Height;
- gs_currentmatrix(pgs, &smat);
- gs_bbox_transform(&sbox, &smat, &dbox);
- pid->bbox.p.x = (int)floor(dbox.p.x);
- pid->bbox.p.y = (int)floor(dbox.p.y);
- pid->bbox.q.x = (int)ceil(dbox.q.x);
- pid->bbox.q.y = (int)ceil(dbox.q.y);
- pid->image.Width = pid->bbox.q.x - pid->bbox.p.x;
- pid->image.Height = pid->bbox.q.y - pid->bbox.p.y;
- pid->image.ImageMatrix = pim->ImageMatrix;
- return 0;
- }
- /* Compute the source size of an ImageType 2 image. */
- private int
- gx_image2_source_size(const gs_imager_state * pis, const gs_image_common_t * pim,
- gs_int_point * psize)
- {
- image2_data_t idata;
- image2_set_data((const gs_image2_t *)pim, &idata);
- psize->x = idata.image.Width;
- psize->y = idata.image.Height;
- return 0;
- }
- /* Begin an ImageType 2 image. */
- /* Note that since ImageType 2 images don't have any source data, */
- /* this procedure does all the work. */
- private int
- gx_begin_image2(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, gx_image_enum_common_t ** pinfo)
- {
- const gs_image2_t *pim = (const gs_image2_t *)pic;
- gs_state *pgs = pim->DataSource;
- gx_device *sdev = gs_currentdevice(pgs);
- int depth = sdev->color_info.depth;
- /****** ONLY HANDLE depth <= 8 FOR PixelCopy ******/
- bool pixel_copy = pim->PixelCopy && depth <= 8 &&
- !memcmp(&dev->color_info, &sdev->color_info,
- sizeof(dev->color_info));
- bool has_alpha;
- bool direct_copy;
- image2_data_t idata;
- byte *row;
- uint row_size, source_size;
- gx_image_enum_common_t *info;
- gs_matrix smat, dmat;
- gs_color_space cs;
- const gs_color_space *pcs;
- int code;
- gs_image_t_init_rgb(&idata.image, pis);
- /* Add Decode entries for K and alpha */
- idata.image.Decode[6] = idata.image.Decode[8] = 0.0;
- idata.image.Decode[7] = idata.image.Decode[9] = 1.0;
- if (pmat == 0) {
- gs_currentmatrix((const gs_state *)pis, &dmat);
- pmat = &dmat;
- } else
- dmat = *pmat;
- gs_currentmatrix(pgs, &smat);
- code = image2_set_data(pim, &idata);
- if (code < 0)
- return code;
- /****** ONLY HANDLE SIMPLE CASES FOR NOW ******/
- if (idata.bbox.p.x != floor(idata.origin.x))
- return_error(gs_error_rangecheck);
- if (!(idata.bbox.p.y == floor(idata.origin.y) ||
- idata.bbox.q.y == ceil(idata.origin.y))
- )
- return_error(gs_error_rangecheck);
- source_size = (idata.image.Width * depth + 7) >> 3;
- row_size = max(3 * idata.image.Width, source_size);
- row = gs_alloc_bytes(mem, row_size, "gx_begin_image2");
- if (row == 0)
- return_error(gs_error_VMerror);
- if (pixel_copy &&
- (pcpath == NULL ||
- gx_cpath_includes_rectangle(pcpath,
- int2fixed(idata.bbox.p.x),
- int2fixed(idata.bbox.p.y),
- int2fixed(idata.bbox.q.x),
- int2fixed(idata.bbox.q.y)))
- ) {
- gs_matrix mat;
- idata.image.BitsPerComponent = depth;
- gs_cspace_init_DevicePixel(&cs, depth);
- pcs = &cs;
- /*
- * Figure 7.2 of the Adobe 3010 Supplement says that we should
- * compute CTM x ImageMatrix here, but I'm almost certain it
- * should be the other way around. Also see gdevx.c.
- */
- gs_matrix_multiply(&idata.image.ImageMatrix, &smat, &mat);
- direct_copy =
- (is_xxyy(&dmat) || is_xyyx(&dmat)) &&
- #define eqe(e) mat.e == dmat.e
- eqe(xx) && eqe(xy) && eqe(yx) && eqe(yy);
- #undef eqe
- has_alpha = false; /* no separate alpha channel */
- } else {
- pixel_copy = false;
- idata.image.BitsPerComponent = 8;
- /* Always use RGB source color for now. */
- pcs = gs_cspace_DeviceRGB(pis);
- direct_copy = false;
- /*
- * The source device has alpha if the same RGB values with
- * different alphas map to different pixel values.
- ****** THIS IS NOT GOOD ENOUGH: WE WANT TO SKIP TRANSFERRING
- ****** ALPHA IF THE SOURCE IS CAPABLE OF HAVING ALPHA BUT
- ****** DOESN'T CURRENTLY HAVE ANY ACTUAL ALPHA VALUES DIFFERENT
- ****** FROM 1.
- */
- /*
- * Since the default implementation of map_rgb_alpha_color
- * premultiplies the color towards white, we can't just test
- * whether changing alpha has an effect on the color.
- */
- {
- gx_color_index trans_black =
- (*dev_proc(sdev, map_rgb_alpha_color))
- (sdev, (gx_color_value) 0, (gx_color_value) 0,
- (gx_color_value) 0, (gx_color_value) 0);
- has_alpha =
- trans_black != (*dev_proc(sdev, map_rgb_alpha_color))
- (sdev, (gx_color_value) 0, (gx_color_value) 0,
- (gx_color_value) 0, gx_max_color_value) &&
- trans_black != (*dev_proc(sdev, map_rgb_alpha_color))
- (sdev, gx_max_color_value, gx_max_color_value,
- gx_max_color_value, gx_max_color_value);
- }
- }
- idata.image.ColorSpace = pcs;
- idata.image.Alpha =
- (has_alpha ? gs_image_alpha_last : gs_image_alpha_none);
- if (smat.yy < 0) {
- /*
- * The source Y axis is reflected. Reflect the mapping from
- * user space to source data.
- */
- idata.image.ImageMatrix.ty += idata.image.Height *
- idata.image.ImageMatrix.yy;
- idata.image.ImageMatrix.xy = -idata.image.ImageMatrix.xy;
- idata.image.ImageMatrix.yy = -idata.image.ImageMatrix.yy;
- }
- if (!direct_copy)
- code = (*dev_proc(dev, begin_typed_image))
- (dev, pis, pmat, (const gs_image_common_t *)&idata.image, NULL,
- pdcolor, pcpath, mem, &info);
- if (code >= 0) {
- int y;
- gs_int_rect rect;
- gs_get_bits_params_t params;
- const byte *data;
- uint offset = row_size - source_size;
- rect = idata.bbox;
- for (y = 0; code >= 0 && y < idata.image.Height; ++y) {
- gs_int_rect *unread = 0;
- int num_unread;
- /****** y COMPUTATION IS ROUNDED -- WRONG ******/
- rect.q.y = rect.p.y + 1;
- /* Insist on x_offset = 0 to simplify the conversion loop. */
- params.options =
- GB_ALIGN_ANY | (GB_RETURN_COPY | GB_RETURN_POINTER) |
- GB_OFFSET_0 | (GB_RASTER_STANDARD | GB_RASTER_ANY) |
- GB_PACKING_CHUNKY;
- if (pixel_copy) {
- params.options |= GB_COLORS_NATIVE;
- params.data[0] = row + offset;
- code = (*dev_proc(sdev, get_bits_rectangle))
- (sdev, &rect, ¶ms, &unread);
- if (code < 0)
- break;
- num_unread = code;
- data = params.data[0];
- if (direct_copy) {
- /*
- * Copy the pixels directly to the destination.
- * We know that the transformation is only a translation,
- * but we must handle an inverted destination Y axis.
- */
- code = (*dev_proc(dev, copy_color))
- (dev, data, 0, row_size, gx_no_bitmap_id,
- (int)(dmat.tx - idata.image.ImageMatrix.tx),
- (int)(dmat.ty - idata.image.ImageMatrix.ty +
- (dmat.yy < 0 ? ~y : y)),
- idata.image.Width, 1);
- continue;
- }
- } else {
- /*
- * Convert the pixels to pure colors. This may be very
- * slow and painful. Eventually we will use indexed color for
- * narrow pixels.
- */
- /* Always use RGB source color for now. */
- params.options |=
- GB_COLORS_RGB | GB_DEPTH_8 |
- (has_alpha ? GB_ALPHA_LAST : GB_ALPHA_NONE);
- params.data[0] = row;
- code = (*dev_proc(sdev, get_bits_rectangle))
- (sdev, &rect, ¶ms, &unread);
- if (code < 0)
- break;
- num_unread = code;
- data = params.data[0];
- }
- if (num_unread > 0 && pim->UnpaintedPath) {
- /* Add the rectangle(s) to the unpainted path. */
- int i;
- for (i = 0; code >= 0 && i < num_unread; ++i)
- code = gx_path_add_rectangle(pim->UnpaintedPath,
- int2fixed(unread[i].p.x),
- int2fixed(unread[i].p.y),
- int2fixed(unread[i].q.x),
- int2fixed(unread[i].q.y));
- gs_free_object(dev->memory, unread, "UnpaintedPath unread");
- }
- code = gx_image_data(info, &data, 0, row_size, 1);
- rect.p.y = rect.q.y;
- }
- if (!direct_copy) {
- if (code >= 0)
- code = gx_image_end(info, true);
- else
- discard(gx_image_end(info, false));
- }
- }
- gs_free_object(mem, row, "gx_begin_image2");
- return (code < 0 ? code : 1);
- }
|