1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gximag3x.c 8803 2008-06-24 14:16:29Z leonardo $ */
15
/* ImageType 3x image implementation */
16
/****** THE REAL WORK IS NYI ******/
17
#include "math_.h" /* for ceil, floor */
31
extern_st(st_color_space);
33
/* Forward references */
34
static dev_proc_begin_typed_image(gx_begin_image3x);
35
static image_enum_proc_plane_data(gx_image3x_plane_data);
36
static image_enum_proc_end_image(gx_image3x_end_image);
37
static image_enum_proc_flush(gx_image3x_flush);
38
static image_enum_proc_planes_wanted(gx_image3x_planes_wanted);
41
private_st_gs_image3x();
43
/* Define the image type for ImageType 3x images. */
44
const gx_image_type_t gs_image_type_3x = {
45
&st_gs_image3x, gx_begin_image3x, gx_data_image_source_size,
46
gx_image_no_sput, gx_image_no_sget, gx_image_default_release,
49
static const gx_image_enum_procs_t image3x_enum_procs = {
50
gx_image3x_plane_data, gx_image3x_end_image,
51
gx_image3x_flush, gx_image3x_planes_wanted
54
/* Initialize an ImageType 3x image. */
56
gs_image3x_mask_init(gs_image3x_mask_t *pimm)
58
pimm->InterleaveType = 0; /* not a valid type */
59
pimm->has_Matte = false;
60
gs_data_image_t_init(&pimm->MaskDict, 1);
61
pimm->MaskDict.BitsPerComponent = 0; /* not supplied */
64
gs_image3x_t_init(gs_image3x_t * pim, gs_color_space * color_space)
66
gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
67
pim->type = &gs_image_type_3x;
68
gs_image3x_mask_init(&pim->Opacity);
69
gs_image3x_mask_init(&pim->Shape);
73
* We implement ImageType 3 images by interposing a mask clipper in
74
* front of an ordinary ImageType 1 image. Note that we build up the
75
* mask row-by-row as we are processing the image.
77
* We export a generalized form of the begin_image procedure for use by
78
* the PDF and PostScript writers.
81
typedef struct image3x_channel_state_s {
82
gx_image_enum_common_t *info;
83
gx_device *mdev; /* gx_device_memory in default impl. */
84
/* (only for masks) */
85
gs_image3_interleave_type_t InterleaveType;
86
int width, height, full_height, depth;
87
byte *data; /* (if chunky) */
88
/* Only the following change dynamically. */
90
int skip; /* only for masks, # of rows to skip, */
92
} image3x_channel_state_t;
93
typedef struct gx_image3x_enum_s {
95
gx_device *pcdev; /* gx_device_mask_clip in default impl. */
96
int num_components; /* (not counting masks) */
97
int bpc; /* pixel BitsPerComponent */
98
#define NUM_MASKS 2 /* opacity, shape */
99
image3x_channel_state_t mask[NUM_MASKS], pixel;
102
extern_st(st_gx_image_enum_common);
103
gs_private_st_suffix_add9(st_image3x_enum, gx_image3x_enum_t,
104
"gx_image3x_enum_t", image3x_enum_enum_ptrs, image3x_enum_reloc_ptrs,
105
st_gx_image_enum_common, pcdev, mask[0].info, mask[0].mdev, mask[0].data,
106
mask[1].info, mask[1].mdev, mask[1].data, pixel.info, pixel.data);
109
* Begin a generic ImageType 3x image, with client handling the creation of
110
* the mask image and mask clip devices.
112
typedef struct image3x_channel_values_s {
117
} image3x_channel_values_t;
118
static int check_image3x_mask(const gs_image3x_t *pim,
119
const gs_image3x_mask_t *pimm,
120
const image3x_channel_values_t *ppcv,
121
image3x_channel_values_t *pmcv,
122
image3x_channel_state_t *pmcs,
125
gx_begin_image3x_generic(gx_device * dev,
126
const gs_imager_state *pis, const gs_matrix *pmat,
127
const gs_image_common_t *pic, const gs_int_rect *prect,
128
const gx_drawing_color *pdcolor,
129
const gx_clip_path *pcpath, gs_memory_t *mem,
130
image3x_make_mid_proc_t make_mid,
131
image3x_make_mcde_proc_t make_mcde,
132
gx_image_enum_common_t **pinfo)
134
const gs_image3x_t *pim = (const gs_image3x_t *)pic;
135
gx_image3x_enum_t *penum;
136
gx_device *pcdev = 0;
137
image3x_channel_values_t mask[2], pixel;
140
gx_image_enum_common_t *minfo[2];
141
gs_int_point origin[2];
145
/* Validate the parameters. */
146
if (pim->Height <= 0)
147
return_error(gs_error_rangecheck);
148
penum = gs_alloc_struct(mem, gx_image3x_enum_t, &st_image3x_enum,
151
return_error(gs_error_VMerror);
152
/* Initialize pointers now in case we bail out. */
153
penum->mask[0].info = 0, penum->mask[0].mdev = 0, penum->mask[0].data = 0;
154
penum->mask[1].info = 0, penum->mask[1].mdev = 0, penum->mask[1].data = 0;
155
penum->pixel.info = 0, penum->pixel.data = 0;
159
pixel.rect.p.x = pixel.rect.p.y = 0;
160
pixel.rect.q.x = pim->Width;
161
pixel.rect.q.y = pim->Height;
163
if ((code = gs_matrix_invert(&pim->ImageMatrix, &pixel.matrix)) < 0 ||
164
(code = gs_point_transform(pim->Width, pim->Height, &pixel.matrix,
165
&pixel.corner)) < 0 ||
166
(code = check_image3x_mask(pim, &pim->Opacity, &pixel, &mask[0],
167
&penum->mask[0], mem)) < 0 ||
168
(code = check_image3x_mask(pim, &pim->Shape, &pixel, &mask[1],
169
&penum->mask[1], mem)) < 0
173
penum->num_components =
174
gs_color_space_num_components(pim->ColorSpace);
175
gx_image_enum_common_init((gx_image_enum_common_t *) penum,
176
(const gs_data_image_t *)pim,
177
&image3x_enum_procs, dev,
178
1 + penum->num_components,
180
penum->pixel.width = pixel.rect.q.x - pixel.rect.p.x;
181
penum->pixel.height = pixel.rect.q.y - pixel.rect.p.y;
182
penum->pixel.full_height = pim->Height;
184
if (penum->mask[0].data || penum->mask[1].data) {
185
/* Also allocate a row buffer for the pixel data. */
188
(penum->pixel.width * pim->BitsPerComponent *
189
penum->num_components + 7) >> 3,
190
"gx_begin_image3x(pixel.data)");
191
if (penum->pixel.data == 0) {
192
code = gs_note_error(gs_error_VMerror);
196
penum->bpc = pim->BitsPerComponent;
199
pmat = &ctm_only(pis);
200
for (i = 0; i < NUM_MASKS; ++i) {
204
* The mask data has to be defined in a DevicePixel color space
205
* of the correct depth so that no color mapping will occur.
207
/****** FREE COLOR SPACE ON ERROR OR AT END ******/
208
gs_color_space *pmcs;
210
if (penum->mask[i].depth == 0) { /* mask not supplied */
215
code = gs_cspace_new_DevicePixel(mem, &pmcs, penum->mask[i].depth);
218
mrect.p.x = mrect.p.y = 0;
219
mrect.q.x = penum->mask[i].width;
220
mrect.q.y = penum->mask[i].height;
221
if ((code = gs_matrix_multiply(&mask[i].matrix, pmat, &mat)) < 0 ||
222
(code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
225
origin[i].x = (int)floor(mrect.p.x);
226
origin[i].y = (int)floor(mrect.p.y);
227
code = make_mid(&mdev, dev,
228
(int)ceil(mrect.q.x) - origin[i].x,
229
(int)ceil(mrect.q.y) - origin[i].y,
230
penum->mask[i].depth, mem);
233
penum->mask[i].mdev = mdev;
234
gs_image_t_init(&mask[i].image, pmcs);
235
mask[i].image.ColorSpace = pmcs;
236
mask[i].image.adjust = false;
238
const gx_image_type_t *type1 = mask[i].image.type;
239
const gs_image3x_mask_t *pixm =
240
(i == 0 ? &pim->Opacity : &pim->Shape);
242
*(gs_data_image_t *)&mask[i].image = pixm->MaskDict;
243
mask[i].image.type = type1;
244
mask[i].image.BitsPerComponent = pixm->MaskDict.BitsPerComponent;
250
* Adjust the translation for rendering the mask to include a
251
* negative translation by origin.{x,y} in device space.
254
m_mat.tx -= origin[i].x;
255
m_mat.ty -= origin[i].y;
257
* Peter put in a comment that said " Note that pis = NULL here,
258
* since we don't want to have to create another imager state with
259
* default log_op, etc." and passed NULL instead of pis to this
260
* routine. However Image type 1 need the imager state (see
261
* bug 688348) thus his optimization was removed.
262
* dcolor = NULL is OK because this is an opaque image with
263
* CombineWithColor = false.
265
code = gx_device_begin_typed_image(mdev, pis, &m_mat,
266
(const gs_image_common_t *)&mask[i].image,
267
&mask[i].rect, NULL, NULL,
268
mem, &penum->mask[i].info);
273
minfo[i] = penum->mask[i].info;
275
gs_image_t_init(&pixel.image, pim->ColorSpace);
277
const gx_image_type_t *type1 = pixel.image.type;
279
*(gs_pixel_image_t *)&pixel.image = *(const gs_pixel_image_t *)pim;
280
pixel.image.type = type1;
282
code = make_mcde(dev, pis, pmat, (const gs_image_common_t *)&pixel.image,
283
prect, pdcolor, pcpath, mem, &penum->pixel.info,
284
&pcdev, midev, minfo, origin, pim);
287
penum->pcdev = pcdev;
289
* Set num_planes, plane_widths, and plane_depths from the values in the
290
* enumerators for the mask(s) and the image data.
296
for (i = 0; i < NUM_MASKS; ++i) {
297
if (penum->mask[i].depth == 0) /* no mask */
299
switch (penum->mask[i].InterleaveType) {
300
case interleave_chunky:
301
/* Add the mask data to the depth of the image data. */
302
added_depth += pim->BitsPerComponent;
304
case interleave_separate_source:
305
/* Insert the mask as a separate plane. */
306
penum->plane_widths[pi] = penum->mask[i].width;
307
penum->plane_depths[pi] = penum->mask[i].depth;
310
default: /* can't happen */
311
code = gs_note_error(gs_error_Fatal);
315
memcpy(&penum->plane_widths[pi], &penum->pixel.info->plane_widths[0],
316
penum->pixel.info->num_planes * sizeof(penum->plane_widths[0]));
317
memcpy(&penum->plane_depths[pi], &penum->pixel.info->plane_depths[0],
318
penum->pixel.info->num_planes * sizeof(penum->plane_depths[0]));
319
penum->plane_depths[pi] += added_depth;
320
penum->num_planes = pi + penum->pixel.info->num_planes;
323
gx_device_retain(midev[0], true); /* will free explicitly */
325
gx_device_retain(midev[1], true); /* ditto */
326
gx_device_retain(pcdev, true); /* ditto */
327
*pinfo = (gx_image_enum_common_t *) penum;
330
if (penum->mask[1].info)
331
gx_image_end(penum->mask[1].info, false);
332
if (penum->mask[0].info)
333
gx_image_end(penum->mask[0].info, false);
335
if (penum->mask[1].mdev) {
336
gs_closedevice(penum->mask[1].mdev);
337
gs_free_object(mem, penum->mask[1].mdev,
338
"gx_begin_image3x(mask[1].mdev)");
340
if (penum->mask[0].mdev) {
341
gs_closedevice(penum->mask[0].mdev);
342
gs_free_object(mem, penum->mask[0].mdev,
343
"gx_begin_image3x(mask[0].mdev)");
346
gs_free_object(mem, penum->mask[0].data, "gx_begin_image3x(mask[0].data)");
347
gs_free_object(mem, penum->mask[1].data, "gx_begin_image3x(mask[1].data)");
348
gs_free_object(mem, penum->pixel.data, "gx_begin_image3x(pixel.data)");
350
gs_free_object(mem, penum, "gx_begin_image3x");
354
check_image3x_extent(floatp mask_coeff, floatp data_coeff)
357
return data_coeff == 0;
358
if (data_coeff == 0 || (mask_coeff > 0) != (data_coeff > 0))
363
* Check mask parameters.
364
* Reads ppcv->{matrix,corner,rect}, sets pmcv->{matrix,corner,rect} and
365
* pmcs->{InterleaveType,width,height,full_height,depth,data,y,skip}.
366
* If the mask is omitted, sets pmcs->depth = 0 and returns normally.
369
check_image3x_mask(const gs_image3x_t *pim, const gs_image3x_mask_t *pimm,
370
const image3x_channel_values_t *ppcv,
371
image3x_channel_values_t *pmcv,
372
image3x_channel_state_t *pmcs, gs_memory_t *mem)
374
int mask_width = pimm->MaskDict.Width, mask_height = pimm->MaskDict.Height;
377
if (pimm->MaskDict.BitsPerComponent == 0) { /* mask missing */
379
pmcs->InterleaveType = 0; /* not a valid type */
382
if (mask_height <= 0)
383
return_error(gs_error_rangecheck);
384
switch (pimm->InterleaveType) {
385
/*case interleave_scan_lines:*/ /* not supported */
387
return_error(gs_error_rangecheck);
388
case interleave_chunky:
389
if (mask_width != pim->Width ||
390
mask_height != pim->Height ||
391
pimm->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
392
pim->format != gs_image_format_chunky
394
return_error(gs_error_rangecheck);
396
case interleave_separate_source:
397
switch (pimm->MaskDict.BitsPerComponent) {
398
case 1: case 2: case 4: case 8: case 12: case 16:
401
return_error(gs_error_rangecheck);
404
if (!check_image3x_extent(pim->ImageMatrix.xx,
405
pimm->MaskDict.ImageMatrix.xx) ||
406
!check_image3x_extent(pim->ImageMatrix.xy,
407
pimm->MaskDict.ImageMatrix.xy) ||
408
!check_image3x_extent(pim->ImageMatrix.yx,
409
pimm->MaskDict.ImageMatrix.yx) ||
410
!check_image3x_extent(pim->ImageMatrix.yy,
411
pimm->MaskDict.ImageMatrix.yy)
413
return_error(gs_error_rangecheck);
414
if ((code = gs_matrix_invert(&pimm->MaskDict.ImageMatrix, &pmcv->matrix)) < 0 ||
415
(code = gs_point_transform(mask_width, mask_height,
416
&pmcv->matrix, &pmcv->corner)) < 0
419
if (fabs(ppcv->matrix.tx - pmcv->matrix.tx) >= 0.5 ||
420
fabs(ppcv->matrix.ty - pmcv->matrix.ty) >= 0.5 ||
421
fabs(ppcv->corner.x - pmcv->corner.x) >= 0.5 ||
422
fabs(ppcv->corner.y - pmcv->corner.y) >= 0.5
424
return_error(gs_error_rangecheck);
425
pmcv->rect.p.x = ppcv->rect.p.x * mask_width / pim->Width;
426
pmcv->rect.p.y = ppcv->rect.p.y * mask_height / pim->Height;
427
pmcv->rect.q.x = (ppcv->rect.q.x * mask_width + pim->Width - 1) /
429
pmcv->rect.q.y = (ppcv->rect.q.y * mask_height + pim->Height - 1) /
431
/* Initialize the channel state in the enumerator. */
432
pmcs->InterleaveType = pimm->InterleaveType;
433
pmcs->width = pmcv->rect.q.x - pmcv->rect.p.x;
434
pmcs->height = pmcv->rect.q.y - pmcv->rect.p.y;
435
pmcs->full_height = pimm->MaskDict.Height;
436
pmcs->depth = pimm->MaskDict.BitsPerComponent;
437
if (pmcs->InterleaveType == interleave_chunky) {
438
/* Allocate a buffer for the data. */
441
(pmcs->width * pimm->MaskDict.BitsPerComponent + 7) >> 3,
442
"gx_begin_image3x(mask data)");
444
return_error(gs_error_VMerror);
446
pmcs->y = pmcs->skip = 0;
451
* Return > 0 if we want more data from channel 1 now, < 0 if we want more
452
* from channel 2 now, 0 if we want both.
455
channel_next(const image3x_channel_state_t *pics1,
456
const image3x_channel_state_t *pics2)
459
* The invariant we need to maintain is that we always have at least as
460
* much channel N as channel N+1 data, where N = 0 = opacity, 1 = shape,
461
* and 2 = pixel. I.e., for any two consecutive channels c1 and c2, we
462
* require c1.y / c1.full_height >= c2.y / c2.full_height, or, to avoid
463
* floating point, c1.y * c2.full_height >= c2.y * c1.full_height. We
464
* know this condition is true now; return a value that indicates how to
467
int h1 = pics1->full_height;
468
int h2 = pics2->full_height;
469
long current = pics1->y * (long)h2 - pics2->y * (long)h1;
473
lprintf4("channel_next invariant fails: %d/%d < %d/%d\n",
474
pics1->y, pics1->full_height,
475
pics2->y, pics2->full_height);
477
return ((current -= h1) >= 0 ? -1 :
478
current + h2 >= 0 ? 0 : 1);
481
/* Define the default implementation of ImageType 3 processing. */
482
static IMAGE3X_MAKE_MID_PROC(make_midx_default); /* check prototype */
484
make_midx_default(gx_device **pmidev, gx_device *dev, int width, int height,
485
int depth, gs_memory_t *mem)
487
const gx_device_memory *mdproto = gdev_mem_device_for_bits(depth);
488
gx_device_memory *midev;
492
if (height > max_ulong/width) /* protect against overflow in bitmap size */
493
return_error(gs_error_VMerror);
495
return_error(gs_error_rangecheck);
496
midev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
499
return_error(gs_error_VMerror);
500
gs_make_mem_device(midev, mdproto, mem, 0, NULL);
501
midev->bitmap_memory = mem;
502
midev->width = width;
503
midev->height = height;
504
check_device_separable((gx_device *)midev);
505
gx_device_fill_in_procs((gx_device *)midev);
506
code = dev_proc(midev, open_device)((gx_device *)midev);
508
gs_free_object(mem, midev, "make_midx_default");
511
midev->is_open = true;
512
dev_proc(midev, fill_rectangle)
513
((gx_device *)midev, 0, 0, width, height, (gx_color_index)0);
514
*pmidev = (gx_device *)midev;
517
static IMAGE3X_MAKE_MCDE_PROC(make_mcdex_default); /* check prototype */
519
make_mcdex_default(gx_device *dev, const gs_imager_state *pis,
520
const gs_matrix *pmat, const gs_image_common_t *pic,
521
const gs_int_rect *prect, const gx_drawing_color *pdcolor,
522
const gx_clip_path *pcpath, gs_memory_t *mem,
523
gx_image_enum_common_t **pinfo,
524
gx_device **pmcdev, gx_device *midev[2],
525
gx_image_enum_common_t *pminfo[2],
526
const gs_int_point origin[2],
527
const gs_image3x_t *pim)
529
/**************** NYI ****************/
531
* There is no soft-mask analogue of make_mcde_default, because
532
* soft-mask clipping is a more complicated operation, implemented
533
* by the general transparency code. As a default, we simply ignore
534
* the soft mask. However, we have to create an intermediate device
535
* that can be freed at the end and that simply forwards all calls.
536
* The most convenient device for this purpose is the bbox device.
538
gx_device_bbox *bbdev =
539
gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox,
540
"make_mcdex_default");
544
return_error(gs_error_VMerror);
545
gx_device_bbox_init(bbdev, dev, mem);
546
gx_device_bbox_fwd_open_close(bbdev, false);
547
code = dev_proc(bbdev, begin_typed_image)
548
((gx_device *)bbdev, pis, pmat, pic, prect, pdcolor, pcpath, mem,
551
gs_free_object(mem, bbdev, "make_mcdex_default");
554
*pmcdev = (gx_device *)bbdev;
558
gx_begin_image3x(gx_device * dev,
559
const gs_imager_state * pis, const gs_matrix * pmat,
560
const gs_image_common_t * pic, const gs_int_rect * prect,
561
const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
562
gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
564
return gx_begin_image3x_generic(dev, pis, pmat, pic, prect, pdcolor,
565
pcpath, mem, make_midx_default,
566
make_mcdex_default, pinfo);
569
/* Process the next piece of an ImageType 3 image. */
571
gx_image3x_plane_data(gx_image_enum_common_t * info,
572
const gx_image_plane_t * planes, int height,
575
gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
576
int pixel_height = penum->pixel.height;
580
int h1 = pixel_height - penum->pixel.y;
582
const gx_image_plane_t *pixel_planes;
583
gx_image_plane_t pixel_plane, mask_plane[2];
588
for (i = 0; i < NUM_MASKS; ++i) {
589
int mh = mask_height[i] = penum->mask[i].height;
591
mask_plane[i].data = 0;
593
if (!penum->mask[i].depth)
595
h1 = min(h1, mh - penum->mask[i].y);
596
if (penum->mask[i].InterleaveType == interleave_chunky)
600
/* Initialized rows_used in case we get an error. */
605
/* Handle masks from separate sources. */
606
for (i = 0; i < NUM_MASKS; ++i)
607
if (penum->mask[i].InterleaveType == interleave_separate_source) {
609
* In order to be able to recover from interruptions, we must
610
* limit separate-source processing to 1 scan line at a time.
614
mask_plane[i] = planes[pi++];
616
pixel_planes = &planes[pi];
618
/* Handle chunky masks. */
620
int bpc = penum->bpc;
621
int num_components = penum->num_components;
622
int width = penum->pixel.width;
623
/* Pull apart the source data and the mask data. */
624
/* We do this in the simplest (not fastest) way for now. */
625
uint bit_x = bpc * (num_components + num_chunky) * planes[pi].data_x;
626
sample_load_declare_setup(sptr, sbit, planes[0].data + (bit_x >> 3),
628
sample_store_declare_setup(pptr, pbit, pbbyte,
629
penum->pixel.data, 0, bpc);
630
sample_store_declare(dptr[NUM_MASKS], dbit[NUM_MASKS],
632
int depth[NUM_MASKS];
636
/* Do the operation one row at a time. */
639
for (i = 0; i < NUM_MASKS; ++i)
640
if (penum->mask[i].data) {
641
depth[i] = penum->mask[i].depth;
642
mask_plane[i].data = dptr[i] = penum->mask[i].data;
643
mask_plane[i].data_x = 0;
644
/* raster doesn't matter */
645
sample_store_setup(dbit[i], 0, depth[i]);
646
sample_store_preload(dbbyte[i], dptr[i], 0, depth[i]);
649
pixel_plane.data = pptr;
650
pixel_plane.data_x = 0;
651
/* raster doesn't matter */
652
pixel_planes = &pixel_plane;
653
for (x = 0; x < width; ++x) {
656
for (i = 0; i < NUM_MASKS; ++i)
658
sample_load_next12(value, sptr, sbit, bpc);
659
sample_store_next12(value, dptr[i], dbit[i], depth[i],
662
for (i = 0; i < num_components; ++i) {
663
sample_load_next12(value, sptr, sbit, bpc);
664
sample_store_next12(value, pptr, pbit, bpc, pbbyte);
667
for (i = 0; i < NUM_MASKS; ++i)
668
if (penum->mask[i].data)
669
sample_store_flush(dptr[i], dbit[i], depth[i], dbbyte[i]);
670
sample_store_flush(pptr, pbit, bpc, pbbyte);
673
* Process the mask data first, so it will set up the mask
674
* device for clipping the pixel data.
676
for (i = 0; i < NUM_MASKS; ++i)
677
if (mask_plane[i].data) {
679
* If, on the last call, we processed some mask rows
680
* successfully but processing the pixel rows was interrupted,
681
* we set rows_used to indicate the number of pixel rows
682
* processed (since there is no way to return two rows_used
683
* values). If this happened, some mask rows may get presented
684
* again. We must skip over them rather than processing them
687
int skip = penum->mask[i].skip;
690
penum->mask[i].skip = skip - (mask_used[i] = h);
692
int mask_h = h - skip;
694
mask_plane[i].data += skip * mask_plane[i].raster;
695
penum->mask[i].skip = 0;
696
code = gx_image_plane_data_rows(penum->mask[i].info,
698
mask_h, &mask_used[i]);
699
mask_used[i] += skip;
701
*rows_used = mask_used[i];
702
penum->mask[i].y += mask_used[i];
706
if (pixel_planes[0].data) {
708
* If necessary, flush any buffered mask data to the mask clipping
711
for (i = 0; i < NUM_MASKS; ++i)
712
if (penum->mask[i].info)
713
gx_image_flush(penum->mask[i].info);
714
code = gx_image_plane_data_rows(penum->pixel.info, pixel_planes, h,
717
* There isn't any way to set rows_used if different amounts of
718
* the mask and pixel data were used. Fake it.
720
*rows_used = pixel_used;
722
* Don't return code yet: we must account for the fact that
723
* some mask data may have been processed.
725
penum->pixel.y += pixel_used;
728
* We must prevent the mask data from being processed again.
729
* We rely on the fact that h > 1 is only possible if the
730
* mask and pixel data have the same Y scaling.
732
for (i = 0; i < NUM_MASKS; ++i)
733
if (mask_used[i] > pixel_used) {
734
int skip = mask_used[i] - pixel_used;
736
penum->mask[i].skip = skip;
737
penum->mask[i].y -= skip;
738
mask_used[i] = pixel_used;
742
if_debug7('b', "[b]image3x h=%d %sopacity.y=%d %sopacity.y=%d %spixel.y=%d\n",
743
h, (mask_plane[0].data ? "+" : ""), penum->mask[0].y,
744
(mask_plane[1].data ? "+" : ""), penum->mask[1].y,
745
(pixel_planes[0].data ? "+" : ""), penum->pixel.y);
746
if (penum->mask[0].depth == 0 || penum->mask[0].y >= penum->mask[0].height) {
747
if (penum->mask[1].depth == 0 || penum->mask[1].y >= penum->mask[1].height) {
748
if (penum->pixel.y >= penum->pixel.height) {
754
* The mask may be complete (gx_image_plane_data_rows returned 1),
755
* but there may still be pixel rows to go, so don't return 1 here.
757
return (code < 0 ? code : 0);
760
/* Flush buffered data. */
762
gx_image3x_flush(gx_image_enum_common_t * info)
764
gx_image3x_enum_t * const penum = (gx_image3x_enum_t *) info;
765
int code = gx_image_flush(penum->mask[0].info);
768
code = gx_image_flush(penum->mask[1].info);
770
code = gx_image_flush(penum->pixel.info);
774
/* Determine which data planes are wanted. */
776
gx_image3x_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
778
const gx_image3x_enum_t * const penum = (const gx_image3x_enum_t *) info;
780
* We always want at least as much of the mask(s) to be filled as the
784
sso = penum->mask[0].InterleaveType == interleave_separate_source,
785
sss = penum->mask[1].InterleaveType == interleave_separate_source;
788
/* Both masks have separate sources. */
789
int mask_next = channel_next(&penum->mask[1], &penum->pixel);
791
memset(wanted + 2, (mask_next <= 0 ? 0xff : 0), info->num_planes - 2);
792
wanted[1] = (mask_next >= 0 ? 0xff : 0);
794
mask_next = channel_next(&penum->mask[0], &penum->mask[1]);
795
wanted[0] = mask_next >= 0;
798
return false; /* see below */
799
} else if (sso | sss) {
800
/* Only one separate source. */
801
const image3x_channel_state_t *pics =
802
(sso ? &penum->mask[0] : &penum->mask[1]);
803
int mask_next = channel_next(pics, &penum->pixel);
805
wanted[0] = (mask_next >= 0 ? 0xff : 0);
806
memset(wanted + 1, (mask_next <= 0 ? 0xff : 0), info->num_planes - 1);
808
* In principle, wanted will always be true for both mask and pixel
809
* data if the full_heights are equal. Unfortunately, even in this
810
* case, processing may be interrupted after a mask row has been
811
* passed to the underlying image processor but before the data row
812
* has been passed, in which case pixel data will be 'wanted', but
813
* not mask data, for the next call. Therefore, we must return
818
pics->full_height == penum->pixel.full_height)*/;
820
/* Everything is chunky, only 1 plane. */
826
/* Clean up after processing an ImageType 3x image. */
828
gx_image3x_end_image(gx_image_enum_common_t * info, bool draw_last)
830
gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
831
gs_memory_t *mem = penum->memory;
832
gx_device *mdev0 = penum->mask[0].mdev;
834
(penum->mask[0].info ? gx_image_end(penum->mask[0].info, draw_last) :
836
gx_device *mdev1 = penum->mask[1].mdev;
838
(penum->mask[1].info ? gx_image_end(penum->mask[1].info, draw_last) :
840
gx_device *pcdev = penum->pcdev;
841
int pcode = gx_image_end(penum->pixel.info, draw_last);
843
gs_closedevice(pcdev);
845
gs_closedevice(mdev0);
847
gs_closedevice(mdev1);
848
gs_free_object(mem, penum->mask[0].data,
849
"gx_image3x_end_image(mask[0].data)");
850
gs_free_object(mem, penum->mask[1].data,
851
"gx_image3x_end_image(mask[1].data)");
852
gs_free_object(mem, penum->pixel.data,
853
"gx_image3x_end_image(pixel.data)");
854
gs_free_object(mem, pcdev, "gx_image3x_end_image(pcdev)");
855
gs_free_object(mem, mdev0, "gx_image3x_end_image(mask[0].mdev)");
856
gs_free_object(mem, mdev1, "gx_image3x_end_image(mask[1].mdev)");
857
gx_image_free_enum(&info);
858
return (pcode < 0 ? pcode : scode < 0 ? scode : ocode);