17dd7cddfSDavid du Colombier /* Copyright (C) 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gximage3.c,v 1.15 2005/03/29 14:26:26 igor Exp $ */
187dd7cddfSDavid du Colombier /* ImageType 3 image implementation */
197dd7cddfSDavid du Colombier #include "math_.h" /* for ceil, floor */
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "gx.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gsbitops.h"
247dd7cddfSDavid du Colombier #include "gscspace.h"
257dd7cddfSDavid du Colombier #include "gsstruct.h"
267dd7cddfSDavid du Colombier #include "gxdevice.h"
277dd7cddfSDavid du Colombier #include "gxdevmem.h"
287dd7cddfSDavid du Colombier #include "gxclipm.h"
293ff48bf5SDavid du Colombier #include "gximage3.h"
307dd7cddfSDavid du Colombier #include "gxistate.h"
317dd7cddfSDavid du Colombier
327dd7cddfSDavid du Colombier /* Forward references */
337dd7cddfSDavid du Colombier private dev_proc_begin_typed_image(gx_begin_image3);
347dd7cddfSDavid du Colombier private image_enum_proc_plane_data(gx_image3_plane_data);
357dd7cddfSDavid du Colombier private image_enum_proc_end_image(gx_image3_end_image);
367dd7cddfSDavid du Colombier private image_enum_proc_flush(gx_image3_flush);
377dd7cddfSDavid du Colombier private image_enum_proc_planes_wanted(gx_image3_planes_wanted);
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier /* GC descriptor */
403ff48bf5SDavid du Colombier private_st_gs_image3();
417dd7cddfSDavid du Colombier
427dd7cddfSDavid du Colombier /* Define the image type for ImageType 3 images. */
437dd7cddfSDavid du Colombier const gx_image_type_t gs_image_type_3 = {
447dd7cddfSDavid du Colombier &st_gs_image3, gx_begin_image3, gx_data_image_source_size,
457dd7cddfSDavid du Colombier gx_image_no_sput, gx_image_no_sget, gx_image_default_release, 3
467dd7cddfSDavid du Colombier };
477dd7cddfSDavid du Colombier private const gx_image_enum_procs_t image3_enum_procs = {
487dd7cddfSDavid du Colombier gx_image3_plane_data, gx_image3_end_image,
497dd7cddfSDavid du Colombier gx_image3_flush, gx_image3_planes_wanted
507dd7cddfSDavid du Colombier };
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier /* Initialize an ImageType 3 image. */
537dd7cddfSDavid du Colombier void
gs_image3_t_init(gs_image3_t * pim,const gs_color_space * color_space,gs_image3_interleave_type_t interleave_type)547dd7cddfSDavid du Colombier gs_image3_t_init(gs_image3_t * pim, const gs_color_space * color_space,
557dd7cddfSDavid du Colombier gs_image3_interleave_type_t interleave_type)
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
587dd7cddfSDavid du Colombier pim->type = &gs_image_type_3;
597dd7cddfSDavid du Colombier pim->InterleaveType = interleave_type;
607dd7cddfSDavid du Colombier gs_data_image_t_init(&pim->MaskDict, -1);
617dd7cddfSDavid du Colombier }
627dd7cddfSDavid du Colombier
637dd7cddfSDavid du Colombier /*
647dd7cddfSDavid du Colombier * We implement ImageType 3 images by interposing a mask clipper in
657dd7cddfSDavid du Colombier * front of an ordinary ImageType 1 image. Note that we build up the
667dd7cddfSDavid du Colombier * mask row-by-row as we are processing the image.
673ff48bf5SDavid du Colombier *
683ff48bf5SDavid du Colombier * We export a generalized form of the begin_image procedure for use by
693ff48bf5SDavid du Colombier * the PDF and PostScript writers.
707dd7cddfSDavid du Colombier */
717dd7cddfSDavid du Colombier typedef struct gx_image3_enum_s {
727dd7cddfSDavid du Colombier gx_image_enum_common;
733ff48bf5SDavid du Colombier gx_device *mdev; /* gx_device_memory in default impl. */
743ff48bf5SDavid du Colombier gx_device *pcdev; /* gx_device_mask_clip in default impl. */
757dd7cddfSDavid du Colombier gx_image_enum_common_t *mask_info;
767dd7cddfSDavid du Colombier gx_image_enum_common_t *pixel_info;
777dd7cddfSDavid du Colombier gs_image3_interleave_type_t InterleaveType;
787dd7cddfSDavid du Colombier int num_components; /* (not counting mask) */
797dd7cddfSDavid du Colombier int bpc; /* BitsPerComponent */
807dd7cddfSDavid du Colombier gs_memory_t *memory;
817dd7cddfSDavid du Colombier int mask_width, mask_height, mask_full_height;
827dd7cddfSDavid du Colombier int pixel_width, pixel_height, pixel_full_height;
837dd7cddfSDavid du Colombier byte *mask_data; /* (if chunky) */
847dd7cddfSDavid du Colombier byte *pixel_data; /* (if chunky) */
857dd7cddfSDavid du Colombier /* The following are the only members that change dynamically. */
867dd7cddfSDavid du Colombier int mask_y;
877dd7cddfSDavid du Colombier int pixel_y;
887dd7cddfSDavid du Colombier int mask_skip; /* # of mask rows to skip, see below */
897dd7cddfSDavid du Colombier } gx_image3_enum_t;
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier extern_st(st_gx_image_enum_common);
927dd7cddfSDavid du Colombier gs_private_st_suffix_add6(st_image3_enum, gx_image3_enum_t, "gx_image3_enum_t",
937dd7cddfSDavid du Colombier image3_enum_enum_ptrs, image3_enum_reloc_ptrs, st_gx_image_enum_common,
947dd7cddfSDavid du Colombier mdev, pcdev, pixel_info, mask_info, pixel_data, mask_data);
957dd7cddfSDavid du Colombier
963ff48bf5SDavid du Colombier /* Define the default implementation of ImageType 3 processing. */
973ff48bf5SDavid du Colombier private IMAGE3_MAKE_MID_PROC(make_mid_default); /* check prototype */
983ff48bf5SDavid du Colombier private int
make_mid_default(gx_device ** pmidev,gx_device * dev,int width,int height,gs_memory_t * mem)993ff48bf5SDavid du Colombier make_mid_default(gx_device **pmidev, gx_device *dev, int width, int height,
1003ff48bf5SDavid du Colombier gs_memory_t *mem)
1013ff48bf5SDavid du Colombier {
1023ff48bf5SDavid du Colombier gx_device_memory *midev =
1033ff48bf5SDavid du Colombier gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
1043ff48bf5SDavid du Colombier "make_mid_default");
1053ff48bf5SDavid du Colombier int code;
1063ff48bf5SDavid du Colombier
1073ff48bf5SDavid du Colombier if (midev == 0)
1083ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
1093ff48bf5SDavid du Colombier gs_make_mem_mono_device(midev, mem, NULL);
1103ff48bf5SDavid du Colombier midev->bitmap_memory = mem;
1113ff48bf5SDavid du Colombier midev->width = width;
1123ff48bf5SDavid du Colombier midev->height = height;
113*593dc095SDavid du Colombier check_device_separable((gx_device *)midev);
1143ff48bf5SDavid du Colombier gx_device_fill_in_procs((gx_device *)midev);
1153ff48bf5SDavid du Colombier code = dev_proc(midev, open_device)((gx_device *)midev);
1163ff48bf5SDavid du Colombier if (code < 0) {
1173ff48bf5SDavid du Colombier gs_free_object(mem, midev, "make_mid_default");
1183ff48bf5SDavid du Colombier return code;
1193ff48bf5SDavid du Colombier }
1203ff48bf5SDavid du Colombier midev->is_open = true;
1213ff48bf5SDavid du Colombier dev_proc(midev, fill_rectangle)
1223ff48bf5SDavid du Colombier ((gx_device *)midev, 0, 0, width, height, (gx_color_index)0);
1233ff48bf5SDavid du Colombier *pmidev = (gx_device *)midev;
1243ff48bf5SDavid du Colombier return 0;
1253ff48bf5SDavid du Colombier }
1263ff48bf5SDavid du Colombier private IMAGE3_MAKE_MCDE_PROC(make_mcde_default); /* check prototype */
1273ff48bf5SDavid du Colombier private int
make_mcde_default(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,gx_device ** pmcdev,gx_device * midev,gx_image_enum_common_t * pminfo,const gs_int_point * origin)1283ff48bf5SDavid du Colombier make_mcde_default(gx_device *dev, const gs_imager_state *pis,
1293ff48bf5SDavid du Colombier const gs_matrix *pmat, const gs_image_common_t *pic,
1303ff48bf5SDavid du Colombier const gs_int_rect *prect, const gx_drawing_color *pdcolor,
1313ff48bf5SDavid du Colombier const gx_clip_path *pcpath, gs_memory_t *mem,
1323ff48bf5SDavid du Colombier gx_image_enum_common_t **pinfo,
1333ff48bf5SDavid du Colombier gx_device **pmcdev, gx_device *midev,
1343ff48bf5SDavid du Colombier gx_image_enum_common_t *pminfo,
1353ff48bf5SDavid du Colombier const gs_int_point *origin)
1363ff48bf5SDavid du Colombier {
1373ff48bf5SDavid du Colombier gx_device_memory *const mdev = (gx_device_memory *)midev;
1383ff48bf5SDavid du Colombier gx_device_mask_clip *mcdev =
1393ff48bf5SDavid du Colombier gs_alloc_struct(mem, gx_device_mask_clip, &st_device_mask_clip,
1403ff48bf5SDavid du Colombier "make_mcde_default");
1413ff48bf5SDavid du Colombier gx_strip_bitmap bits; /* only gx_bitmap */
1423ff48bf5SDavid du Colombier int code;
1433ff48bf5SDavid du Colombier
1443ff48bf5SDavid du Colombier if (mcdev == 0)
1453ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
1463ff48bf5SDavid du Colombier bits.data = mdev->base;
1473ff48bf5SDavid du Colombier bits.raster = mdev->raster;
1483ff48bf5SDavid du Colombier bits.size.x = mdev->width;
1493ff48bf5SDavid du Colombier bits.size.y = mdev->height;
1503ff48bf5SDavid du Colombier bits.id = gx_no_bitmap_id;
1513ff48bf5SDavid du Colombier code = gx_mask_clip_initialize(mcdev, &gs_mask_clip_device,
1523ff48bf5SDavid du Colombier (const gx_bitmap *)&bits, dev,
1533ff48bf5SDavid du Colombier origin->x, origin->y, mem);
1543ff48bf5SDavid du Colombier if (code < 0) {
1553ff48bf5SDavid du Colombier gs_free_object(mem, mcdev, "make_mcde_default");
1563ff48bf5SDavid du Colombier return code;
1573ff48bf5SDavid du Colombier }
1583ff48bf5SDavid du Colombier mcdev->tiles = bits;
1593ff48bf5SDavid du Colombier code = dev_proc(mcdev, begin_typed_image)
1603ff48bf5SDavid du Colombier ((gx_device *)mcdev, pis, pmat, pic, prect, pdcolor, pcpath, mem,
1613ff48bf5SDavid du Colombier pinfo);
1623ff48bf5SDavid du Colombier if (code < 0) {
1633ff48bf5SDavid du Colombier gs_free_object(mem, mcdev, "make_mcde_default");
1643ff48bf5SDavid du Colombier return code;
1653ff48bf5SDavid du Colombier }
1663ff48bf5SDavid du Colombier *pmcdev = (gx_device *)mcdev;
1673ff48bf5SDavid du Colombier return 0;
1683ff48bf5SDavid du Colombier }
1697dd7cddfSDavid du Colombier private int
gx_begin_image3(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)1707dd7cddfSDavid du Colombier gx_begin_image3(gx_device * dev,
1717dd7cddfSDavid du Colombier const gs_imager_state * pis, const gs_matrix * pmat,
1727dd7cddfSDavid du Colombier const gs_image_common_t * pic, const gs_int_rect * prect,
1737dd7cddfSDavid du Colombier const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
1747dd7cddfSDavid du Colombier gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
1757dd7cddfSDavid du Colombier {
1763ff48bf5SDavid du Colombier return gx_begin_image3_generic(dev, pis, pmat, pic, prect, pdcolor,
1773ff48bf5SDavid du Colombier pcpath, mem, make_mid_default,
1783ff48bf5SDavid du Colombier make_mcde_default, pinfo);
1793ff48bf5SDavid du Colombier }
1803ff48bf5SDavid du Colombier
1813ff48bf5SDavid du Colombier /*
1823ff48bf5SDavid du Colombier * Begin a generic ImageType 3 image, with client handling the creation of
1833ff48bf5SDavid du Colombier * the mask image and mask clip devices.
1843ff48bf5SDavid du Colombier */
185*593dc095SDavid du Colombier private bool check_image3_extent(floatp mask_coeff, floatp data_coeff);
1863ff48bf5SDavid du Colombier int
gx_begin_image3_generic(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,image3_make_mid_proc_t make_mid,image3_make_mcde_proc_t make_mcde,gx_image_enum_common_t ** pinfo)1873ff48bf5SDavid du Colombier gx_begin_image3_generic(gx_device * dev,
1883ff48bf5SDavid du Colombier const gs_imager_state *pis, const gs_matrix *pmat,
1893ff48bf5SDavid du Colombier const gs_image_common_t *pic, const gs_int_rect *prect,
1903ff48bf5SDavid du Colombier const gx_drawing_color *pdcolor,
1913ff48bf5SDavid du Colombier const gx_clip_path *pcpath, gs_memory_t *mem,
1923ff48bf5SDavid du Colombier image3_make_mid_proc_t make_mid,
1933ff48bf5SDavid du Colombier image3_make_mcde_proc_t make_mcde,
1943ff48bf5SDavid du Colombier gx_image_enum_common_t **pinfo)
1953ff48bf5SDavid du Colombier {
1967dd7cddfSDavid du Colombier const gs_image3_t *pim = (const gs_image3_t *)pic;
1977dd7cddfSDavid du Colombier gx_image3_enum_t *penum;
1987dd7cddfSDavid du Colombier gs_int_rect mask_rect, data_rect;
1993ff48bf5SDavid du Colombier gx_device *mdev = 0;
2003ff48bf5SDavid du Colombier gx_device *pcdev = 0;
2017dd7cddfSDavid du Colombier gs_image_t i_pixel, i_mask;
2027dd7cddfSDavid du Colombier gs_matrix mi_pixel, mi_mask, mat;
2037dd7cddfSDavid du Colombier gs_rect mrect;
2047dd7cddfSDavid du Colombier gs_int_point origin;
2057dd7cddfSDavid du Colombier int code;
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier /* Validate the parameters. */
2087dd7cddfSDavid du Colombier if (pim->Height <= 0 || pim->MaskDict.Height <= 0)
2097dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2107dd7cddfSDavid du Colombier switch (pim->InterleaveType) {
2117dd7cddfSDavid du Colombier default:
2127dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2137dd7cddfSDavid du Colombier case interleave_chunky:
2147dd7cddfSDavid du Colombier if (pim->MaskDict.Width != pim->Width ||
2157dd7cddfSDavid du Colombier pim->MaskDict.Height != pim->Height ||
2167dd7cddfSDavid du Colombier pim->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
2177dd7cddfSDavid du Colombier pim->format != gs_image_format_chunky
2187dd7cddfSDavid du Colombier )
2197dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2207dd7cddfSDavid du Colombier break;
2217dd7cddfSDavid du Colombier case interleave_scan_lines:
2227dd7cddfSDavid du Colombier if (pim->MaskDict.Height % pim->Height != 0 &&
2237dd7cddfSDavid du Colombier pim->Height % pim->MaskDict.Height != 0
2247dd7cddfSDavid du Colombier )
2257dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2267dd7cddfSDavid du Colombier /* falls through */
2277dd7cddfSDavid du Colombier case interleave_separate_source:
2287dd7cddfSDavid du Colombier if (pim->MaskDict.BitsPerComponent != 1)
2297dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier if (!check_image3_extent(pim->ImageMatrix.xx,
2327dd7cddfSDavid du Colombier pim->MaskDict.ImageMatrix.xx) ||
2337dd7cddfSDavid du Colombier !check_image3_extent(pim->ImageMatrix.xy,
2347dd7cddfSDavid du Colombier pim->MaskDict.ImageMatrix.xy) ||
2357dd7cddfSDavid du Colombier !check_image3_extent(pim->ImageMatrix.yx,
2367dd7cddfSDavid du Colombier pim->MaskDict.ImageMatrix.yx) ||
2377dd7cddfSDavid du Colombier !check_image3_extent(pim->ImageMatrix.yy,
2387dd7cddfSDavid du Colombier pim->MaskDict.ImageMatrix.yy)
2397dd7cddfSDavid du Colombier )
2407dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2417dd7cddfSDavid du Colombier if ((code = gs_matrix_invert(&pim->ImageMatrix, &mi_pixel)) < 0 ||
2427dd7cddfSDavid du Colombier (code = gs_matrix_invert(&pim->MaskDict.ImageMatrix, &mi_mask)) < 0
2437dd7cddfSDavid du Colombier )
2447dd7cddfSDavid du Colombier return code;
2457dd7cddfSDavid du Colombier if (fabs(mi_pixel.tx - mi_mask.tx) >= 0.5 ||
2467dd7cddfSDavid du Colombier fabs(mi_pixel.ty - mi_mask.ty) >= 0.5
2477dd7cddfSDavid du Colombier )
2487dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2497dd7cddfSDavid du Colombier {
2507dd7cddfSDavid du Colombier gs_point ep, em;
2517dd7cddfSDavid du Colombier
2527dd7cddfSDavid du Colombier if ((code = gs_point_transform(pim->Width, pim->Height, &mi_pixel,
2537dd7cddfSDavid du Colombier &ep)) < 0 ||
2547dd7cddfSDavid du Colombier (code = gs_point_transform(pim->MaskDict.Width,
2557dd7cddfSDavid du Colombier pim->MaskDict.Height, &mi_mask,
2567dd7cddfSDavid du Colombier &em)) < 0
2577dd7cddfSDavid du Colombier )
2587dd7cddfSDavid du Colombier return code;
2597dd7cddfSDavid du Colombier if (fabs(ep.x - em.x) >= 0.5 || fabs(ep.y - em.y) >= 0.5)
2607dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
2617dd7cddfSDavid du Colombier }
2627dd7cddfSDavid du Colombier penum = gs_alloc_struct(mem, gx_image3_enum_t, &st_image3_enum,
2637dd7cddfSDavid du Colombier "gx_begin_image3");
2647dd7cddfSDavid du Colombier if (penum == 0)
2657dd7cddfSDavid du Colombier return_error(gs_error_VMerror);
2667dd7cddfSDavid du Colombier penum->num_components =
2677dd7cddfSDavid du Colombier gs_color_space_num_components(pim->ColorSpace);
2687dd7cddfSDavid du Colombier gx_image_enum_common_init((gx_image_enum_common_t *) penum,
2697dd7cddfSDavid du Colombier (const gs_data_image_t *)pim,
2707dd7cddfSDavid du Colombier &image3_enum_procs, dev,
2717dd7cddfSDavid du Colombier 1 + penum->num_components,
2727dd7cddfSDavid du Colombier pim->format);
2737dd7cddfSDavid du Colombier /* Initialize pointers now in case we bail out. */
2747dd7cddfSDavid du Colombier penum->mask_data = 0;
2757dd7cddfSDavid du Colombier penum->pixel_data = 0;
2767dd7cddfSDavid du Colombier if (prect) {
2777dd7cddfSDavid du Colombier long lmw = pim->MaskDict.Width, lmh = pim->MaskDict.Height;
2787dd7cddfSDavid du Colombier
2797dd7cddfSDavid du Colombier data_rect = *prect;
2807dd7cddfSDavid du Colombier mask_rect.p.x = (int)(data_rect.p.x * lmw / pim->Width);
2817dd7cddfSDavid du Colombier mask_rect.p.y = (int)(data_rect.p.y * lmh / pim->Height);
2827dd7cddfSDavid du Colombier mask_rect.q.x = (int)((data_rect.q.x + pim->Width - 1) * lmw /
2837dd7cddfSDavid du Colombier pim->Width);
2847dd7cddfSDavid du Colombier mask_rect.q.y = (int)((data_rect.q.y + pim->Height - 1) * lmh /
2857dd7cddfSDavid du Colombier pim->Height);
2867dd7cddfSDavid du Colombier } else {
2877dd7cddfSDavid du Colombier mask_rect.p.x = mask_rect.p.y = 0;
2887dd7cddfSDavid du Colombier mask_rect.q.x = pim->MaskDict.Width;
2897dd7cddfSDavid du Colombier mask_rect.q.y = pim->MaskDict.Height;
2907dd7cddfSDavid du Colombier data_rect.p.x = data_rect.p.y = 0;
2917dd7cddfSDavid du Colombier data_rect.q.x = pim->Width;
2927dd7cddfSDavid du Colombier data_rect.q.y = pim->Height;
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier penum->mask_width = mask_rect.q.x - mask_rect.p.x;
2957dd7cddfSDavid du Colombier penum->mask_height = mask_rect.q.y - mask_rect.p.y;
2967dd7cddfSDavid du Colombier penum->mask_full_height = pim->MaskDict.Height;
2977dd7cddfSDavid du Colombier penum->mask_y = 0;
2987dd7cddfSDavid du Colombier penum->mask_skip = 0;
2997dd7cddfSDavid du Colombier penum->pixel_width = data_rect.q.x - data_rect.p.x;
3007dd7cddfSDavid du Colombier penum->pixel_height = data_rect.q.y - data_rect.p.y;
3017dd7cddfSDavid du Colombier penum->pixel_full_height = pim->Height;
3027dd7cddfSDavid du Colombier penum->pixel_y = 0;
3037dd7cddfSDavid du Colombier penum->mask_info = 0;
3047dd7cddfSDavid du Colombier penum->pixel_info = 0;
3057dd7cddfSDavid du Colombier if (pim->InterleaveType == interleave_chunky) {
3067dd7cddfSDavid du Colombier /* Allocate row buffers for the mask and pixel data. */
3077dd7cddfSDavid du Colombier penum->pixel_data =
3087dd7cddfSDavid du Colombier gs_alloc_bytes(mem,
3097dd7cddfSDavid du Colombier (penum->pixel_width * pim->BitsPerComponent *
3107dd7cddfSDavid du Colombier penum->num_components + 7) >> 3,
3117dd7cddfSDavid du Colombier "gx_begin_image3(pixel_data)");
3127dd7cddfSDavid du Colombier penum->mask_data =
3137dd7cddfSDavid du Colombier gs_alloc_bytes(mem, (penum->mask_width + 7) >> 3,
3147dd7cddfSDavid du Colombier "gx_begin_image3(mask_data)");
3153ff48bf5SDavid du Colombier if (penum->pixel_data == 0 || penum->mask_data == 0) {
3163ff48bf5SDavid du Colombier code = gs_note_error(gs_error_VMerror);
3173ff48bf5SDavid du Colombier goto out1;
3183ff48bf5SDavid du Colombier }
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier penum->InterleaveType = pim->InterleaveType;
3217dd7cddfSDavid du Colombier penum->bpc = pim->BitsPerComponent;
3227dd7cddfSDavid du Colombier penum->memory = mem;
3237dd7cddfSDavid du Colombier mrect.p.x = mrect.p.y = 0;
3247dd7cddfSDavid du Colombier mrect.q.x = pim->MaskDict.Width;
3257dd7cddfSDavid du Colombier mrect.q.y = pim->MaskDict.Height;
3267dd7cddfSDavid du Colombier if (pmat == 0)
3277dd7cddfSDavid du Colombier pmat = &ctm_only(pis);
3287dd7cddfSDavid du Colombier if ((code = gs_matrix_multiply(&mi_mask, pmat, &mat)) < 0 ||
3297dd7cddfSDavid du Colombier (code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
3307dd7cddfSDavid du Colombier )
3317dd7cddfSDavid du Colombier return code;
332*593dc095SDavid du Colombier
333*593dc095SDavid du Colombier origin.x = (mrect.p.x < 0) ? (int)ceil(mrect.p.x) : (int)floor(mrect.p.x);
334*593dc095SDavid du Colombier origin.y = (mrect.p.y < 0) ? (int)ceil(mrect.p.y) : (int)floor(mrect.p.y);
3353ff48bf5SDavid du Colombier code = make_mid(&mdev, dev, (int)ceil(mrect.q.x) - origin.x,
3363ff48bf5SDavid du Colombier (int)ceil(mrect.q.y) - origin.y, mem);
3377dd7cddfSDavid du Colombier if (code < 0)
3383ff48bf5SDavid du Colombier goto out1;
3393ff48bf5SDavid du Colombier penum->mdev = mdev;
3407dd7cddfSDavid du Colombier gs_image_t_init_mask(&i_mask, false);
3417dd7cddfSDavid du Colombier i_mask.adjust = false;
3427dd7cddfSDavid du Colombier {
3437dd7cddfSDavid du Colombier const gx_image_type_t *type1 = i_mask.type;
3447dd7cddfSDavid du Colombier
3457dd7cddfSDavid du Colombier *(gs_data_image_t *)&i_mask = pim->MaskDict;
3467dd7cddfSDavid du Colombier i_mask.type = type1;
3477dd7cddfSDavid du Colombier i_mask.BitsPerComponent = 1;
3487dd7cddfSDavid du Colombier }
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier gx_drawing_color dcolor;
3517dd7cddfSDavid du Colombier gs_matrix m_mat;
3527dd7cddfSDavid du Colombier
353*593dc095SDavid du Colombier set_nonclient_dev_color(&dcolor, 1);
3547dd7cddfSDavid du Colombier /*
3557dd7cddfSDavid du Colombier * Adjust the translation for rendering the mask to include a
3567dd7cddfSDavid du Colombier * negative translation by origin.{x,y} in device space.
3577dd7cddfSDavid du Colombier */
3587dd7cddfSDavid du Colombier m_mat = *pmat;
3597dd7cddfSDavid du Colombier m_mat.tx -= origin.x;
3607dd7cddfSDavid du Colombier m_mat.ty -= origin.y;
3617dd7cddfSDavid du Colombier /*
3627dd7cddfSDavid du Colombier * Note that pis = NULL here, since we don't want to have to
3637dd7cddfSDavid du Colombier * create another imager state with default log_op, etc.
3647dd7cddfSDavid du Colombier */
3653ff48bf5SDavid du Colombier code = gx_device_begin_typed_image(mdev, NULL, &m_mat,
3667dd7cddfSDavid du Colombier (const gs_image_common_t *)&i_mask,
3677dd7cddfSDavid du Colombier &mask_rect, &dcolor, NULL, mem,
3687dd7cddfSDavid du Colombier &penum->mask_info);
3697dd7cddfSDavid du Colombier if (code < 0)
3703ff48bf5SDavid du Colombier goto out2;
3717dd7cddfSDavid du Colombier }
3727dd7cddfSDavid du Colombier gs_image_t_init(&i_pixel, pim->ColorSpace);
3737dd7cddfSDavid du Colombier {
3747dd7cddfSDavid du Colombier const gx_image_type_t *type1 = i_pixel.type;
375*593dc095SDavid du Colombier const bool mask = i_pixel.ImageMask;
3767dd7cddfSDavid du Colombier
377*593dc095SDavid du Colombier /* On gcc 2.95.4 for Alpha all structures are padded to 8 byte
378*593dc095SDavid du Colombier * boundary but sizeof(bool) == 4. First member of the subclass
379*593dc095SDavid du Colombier * is restored because it is overwritten by padding data.
380*593dc095SDavid du Colombier */
3817dd7cddfSDavid du Colombier *(gs_pixel_image_t *)&i_pixel = *(const gs_pixel_image_t *)pim;
382*593dc095SDavid du Colombier i_pixel.ImageMask = mask;
3837dd7cddfSDavid du Colombier i_pixel.type = type1;
3847dd7cddfSDavid du Colombier }
3853ff48bf5SDavid du Colombier code = make_mcde(dev, pis, pmat, (const gs_image_common_t *)&i_pixel,
3863ff48bf5SDavid du Colombier prect, pdcolor, pcpath, mem, &penum->pixel_info,
3873ff48bf5SDavid du Colombier &pcdev, mdev, penum->mask_info, &origin);
3887dd7cddfSDavid du Colombier if (code < 0)
3893ff48bf5SDavid du Colombier goto out3;
3903ff48bf5SDavid du Colombier penum->pcdev = pcdev;
3917dd7cddfSDavid du Colombier /*
3927dd7cddfSDavid du Colombier * Set num_planes, plane_widths, and plane_depths from the values in the
3937dd7cddfSDavid du Colombier * enumerators for the mask and the image data.
3947dd7cddfSDavid du Colombier */
3957dd7cddfSDavid du Colombier switch (pim->InterleaveType) {
3967dd7cddfSDavid du Colombier case interleave_chunky:
3977dd7cddfSDavid du Colombier /* Add the mask data to the depth of the image data. */
3987dd7cddfSDavid du Colombier penum->num_planes = 1;
3997dd7cddfSDavid du Colombier penum->plane_widths[0] = pim->Width;
4007dd7cddfSDavid du Colombier penum->plane_depths[0] =
4017dd7cddfSDavid du Colombier penum->pixel_info->plane_depths[0] *
4027dd7cddfSDavid du Colombier (penum->num_components + 1) / penum->num_components;
4037dd7cddfSDavid du Colombier break;
4047dd7cddfSDavid du Colombier case interleave_scan_lines:
4057dd7cddfSDavid du Colombier /*
4067dd7cddfSDavid du Colombier * There is only 1 plane, with dynamically changing width & depth.
4077dd7cddfSDavid du Colombier * Initialize it for the mask data, since that is what will be
4087dd7cddfSDavid du Colombier * read first.
4097dd7cddfSDavid du Colombier */
4107dd7cddfSDavid du Colombier penum->num_planes = 1;
4117dd7cddfSDavid du Colombier penum->plane_depths[0] = 1;
4127dd7cddfSDavid du Colombier penum->plane_widths[0] = pim->MaskDict.Width;
4137dd7cddfSDavid du Colombier break;
4147dd7cddfSDavid du Colombier case interleave_separate_source:
4157dd7cddfSDavid du Colombier /* Insert the mask data as a separate plane before the image data. */
4167dd7cddfSDavid du Colombier penum->num_planes = penum->pixel_info->num_planes + 1;
4177dd7cddfSDavid du Colombier penum->plane_widths[0] = pim->MaskDict.Width;
4187dd7cddfSDavid du Colombier penum->plane_depths[0] = 1;
4197dd7cddfSDavid du Colombier memcpy(&penum->plane_widths[1], &penum->pixel_info->plane_widths[0],
4207dd7cddfSDavid du Colombier (penum->num_planes - 1) * sizeof(penum->plane_widths[0]));
4217dd7cddfSDavid du Colombier memcpy(&penum->plane_depths[1], &penum->pixel_info->plane_depths[0],
4227dd7cddfSDavid du Colombier (penum->num_planes - 1) * sizeof(penum->plane_depths[0]));
4237dd7cddfSDavid du Colombier break;
4247dd7cddfSDavid du Colombier }
4253ff48bf5SDavid du Colombier gx_device_retain(mdev, true); /* will free explicitly */
4263ff48bf5SDavid du Colombier gx_device_retain(pcdev, true); /* ditto */
4277dd7cddfSDavid du Colombier *pinfo = (gx_image_enum_common_t *) penum;
4287dd7cddfSDavid du Colombier return 0;
4293ff48bf5SDavid du Colombier out3:
4303ff48bf5SDavid du Colombier gx_image_end(penum->mask_info, false);
4313ff48bf5SDavid du Colombier out2:
4323ff48bf5SDavid du Colombier gs_closedevice(mdev);
4333ff48bf5SDavid du Colombier gs_free_object(mem, mdev, "gx_begin_image3(mdev)");
4343ff48bf5SDavid du Colombier out1:
4353ff48bf5SDavid du Colombier gs_free_object(mem, penum->mask_data, "gx_begin_image3(mask_data)");
4367dd7cddfSDavid du Colombier gs_free_object(mem, penum->pixel_data, "gx_begin_image3(pixel_data)");
4377dd7cddfSDavid du Colombier gs_free_object(mem, penum, "gx_begin_image3");
4383ff48bf5SDavid du Colombier return code;
4397dd7cddfSDavid du Colombier }
4407dd7cddfSDavid du Colombier private bool
check_image3_extent(floatp mask_coeff,floatp data_coeff)4417dd7cddfSDavid du Colombier check_image3_extent(floatp mask_coeff, floatp data_coeff)
4427dd7cddfSDavid du Colombier {
4437dd7cddfSDavid du Colombier if (mask_coeff == 0)
4447dd7cddfSDavid du Colombier return data_coeff == 0;
4457dd7cddfSDavid du Colombier if (data_coeff == 0 || (mask_coeff > 0) != (data_coeff > 0))
4467dd7cddfSDavid du Colombier return false;
4477dd7cddfSDavid du Colombier return true;
4487dd7cddfSDavid du Colombier }
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier /*
4517dd7cddfSDavid du Colombier * Return > 0 if we want more mask now, < 0 if we want more data now,
4527dd7cddfSDavid du Colombier * 0 if we want both.
4537dd7cddfSDavid du Colombier */
4547dd7cddfSDavid du Colombier private int
planes_next(const gx_image3_enum_t * penum)4557dd7cddfSDavid du Colombier planes_next(const gx_image3_enum_t *penum)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier /*
4587dd7cddfSDavid du Colombier * The invariant we need to maintain is that we always have at least as
4597dd7cddfSDavid du Colombier * much mask as pixel data, i.e., mask_y / mask_full_height >=
4607dd7cddfSDavid du Colombier * pixel_y / pixel_full_height, or, to avoid floating point,
4617dd7cddfSDavid du Colombier * mask_y * pixel_full_height >= pixel_y * mask_full_height.
4627dd7cddfSDavid du Colombier * We know this condition is true now;
4637dd7cddfSDavid du Colombier * return a value that indicates how to maintain it.
4647dd7cddfSDavid du Colombier */
4657dd7cddfSDavid du Colombier int mask_h = penum->mask_full_height;
4667dd7cddfSDavid du Colombier int pixel_h = penum->pixel_full_height;
4677dd7cddfSDavid du Colombier long current = penum->pixel_y * (long)mask_h -
4687dd7cddfSDavid du Colombier penum->mask_y * (long)pixel_h;
4697dd7cddfSDavid du Colombier
4707dd7cddfSDavid du Colombier #ifdef DEBUG
4717dd7cddfSDavid du Colombier if (current > 0)
4727dd7cddfSDavid du Colombier lprintf4("planes_next invariant fails: %d/%d > %d/%d\n",
4737dd7cddfSDavid du Colombier penum->pixel_y, penum->pixel_full_height,
4747dd7cddfSDavid du Colombier penum->mask_y, penum->mask_full_height);
4757dd7cddfSDavid du Colombier #endif
4767dd7cddfSDavid du Colombier return ((current += mask_h) <= 0 ? -1 :
4777dd7cddfSDavid du Colombier current - pixel_h <= 0 ? 0 : 1);
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier /* Process the next piece of an ImageType 3 image. */
4817dd7cddfSDavid du Colombier private int
gx_image3_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)4827dd7cddfSDavid du Colombier gx_image3_plane_data(gx_image_enum_common_t * info,
4837dd7cddfSDavid du Colombier const gx_image_plane_t * planes, int height,
4847dd7cddfSDavid du Colombier int *rows_used)
4857dd7cddfSDavid du Colombier {
4867dd7cddfSDavid du Colombier gx_image3_enum_t *penum = (gx_image3_enum_t *) info;
4877dd7cddfSDavid du Colombier int pixel_height = penum->pixel_height;
4887dd7cddfSDavid du Colombier int pixel_used = 0;
4897dd7cddfSDavid du Colombier int mask_height = penum->mask_height;
4907dd7cddfSDavid du Colombier int mask_used = 0;
4917dd7cddfSDavid du Colombier int h1 = max(pixel_height - penum->pixel_y, mask_height - penum->mask_y);
4927dd7cddfSDavid du Colombier int h = min(height, h1);
4937dd7cddfSDavid du Colombier const gx_image_plane_t *pixel_planes;
4947dd7cddfSDavid du Colombier gx_image_plane_t pixel_plane, mask_plane;
4957dd7cddfSDavid du Colombier int code = 0;
4967dd7cddfSDavid du Colombier
4977dd7cddfSDavid du Colombier /* Initialized rows_used in case we get an error. */
4987dd7cddfSDavid du Colombier *rows_used = 0;
4997dd7cddfSDavid du Colombier switch (penum->InterleaveType) {
5007dd7cddfSDavid du Colombier case interleave_chunky:
5017dd7cddfSDavid du Colombier if (h <= 0)
5027dd7cddfSDavid du Colombier return 0;
5037dd7cddfSDavid du Colombier if (h > 1) {
5047dd7cddfSDavid du Colombier /* Do the operation one row at a time. */
5057dd7cddfSDavid du Colombier int h_orig = h;
5067dd7cddfSDavid du Colombier
5077dd7cddfSDavid du Colombier mask_plane = planes[0];
5087dd7cddfSDavid du Colombier do {
5097dd7cddfSDavid du Colombier code = gx_image3_plane_data(info, &mask_plane, 1,
5107dd7cddfSDavid du Colombier rows_used);
5117dd7cddfSDavid du Colombier h -= *rows_used;
5127dd7cddfSDavid du Colombier if (code)
5137dd7cddfSDavid du Colombier break;
5147dd7cddfSDavid du Colombier mask_plane.data += mask_plane.raster;
5157dd7cddfSDavid du Colombier } while (h);
5167dd7cddfSDavid du Colombier *rows_used = h_orig - h;
5177dd7cddfSDavid du Colombier return code;
5187dd7cddfSDavid du Colombier } {
5197dd7cddfSDavid du Colombier /* Pull apart the source data and the mask data. */
5207dd7cddfSDavid du Colombier int bpc = penum->bpc;
5217dd7cddfSDavid du Colombier int num_components = penum->num_components;
5227dd7cddfSDavid du Colombier int width = penum->pixel_width;
5237dd7cddfSDavid du Colombier
5247dd7cddfSDavid du Colombier /* We do this in the simplest (not fastest) way for now. */
5257dd7cddfSDavid du Colombier uint bit_x = bpc * (num_components + 1) * planes[0].data_x;
5267dd7cddfSDavid du Colombier
5277dd7cddfSDavid du Colombier sample_load_declare_setup(sptr, sbit,
5287dd7cddfSDavid du Colombier planes[0].data + (bit_x >> 3),
5297dd7cddfSDavid du Colombier bit_x & 7, bpc);
5307dd7cddfSDavid du Colombier sample_store_declare_setup(mptr, mbit, mbbyte,
5317dd7cddfSDavid du Colombier penum->mask_data, 0, 1);
5327dd7cddfSDavid du Colombier sample_store_declare_setup(pptr, pbit, pbbyte,
5337dd7cddfSDavid du Colombier penum->pixel_data, 0, bpc);
5347dd7cddfSDavid du Colombier int x;
5357dd7cddfSDavid du Colombier
5367dd7cddfSDavid du Colombier mask_plane.data = mptr;
5377dd7cddfSDavid du Colombier mask_plane.data_x = 0;
5387dd7cddfSDavid du Colombier /* raster doesn't matter */
5397dd7cddfSDavid du Colombier pixel_plane.data = pptr;
5407dd7cddfSDavid du Colombier pixel_plane.data_x = 0;
5417dd7cddfSDavid du Colombier /* raster doesn't matter */
5427dd7cddfSDavid du Colombier pixel_planes = &pixel_plane;
5437dd7cddfSDavid du Colombier for (x = 0; x < width; ++x) {
5447dd7cddfSDavid du Colombier uint value;
5457dd7cddfSDavid du Colombier int i;
5467dd7cddfSDavid du Colombier
5477dd7cddfSDavid du Colombier sample_load_next12(value, sptr, sbit, bpc);
5487dd7cddfSDavid du Colombier sample_store_next12(value != 0, mptr, mbit, 1, mbbyte);
5497dd7cddfSDavid du Colombier for (i = 0; i < num_components; ++i) {
5507dd7cddfSDavid du Colombier sample_load_next12(value, sptr, sbit, bpc);
5517dd7cddfSDavid du Colombier sample_store_next12(value, pptr, pbit, bpc, pbbyte);
5527dd7cddfSDavid du Colombier }
5537dd7cddfSDavid du Colombier }
5547dd7cddfSDavid du Colombier sample_store_flush(mptr, mbit, 1, mbbyte);
5557dd7cddfSDavid du Colombier sample_store_flush(pptr, pbit, bpc, pbbyte);
5567dd7cddfSDavid du Colombier }
5577dd7cddfSDavid du Colombier break;
5587dd7cddfSDavid du Colombier case interleave_scan_lines:
5597dd7cddfSDavid du Colombier if (planes_next(penum) >= 0) {
5607dd7cddfSDavid du Colombier /* This is mask data. */
5617dd7cddfSDavid du Colombier mask_plane = planes[0];
5627dd7cddfSDavid du Colombier pixel_planes = &pixel_plane;
5637dd7cddfSDavid du Colombier pixel_plane.data = 0;
5647dd7cddfSDavid du Colombier } else {
5657dd7cddfSDavid du Colombier /* This is pixel data. */
5667dd7cddfSDavid du Colombier mask_plane.data = 0;
5677dd7cddfSDavid du Colombier pixel_planes = planes;
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier break;
5707dd7cddfSDavid du Colombier case interleave_separate_source:
5717dd7cddfSDavid du Colombier /*
5727dd7cddfSDavid du Colombier * In order to be able to recover from interruptions, we must
5737dd7cddfSDavid du Colombier * limit separate-source processing to 1 scan line at a time.
5747dd7cddfSDavid du Colombier */
5757dd7cddfSDavid du Colombier if (h > 1)
5767dd7cddfSDavid du Colombier h = 1;
5777dd7cddfSDavid du Colombier mask_plane = planes[0];
5787dd7cddfSDavid du Colombier pixel_planes = planes + 1;
5797dd7cddfSDavid du Colombier break;
5807dd7cddfSDavid du Colombier default: /* not possible */
5817dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier /*
5847dd7cddfSDavid du Colombier * Process the mask data first, so it will set up the mask
5857dd7cddfSDavid du Colombier * device for clipping the pixel data.
5867dd7cddfSDavid du Colombier */
5877dd7cddfSDavid du Colombier if (mask_plane.data) {
5887dd7cddfSDavid du Colombier /*
5897dd7cddfSDavid du Colombier * If, on the last call, we processed some mask rows successfully
5907dd7cddfSDavid du Colombier * but processing the pixel rows was interrupted, we set rows_used
5917dd7cddfSDavid du Colombier * to indicate the number of pixel rows processed (since there is
5927dd7cddfSDavid du Colombier * no way to return two rows_used values). If this happened, some
5937dd7cddfSDavid du Colombier * mask rows may get presented again. We must skip over them
5947dd7cddfSDavid du Colombier * rather than processing them again.
5957dd7cddfSDavid du Colombier */
5967dd7cddfSDavid du Colombier int skip = penum->mask_skip;
5977dd7cddfSDavid du Colombier
5987dd7cddfSDavid du Colombier if (skip >= h) {
5997dd7cddfSDavid du Colombier penum->mask_skip = skip - (mask_used = h);
6007dd7cddfSDavid du Colombier } else {
6017dd7cddfSDavid du Colombier int mask_h = h - skip;
6027dd7cddfSDavid du Colombier
6037dd7cddfSDavid du Colombier mask_plane.data += skip * mask_plane.raster;
6047dd7cddfSDavid du Colombier penum->mask_skip = 0;
6057dd7cddfSDavid du Colombier code = gx_image_plane_data_rows(penum->mask_info, &mask_plane,
6067dd7cddfSDavid du Colombier mask_h, &mask_used);
6077dd7cddfSDavid du Colombier mask_used += skip;
6087dd7cddfSDavid du Colombier }
6097dd7cddfSDavid du Colombier *rows_used = mask_used;
6107dd7cddfSDavid du Colombier penum->mask_y += mask_used;
6117dd7cddfSDavid du Colombier if (code < 0)
6127dd7cddfSDavid du Colombier return code;
6137dd7cddfSDavid du Colombier }
6147dd7cddfSDavid du Colombier if (pixel_planes[0].data) {
6157dd7cddfSDavid du Colombier /*
6167dd7cddfSDavid du Colombier * If necessary, flush any buffered mask data to the mask clipping
6177dd7cddfSDavid du Colombier * device.
6187dd7cddfSDavid du Colombier */
6197dd7cddfSDavid du Colombier gx_image_flush(penum->mask_info);
6207dd7cddfSDavid du Colombier code = gx_image_plane_data_rows(penum->pixel_info, pixel_planes, h,
6217dd7cddfSDavid du Colombier &pixel_used);
6227dd7cddfSDavid du Colombier /*
6237dd7cddfSDavid du Colombier * There isn't any way to set rows_used if different amounts of
6247dd7cddfSDavid du Colombier * the mask and pixel data were used. Fake it.
6257dd7cddfSDavid du Colombier */
6267dd7cddfSDavid du Colombier *rows_used = pixel_used;
6277dd7cddfSDavid du Colombier /*
6287dd7cddfSDavid du Colombier * Don't return code yet: we must account for the fact that
6297dd7cddfSDavid du Colombier * some mask data may have been processed.
6307dd7cddfSDavid du Colombier */
6317dd7cddfSDavid du Colombier penum->pixel_y += pixel_used;
6327dd7cddfSDavid du Colombier if (code < 0) {
6337dd7cddfSDavid du Colombier /*
6347dd7cddfSDavid du Colombier * We must prevent the mask data from being processed again.
6357dd7cddfSDavid du Colombier * We rely on the fact that h > 1 is only possible if the
6367dd7cddfSDavid du Colombier * mask and pixel data have the same Y scaling.
6377dd7cddfSDavid du Colombier */
6387dd7cddfSDavid du Colombier if (mask_used > pixel_used) {
6397dd7cddfSDavid du Colombier int skip = mask_used - pixel_used;
6407dd7cddfSDavid du Colombier
6417dd7cddfSDavid du Colombier penum->mask_skip = skip;
6427dd7cddfSDavid du Colombier penum->mask_y -= skip;
6437dd7cddfSDavid du Colombier mask_used = pixel_used;
6447dd7cddfSDavid du Colombier }
6457dd7cddfSDavid du Colombier }
6467dd7cddfSDavid du Colombier }
6477dd7cddfSDavid du Colombier if_debug5('b', "[b]image3 h=%d %smask_y=%d %spixel_y=%d\n",
6487dd7cddfSDavid du Colombier h, (mask_plane.data ? "+" : ""), penum->mask_y,
6497dd7cddfSDavid du Colombier (pixel_planes[0].data ? "+" : ""), penum->pixel_y);
6507dd7cddfSDavid du Colombier if (penum->mask_y >= penum->mask_height &&
6517dd7cddfSDavid du Colombier penum->pixel_y >= penum->pixel_height)
6527dd7cddfSDavid du Colombier return 1;
6537dd7cddfSDavid du Colombier if (penum->InterleaveType == interleave_scan_lines) {
6547dd7cddfSDavid du Colombier /* Update the width and depth in the enumerator. */
6557dd7cddfSDavid du Colombier if (planes_next(penum) >= 0) { /* want mask data next */
6567dd7cddfSDavid du Colombier penum->plane_widths[0] = penum->mask_width;
6577dd7cddfSDavid du Colombier penum->plane_depths[0] = 1;
6587dd7cddfSDavid du Colombier } else { /* want pixel data next */
6597dd7cddfSDavid du Colombier penum->plane_widths[0] = penum->pixel_width;
6607dd7cddfSDavid du Colombier penum->plane_depths[0] = penum->pixel_info->plane_depths[0];
6617dd7cddfSDavid du Colombier }
6627dd7cddfSDavid du Colombier }
6637dd7cddfSDavid du Colombier /*
6647dd7cddfSDavid du Colombier * The mask may be complete (gx_image_plane_data_rows returned 1),
6657dd7cddfSDavid du Colombier * but there may still be pixel rows to go, so don't return 1 here.
6667dd7cddfSDavid du Colombier */
6677dd7cddfSDavid du Colombier return (code < 0 ? code : 0);
6687dd7cddfSDavid du Colombier }
6697dd7cddfSDavid du Colombier
6707dd7cddfSDavid du Colombier /* Flush buffered data. */
6717dd7cddfSDavid du Colombier private int
gx_image3_flush(gx_image_enum_common_t * info)6727dd7cddfSDavid du Colombier gx_image3_flush(gx_image_enum_common_t * info)
6737dd7cddfSDavid du Colombier {
6747dd7cddfSDavid du Colombier gx_image3_enum_t * const penum = (gx_image3_enum_t *) info;
6757dd7cddfSDavid du Colombier int code = gx_image_flush(penum->mask_info);
6767dd7cddfSDavid du Colombier
6777dd7cddfSDavid du Colombier if (code >= 0)
6787dd7cddfSDavid du Colombier code = gx_image_flush(penum->pixel_info);
6797dd7cddfSDavid du Colombier return code;
6807dd7cddfSDavid du Colombier }
6817dd7cddfSDavid du Colombier
6827dd7cddfSDavid du Colombier /* Determine which data planes are wanted. */
6837dd7cddfSDavid du Colombier private bool
gx_image3_planes_wanted(const gx_image_enum_common_t * info,byte * wanted)6847dd7cddfSDavid du Colombier gx_image3_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
6857dd7cddfSDavid du Colombier {
6867dd7cddfSDavid du Colombier const gx_image3_enum_t * const penum = (const gx_image3_enum_t *) info;
6877dd7cddfSDavid du Colombier
6887dd7cddfSDavid du Colombier switch (penum->InterleaveType) {
6897dd7cddfSDavid du Colombier case interleave_chunky: /* only 1 plane */
6907dd7cddfSDavid du Colombier wanted[0] = 0xff;
6917dd7cddfSDavid du Colombier return true;
6927dd7cddfSDavid du Colombier case interleave_scan_lines: /* only 1 plane, but varying width/depth */
6937dd7cddfSDavid du Colombier wanted[0] = 0xff;
6947dd7cddfSDavid du Colombier return false;
6957dd7cddfSDavid du Colombier case interleave_separate_source: {
6967dd7cddfSDavid du Colombier /*
6977dd7cddfSDavid du Colombier * We always want at least as much of the mask to be filled as the
6987dd7cddfSDavid du Colombier * pixel data. next > 0 iff we've processed more data than mask.
6997dd7cddfSDavid du Colombier * Plane 0 is the mask, planes [1 .. num_planes - 1] are pixel data.
7007dd7cddfSDavid du Colombier */
7017dd7cddfSDavid du Colombier int next = planes_next(penum);
7027dd7cddfSDavid du Colombier
7037dd7cddfSDavid du Colombier wanted[0] = (next >= 0 ? 0xff : 0);
7047dd7cddfSDavid du Colombier memset(wanted + 1, (next <= 0 ? 0xff : 0), info->num_planes - 1);
7057dd7cddfSDavid du Colombier /*
7067dd7cddfSDavid du Colombier * In principle, wanted will always be true for both mask and pixel
7077dd7cddfSDavid du Colombier * data if the full_heights are equal. Unfortunately, even in this
7087dd7cddfSDavid du Colombier * case, processing may be interrupted after a mask row has been
7097dd7cddfSDavid du Colombier * passed to the underlying image processor but before the data row
7107dd7cddfSDavid du Colombier * has been passed, in which case pixel data will be 'wanted', but
7117dd7cddfSDavid du Colombier * not mask data, for the next call. Therefore, we must return
7127dd7cddfSDavid du Colombier * false.
7137dd7cddfSDavid du Colombier */
7147dd7cddfSDavid du Colombier return false
7157dd7cddfSDavid du Colombier /*(next == 0 &&
7167dd7cddfSDavid du Colombier penum->mask_full_height == penum->pixel_full_height)*/;
7177dd7cddfSDavid du Colombier }
7187dd7cddfSDavid du Colombier default: /* can't happen */
7197dd7cddfSDavid du Colombier memset(wanted, 0, info->num_planes);
7207dd7cddfSDavid du Colombier return false;
7217dd7cddfSDavid du Colombier }
7227dd7cddfSDavid du Colombier }
7237dd7cddfSDavid du Colombier
7247dd7cddfSDavid du Colombier /* Clean up after processing an ImageType 3 image. */
7257dd7cddfSDavid du Colombier private int
gx_image3_end_image(gx_image_enum_common_t * info,bool draw_last)7267dd7cddfSDavid du Colombier gx_image3_end_image(gx_image_enum_common_t * info, bool draw_last)
7277dd7cddfSDavid du Colombier {
7287dd7cddfSDavid du Colombier gx_image3_enum_t *penum = (gx_image3_enum_t *) info;
7297dd7cddfSDavid du Colombier gs_memory_t *mem = penum->memory;
7303ff48bf5SDavid du Colombier gx_device *mdev = penum->mdev;
7317dd7cddfSDavid du Colombier int mcode = gx_image_end(penum->mask_info, draw_last);
7323ff48bf5SDavid du Colombier gx_device *pcdev = penum->pcdev;
7337dd7cddfSDavid du Colombier int pcode = gx_image_end(penum->pixel_info, draw_last);
734*593dc095SDavid du Colombier int code1 = gs_closedevice(pcdev);
735*593dc095SDavid du Colombier int code2 = gs_closedevice(mdev);
7367dd7cddfSDavid du Colombier
7377dd7cddfSDavid du Colombier gs_free_object(mem, penum->mask_data,
7387dd7cddfSDavid du Colombier "gx_image3_end_image(mask_data)");
7397dd7cddfSDavid du Colombier gs_free_object(mem, penum->pixel_data,
7407dd7cddfSDavid du Colombier "gx_image3_end_image(pixel_data)");
7417dd7cddfSDavid du Colombier gs_free_object(mem, pcdev, "gx_image3_end_image(pcdev)");
7427dd7cddfSDavid du Colombier gs_free_object(mem, mdev, "gx_image3_end_image(mdev)");
7437dd7cddfSDavid du Colombier gs_free_object(mem, penum, "gx_image3_end_image");
744*593dc095SDavid du Colombier return (pcode < 0 ? pcode : mcode < 0 ? mcode : code1 < 0 ? code1 : code2);
7457dd7cddfSDavid du Colombier }
746