2 |
- |
1 |
/* Copyright (C) 2000 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: gximag3x.c,v 1.20 2004/09/16 08:03:56 igor Exp $ */
|
|
|
18 |
/* ImageType 3x image implementation */
|
|
|
19 |
/****** THE REAL WORK IS NYI ******/
|
|
|
20 |
#include "math_.h" /* for ceil, floor */
|
|
|
21 |
#include "memory_.h"
|
|
|
22 |
#include "gx.h"
|
|
|
23 |
#include "gserrors.h"
|
|
|
24 |
#include "gsbitops.h"
|
|
|
25 |
#include "gscspace.h"
|
|
|
26 |
#include "gscpixel.h"
|
|
|
27 |
#include "gsstruct.h"
|
|
|
28 |
#include "gxdevice.h"
|
|
|
29 |
#include "gxdevmem.h"
|
|
|
30 |
#include "gximag3x.h"
|
|
|
31 |
#include "gxistate.h"
|
|
|
32 |
#include "gdevbbox.h"
|
|
|
33 |
|
|
|
34 |
extern_st(st_color_space);
|
|
|
35 |
|
|
|
36 |
/* Forward references */
|
|
|
37 |
private dev_proc_begin_typed_image(gx_begin_image3x);
|
|
|
38 |
private image_enum_proc_plane_data(gx_image3x_plane_data);
|
|
|
39 |
private image_enum_proc_end_image(gx_image3x_end_image);
|
|
|
40 |
private image_enum_proc_flush(gx_image3x_flush);
|
|
|
41 |
private image_enum_proc_planes_wanted(gx_image3x_planes_wanted);
|
|
|
42 |
|
|
|
43 |
/* GC descriptor */
|
|
|
44 |
private_st_gs_image3x();
|
|
|
45 |
|
|
|
46 |
/* Define the image type for ImageType 3x images. */
|
|
|
47 |
const gx_image_type_t gs_image_type_3x = {
|
|
|
48 |
&st_gs_image3x, gx_begin_image3x, gx_data_image_source_size,
|
|
|
49 |
gx_image_no_sput, gx_image_no_sget, gx_image_default_release,
|
|
|
50 |
IMAGE3X_IMAGETYPE
|
|
|
51 |
};
|
|
|
52 |
private const gx_image_enum_procs_t image3x_enum_procs = {
|
|
|
53 |
gx_image3x_plane_data, gx_image3x_end_image,
|
|
|
54 |
gx_image3x_flush, gx_image3x_planes_wanted
|
|
|
55 |
};
|
|
|
56 |
|
|
|
57 |
/* Initialize an ImageType 3x image. */
|
|
|
58 |
private void
|
|
|
59 |
gs_image3x_mask_init(gs_image3x_mask_t *pimm)
|
|
|
60 |
{
|
|
|
61 |
pimm->InterleaveType = 0; /* not a valid type */
|
|
|
62 |
pimm->has_Matte = false;
|
|
|
63 |
gs_data_image_t_init(&pimm->MaskDict, 1);
|
|
|
64 |
pimm->MaskDict.BitsPerComponent = 0; /* not supplied */
|
|
|
65 |
}
|
|
|
66 |
void
|
|
|
67 |
gs_image3x_t_init(gs_image3x_t * pim, const gs_color_space * color_space)
|
|
|
68 |
{
|
|
|
69 |
gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
|
|
|
70 |
pim->type = &gs_image_type_3x;
|
|
|
71 |
gs_image3x_mask_init(&pim->Opacity);
|
|
|
72 |
gs_image3x_mask_init(&pim->Shape);
|
|
|
73 |
}
|
|
|
74 |
|
|
|
75 |
/*
|
|
|
76 |
* We implement ImageType 3 images by interposing a mask clipper in
|
|
|
77 |
* front of an ordinary ImageType 1 image. Note that we build up the
|
|
|
78 |
* mask row-by-row as we are processing the image.
|
|
|
79 |
*
|
|
|
80 |
* We export a generalized form of the begin_image procedure for use by
|
|
|
81 |
* the PDF and PostScript writers.
|
|
|
82 |
*/
|
|
|
83 |
|
|
|
84 |
typedef struct image3x_channel_state_s {
|
|
|
85 |
gx_image_enum_common_t *info;
|
|
|
86 |
gx_device *mdev; /* gx_device_memory in default impl. */
|
|
|
87 |
/* (only for masks) */
|
|
|
88 |
gs_image3_interleave_type_t InterleaveType;
|
|
|
89 |
int width, height, full_height, depth;
|
|
|
90 |
byte *data; /* (if chunky) */
|
|
|
91 |
/* Only the following change dynamically. */
|
|
|
92 |
int y;
|
|
|
93 |
int skip; /* only for masks, # of rows to skip, */
|
|
|
94 |
/* see below */
|
|
|
95 |
} image3x_channel_state_t;
|
|
|
96 |
typedef struct gx_image3x_enum_s {
|
|
|
97 |
gx_image_enum_common;
|
|
|
98 |
gx_device *pcdev; /* gx_device_mask_clip in default impl. */
|
|
|
99 |
int num_components; /* (not counting masks) */
|
|
|
100 |
int bpc; /* pixel BitsPerComponent */
|
|
|
101 |
gs_memory_t *memory;
|
|
|
102 |
#define NUM_MASKS 2 /* opacity, shape */
|
|
|
103 |
image3x_channel_state_t mask[NUM_MASKS], pixel;
|
|
|
104 |
} gx_image3x_enum_t;
|
|
|
105 |
|
|
|
106 |
extern_st(st_gx_image_enum_common);
|
|
|
107 |
gs_private_st_suffix_add9(st_image3x_enum, gx_image3x_enum_t,
|
|
|
108 |
"gx_image3x_enum_t", image3x_enum_enum_ptrs, image3x_enum_reloc_ptrs,
|
|
|
109 |
st_gx_image_enum_common, pcdev, mask[0].info, mask[0].mdev, mask[0].data,
|
|
|
110 |
mask[1].info, mask[1].mdev, mask[1].data, pixel.info, pixel.data);
|
|
|
111 |
|
|
|
112 |
/*
|
|
|
113 |
* Begin a generic ImageType 3x image, with client handling the creation of
|
|
|
114 |
* the mask image and mask clip devices.
|
|
|
115 |
*/
|
|
|
116 |
typedef struct image3x_channel_values_s {
|
|
|
117 |
gs_matrix matrix;
|
|
|
118 |
gs_point corner;
|
|
|
119 |
gs_int_rect rect;
|
|
|
120 |
gs_image_t image;
|
|
|
121 |
} image3x_channel_values_t;
|
|
|
122 |
private int check_image3x_mask(const gs_image3x_t *pim,
|
|
|
123 |
const gs_image3x_mask_t *pimm,
|
|
|
124 |
const image3x_channel_values_t *ppcv,
|
|
|
125 |
image3x_channel_values_t *pmcv,
|
|
|
126 |
image3x_channel_state_t *pmcs,
|
|
|
127 |
gs_memory_t *mem);
|
|
|
128 |
int
|
|
|
129 |
gx_begin_image3x_generic(gx_device * dev,
|
|
|
130 |
const gs_imager_state *pis, const gs_matrix *pmat,
|
|
|
131 |
const gs_image_common_t *pic, const gs_int_rect *prect,
|
|
|
132 |
const gx_drawing_color *pdcolor,
|
|
|
133 |
const gx_clip_path *pcpath, gs_memory_t *mem,
|
|
|
134 |
image3x_make_mid_proc_t make_mid,
|
|
|
135 |
image3x_make_mcde_proc_t make_mcde,
|
|
|
136 |
gx_image_enum_common_t **pinfo)
|
|
|
137 |
{
|
|
|
138 |
const gs_image3x_t *pim = (const gs_image3x_t *)pic;
|
|
|
139 |
gx_image3x_enum_t *penum;
|
|
|
140 |
gx_device *pcdev = 0;
|
|
|
141 |
image3x_channel_values_t mask[2], pixel;
|
|
|
142 |
gs_matrix mat;
|
|
|
143 |
gx_device *midev[2];
|
|
|
144 |
gx_image_enum_common_t *minfo[2];
|
|
|
145 |
gs_int_point origin[2];
|
|
|
146 |
int code;
|
|
|
147 |
int i;
|
|
|
148 |
|
|
|
149 |
/* Validate the parameters. */
|
|
|
150 |
if (pim->Height <= 0)
|
|
|
151 |
return_error(gs_error_rangecheck);
|
|
|
152 |
penum = gs_alloc_struct(mem, gx_image3x_enum_t, &st_image3x_enum,
|
|
|
153 |
"gx_begin_image3x");
|
|
|
154 |
if (penum == 0)
|
|
|
155 |
return_error(gs_error_VMerror);
|
|
|
156 |
/* Initialize pointers now in case we bail out. */
|
|
|
157 |
penum->mask[0].info = 0, penum->mask[0].mdev = 0, penum->mask[0].data = 0;
|
|
|
158 |
penum->mask[1].info = 0, penum->mask[1].mdev = 0, penum->mask[1].data = 0;
|
|
|
159 |
penum->pixel.info = 0, penum->pixel.data = 0;
|
|
|
160 |
if (prect)
|
|
|
161 |
pixel.rect = *prect;
|
|
|
162 |
else {
|
|
|
163 |
pixel.rect.p.x = pixel.rect.p.y = 0;
|
|
|
164 |
pixel.rect.q.x = pim->Width;
|
|
|
165 |
pixel.rect.q.y = pim->Height;
|
|
|
166 |
}
|
|
|
167 |
if ((code = gs_matrix_invert(&pim->ImageMatrix, &pixel.matrix)) < 0 ||
|
|
|
168 |
(code = gs_point_transform(pim->Width, pim->Height, &pixel.matrix,
|
|
|
169 |
&pixel.corner)) < 0 ||
|
|
|
170 |
(code = check_image3x_mask(pim, &pim->Opacity, &pixel, &mask[0],
|
|
|
171 |
&penum->mask[0], mem)) < 0 ||
|
|
|
172 |
(code = check_image3x_mask(pim, &pim->Shape, &pixel, &mask[1],
|
|
|
173 |
&penum->mask[1], mem)) < 0
|
|
|
174 |
) {
|
|
|
175 |
goto out0;
|
|
|
176 |
}
|
|
|
177 |
penum->num_components =
|
|
|
178 |
gs_color_space_num_components(pim->ColorSpace);
|
|
|
179 |
gx_image_enum_common_init((gx_image_enum_common_t *) penum,
|
|
|
180 |
(const gs_data_image_t *)pim,
|
|
|
181 |
&image3x_enum_procs, dev,
|
|
|
182 |
1 + penum->num_components,
|
|
|
183 |
pim->format);
|
|
|
184 |
penum->pixel.width = pixel.rect.q.x - pixel.rect.p.x;
|
|
|
185 |
penum->pixel.height = pixel.rect.q.y - pixel.rect.p.y;
|
|
|
186 |
penum->pixel.full_height = pim->Height;
|
|
|
187 |
penum->pixel.y = 0;
|
|
|
188 |
if (penum->mask[0].data || penum->mask[1].data) {
|
|
|
189 |
/* Also allocate a row buffer for the pixel data. */
|
|
|
190 |
penum->pixel.data =
|
|
|
191 |
gs_alloc_bytes(mem,
|
|
|
192 |
(penum->pixel.width * pim->BitsPerComponent *
|
|
|
193 |
penum->num_components + 7) >> 3,
|
|
|
194 |
"gx_begin_image3x(pixel.data)");
|
|
|
195 |
if (penum->pixel.data == 0) {
|
|
|
196 |
code = gs_note_error(gs_error_VMerror);
|
|
|
197 |
goto out1;
|
|
|
198 |
}
|
|
|
199 |
}
|
|
|
200 |
penum->bpc = pim->BitsPerComponent;
|
|
|
201 |
penum->memory = mem;
|
|
|
202 |
if (pmat == 0)
|
|
|
203 |
pmat = &ctm_only(pis);
|
|
|
204 |
for (i = 0; i < NUM_MASKS; ++i) {
|
|
|
205 |
gs_rect mrect;
|
|
|
206 |
gx_device *mdev;
|
|
|
207 |
/*
|
|
|
208 |
* The mask data has to be defined in a DevicePixel color space
|
|
|
209 |
* of the correct depth so that no color mapping will occur.
|
|
|
210 |
*/
|
|
|
211 |
/****** FREE COLOR SPACE ON ERROR OR AT END ******/
|
|
|
212 |
gs_color_space *pmcs;
|
|
|
213 |
|
|
|
214 |
if (penum->mask[i].depth == 0) { /* mask not supplied */
|
|
|
215 |
midev[i] = 0;
|
|
|
216 |
minfo[i] = 0;
|
|
|
217 |
continue;
|
|
|
218 |
}
|
|
|
219 |
pmcs = gs_alloc_struct(mem, gs_color_space, &st_color_space,
|
|
|
220 |
"gx_begin_image3x_generic");
|
|
|
221 |
if (pmcs == 0)
|
|
|
222 |
return_error(gs_error_VMerror);
|
|
|
223 |
gs_cspace_init_DevicePixel(mem, pmcs, penum->mask[i].depth);
|
|
|
224 |
mrect.p.x = mrect.p.y = 0;
|
|
|
225 |
mrect.q.x = penum->mask[i].width;
|
|
|
226 |
mrect.q.y = penum->mask[i].height;
|
|
|
227 |
if ((code = gs_matrix_multiply(&mask[i].matrix, pmat, &mat)) < 0 ||
|
|
|
228 |
(code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
|
|
|
229 |
)
|
|
|
230 |
return code;
|
|
|
231 |
origin[i].x = (int)floor(mrect.p.x);
|
|
|
232 |
origin[i].y = (int)floor(mrect.p.y);
|
|
|
233 |
code = make_mid(&mdev, dev,
|
|
|
234 |
(int)ceil(mrect.q.x) - origin[i].x,
|
|
|
235 |
(int)ceil(mrect.q.y) - origin[i].y,
|
|
|
236 |
penum->mask[i].depth, mem);
|
|
|
237 |
if (code < 0)
|
|
|
238 |
goto out1;
|
|
|
239 |
penum->mask[i].mdev = mdev;
|
|
|
240 |
gs_image_t_init(&mask[i].image, pmcs);
|
|
|
241 |
mask[i].image.ColorSpace = pmcs;
|
|
|
242 |
mask[i].image.adjust = false;
|
|
|
243 |
{
|
|
|
244 |
const gx_image_type_t *type1 = mask[i].image.type;
|
|
|
245 |
const gs_image3x_mask_t *pixm =
|
|
|
246 |
(i == 0 ? &pim->Opacity : &pim->Shape);
|
|
|
247 |
|
|
|
248 |
*(gs_data_image_t *)&mask[i].image = pixm->MaskDict;
|
|
|
249 |
mask[i].image.type = type1;
|
|
|
250 |
mask[i].image.BitsPerComponent = pixm->MaskDict.BitsPerComponent;
|
|
|
251 |
}
|
|
|
252 |
{
|
|
|
253 |
gs_matrix m_mat;
|
|
|
254 |
|
|
|
255 |
/*
|
|
|
256 |
* Adjust the translation for rendering the mask to include a
|
|
|
257 |
* negative translation by origin.{x,y} in device space.
|
|
|
258 |
*/
|
|
|
259 |
m_mat = *pmat;
|
|
|
260 |
m_mat.tx -= origin[i].x;
|
|
|
261 |
m_mat.ty -= origin[i].y;
|
|
|
262 |
/*
|
|
|
263 |
* Note that pis = NULL here, since we don't want to have to
|
|
|
264 |
* create another imager state with default log_op, etc.
|
|
|
265 |
* dcolor = NULL is OK because this is an opaque image with
|
|
|
266 |
* CombineWithColor = false.
|
|
|
267 |
*/
|
|
|
268 |
code = gx_device_begin_typed_image(mdev, NULL, &m_mat,
|
|
|
269 |
(const gs_image_common_t *)&mask[i].image,
|
|
|
270 |
&mask[i].rect, NULL, NULL,
|
|
|
271 |
mem, &penum->mask[i].info);
|
|
|
272 |
if (code < 0)
|
|
|
273 |
goto out2;
|
|
|
274 |
}
|
|
|
275 |
midev[i] = mdev;
|
|
|
276 |
minfo[i] = penum->mask[i].info;
|
|
|
277 |
}
|
|
|
278 |
gs_image_t_init(&pixel.image, pim->ColorSpace);
|
|
|
279 |
{
|
|
|
280 |
const gx_image_type_t *type1 = pixel.image.type;
|
|
|
281 |
|
|
|
282 |
*(gs_pixel_image_t *)&pixel.image = *(const gs_pixel_image_t *)pim;
|
|
|
283 |
pixel.image.type = type1;
|
|
|
284 |
}
|
|
|
285 |
code = make_mcde(dev, pis, pmat, (const gs_image_common_t *)&pixel.image,
|
|
|
286 |
prect, pdcolor, pcpath, mem, &penum->pixel.info,
|
|
|
287 |
&pcdev, midev, minfo, origin, pim);
|
|
|
288 |
if (code < 0)
|
|
|
289 |
goto out3;
|
|
|
290 |
penum->pcdev = pcdev;
|
|
|
291 |
/*
|
|
|
292 |
* Set num_planes, plane_widths, and plane_depths from the values in the
|
|
|
293 |
* enumerators for the mask(s) and the image data.
|
|
|
294 |
*/
|
|
|
295 |
{
|
|
|
296 |
int added_depth = 0;
|
|
|
297 |
int pi = 0;
|
|
|
298 |
|
|
|
299 |
for (i = 0; i < NUM_MASKS; ++i) {
|
|
|
300 |
if (penum->mask[i].depth == 0) /* no mask */
|
|
|
301 |
continue;
|
|
|
302 |
switch (penum->mask[i].InterleaveType) {
|
|
|
303 |
case interleave_chunky:
|
|
|
304 |
/* Add the mask data to the depth of the image data. */
|
|
|
305 |
added_depth += pim->BitsPerComponent;
|
|
|
306 |
break;
|
|
|
307 |
case interleave_separate_source:
|
|
|
308 |
/* Insert the mask as a separate plane. */
|
|
|
309 |
penum->plane_widths[pi] = penum->mask[i].width;
|
|
|
310 |
penum->plane_depths[pi] = penum->mask[i].depth;
|
|
|
311 |
++pi;
|
|
|
312 |
break;
|
|
|
313 |
default: /* can't happen */
|
|
|
314 |
code = gs_note_error(gs_error_Fatal);
|
|
|
315 |
goto out3;
|
|
|
316 |
}
|
|
|
317 |
}
|
|
|
318 |
memcpy(&penum->plane_widths[pi], &penum->pixel.info->plane_widths[0],
|
|
|
319 |
penum->pixel.info->num_planes * sizeof(penum->plane_widths[0]));
|
|
|
320 |
memcpy(&penum->plane_depths[pi], &penum->pixel.info->plane_depths[0],
|
|
|
321 |
penum->pixel.info->num_planes * sizeof(penum->plane_depths[0]));
|
|
|
322 |
penum->plane_depths[pi] += added_depth;
|
|
|
323 |
penum->num_planes = pi + penum->pixel.info->num_planes;
|
|
|
324 |
}
|
|
|
325 |
if (midev[0])
|
|
|
326 |
gx_device_retain(midev[0], true); /* will free explicitly */
|
|
|
327 |
if (midev[1])
|
|
|
328 |
gx_device_retain(midev[1], true); /* ditto */
|
|
|
329 |
gx_device_retain(pcdev, true); /* ditto */
|
|
|
330 |
*pinfo = (gx_image_enum_common_t *) penum;
|
|
|
331 |
return 0;
|
|
|
332 |
out3:
|
|
|
333 |
if (penum->mask[1].info)
|
|
|
334 |
gx_image_end(penum->mask[1].info, false);
|
|
|
335 |
if (penum->mask[0].info)
|
|
|
336 |
gx_image_end(penum->mask[0].info, false);
|
|
|
337 |
out2:
|
|
|
338 |
if (penum->mask[1].mdev) {
|
|
|
339 |
gs_closedevice(penum->mask[1].mdev);
|
|
|
340 |
gs_free_object(mem, penum->mask[1].mdev,
|
|
|
341 |
"gx_begin_image3x(mask[1].mdev)");
|
|
|
342 |
}
|
|
|
343 |
if (penum->mask[0].mdev) {
|
|
|
344 |
gs_closedevice(penum->mask[0].mdev);
|
|
|
345 |
gs_free_object(mem, penum->mask[0].mdev,
|
|
|
346 |
"gx_begin_image3x(mask[0].mdev)");
|
|
|
347 |
}
|
|
|
348 |
out1:
|
|
|
349 |
gs_free_object(mem, penum->mask[0].data, "gx_begin_image3x(mask[0].data)");
|
|
|
350 |
gs_free_object(mem, penum->mask[1].data, "gx_begin_image3x(mask[1].data)");
|
|
|
351 |
gs_free_object(mem, penum->pixel.data, "gx_begin_image3x(pixel.data)");
|
|
|
352 |
out0:
|
|
|
353 |
gs_free_object(mem, penum, "gx_begin_image3x");
|
|
|
354 |
return code;
|
|
|
355 |
}
|
|
|
356 |
private bool
|
|
|
357 |
check_image3x_extent(floatp mask_coeff, floatp data_coeff)
|
|
|
358 |
{
|
|
|
359 |
if (mask_coeff == 0)
|
|
|
360 |
return data_coeff == 0;
|
|
|
361 |
if (data_coeff == 0 || (mask_coeff > 0) != (data_coeff > 0))
|
|
|
362 |
return false;
|
|
|
363 |
return true;
|
|
|
364 |
}
|
|
|
365 |
/*
|
|
|
366 |
* Check mask parameters.
|
|
|
367 |
* Reads ppcv->{matrix,corner,rect}, sets pmcv->{matrix,corner,rect} and
|
|
|
368 |
* pmcs->{InterleaveType,width,height,full_height,depth,data,y,skip}.
|
|
|
369 |
* If the mask is omitted, sets pmcs->depth = 0 and returns normally.
|
|
|
370 |
*/
|
|
|
371 |
private bool
|
|
|
372 |
check_image3x_mask(const gs_image3x_t *pim, const gs_image3x_mask_t *pimm,
|
|
|
373 |
const image3x_channel_values_t *ppcv,
|
|
|
374 |
image3x_channel_values_t *pmcv,
|
|
|
375 |
image3x_channel_state_t *pmcs, gs_memory_t *mem)
|
|
|
376 |
{
|
|
|
377 |
int mask_width = pimm->MaskDict.Width, mask_height = pimm->MaskDict.Height;
|
|
|
378 |
int code;
|
|
|
379 |
|
|
|
380 |
if (pimm->MaskDict.BitsPerComponent == 0) { /* mask missing */
|
|
|
381 |
pmcs->depth = 0;
|
|
|
382 |
pmcs->InterleaveType = 0; /* not a valid type */
|
|
|
383 |
return 0;
|
|
|
384 |
}
|
|
|
385 |
if (mask_height <= 0)
|
|
|
386 |
return_error(gs_error_rangecheck);
|
|
|
387 |
switch (pimm->InterleaveType) {
|
|
|
388 |
/*case interleave_scan_lines:*/ /* not supported */
|
|
|
389 |
default:
|
|
|
390 |
return_error(gs_error_rangecheck);
|
|
|
391 |
case interleave_chunky:
|
|
|
392 |
if (mask_width != pim->Width ||
|
|
|
393 |
mask_height != pim->Height ||
|
|
|
394 |
pimm->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
|
|
|
395 |
pim->format != gs_image_format_chunky
|
|
|
396 |
)
|
|
|
397 |
return_error(gs_error_rangecheck);
|
|
|
398 |
break;
|
|
|
399 |
case interleave_separate_source:
|
|
|
400 |
switch (pimm->MaskDict.BitsPerComponent) {
|
|
|
401 |
case 1: case 2: case 4: case 8:
|
|
|
402 |
break;
|
|
|
403 |
default:
|
|
|
404 |
return_error(gs_error_rangecheck);
|
|
|
405 |
}
|
|
|
406 |
}
|
|
|
407 |
if (!check_image3x_extent(pim->ImageMatrix.xx,
|
|
|
408 |
pimm->MaskDict.ImageMatrix.xx) ||
|
|
|
409 |
!check_image3x_extent(pim->ImageMatrix.xy,
|
|
|
410 |
pimm->MaskDict.ImageMatrix.xy) ||
|
|
|
411 |
!check_image3x_extent(pim->ImageMatrix.yx,
|
|
|
412 |
pimm->MaskDict.ImageMatrix.yx) ||
|
|
|
413 |
!check_image3x_extent(pim->ImageMatrix.yy,
|
|
|
414 |
pimm->MaskDict.ImageMatrix.yy)
|
|
|
415 |
)
|
|
|
416 |
return_error(gs_error_rangecheck);
|
|
|
417 |
if ((code = gs_matrix_invert(&pimm->MaskDict.ImageMatrix, &pmcv->matrix)) < 0 ||
|
|
|
418 |
(code = gs_point_transform(mask_width, mask_height,
|
|
|
419 |
&pmcv->matrix, &pmcv->corner)) < 0
|
|
|
420 |
)
|
|
|
421 |
return code;
|
|
|
422 |
if (fabs(ppcv->matrix.tx - pmcv->matrix.tx) >= 0.5 ||
|
|
|
423 |
fabs(ppcv->matrix.ty - pmcv->matrix.ty) >= 0.5 ||
|
|
|
424 |
fabs(ppcv->corner.x - pmcv->corner.x) >= 0.5 ||
|
|
|
425 |
fabs(ppcv->corner.y - pmcv->corner.y) >= 0.5
|
|
|
426 |
)
|
|
|
427 |
return_error(gs_error_rangecheck);
|
|
|
428 |
pmcv->rect.p.x = ppcv->rect.p.x * mask_width / pim->Width;
|
|
|
429 |
pmcv->rect.p.y = ppcv->rect.p.y * mask_height / pim->Height;
|
|
|
430 |
pmcv->rect.q.x = (ppcv->rect.q.x * mask_width + pim->Width - 1) /
|
|
|
431 |
pim->Width;
|
|
|
432 |
pmcv->rect.q.y = (ppcv->rect.q.y * mask_height + pim->Height - 1) /
|
|
|
433 |
pim->Height;
|
|
|
434 |
/* Initialize the channel state in the enumerator. */
|
|
|
435 |
pmcs->InterleaveType = pimm->InterleaveType;
|
|
|
436 |
pmcs->width = pmcv->rect.q.x - pmcv->rect.p.x;
|
|
|
437 |
pmcs->height = pmcv->rect.q.y - pmcv->rect.p.y;
|
|
|
438 |
pmcs->full_height = pimm->MaskDict.Height;
|
|
|
439 |
pmcs->depth = pimm->MaskDict.BitsPerComponent;
|
|
|
440 |
if (pmcs->InterleaveType == interleave_chunky) {
|
|
|
441 |
/* Allocate a buffer for the data. */
|
|
|
442 |
pmcs->data =
|
|
|
443 |
gs_alloc_bytes(mem,
|
|
|
444 |
(pmcs->width * pimm->MaskDict.BitsPerComponent + 7) >> 3,
|
|
|
445 |
"gx_begin_image3x(mask data)");
|
|
|
446 |
if (pmcs->data == 0)
|
|
|
447 |
return_error(gs_error_VMerror);
|
|
|
448 |
}
|
|
|
449 |
pmcs->y = pmcs->skip = 0;
|
|
|
450 |
return 0;
|
|
|
451 |
}
|
|
|
452 |
|
|
|
453 |
/*
|
|
|
454 |
* Return > 0 if we want more data from channel 1 now, < 0 if we want more
|
|
|
455 |
* from channel 2 now, 0 if we want both.
|
|
|
456 |
*/
|
|
|
457 |
private int
|
|
|
458 |
channel_next(const image3x_channel_state_t *pics1,
|
|
|
459 |
const image3x_channel_state_t *pics2)
|
|
|
460 |
{
|
|
|
461 |
/*
|
|
|
462 |
* The invariant we need to maintain is that we always have at least as
|
|
|
463 |
* much channel N as channel N+1 data, where N = 0 = opacity, 1 = shape,
|
|
|
464 |
* and 2 = pixel. I.e., for any two consecutive channels c1 and c2, we
|
|
|
465 |
* require c1.y / c1.full_height >= c2.y / c2.full_height, or, to avoid
|
|
|
466 |
* floating point, c1.y * c2.full_height >= c2.y * c1.full_height. We
|
|
|
467 |
* know this condition is true now; return a value that indicates how to
|
|
|
468 |
* maintain it.
|
|
|
469 |
*/
|
|
|
470 |
int h1 = pics1->full_height;
|
|
|
471 |
int h2 = pics2->full_height;
|
|
|
472 |
long current = pics1->y * (long)h2 - pics2->y * (long)h1;
|
|
|
473 |
|
|
|
474 |
#ifdef DEBUG
|
|
|
475 |
if (current < 0)
|
|
|
476 |
lprintf4("channel_next invariant fails: %d/%d < %d/%d\n",
|
|
|
477 |
pics1->y, pics1->full_height,
|
|
|
478 |
pics2->y, pics2->full_height);
|
|
|
479 |
#endif
|
|
|
480 |
return ((current -= h1) >= 0 ? -1 :
|
|
|
481 |
current + h2 >= 0 ? 0 : 1);
|
|
|
482 |
}
|
|
|
483 |
|
|
|
484 |
/* Define the default implementation of ImageType 3 processing. */
|
|
|
485 |
private IMAGE3X_MAKE_MID_PROC(make_midx_default); /* check prototype */
|
|
|
486 |
private int
|
|
|
487 |
make_midx_default(gx_device **pmidev, gx_device *dev, int width, int height,
|
|
|
488 |
int depth, gs_memory_t *mem)
|
|
|
489 |
{
|
|
|
490 |
const gx_device_memory *mdproto = gdev_mem_device_for_bits(depth);
|
|
|
491 |
gx_device_memory *midev;
|
|
|
492 |
int code;
|
|
|
493 |
|
|
|
494 |
if (mdproto == 0)
|
|
|
495 |
return_error(gs_error_rangecheck);
|
|
|
496 |
midev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
|
|
|
497 |
"make_mid_default");
|
|
|
498 |
if (midev == 0)
|
|
|
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);
|
|
|
507 |
if (code < 0) {
|
|
|
508 |
gs_free_object(mem, midev, "make_midx_default");
|
|
|
509 |
return code;
|
|
|
510 |
}
|
|
|
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;
|
|
|
515 |
return 0;
|
|
|
516 |
}
|
|
|
517 |
private IMAGE3X_MAKE_MCDE_PROC(make_mcdex_default); /* check prototype */
|
|
|
518 |
private int
|
|
|
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)
|
|
|
528 |
{
|
|
|
529 |
/**************** NYI ****************/
|
|
|
530 |
/*
|
|
|
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.
|
|
|
537 |
*/
|
|
|
538 |
gx_device_bbox *bbdev =
|
|
|
539 |
gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox,
|
|
|
540 |
"make_mcdex_default");
|
|
|
541 |
int code;
|
|
|
542 |
|
|
|
543 |
if (bbdev == 0)
|
|
|
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,
|
|
|
549 |
pinfo);
|
|
|
550 |
if (code < 0) {
|
|
|
551 |
gs_free_object(mem, bbdev, "make_mcdex_default");
|
|
|
552 |
return code;
|
|
|
553 |
}
|
|
|
554 |
*pmcdev = (gx_device *)bbdev;
|
|
|
555 |
return 0;
|
|
|
556 |
}
|
|
|
557 |
private int
|
|
|
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)
|
|
|
563 |
{
|
|
|
564 |
return gx_begin_image3x_generic(dev, pis, pmat, pic, prect, pdcolor,
|
|
|
565 |
pcpath, mem, make_midx_default,
|
|
|
566 |
make_mcdex_default, pinfo);
|
|
|
567 |
}
|
|
|
568 |
|
|
|
569 |
/* Process the next piece of an ImageType 3 image. */
|
|
|
570 |
private int
|
|
|
571 |
gx_image3x_plane_data(gx_image_enum_common_t * info,
|
|
|
572 |
const gx_image_plane_t * planes, int height,
|
|
|
573 |
int *rows_used)
|
|
|
574 |
{
|
|
|
575 |
gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
|
|
|
576 |
int pixel_height = penum->pixel.height;
|
|
|
577 |
int pixel_used = 0;
|
|
|
578 |
int mask_height[2];
|
|
|
579 |
int mask_used[2];
|
|
|
580 |
int h1 = pixel_height - penum->pixel.y;
|
|
|
581 |
int h;
|
|
|
582 |
const gx_image_plane_t *pixel_planes;
|
|
|
583 |
gx_image_plane_t pixel_plane, mask_plane[2];
|
|
|
584 |
int code = 0;
|
|
|
585 |
int i, pi = 0;
|
|
|
586 |
int num_chunky = 0;
|
|
|
587 |
|
|
|
588 |
for (i = 0; i < NUM_MASKS; ++i) {
|
|
|
589 |
int mh = mask_height[i] = penum->mask[i].height;
|
|
|
590 |
|
|
|
591 |
mask_plane[i].data = 0;
|
|
|
592 |
mask_used[i] = 0;
|
|
|
593 |
if (!penum->mask[i].depth)
|
|
|
594 |
continue;
|
|
|
595 |
h1 = min(h1, mh - penum->mask[i].y);
|
|
|
596 |
if (penum->mask[i].InterleaveType == interleave_chunky)
|
|
|
597 |
++num_chunky;
|
|
|
598 |
}
|
|
|
599 |
h = min(height, h1);
|
|
|
600 |
/* Initialized rows_used in case we get an error. */
|
|
|
601 |
*rows_used = 0;
|
|
|
602 |
if (h <= 0)
|
|
|
603 |
return 0;
|
|
|
604 |
|
|
|
605 |
/* Handle masks from separate sources. */
|
|
|
606 |
for (i = 0; i < NUM_MASKS; ++i)
|
|
|
607 |
if (penum->mask[i].InterleaveType == interleave_separate_source) {
|
|
|
608 |
/*
|
|
|
609 |
* In order to be able to recover from interruptions, we must
|
|
|
610 |
* limit separate-source processing to 1 scan line at a time.
|
|
|
611 |
*/
|
|
|
612 |
if (h > 1)
|
|
|
613 |
h = 1;
|
|
|
614 |
mask_plane[i] = planes[pi++];
|
|
|
615 |
}
|
|
|
616 |
pixel_planes = &planes[pi];
|
|
|
617 |
|
|
|
618 |
/* Handle chunky masks. */
|
|
|
619 |
if (num_chunky) {
|
|
|
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),
|
|
|
627 |
bit_x & 7, bpc);
|
|
|
628 |
sample_store_declare_setup(pptr, pbit, pbbyte,
|
|
|
629 |
penum->pixel.data, 0, bpc);
|
|
|
630 |
sample_store_declare(dptr[NUM_MASKS], dbit[NUM_MASKS],
|
|
|
631 |
dbbyte[NUM_MASKS]);
|
|
|
632 |
int depth[NUM_MASKS];
|
|
|
633 |
int x;
|
|
|
634 |
|
|
|
635 |
if (h > 1) {
|
|
|
636 |
/* Do the operation one row at a time. */
|
|
|
637 |
h = 1;
|
|
|
638 |
}
|
|
|
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]);
|
|
|
647 |
} else
|
|
|
648 |
depth[i] = 0;
|
|
|
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) {
|
|
|
654 |
uint value;
|
|
|
655 |
|
|
|
656 |
for (i = 0; i < NUM_MASKS; ++i)
|
|
|
657 |
if (depth[i]) {
|
|
|
658 |
sample_load_next12(value, sptr, sbit, bpc);
|
|
|
659 |
sample_store_next12(value, dptr[i], dbit[i], depth[i],
|
|
|
660 |
dbbyte[i]);
|
|
|
661 |
}
|
|
|
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);
|
|
|
665 |
}
|
|
|
666 |
}
|
|
|
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);
|
|
|
671 |
}
|
|
|
672 |
/*
|
|
|
673 |
* Process the mask data first, so it will set up the mask
|
|
|
674 |
* device for clipping the pixel data.
|
|
|
675 |
*/
|
|
|
676 |
for (i = 0; i < NUM_MASKS; ++i)
|
|
|
677 |
if (mask_plane[i].data) {
|
|
|
678 |
/*
|
|
|
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
|
|
|
685 |
* again.
|
|
|
686 |
*/
|
|
|
687 |
int skip = penum->mask[i].skip;
|
|
|
688 |
|
|
|
689 |
if (skip >= h) {
|
|
|
690 |
penum->mask[i].skip = skip - (mask_used[i] = h);
|
|
|
691 |
} else {
|
|
|
692 |
int mask_h = h - skip;
|
|
|
693 |
|
|
|
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,
|
|
|
697 |
&mask_plane[i],
|
|
|
698 |
mask_h, &mask_used[i]);
|
|
|
699 |
mask_used[i] += skip;
|
|
|
700 |
}
|
|
|
701 |
*rows_used = mask_used[i];
|
|
|
702 |
penum->mask[i].y += mask_used[i];
|
|
|
703 |
if (code < 0)
|
|
|
704 |
return code;
|
|
|
705 |
}
|
|
|
706 |
if (pixel_planes[0].data) {
|
|
|
707 |
/*
|
|
|
708 |
* If necessary, flush any buffered mask data to the mask clipping
|
|
|
709 |
* device.
|
|
|
710 |
*/
|
|
|
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,
|
|
|
715 |
&pixel_used);
|
|
|
716 |
/*
|
|
|
717 |
* There isn't any way to set rows_used if different amounts of
|
|
|
718 |
* the mask and pixel data were used. Fake it.
|
|
|
719 |
*/
|
|
|
720 |
*rows_used = pixel_used;
|
|
|
721 |
/*
|
|
|
722 |
* Don't return code yet: we must account for the fact that
|
|
|
723 |
* some mask data may have been processed.
|
|
|
724 |
*/
|
|
|
725 |
penum->pixel.y += pixel_used;
|
|
|
726 |
if (code < 0) {
|
|
|
727 |
/*
|
|
|
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.
|
|
|
731 |
*/
|
|
|
732 |
for (i = 0; i < NUM_MASKS; ++i)
|
|
|
733 |
if (mask_used[i] > pixel_used) {
|
|
|
734 |
int skip = mask_used[i] - pixel_used;
|
|
|
735 |
|
|
|
736 |
penum->mask[i].skip = skip;
|
|
|
737 |
penum->mask[i].y -= skip;
|
|
|
738 |
mask_used[i] = pixel_used;
|
|
|
739 |
}
|
|
|
740 |
}
|
|
|
741 |
}
|
|
|
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].y >= penum->mask[0].height &&
|
|
|
747 |
penum->mask[1].y >= penum->mask[1].height &&
|
|
|
748 |
penum->pixel.y >= penum->pixel.height)
|
|
|
749 |
return 1;
|
|
|
750 |
/*
|
|
|
751 |
* The mask may be complete (gx_image_plane_data_rows returned 1),
|
|
|
752 |
* but there may still be pixel rows to go, so don't return 1 here.
|
|
|
753 |
*/
|
|
|
754 |
return (code < 0 ? code : 0);
|
|
|
755 |
}
|
|
|
756 |
|
|
|
757 |
/* Flush buffered data. */
|
|
|
758 |
private int
|
|
|
759 |
gx_image3x_flush(gx_image_enum_common_t * info)
|
|
|
760 |
{
|
|
|
761 |
gx_image3x_enum_t * const penum = (gx_image3x_enum_t *) info;
|
|
|
762 |
int code = gx_image_flush(penum->mask[0].info);
|
|
|
763 |
|
|
|
764 |
if (code >= 0)
|
|
|
765 |
code = gx_image_flush(penum->mask[1].info);
|
|
|
766 |
if (code >= 0)
|
|
|
767 |
code = gx_image_flush(penum->pixel.info);
|
|
|
768 |
return code;
|
|
|
769 |
}
|
|
|
770 |
|
|
|
771 |
/* Determine which data planes are wanted. */
|
|
|
772 |
private bool
|
|
|
773 |
gx_image3x_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
|
|
|
774 |
{
|
|
|
775 |
const gx_image3x_enum_t * const penum = (const gx_image3x_enum_t *) info;
|
|
|
776 |
/*
|
|
|
777 |
* We always want at least as much of the mask(s) to be filled as the
|
|
|
778 |
* pixel data.
|
|
|
779 |
*/
|
|
|
780 |
bool
|
|
|
781 |
sso = penum->mask[0].InterleaveType == interleave_separate_source,
|
|
|
782 |
sss = penum->mask[1].InterleaveType == interleave_separate_source;
|
|
|
783 |
|
|
|
784 |
if (sso & sss) {
|
|
|
785 |
/* Both masks have separate sources. */
|
|
|
786 |
int mask_next = channel_next(&penum->mask[1], &penum->pixel);
|
|
|
787 |
|
|
|
788 |
memset(wanted + 2, (mask_next <= 0 ? 0xff : 0), info->num_planes - 2);
|
|
|
789 |
wanted[1] = (mask_next >= 0 ? 0xff : 0);
|
|
|
790 |
if (wanted[1]) {
|
|
|
791 |
mask_next = channel_next(&penum->mask[0], &penum->mask[1]);
|
|
|
792 |
wanted[0] = mask_next >= 0;
|
|
|
793 |
} else
|
|
|
794 |
wanted[0] = 0;
|
|
|
795 |
return false; /* see below */
|
|
|
796 |
} else if (sso | sss) {
|
|
|
797 |
/* Only one separate source. */
|
|
|
798 |
const image3x_channel_state_t *pics =
|
|
|
799 |
(sso ? &penum->mask[0] : &penum->mask[1]);
|
|
|
800 |
int mask_next = channel_next(pics, &penum->pixel);
|
|
|
801 |
|
|
|
802 |
wanted[0] = (mask_next >= 0 ? 0xff : 0);
|
|
|
803 |
memset(wanted + 1, (mask_next <= 0 ? 0xff : 0), info->num_planes - 1);
|
|
|
804 |
/*
|
|
|
805 |
* In principle, wanted will always be true for both mask and pixel
|
|
|
806 |
* data if the full_heights are equal. Unfortunately, even in this
|
|
|
807 |
* case, processing may be interrupted after a mask row has been
|
|
|
808 |
* passed to the underlying image processor but before the data row
|
|
|
809 |
* has been passed, in which case pixel data will be 'wanted', but
|
|
|
810 |
* not mask data, for the next call. Therefore, we must return
|
|
|
811 |
* false.
|
|
|
812 |
*/
|
|
|
813 |
return false
|
|
|
814 |
/*(next == 0 &&
|
|
|
815 |
pics->full_height == penum->pixel.full_height)*/;
|
|
|
816 |
} else {
|
|
|
817 |
/* Everything is chunky, only 1 plane. */
|
|
|
818 |
wanted[0] = 0xff;
|
|
|
819 |
return true;
|
|
|
820 |
}
|
|
|
821 |
}
|
|
|
822 |
|
|
|
823 |
/* Clean up after processing an ImageType 3x image. */
|
|
|
824 |
private int
|
|
|
825 |
gx_image3x_end_image(gx_image_enum_common_t * info, bool draw_last)
|
|
|
826 |
{
|
|
|
827 |
gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
|
|
|
828 |
gs_memory_t *mem = penum->memory;
|
|
|
829 |
gx_device *mdev0 = penum->mask[0].mdev;
|
|
|
830 |
int ocode =
|
|
|
831 |
(penum->mask[0].info ? gx_image_end(penum->mask[0].info, draw_last) :
|
|
|
832 |
0);
|
|
|
833 |
gx_device *mdev1 = penum->mask[1].mdev;
|
|
|
834 |
int scode =
|
|
|
835 |
(penum->mask[1].info ? gx_image_end(penum->mask[1].info, draw_last) :
|
|
|
836 |
0);
|
|
|
837 |
gx_device *pcdev = penum->pcdev;
|
|
|
838 |
int pcode = gx_image_end(penum->pixel.info, draw_last);
|
|
|
839 |
|
|
|
840 |
gs_closedevice(pcdev);
|
|
|
841 |
if (mdev0)
|
|
|
842 |
gs_closedevice(mdev0);
|
|
|
843 |
if (mdev1)
|
|
|
844 |
gs_closedevice(mdev1);
|
|
|
845 |
gs_free_object(mem, penum->mask[0].data,
|
|
|
846 |
"gx_image3x_end_image(mask[0].data)");
|
|
|
847 |
gs_free_object(mem, penum->mask[1].data,
|
|
|
848 |
"gx_image3x_end_image(mask[1].data)");
|
|
|
849 |
gs_free_object(mem, penum->pixel.data,
|
|
|
850 |
"gx_image3x_end_image(pixel.data)");
|
|
|
851 |
gs_free_object(mem, pcdev, "gx_image3x_end_image(pcdev)");
|
|
|
852 |
gs_free_object(mem, mdev0, "gx_image3x_end_image(mask[0].mdev)");
|
|
|
853 |
gs_free_object(mem, mdev1, "gx_image3x_end_image(mask[1].mdev)");
|
|
|
854 |
gs_free_object(mem, penum, "gx_image3x_end_image");
|
|
|
855 |
return (pcode < 0 ? pcode : scode < 0 ? scode : ocode);
|
|
|
856 |
}
|