/src/ghostpdl/base/gxblend1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | /* PDF 1.4 blending functions */ |
17 | | |
18 | | #include "memory_.h" |
19 | | #include "gx.h" |
20 | | #include "gp.h" |
21 | | #include "gstparam.h" |
22 | | #include "gsrect.h" |
23 | | #include "gxblend.h" |
24 | | #include "gxdcconv.h" |
25 | | #include "gxdevcli.h" |
26 | | #include "gxgstate.h" |
27 | | #include "gdevdevn.h" |
28 | | #include "gdevp14.h" |
29 | | #include "gxdcconv.h" |
30 | | #include "gsicc_cache.h" |
31 | | #include "gxdevsop.h" |
32 | | |
33 | | #ifdef DUMP_TO_PNG |
34 | | #include "png_.h" |
35 | | #endif |
36 | | |
37 | | /* A case where we have RGB + spots. This is actually an RGB color and we |
38 | | * should zero out the spot colorants */ |
39 | | void |
40 | | pdf14_unpack_rgb_mix(int num_comp, gx_color_index color, |
41 | | pdf14_device * p14dev, byte * out) |
42 | 0 | { |
43 | 0 | int i; |
44 | |
|
45 | 0 | memset(out, 0, num_comp); |
46 | 0 | for (i = 2; i >= 0; i--) { |
47 | 0 | out[i] = (byte)(color & 0xff); |
48 | 0 | color >>= 8; |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | | void |
53 | | pdf14_unpack16_rgb_mix(int num_comp, gx_color_index color, |
54 | | pdf14_device * p14dev, uint16_t * out) |
55 | 0 | { |
56 | 0 | int i; |
57 | |
|
58 | 0 | memset(out, 0, num_comp); |
59 | 0 | for (i = 2; i >= 0; i--) { |
60 | 0 | out[i] = (uint16_t)color; |
61 | 0 | color >>= 16; |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | /* A case where we have Gray + spots. This is actually a Gray color and we |
66 | | * should zero out the spot colorants */ |
67 | | void |
68 | | pdf14_unpack_gray_mix(int num_comp, gx_color_index color, |
69 | | pdf14_device * p14dev, byte * out) |
70 | 0 | { |
71 | 0 | memset(out, 0, num_comp); |
72 | 0 | out[0] = (byte)(color & 0xff); |
73 | 0 | } |
74 | | |
75 | | void |
76 | | pdf14_unpack16_gray_mix(int num_comp, gx_color_index color, |
77 | | pdf14_device * p14dev, uint16_t * out) |
78 | 0 | { |
79 | 0 | memset(out, 0, num_comp); |
80 | 0 | out[0] = (uint16_t)color; |
81 | 0 | } |
82 | | |
83 | | /* |
84 | | * Unpack a device color. This routine is similar to the device's |
85 | | * decode_color procedure except for two things. The procedure produces 1 |
86 | | * byte values instead of gx_color_values (2 bytes). A separate |
87 | | * procedure is used instead of the decode_color to minimize execution time. |
88 | | */ |
89 | | void |
90 | | pdf14_unpack_additive(int num_comp, gx_color_index color, |
91 | | pdf14_device * p14dev, byte * out) |
92 | 700M | { |
93 | 700M | int i; |
94 | | |
95 | 2.49G | for (i = num_comp - 1; i >= 0; i--) { |
96 | 1.79G | out[i] = (byte)(color & 0xff); |
97 | 1.79G | color >>= 8; |
98 | 1.79G | } |
99 | 700M | } |
100 | | |
101 | | void |
102 | | pdf14_unpack16_additive(int num_comp, gx_color_index color, |
103 | | pdf14_device * p14dev, uint16_t * out) |
104 | 0 | { |
105 | 0 | int i; |
106 | |
|
107 | 0 | for (i = num_comp - 1; i >= 0; i--) { |
108 | 0 | out[i] = (uint16_t)color; |
109 | 0 | color >>= 16; |
110 | 0 | } |
111 | 0 | } |
112 | | |
113 | | /* |
114 | | * Unpack a device color. This routine is similar to the device's |
115 | | * decode_color procedure except for two things. The procedure produces 1 |
116 | | * byte values instead of gx_color_values (2 bytes) and the output values |
117 | | * are inverted for subtractive color spaces (like CMYK). A separate |
118 | | * procedure is used instead of the decode_color to minimize execution time. |
119 | | */ |
120 | | void |
121 | | pdf14_unpack_subtractive(int num_comp, gx_color_index color, |
122 | | pdf14_device * p14dev, byte * out) |
123 | 71.7M | { |
124 | 71.7M | int i; |
125 | | |
126 | 358M | for (i = num_comp - 1; i >= 0; i--) { |
127 | 287M | out[i] = 0xff - (byte)(color & 0xff); |
128 | 287M | color >>= 8; |
129 | 287M | } |
130 | 71.7M | } |
131 | | |
132 | | void |
133 | | pdf14_unpack16_subtractive(int num_comp, gx_color_index color, |
134 | | pdf14_device * p14dev, uint16_t * out) |
135 | 0 | { |
136 | 0 | int i; |
137 | |
|
138 | 0 | for (i = num_comp - 1; i >= 0; i--) { |
139 | 0 | out[i] = (uint16_t)~color; |
140 | 0 | color >>= 16; |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | /* |
145 | | * Unpack a device color. This routine is used for devices in which we do |
146 | | * not know the details of the process color model. In this case we use |
147 | | * the device's decode_color procedure. |
148 | | */ |
149 | | void |
150 | | pdf14_unpack_custom(int num_comp, gx_color_index color, |
151 | | pdf14_device * p14dev, byte * out) |
152 | 0 | { |
153 | 0 | int i; |
154 | 0 | gx_device * tdev = p14dev->target; |
155 | 0 | gx_color_value cm_values[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
156 | |
|
157 | 0 | dev_proc(tdev, decode_color)(tdev, color, cm_values); |
158 | 0 | for (i = 0; i < num_comp; i++) |
159 | 0 | out[i] = 0xff - gx_color_value_to_byte(cm_values[i]); |
160 | 0 | } |
161 | | |
162 | | void |
163 | | pdf14_unpack16_custom(int num_comp, gx_color_index color, |
164 | | pdf14_device * p14dev, uint16_t * out) |
165 | 0 | { |
166 | 0 | int i; |
167 | 0 | gx_device * tdev = p14dev->target; |
168 | 0 | gx_color_value cm_values[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
169 | |
|
170 | 0 | dev_proc(tdev, decode_color)(tdev, color, cm_values); |
171 | 0 | for (i = 0; i < num_comp; i++) |
172 | 0 | out[i] = ~cm_values[i]; |
173 | 0 | } |
174 | | |
175 | | #if RAW_DUMP |
176 | | extern unsigned int global_index; |
177 | | #endif |
178 | | |
179 | | static void |
180 | | copy_plane_part(byte *des_ptr, int des_rowstride, byte *src_ptr, int src_rowstride, |
181 | | int width, int height, bool deep) |
182 | 1.65M | { |
183 | 1.65M | int y; |
184 | | |
185 | 1.65M | width <<= deep; |
186 | | |
187 | 1.65M | if (width == des_rowstride && width == src_rowstride) { |
188 | 864k | width *= height; |
189 | 864k | height = 1; |
190 | 864k | } |
191 | | |
192 | 10.6M | for (y = 0; y < height; ++y) { |
193 | 9.04M | memcpy(des_ptr, src_ptr, width); |
194 | 9.04M | des_ptr += des_rowstride; |
195 | 9.04M | src_ptr += src_rowstride; |
196 | 9.04M | } |
197 | 1.65M | } |
198 | | |
199 | | static void |
200 | | copy_extra_planes(byte *des_buf, pdf14_buf *des_info, byte *src_buf, |
201 | | pdf14_buf *src_info, int width, int height) |
202 | 453k | { |
203 | | /* alpha_g and shape do not copy */ |
204 | 453k | des_buf += des_info->planestride * (size_t)((des_info->has_shape ? 1 : 0) + |
205 | 453k | (des_info->has_alpha_g ? 1 : 0)); |
206 | 453k | src_buf += src_info->planestride * (size_t)((src_info->has_shape ? 1 : 0) + |
207 | 453k | (src_info->has_alpha_g ? 1 : 0)); |
208 | | /* tags plane does copy */ |
209 | 453k | if (des_info->has_tags) { |
210 | 0 | if (src_info->has_tags) { |
211 | 0 | copy_plane_part(des_buf, des_info->rowstride, src_buf, |
212 | 0 | src_info->rowstride, width, height, src_info->deep); |
213 | 0 | } |
214 | 0 | } |
215 | 453k | } |
216 | | |
217 | | int |
218 | | pdf14_preserve_backdrop_cm(pdf14_buf *buf, cmm_profile_t *group_profile, |
219 | | pdf14_buf *tos, cmm_profile_t *tos_profile, |
220 | | gs_memory_t *memory, gs_gstate *pgs, gx_device *dev, |
221 | | bool knockout_buff) |
222 | 0 | { |
223 | | /* Make copy of backdrop, but convert to new group's colorspace */ |
224 | 0 | int x0 = max(buf->rect.p.x, tos->rect.p.x); |
225 | 0 | int x1 = min(buf->rect.q.x, tos->rect.q.x); |
226 | 0 | int y0 = max(buf->rect.p.y, tos->rect.p.y); |
227 | 0 | int y1 = min(buf->rect.q.y, tos->rect.q.y); |
228 | 0 | bool deep = buf->deep; |
229 | 0 | int code; |
230 | |
|
231 | 0 | if (x0 < x1 && y0 < y1) { |
232 | 0 | int width = x1 - x0; |
233 | 0 | int height = y1 - y0; |
234 | 0 | byte *buf_plane, *tos_plane; |
235 | 0 | gsicc_rendering_param_t rendering_params; |
236 | 0 | gsicc_link_t *icc_link; |
237 | 0 | gsicc_bufferdesc_t input_buff_desc; |
238 | 0 | gsicc_bufferdesc_t output_buff_desc; |
239 | | |
240 | | /* Define the rendering intents */ |
241 | 0 | rendering_params.black_point_comp = gsBLACKPTCOMP_ON; |
242 | 0 | rendering_params.graphics_type_tag = GS_IMAGE_TAG; |
243 | 0 | rendering_params.override_icc = false; |
244 | 0 | rendering_params.preserve_black = gsBKPRESNOTSPECIFIED; |
245 | 0 | rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC; |
246 | 0 | rendering_params.cmm = gsCMM_DEFAULT; |
247 | | /* Request the ICC link for the transform that we will need to use */ |
248 | 0 | icc_link = gsicc_get_link_profile(pgs, dev, tos_profile, group_profile, |
249 | 0 | &rendering_params, memory, false); |
250 | 0 | if (icc_link == NULL) |
251 | 0 | return gs_throw(gs_error_unknownerror, "ICC link failed. Trans backdrop"); |
252 | | |
253 | 0 | if (icc_link->is_identity) { |
254 | 0 | pdf14_preserve_backdrop(buf, tos, knockout_buff |
255 | | #if RAW_DUMP |
256 | | , dev->memory |
257 | | #endif |
258 | 0 | ); |
259 | 0 | gsicc_release_link(icc_link); |
260 | 0 | return 0; |
261 | 0 | } else { |
262 | 0 | if (knockout_buff) { |
263 | 0 | buf_plane = buf->backdrop + ((x0 - buf->rect.p.x)<<deep) + |
264 | 0 | (y0 - buf->rect.p.y) * (size_t)buf->rowstride; |
265 | 0 | tos_plane = tos->backdrop + ((x0 - tos->rect.p.x)<<deep) + |
266 | 0 | (y0 - tos->rect.p.y) * (size_t)tos->rowstride; |
267 | 0 | memset(buf->backdrop, 0, buf->n_chan * ((size_t)buf->planestride)<<deep); |
268 | 0 | } else { |
269 | 0 | buf_plane = buf->data + ((x0 - buf->rect.p.x)<<deep) + |
270 | 0 | (y0 - buf->rect.p.y) * (size_t)buf->rowstride; |
271 | 0 | tos_plane = tos->data + ((x0 - tos->rect.p.x)<<deep) + |
272 | 0 | (y0 - tos->rect.p.y) * (size_t)tos->rowstride; |
273 | | /* First clear out everything. There are cases where the incoming buf |
274 | | has a region outside the existing tos group. Need to check if this |
275 | | is getting clipped in which case we need to fix the allocation of |
276 | | the buffer to be smaller */ |
277 | 0 | memset(buf->data, 0, buf->n_planes * ((size_t)buf->planestride)<<deep); |
278 | 0 | } |
279 | | /* Set up the buffer descriptors. */ |
280 | 0 | gsicc_init_buffer(&input_buff_desc, tos_profile->num_comps, 1<<deep, false, |
281 | 0 | false, true, tos->planestride, tos->rowstride, height, |
282 | 0 | width); |
283 | 0 | gsicc_init_buffer(&output_buff_desc, group_profile->num_comps, 1<<deep, false, |
284 | 0 | false, true, buf->planestride, buf->rowstride, height, |
285 | 0 | width); |
286 | | /* Transform the data. */ |
287 | 0 | code = (icc_link->procs.map_buffer)(dev, icc_link, &input_buff_desc, |
288 | 0 | &output_buff_desc, tos_plane, buf_plane); |
289 | 0 | gsicc_release_link(icc_link); |
290 | 0 | if (code < 0) |
291 | 0 | return gs_throw(gs_error_unknownerror, "ICC transform failed. Trans backdrop"); |
292 | 0 | } |
293 | | /* Copy the alpha data */ |
294 | 0 | buf_plane += (buf->planestride) * (size_t)(buf->n_chan - 1); |
295 | 0 | tos_plane += (tos->planestride) * (size_t)(tos->n_chan - 1); |
296 | 0 | copy_plane_part(buf_plane, buf->rowstride, tos_plane, tos->rowstride, width, |
297 | 0 | height, deep); |
298 | 0 | buf_plane += buf->planestride; |
299 | 0 | tos_plane += tos->planestride; |
300 | |
|
301 | 0 | if (!knockout_buff) |
302 | 0 | copy_extra_planes(buf_plane, buf, tos_plane, tos, width, height); |
303 | 0 | } |
304 | | #if RAW_DUMP |
305 | | if (x0 < x1 && y0 < y1) { |
306 | | byte *buf_plane = buf->data + ((x0 - buf->rect.p.x)<<deep) + |
307 | | (y0 - buf->rect.p.y) * (size_t)buf->rowstride; |
308 | | dump_raw_buffer(dev->memory, y1 - y0, x1 - x0, buf->n_planes, buf->planestride, |
309 | | buf->rowstride, "BackDropInit_CM", buf_plane, deep); |
310 | | global_index++; |
311 | | } |
312 | | #endif |
313 | 0 | return 0; |
314 | 0 | } |
315 | | |
316 | | void |
317 | | pdf14_preserve_backdrop(pdf14_buf *buf, pdf14_buf *tos, bool from_backdrop |
318 | | #if RAW_DUMP |
319 | | , const gs_memory_t *mem |
320 | | #endif |
321 | | ) |
322 | 468k | { |
323 | | /* make copy of backdrop for compositing */ |
324 | 468k | int x0 = max(buf->rect.p.x, tos->rect.p.x); |
325 | 468k | int x1 = min(buf->rect.q.x, tos->rect.q.x); |
326 | 468k | int y0 = max(buf->rect.p.y, tos->rect.p.y); |
327 | 468k | int y1 = min(buf->rect.q.y, tos->rect.q.y); |
328 | | |
329 | 468k | if (x0 < x1 && y0 < y1) { |
330 | 453k | int width = x1 - x0; |
331 | 453k | int height = y1 - y0; |
332 | 453k | byte *buf_plane, *tos_plane; |
333 | 453k | int i, n_planes; |
334 | 453k | bool deep = buf->deep; |
335 | | |
336 | 453k | buf_plane = buf->data; |
337 | 453k | n_planes = buf->n_planes; |
338 | 453k | if (from_backdrop) { |
339 | 28 | tos_plane = tos->backdrop; |
340 | 453k | } else { |
341 | 453k | tos_plane = tos->data; |
342 | 453k | } |
343 | | |
344 | | /* First clear out everything. There are cases where the incoming buf |
345 | | has a region outside the existing tos group. Need to check if this |
346 | | is getting clipped in which case we need to fix the allocation of |
347 | | the buffer to be smaller */ |
348 | 453k | if (x0 > buf->rect.p.x || x1 < buf->rect.q.x || |
349 | 453k | y0 > buf->rect.p.y || y1 < buf->rect.q.y) { |
350 | | /* FIXME: There is potential for more optimisation here, |
351 | | * but I don't know how often we hit this case. */ |
352 | 457 | memset(buf_plane, 0, n_planes * (size_t)buf->planestride); |
353 | 452k | } else if (n_planes > tos->n_chan) { |
354 | | /* The next planes are alpha_g, shape, tags. We need to clear |
355 | | * alpha_g and shape, but don't need to clear the tag plane |
356 | | * if it would be copied below (and if it exists). */ |
357 | 452k | int tag_plane_num = tos->n_chan + !!buf->has_shape + !!buf->has_alpha_g; |
358 | 452k | if (!from_backdrop && n_planes > tag_plane_num) |
359 | 0 | n_planes = tag_plane_num; |
360 | 452k | if (n_planes > tos->n_chan) |
361 | 452k | memset(buf->data + tos->n_chan * (size_t)buf->planestride, 0, |
362 | 452k | (n_planes - tos->n_chan) * (size_t)buf->planestride); |
363 | 452k | } |
364 | 453k | buf_plane += (y0 - buf->rect.p.y) * (size_t)buf->rowstride + |
365 | 453k | ((x0 - buf->rect.p.x)<<deep); |
366 | 453k | tos_plane += (y0 - tos->rect.p.y) * (size_t)tos->rowstride + |
367 | 453k | ((x0 - tos->rect.p.x)<<deep); |
368 | | /* Color and alpha plane */ |
369 | 2.10M | for (i = 0; i < tos->n_chan; i++) { |
370 | 1.65M | copy_plane_part(buf_plane, buf->rowstride, tos_plane, tos->rowstride, |
371 | 1.65M | width, height, buf->deep); |
372 | 1.65M | buf_plane += buf->planestride; |
373 | 1.65M | tos_plane += tos->planestride; |
374 | 1.65M | } |
375 | 453k | if (!from_backdrop) |
376 | 453k | copy_extra_planes(buf_plane, buf, tos_plane, tos, width, height); |
377 | 453k | } |
378 | | #if RAW_DUMP |
379 | | if (x0 < x1 && y0 < y1) { |
380 | | byte *buf_plane = (from_backdrop ? buf->backdrop : buf->data); |
381 | | if (buf_plane != NULL) { |
382 | | buf_plane += ((x0 - buf->rect.p.x) << buf->deep) + |
383 | | (y0 - buf->rect.p.y) * (size_t)buf->rowstride; |
384 | | dump_raw_buffer(mem, y1 - y0, x1 - x0, buf->n_planes, buf->planestride, |
385 | | buf->rowstride, "BackDropInit", buf_plane, buf->deep); |
386 | | global_index++; |
387 | | } |
388 | | } |
389 | | #endif |
390 | 468k | } |
391 | | |
392 | | /* |
393 | | * Encode a list of colorant values into a gx_color_index_value. |
394 | | */ |
395 | | gx_color_index |
396 | | pdf14_encode_color(gx_device *dev, const gx_color_value colors[]) |
397 | 380M | { |
398 | 380M | gx_color_index color = 0; |
399 | 380M | uchar i; |
400 | 380M | uchar ncomp = dev->color_info.num_components; |
401 | 380M | COLROUND_VARS; |
402 | | |
403 | 380M | COLROUND_SETUP(8); |
404 | 1.50G | for (i = 0; i < ncomp; i++) { |
405 | 1.12G | color <<= 8; |
406 | 1.12G | color |= COLROUND_ROUND(colors[i]); |
407 | 1.12G | } |
408 | 380M | return (color == gx_no_color_index ? color ^ 1 : color); |
409 | 380M | } |
410 | | |
411 | | gx_color_index |
412 | | pdf14_encode_color16(gx_device *dev, const gx_color_value colors[]) |
413 | 0 | { |
414 | 0 | gx_color_index color = 0; |
415 | 0 | uchar i; |
416 | 0 | uchar ncomp = dev->color_info.num_components; |
417 | 0 | COLROUND_VARS; |
418 | |
|
419 | 0 | COLROUND_SETUP(16); |
420 | 0 | for (i = 0; i < ncomp; i++) { |
421 | 0 | color <<= 16; |
422 | 0 | color |= COLROUND_ROUND(colors[i]); |
423 | 0 | } |
424 | 0 | return (color == gx_no_color_index ? color ^ 1 : color); |
425 | 0 | } |
426 | | |
427 | | /* |
428 | | * Encode a list of colorant values into a gx_color_index_value. |
429 | | Stick the tag information at the end. |
430 | | */ |
431 | | gx_color_index |
432 | | pdf14_encode_color_tag(gx_device *dev, const gx_color_value colors[]) |
433 | 0 | { |
434 | 0 | gx_color_index color; |
435 | 0 | uchar i; |
436 | 0 | uchar ncomp = dev->color_info.num_components - 1; |
437 | 0 | COLROUND_VARS; |
438 | |
|
439 | 0 | COLROUND_SETUP(8); |
440 | | /* Add in the tag information */ |
441 | 0 | color = dev->graphics_type_tag & 255; |
442 | 0 | for (i = 0; i < ncomp; i++) { |
443 | 0 | color <<= 8; |
444 | 0 | color |= COLROUND_ROUND(colors[i]); |
445 | 0 | } |
446 | 0 | return (color == gx_no_color_index ? color ^ 1 : color); |
447 | 0 | } |
448 | | |
449 | | gx_color_index |
450 | | pdf14_encode_color16_tag(gx_device *dev, const gx_color_value colors[]) |
451 | 0 | { |
452 | 0 | gx_color_index color; |
453 | 0 | uchar i; |
454 | 0 | uchar ncomp = dev->color_info.num_components - 1; |
455 | 0 | COLROUND_VARS; |
456 | |
|
457 | 0 | COLROUND_SETUP(16); |
458 | | /* Add in the tag information */ |
459 | 0 | color = dev->graphics_type_tag & 65535; |
460 | 0 | for (i = 0; i < ncomp; i++) { |
461 | 0 | color <<= 16; |
462 | 0 | color |= COLROUND_ROUND(colors[i]); |
463 | 0 | } |
464 | 0 | return (color == gx_no_color_index ? color ^ 1 : color); |
465 | 0 | } |
466 | | |
467 | | /* |
468 | | * Decode a gx_color_index value back to a list of colorant values. |
469 | | */ |
470 | | int |
471 | | pdf14_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out) |
472 | 0 | { |
473 | 0 | uchar i; |
474 | 0 | uchar ncomp = dev->color_info.num_components; |
475 | |
|
476 | 0 | for (i = 0; i < ncomp; i++) { |
477 | 0 | out[ncomp - i - 1] = (gx_color_value) ((color & 0xff) * 0x101); |
478 | 0 | color >>= 8; |
479 | 0 | } |
480 | 0 | return 0; |
481 | 0 | } |
482 | | |
483 | | int |
484 | | pdf14_decode_color16(gx_device * dev, gx_color_index color, gx_color_value * out) |
485 | 0 | { |
486 | 0 | uchar i; |
487 | 0 | uchar ncomp = dev->color_info.num_components; |
488 | |
|
489 | 0 | for (i = 0; i < ncomp; i++) { |
490 | 0 | out[ncomp - i - 1] = (gx_color_value) (color & 0xffff); |
491 | 0 | color >>= 16; |
492 | 0 | } |
493 | 0 | return 0; |
494 | 0 | } |
495 | | |
496 | | void |
497 | | pdf14_gray_cs_to_cmyk_cm(const gx_device * dev, frac gray, frac out[]) |
498 | 4 | { |
499 | 4 | uchar num_comp = dev->color_info.num_components; |
500 | | |
501 | 4 | out[0] = out[1] = out[2] = frac_0; |
502 | 4 | out[3] = frac_1 - gray; |
503 | 4 | for (--num_comp; num_comp > 3; num_comp--) |
504 | 0 | out[num_comp] = 0; |
505 | 4 | } |
506 | | |
507 | | /* These three must handle rgb + spot */ |
508 | | void |
509 | | pdf14_gray_cs_to_rgbspot_cm(const gx_device * dev, frac gray, frac out[]) |
510 | 2.28k | { |
511 | 2.28k | uchar num_comp = dev->color_info.num_components; |
512 | | |
513 | 2.28k | out[0] = out[1] = out[2] = gray; |
514 | 2.28k | for (--num_comp; num_comp > 2; num_comp--) |
515 | 0 | out[num_comp] = 0; |
516 | 2.28k | } |
517 | | |
518 | | void |
519 | | pdf14_rgb_cs_to_rgbspot_cm(const gx_device * dev, const gs_gstate *pgs, |
520 | | frac r, frac g, frac b, frac out[]) |
521 | 6.75M | { |
522 | 6.75M | uchar num_comp = dev->color_info.num_components; |
523 | | |
524 | 6.75M | out[0] = r; |
525 | 6.75M | out[1] = g; |
526 | 6.75M | out[2] = b; |
527 | 6.77M | for (--num_comp; num_comp > 2; num_comp--) |
528 | 11.3k | out[num_comp] = 0; |
529 | 6.75M | } |
530 | | |
531 | | void |
532 | | pdf14_cmyk_cs_to_rgbspot_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[]) |
533 | 868 | { |
534 | 868 | uchar num_comp = dev->color_info.num_components; |
535 | | |
536 | 868 | color_cmyk_to_rgb(c, m, y, k, NULL, out, dev->memory); |
537 | 868 | for (--num_comp; num_comp > 2; num_comp--) |
538 | 0 | out[num_comp] = 0; |
539 | 868 | } |
540 | | |
541 | | /* These three must handle gray + spot */ |
542 | | void |
543 | | pdf14_gray_cs_to_grayspot_cm(const gx_device * dev, frac gray, frac out[]) |
544 | 0 | { |
545 | 0 | uchar num_comp = dev->color_info.num_components; |
546 | |
|
547 | 0 | out[0] = gray; |
548 | 0 | for (--num_comp; num_comp > 0; num_comp--) |
549 | 0 | out[num_comp] = 0; |
550 | 0 | } |
551 | | |
552 | | void |
553 | | pdf14_rgb_cs_to_grayspot_cm(const gx_device * dev, const gs_gstate *pgs, |
554 | | frac r, frac g, frac b, frac out[]) |
555 | 0 | { |
556 | 0 | uchar num_comp = dev->color_info.num_components; |
557 | |
|
558 | 0 | out[0] = (r + g + b) / 3; |
559 | 0 | for (--num_comp; num_comp > 0; num_comp--) |
560 | 0 | out[num_comp] = 0; |
561 | 0 | } |
562 | | |
563 | | void |
564 | | pdf14_cmyk_cs_to_grayspot_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[]) |
565 | 0 | { |
566 | 0 | uchar num_comp = dev->color_info.num_components; |
567 | |
|
568 | 0 | out[0] = color_cmyk_to_gray(c, m, y, k, NULL); |
569 | 0 | for (--num_comp; num_comp > 0; num_comp--) |
570 | 0 | out[num_comp] = 0; |
571 | 0 | } |
572 | | |
573 | | /* |
574 | | * Default map from DeviceRGB color space to DeviceCMYK color |
575 | | * model. Since this mapping is defined by the PostScript language |
576 | | * it is unlikely that any device with a DeviceCMYK color model |
577 | | * would define this mapping on its own. |
578 | | * |
579 | | * If the gs_gstate is not available, map as though the black |
580 | | * generation and undercolor removal functions are identity |
581 | | * transformations. This mode is used primarily to support the |
582 | | * raster operation (rop) feature of PCL, which requires that |
583 | | * the raster operation be performed in an RGB color space. |
584 | | * Note that default black generation and undercolor removal |
585 | | * functions in PostScript need NOT be identity transformations: |
586 | | * often they are { pop 0 }. |
587 | | */ |
588 | | void |
589 | | pdf14_rgb_cs_to_cmyk_cm(const gx_device * dev, const gs_gstate *pgs, |
590 | | frac r, frac g, frac b, frac out[]) |
591 | 0 | { |
592 | 0 | uchar num_comp = dev->color_info.num_components; |
593 | |
|
594 | 0 | if (pgs != 0) |
595 | 0 | color_rgb_to_cmyk(r, g, b, pgs, out, dev->memory); |
596 | 0 | else { |
597 | 0 | frac c = frac_1 - r, m = frac_1 - g, y = frac_1 - b; |
598 | 0 | frac k = min(c, min(m, y)); |
599 | |
|
600 | 0 | out[0] = c - k; |
601 | 0 | out[1] = m - k; |
602 | 0 | out[2] = y - k; |
603 | 0 | out[3] = k; |
604 | 0 | } |
605 | 0 | for (--num_comp; num_comp > 3; num_comp--) |
606 | 0 | out[num_comp] = 0; |
607 | 0 | } |
608 | | |
609 | | void |
610 | | pdf14_cmyk_cs_to_cmyk_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[]) |
611 | 7.20M | { |
612 | 7.20M | uchar num_comp = dev->color_info.num_components; |
613 | | |
614 | 7.20M | out[0] = c; |
615 | 7.20M | out[1] = m; |
616 | 7.20M | out[2] = y; |
617 | 7.20M | out[3] = k; |
618 | 7.20M | for (--num_comp; num_comp > 3; num_comp--) |
619 | 1 | out[num_comp] = 0; |
620 | 7.20M | } |
621 | | |
622 | | #ifdef DUMP_TO_PNG |
623 | | /* Dumps a planar RGBA image to a PNG file. */ |
624 | | static int |
625 | | dump_planar_rgba(gs_memory_t *mem, const pdf14_buf *pbuf) |
626 | | { |
627 | | size_t rowstride = pbuf->rowstride, planestride = pbuf->planestride; |
628 | | int rowbytes = width << 2; |
629 | | gs_int_rect rect = buf->rect; |
630 | | int x1 = min(pdev->width, rect.q.x); |
631 | | int y1 = min(pdev->height, rect.q.y); |
632 | | int width = x1 - rect.p.x; |
633 | | int height = y1 - rect.p.y; |
634 | | byte *buf_ptr = buf->data + rect.p.y * (size_t)buf->rowstride + rect.p.x; |
635 | | byte *row = gs_malloc(mem, rowbytes, 1, "png raster buffer"); |
636 | | png_struct *png_ptr = |
637 | | png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
638 | | png_info *info_ptr = |
639 | | png_create_info_struct(png_ptr); |
640 | | const char *software_key = "Software"; |
641 | | char software_text[256]; |
642 | | png_text text_png; |
643 | | gp_file *file; |
644 | | int code; |
645 | | int y; |
646 | | |
647 | | if (buf->data == NULL) |
648 | | return 0; |
649 | | |
650 | | file = gp_fopen (mem, "c:\\temp\\tmp.png", "wb"); |
651 | | |
652 | | if_debug0m('v', mem, "[v]pnga_output_page\n"); |
653 | | |
654 | | if (row == 0 || png_ptr == 0 || info_ptr == 0) { |
655 | | code = gs_note_error(gs_error_VMerror); |
656 | | goto done; |
657 | | } |
658 | | /* set error handling */ |
659 | | if (setjmp(png_ptr->jmpbuf)) { |
660 | | /* If we get here, we had a problem reading the file */ |
661 | | code = gs_note_error(gs_error_VMerror); |
662 | | goto done; |
663 | | } |
664 | | |
665 | | code = 0; /* for normal path */ |
666 | | /* set up the output control */ |
667 | | png_init_io(png_ptr, file); |
668 | | |
669 | | /* set the file information here */ |
670 | | info_ptr->width = width; |
671 | | info_ptr->height = height; |
672 | | /* resolution is in pixels per meter vs. dpi */ |
673 | | info_ptr->x_pixels_per_unit = |
674 | | (png_uint_32) (96.0 * (100.0 / 2.54)); |
675 | | info_ptr->y_pixels_per_unit = |
676 | | (png_uint_32) (96.0 * (100.0 / 2.54)); |
677 | | info_ptr->phys_unit_type = PNG_RESOLUTION_METER; |
678 | | info_ptr->valid |= PNG_INFO_pHYs; |
679 | | |
680 | | /* At present, only supporting 32-bit rgba */ |
681 | | info_ptr->bit_depth = 8; |
682 | | info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
683 | | |
684 | | /* add comment */ |
685 | | gs_snprintf(software_text, sizeof(software_text), "%s %d.%02d", gs_product, |
686 | | (int)(gs_revision / 100), (int)(gs_revision % 100)); |
687 | | text_png.compression = -1; /* uncompressed */ |
688 | | text_png.key = (char *)software_key; /* not const, unfortunately */ |
689 | | text_png.text = software_text; |
690 | | text_png.text_length = strlen(software_text); |
691 | | info_ptr->text = &text_png; |
692 | | info_ptr->num_text = 1; |
693 | | |
694 | | /* write the file information */ |
695 | | png_write_info(png_ptr, info_ptr); |
696 | | |
697 | | /* don't write the comments twice */ |
698 | | info_ptr->num_text = 0; |
699 | | info_ptr->text = NULL; |
700 | | |
701 | | /* Write the contents of the image. */ |
702 | | for (y = 0; y < height; ++y) { |
703 | | int x; |
704 | | |
705 | | for (x = 0; x < width; ++x) { |
706 | | row[(x << 2)] = buf_ptr[x]; |
707 | | row[(x << 2) + 1] = buf_ptr[x + planestride]; |
708 | | row[(x << 2) + 2] = buf_ptr[x + planestride * (size_t)2]; |
709 | | row[(x << 2) + 3] = buf_ptr[x + planestride * (size_t)3]; |
710 | | } |
711 | | png_write_row(png_ptr, row); |
712 | | buf_ptr += rowstride; |
713 | | } |
714 | | |
715 | | /* write the rest of the file */ |
716 | | png_write_end(png_ptr, info_ptr); |
717 | | |
718 | | done: |
719 | | /* free the structures */ |
720 | | png_destroy_write_struct(&png_ptr, &info_ptr); |
721 | | gs_free(mem, row, rowbytes, 1, "png raster buffer"); |
722 | | |
723 | | fclose (file); |
724 | | return code; |
725 | | } |
726 | | #endif |
727 | | |
728 | | void |
729 | | gx_build_blended_image_row(const byte *gs_restrict buf_ptr, int planestride, |
730 | | int width, int num_comp, uint16_t bg, byte *gs_restrict linebuf) |
731 | 11.4M | { |
732 | 11.4M | size_t inc = planestride * (size_t)num_comp; |
733 | | |
734 | 11.4M | buf_ptr += inc - 1; |
735 | 12.4G | for (; width > 0; width--) { |
736 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
737 | 12.4G | byte a = *++buf_ptr; |
738 | 12.4G | int i = num_comp; |
739 | | |
740 | 12.4G | if (a == 0) { |
741 | 13.4G | do { |
742 | 13.4G | *linebuf++ = bg; |
743 | 13.4G | } while (--i); |
744 | 7.15G | } else { |
745 | 7.15G | buf_ptr -= inc; |
746 | 7.15G | if (a == 0xff) { |
747 | 19.3G | do { |
748 | 19.3G | *linebuf++ = *buf_ptr; |
749 | 19.3G | buf_ptr += planestride; |
750 | 19.3G | } while (--i); |
751 | 6.83G | } else { |
752 | 323M | a ^= 0xff; |
753 | 917M | do { |
754 | 917M | byte comp = *buf_ptr; |
755 | 917M | int tmp = ((bg - comp) * a) + 0x80; |
756 | 917M | buf_ptr += planestride; |
757 | 917M | comp += (tmp + (tmp >> 8)) >> 8; |
758 | 917M | *linebuf++ = comp; |
759 | 917M | } while (--i); |
760 | 323M | } |
761 | 7.15G | } |
762 | 12.4G | } |
763 | 11.4M | } |
764 | | |
765 | | void |
766 | | gx_build_blended_image_row16(const byte *gs_restrict buf_ptr_, int planestride, |
767 | | int width, int num_comp, uint16_t bg, byte *gs_restrict linebuf) |
768 | 0 | { |
769 | 0 | const uint16_t *gs_restrict buf_ptr = (const uint16_t *)(const void *)buf_ptr_; |
770 | 0 | size_t inc; |
771 | | |
772 | | /* Note that we read in in native endian and blend, |
773 | | * then store out in big endian. */ |
774 | 0 | planestride >>= 1; /* Array indexing, not byte indexing */ |
775 | 0 | inc = planestride * (size_t)num_comp; |
776 | 0 | buf_ptr += inc - 1; |
777 | 0 | for (; width > 0; width--) { |
778 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
779 | 0 | uint16_t a = *++buf_ptr; |
780 | 0 | int i = num_comp; |
781 | |
|
782 | 0 | if (a == 0) { |
783 | 0 | do { |
784 | 0 | *linebuf++ = bg>>8; |
785 | 0 | *linebuf++ = bg; |
786 | 0 | } while (--i); |
787 | 0 | } else { |
788 | 0 | buf_ptr -= inc; |
789 | 0 | if (a == 0xffff) { |
790 | 0 | do { |
791 | 0 | uint16_t comp = *buf_ptr; |
792 | 0 | *linebuf++ = comp>>8; |
793 | 0 | *linebuf++ = comp; |
794 | 0 | buf_ptr += planestride; |
795 | 0 | } while (--i); |
796 | 0 | } else { |
797 | 0 | a ^= 0xffff; |
798 | 0 | a += a>>15; |
799 | 0 | do { |
800 | 0 | uint32_t comp = *buf_ptr; |
801 | 0 | comp += (((bg - comp) * a) + 0x8000)>>16; |
802 | | /* Errors in bit 16 and above will be ignored */ |
803 | 0 | buf_ptr += planestride; |
804 | 0 | *linebuf++ = comp>>8; |
805 | 0 | *linebuf++ = comp; |
806 | 0 | } while (--i); |
807 | 0 | } |
808 | 0 | } |
809 | 0 | } |
810 | 0 | } |
811 | | |
812 | | void |
813 | | gx_blend_image_buffer(byte *buf_ptr, int width, int height, int rowstride, |
814 | | int planestride, int num_comp, int additive) |
815 | 35.5k | { |
816 | 35.5k | int x, y; |
817 | 35.5k | int position; |
818 | 35.5k | byte comp, a; |
819 | 35.5k | int tmp, comp_num; |
820 | | |
821 | 35.5k | if (additive) { |
822 | 0 | if (num_comp > 3) { |
823 | 0 | for (y = 0; y < height; y++) { |
824 | 0 | position = y * rowstride; |
825 | 0 | for (x = 0; x < width; x++) { |
826 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
827 | 0 | a = buf_ptr[position + planestride * (size_t)num_comp]; |
828 | 0 | if ((a + 1) & 0xfe) { |
829 | 0 | int b = 0xFF; |
830 | 0 | a ^= 0xff; |
831 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
832 | 0 | if (comp_num == 3) |
833 | 0 | b = 0; |
834 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
835 | 0 | tmp = ((b - comp) * a) + 0x80; |
836 | 0 | comp += (tmp + (tmp >> 8)) >> 8; |
837 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = comp; |
838 | 0 | } |
839 | 0 | } else if (a == 0) { |
840 | 0 | for (comp_num = 0; comp_num < 3; comp_num++) |
841 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = 0xFF; |
842 | 0 | for (; comp_num < num_comp; comp_num++) |
843 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = 0; |
844 | 0 | } |
845 | 0 | position += 1; |
846 | 0 | } |
847 | 0 | } |
848 | 0 | } |
849 | 0 | else { |
850 | 0 | for (y = 0; y < height; y++) { |
851 | 0 | position = y * rowstride; |
852 | 0 | for (x = 0; x < width; x++) { |
853 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
854 | 0 | a = buf_ptr[position + planestride * (size_t)num_comp]; |
855 | 0 | if ((a + 1) & 0xfe) { |
856 | 0 | a ^= 0xff; |
857 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
858 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
859 | 0 | tmp = ((0xFF - comp) * a) + 0x80; |
860 | 0 | comp += (tmp + (tmp >> 8)) >> 8; |
861 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = comp; |
862 | 0 | } |
863 | 0 | } else if (a == 0) { |
864 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) |
865 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = 0xFF; |
866 | 0 | } |
867 | 0 | position += 1; |
868 | 0 | } |
869 | 0 | } |
870 | 0 | } |
871 | 35.5k | } else { |
872 | 397k | for (y = 0; y < height; y++) { |
873 | 362k | position = y * rowstride; |
874 | 343M | for (x = 0; x < width; x++) { |
875 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
876 | 343M | a = buf_ptr[position + planestride * (size_t)num_comp]; |
877 | 343M | if ((a + 1) & 0xfe) { |
878 | 5.09M | a ^= 0xff; |
879 | 25.4M | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
880 | 20.3M | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
881 | 20.3M | tmp = ((- comp) * a) + 0x80; |
882 | 20.3M | comp += (tmp + (tmp >> 8)) >> 8; |
883 | 20.3M | buf_ptr[position + planestride * (size_t)comp_num] = comp; |
884 | 20.3M | } |
885 | 338M | } else if (a == 0) { |
886 | 1.04G | for (comp_num = 0; comp_num < num_comp; comp_num++) |
887 | 834M | buf_ptr[position + planestride * (size_t)comp_num] = 0; |
888 | 208M | } |
889 | 343M | position += 1; |
890 | 343M | } |
891 | 362k | } |
892 | 35.5k | } |
893 | 35.5k | } |
894 | | |
895 | | void |
896 | | gx_blend_image_buffer16(byte *buf_ptr_, int width, int height, int rowstride, |
897 | | int planestride, int num_comp, int additive, bool keep_native) |
898 | 0 | { |
899 | 0 | uint16_t *buf_ptr = (uint16_t *)(void *)buf_ptr_; |
900 | 0 | int x, y; |
901 | 0 | int position; |
902 | 0 | int comp, a; |
903 | 0 | int tmp, comp_num; |
904 | | |
905 | | /* planestride and rowstride are in bytes, and we want them in shorts */ |
906 | 0 | planestride >>= 1; |
907 | 0 | rowstride >>= 1; |
908 | |
|
909 | 0 | if (additive) |
910 | 0 | { |
911 | 0 | if (num_comp > 3) { |
912 | | /* Note that the input here is native endian, and the output must be in big endian! */ |
913 | 0 | for (y = 0; y < height; y++) { |
914 | 0 | position = y * rowstride; |
915 | 0 | for (x = 0; x < width; x++) { |
916 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
917 | 0 | a = buf_ptr[position + planestride * (size_t)num_comp]; |
918 | 0 | if (a == 0) { |
919 | 0 | for (comp_num = 0; comp_num < 3; comp_num++) |
920 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = 65535; |
921 | 0 | for (; comp_num < num_comp; comp_num++) |
922 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = 0; |
923 | 0 | } else if (a == 0xffff) { |
924 | | #if ARCH_IS_BIG_ENDIAN |
925 | | #else |
926 | 0 | if (!keep_native) { |
927 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
928 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
929 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8; |
930 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp; |
931 | 0 | } |
932 | 0 | } |
933 | 0 | #endif |
934 | 0 | } else { |
935 | 0 | int b = 65535; |
936 | 0 | a ^= 0xffff; |
937 | 0 | a += a >> 15; /* a is now 0 to 0x10000 */ |
938 | 0 | a >>= 1; /* We can only use 15 bits as bg-comp has a sign bit we can't lose */ |
939 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
940 | 0 | if (comp_num == 3) |
941 | 0 | b = 0; |
942 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
943 | 0 | tmp = ((b - comp) * a) + 0x4000; |
944 | 0 | comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */ |
945 | | /* Store as big endian */ |
946 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8; |
947 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp; |
948 | 0 | } |
949 | 0 | } |
950 | 0 | position += 1; |
951 | 0 | } |
952 | 0 | } |
953 | 0 | } |
954 | 0 | else { |
955 | | /* Note that the input here is native endian, and the output must be in big endian! */ |
956 | 0 | for (y = 0; y < height; y++) { |
957 | 0 | position = y * rowstride; |
958 | 0 | for (x = 0; x < width; x++) { |
959 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
960 | 0 | a = buf_ptr[position + planestride * (size_t)num_comp]; |
961 | 0 | if (a == 0) { |
962 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
963 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = 65535; |
964 | 0 | } |
965 | 0 | } else if (a == 0xffff) { |
966 | | #if ARCH_IS_BIG_ENDIAN |
967 | | #else |
968 | 0 | if (!keep_native) { |
969 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
970 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
971 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8; |
972 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp; |
973 | 0 | } |
974 | 0 | } |
975 | 0 | #endif |
976 | 0 | } else { |
977 | 0 | a ^= 0xffff; |
978 | 0 | a += a >> 15; /* a is now 0 to 0x10000 */ |
979 | 0 | a >>= 1; /* We can only use 15 bits as bg-comp has a sign bit we can't lose */ |
980 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
981 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
982 | 0 | tmp = ((65535 - comp) * a) + 0x4000; |
983 | 0 | comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */ |
984 | | /* Store as big endian */ |
985 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8; |
986 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp; |
987 | 0 | } |
988 | 0 | } |
989 | 0 | position += 1; |
990 | 0 | } |
991 | 0 | } |
992 | 0 | } |
993 | 0 | } else { |
994 | | /* Note that the input here is native endian, and the output must be in big endian! */ |
995 | 0 | for (y = 0; y < height; y++) { |
996 | 0 | position = y * rowstride; |
997 | 0 | for (x = 0; x < width; x++) { |
998 | | /* composite RGBA (or CMYKA, etc.) pixel with over solid background */ |
999 | 0 | a = buf_ptr[position + planestride * (size_t)num_comp]; |
1000 | 0 | if (a == 0) { |
1001 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1002 | 0 | buf_ptr[position + planestride * (size_t)comp_num] = 0; |
1003 | 0 | } |
1004 | 0 | } else if (a == 0xffff) { |
1005 | | #if ARCH_IS_BIG_ENDIAN |
1006 | | #else |
1007 | 0 | if (!keep_native) { |
1008 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1009 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
1010 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8; |
1011 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp; |
1012 | 0 | } |
1013 | 0 | } |
1014 | 0 | #endif |
1015 | 0 | } else { |
1016 | 0 | a ^= 0xffff; |
1017 | 0 | a += a >> 15; /* a is now 0 to 0x10000 */ |
1018 | 0 | a >>= 1; /* We can only use 15 bits as -comp has a sign bit we can't lose */ |
1019 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1020 | 0 | comp = buf_ptr[position + planestride * (size_t)comp_num]; |
1021 | 0 | tmp = ((- comp) * a) + 0x4000; |
1022 | 0 | comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */ |
1023 | | /* Store as big endian */ |
1024 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8; |
1025 | 0 | ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp; |
1026 | 0 | } |
1027 | 0 | } |
1028 | 0 | position += 1; |
1029 | 0 | } |
1030 | 0 | } |
1031 | 0 | } |
1032 | 0 | } |
1033 | | |
1034 | | int |
1035 | | gx_put_blended_image_custom(gx_device *target, byte *buf_ptr_, |
1036 | | int planestride, int rowstride, |
1037 | | int x0, int y0, int width, int height, |
1038 | | int num_comp, uint16_t bg, bool deep) |
1039 | 0 | { |
1040 | 0 | int code = 0; |
1041 | 0 | int x, y, tmp, comp_num; |
1042 | 0 | gx_color_index color; |
1043 | 0 | gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
1044 | 0 | gx_color_value comp; |
1045 | 0 | uint16_t *buf_ptr = (uint16_t *)(void *)buf_ptr_; |
1046 | | |
1047 | | /* Send pixel data to the target device. */ |
1048 | 0 | if (deep) { |
1049 | 0 | for (y = 0; y < height; y++) { |
1050 | 0 | for (x = 0; x < width; x++) { |
1051 | | |
1052 | | /* composite CMYKA, etc. pixel with over solid background */ |
1053 | 0 | #define GET16(v) (*((uint16_t *)(void *)&(v))) |
1054 | 0 | uint16_t a = GET16(buf_ptr[x + planestride * (size_t)num_comp]); |
1055 | |
|
1056 | 0 | if (a == 0) { |
1057 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1058 | 0 | cv[comp_num] = bg; |
1059 | 0 | } |
1060 | 0 | } else if (a == 0xffff) { |
1061 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1062 | 0 | comp = buf_ptr[x + planestride * (size_t)comp_num]; |
1063 | 0 | cv[comp_num] = comp; |
1064 | 0 | } |
1065 | 0 | } else { |
1066 | 0 | a ^= 0xffff; |
1067 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1068 | 0 | comp = GET16(buf_ptr[x + planestride * (size_t)comp_num]); |
1069 | 0 | tmp = ((bg - comp) * a) + 0x8000; |
1070 | 0 | cv[comp_num] = comp + ((tmp + (tmp>>16))>>16); |
1071 | 0 | } |
1072 | 0 | } |
1073 | 0 | color = dev_proc(target, encode_color)(target, cv); |
1074 | 0 | code = dev_proc(target, fill_rectangle)(target, x + x0, |
1075 | 0 | y + y0, 1, 1, color); |
1076 | 0 | if (code < 0) |
1077 | 0 | return code; |
1078 | 0 | } |
1079 | | |
1080 | 0 | buf_ptr += rowstride; |
1081 | 0 | } |
1082 | 0 | } else { |
1083 | 0 | bg >>= 8; |
1084 | 0 | for (y = 0; y < height; y++) { |
1085 | 0 | for (x = 0; x < width; x++) { |
1086 | | |
1087 | | /* composite CMYKA, etc. pixel with over solid background */ |
1088 | 0 | byte a = buf_ptr[x + planestride * (size_t)num_comp]; |
1089 | |
|
1090 | 0 | if ((a + 1) & 0xfe) { |
1091 | 0 | a ^= 0xff; |
1092 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1093 | 0 | comp = buf_ptr[x + planestride * (size_t)comp_num]; |
1094 | 0 | tmp = ((bg - comp) * a) + 0x80; |
1095 | 0 | comp += tmp + (tmp >> 8); |
1096 | 0 | cv[comp_num] = comp; |
1097 | 0 | } |
1098 | 0 | } else if (a == 0) { |
1099 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1100 | 0 | cv[comp_num] = bg; |
1101 | 0 | } |
1102 | 0 | } else { |
1103 | 0 | for (comp_num = 0; comp_num < num_comp; comp_num++) { |
1104 | 0 | comp = buf_ptr[x + planestride * (size_t)comp_num]; |
1105 | 0 | cv[comp_num] = (comp << 8) + comp; |
1106 | 0 | } |
1107 | 0 | } |
1108 | 0 | color = dev_proc(target, encode_color)(target, cv); |
1109 | 0 | code = dev_proc(target, fill_rectangle)(target, x + x0, |
1110 | 0 | y + y0, 1, 1, color); |
1111 | 0 | if (code < 0) |
1112 | 0 | return code; |
1113 | 0 | } |
1114 | | |
1115 | 0 | buf_ptr += rowstride; |
1116 | 0 | } |
1117 | 0 | } |
1118 | 0 | return code; |
1119 | 0 | } |