1 /* Copyright (C) 2001-2019 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.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* 12-bit image procedures */
18 #include "gx.h"
19 #include "memory_.h"
20 #include "gpcheck.h"
21 #include "gserrors.h"
22 #include "gxfixed.h"
23 #include "gxfrac.h"
24 #include "gxarith.h"
25 #include "gxmatrix.h"
26 #include "gsccolor.h"
27 #include "gspaint.h"
28 #include "gxdevice.h"
29 #include "gxcmap.h"
30 #include "gxdcolor.h"
31 #include "gxgstate.h"
32 #include "gxdevmem.h"
33 #include "gxcpath.h"
34 #include "gximage.h"
35 #include "gsicc.h"
36 #include "gsicc_cache.h"
37 #include "gsicc_cms.h"
38 #include "gxcie.h"
39 #include "gscie.h"
40 #include "gxdevsop.h"
41 
42 /* ---------------- Unpacking procedures ---------------- */
43 
44 const byte *
sample_unpack_12(byte * bptr,int * pdata_x,const byte * data,int data_x,uint dsize,const sample_map * ignore_smap,int spread,int ignore_num_components_per_plane)45 sample_unpack_12(byte * bptr, int *pdata_x, const byte * data,
46                  int data_x, uint dsize, const sample_map *ignore_smap, int spread,
47                  int ignore_num_components_per_plane)
48 {
49     /* Assuming an identity map for all components. */
50     register frac *bufp = (frac *) bptr;
51     uint dskip = (data_x >> 1) * 3;
52     const byte *psrc = data + dskip;
53 #define inc_bufp(bp, n) bp = (frac *)((byte *)(bp) + (n))
54     uint sample;
55     int left = dsize - dskip;
56 
57     if ((data_x & 1) && left > 0)
58         switch (left) {
59             default:
60                 sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
61                 *bufp = bits2frac(sample, 12);
62                 inc_bufp(bufp, spread);
63                 psrc += 3;
64                 left -= 3;
65                 break;
66             case 2:		/* xxxxxxxx xxxxdddd */
67                 *bufp = (psrc[1] & 0xf) * (frac_1 / 15);
68             case 1:		/* xxxxxxxx */
69                 left = 0;
70         }
71     while (left >= 3) {
72         sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
73         *bufp = bits2frac(sample, 12);
74         inc_bufp(bufp, spread);
75         sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
76         *bufp = bits2frac(sample, 12);
77         inc_bufp(bufp, spread);
78         psrc += 3;
79         left -= 3;
80     }
81     /* Handle trailing bytes. */
82     switch (left) {
83         case 2:		/* dddddddd ddddxxxx */
84             sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
85             *bufp = bits2frac(sample, 12);
86             inc_bufp(bufp, spread);
87             *bufp = (psrc[1] & 0xf) * (frac_1 / 15);
88             break;
89         case 1:		/* dddddddd */
90             sample = (uint) * psrc << 4;
91             *bufp = bits2frac(sample, 12);
92             break;
93         case 0:		/* Nothing more to do. */
94             ;
95     }
96     *pdata_x = 0;
97     return bptr;
98 }
99 
100 /* ------ Strategy procedure ------ */
101 
102 /* Check the prototype. */
103 iclass_proc(gs_image_class_2_fracs);
104 
105 /* Use special (slow) logic for 12-bit source values. */
106 static irender_proc(image_render_frac);
107 static irender_proc(image_render_icc16); /* icc 16bit case */
108 
109 int
gs_image_class_2_fracs(gx_image_enum * penum,irender_proc_t * render_fn)110 gs_image_class_2_fracs(gx_image_enum * penum, irender_proc_t *render_fn)
111 {
112     bool std_cmap_procs;
113 
114     if (penum->bps > 8) {
115         if (penum->use_mask_color) {
116             /* Convert color mask values to fracs. */
117             int i;
118 
119             for (i = 0; i < penum->spp * 2; ++i)
120                 penum->mask_color.values[i] =
121                     bits2frac(penum->mask_color.values[i], 12);
122         }
123         /* If the device has some unique color mapping procs due to its color space,
124            then we will need to use those and go through pixel by pixel instead
125            of blasting through buffers.  This is true for example with many of
126            the color spaces for CUPs */
127         std_cmap_procs = gx_device_uses_std_cmap_procs(penum->dev, penum->pgs);
128         if ( (gs_color_space_get_index(penum->pcs) == gs_color_space_index_DeviceN &&
129             penum->pcs->cmm_icc_profile_data == NULL) || penum->use_mask_color ||
130             penum->bps != 16 || !std_cmap_procs ||
131             gs_color_space_get_index(penum->pcs) == gs_color_space_index_DevicePixel ||
132             gs_color_space_get_index(penum->pcs) == gs_color_space_index_Indexed) {
133             /* DevicePixel color space used in mask from 3x type.  Basically
134                a simple color space that just is scaled to the device bit
135                depth when remapped. No CM needed */
136             if_debug0m('b', penum->memory, "[b]render=frac\n");
137             *render_fn =  &image_render_frac;
138             return 0;
139         } else {
140             /* Set up the link now */
141             const gs_color_space *pcs;
142             gsicc_rendering_param_t rendering_params;
143             int k;
144             int src_num_comp = cs_num_components(penum->pcs);
145             int num_des_comps;
146             int code;
147             cmm_dev_profile_t *dev_profile;
148 
149             code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile);
150             if (code < 0)
151                 return 0;
152             num_des_comps = gsicc_get_device_profile_comps(dev_profile);
153             penum->icc_setup.need_decode = false;
154             /* Check if we need to do any decoding.  If yes, then that will slow us down */
155             for (k = 0; k < src_num_comp; k++) {
156                 if ( penum->map[k].decoding != sd_none ) {
157                     penum->icc_setup.need_decode = true;
158                     break;
159                 }
160             }
161             /* Define the rendering intents */
162             rendering_params.black_point_comp = penum->pgs->blackptcomp;
163             rendering_params.graphics_type_tag = GS_IMAGE_TAG;
164             rendering_params.override_icc = false;
165             rendering_params.preserve_black = gsBKPRESNOTSPECIFIED;
166             rendering_params.rendering_intent = penum->pgs->renderingintent;
167             rendering_params.cmm = gsCMM_DEFAULT;
168             if (gs_color_space_is_PSCIE(penum->pcs) && penum->pcs->icc_equivalent != NULL) {
169                 pcs = penum->pcs->icc_equivalent;
170             } else {
171                 pcs = penum->pcs;
172             }
173             penum->icc_setup.is_lab = pcs->cmm_icc_profile_data->islab;
174             penum->icc_setup.must_halftone = gx_device_must_halftone(penum->dev);
175             penum->icc_setup.has_transfer =
176                 gx_has_transfer(penum->pgs, num_des_comps);
177             if (penum->icc_setup.is_lab) penum->icc_setup.need_decode = false;
178             if (penum->icc_link == NULL) {
179                 penum->icc_link = gsicc_get_link(penum->pgs, penum->dev, pcs, NULL,
180                     &rendering_params, penum->memory);
181             }
182             /* Use the direct unpacking proc */
183             penum->unpack = sample_unpackicc_16;
184             if_debug0m('b', penum->memory, "[b]render=icc16\n");
185             *render_fn = &image_render_icc16;
186             return 0;
187         }
188     }
189     return 0;
190 }
191 
192 /* ---------------- Rendering procedures ---------------- */
193 
194 /* ------ Rendering for 12-bit samples ------ */
195 
196 #define FRACS_PER_LONG (ARCH_SIZEOF_LONG / arch_sizeof_frac)
197 typedef union {
198     frac v[GS_IMAGE_MAX_COLOR_COMPONENTS];
199 #define LONGS_PER_COLOR_FRACS\
200   ((GS_IMAGE_MAX_COLOR_COMPONENTS + FRACS_PER_LONG - 1) / FRACS_PER_LONG)
201     long all[LONGS_PER_COLOR_FRACS];	/* for fast comparison */
202 } color_fracs;
203 
204 #define LONGS_PER_4_FRACS ((arch_sizeof_frac * 4 + ARCH_SIZEOF_LONG - 1) / ARCH_SIZEOF_LONG)
205 #if LONGS_PER_4_FRACS == 1
206 #  define COLOR_FRACS_4_EQ(f1, f2)\
207      ((f1).all[0] == (f2).all[0])
208 #else
209 #if LONGS_PER_4_FRACS == 2
210 #  define COLOR_FRACS_4_EQ(f1, f2)\
211      ((f1).all[0] == (f2).all[0] && (f1).all[1] == (f2).all[1])
212 #endif
213 #endif
214 
215 /* Test whether a color is transparent. */
216 static bool
mask_color12_matches(const frac * v,const gx_image_enum * penum,int num_components)217 mask_color12_matches(const frac *v, const gx_image_enum *penum,
218                    int num_components)
219 {
220     int i;
221 
222     for (i = num_components * 2, v += num_components - 1; (i -= 2) >= 0; --v)
223         if (*v < penum->mask_color.values[i] ||
224             *v > penum->mask_color.values[i + 1]
225             )
226             return false;
227     return true;
228 }
229 
230 /* Render an image with more than 8 bits per sample. */
231 /* The samples have been expanded into fracs. */
232 static int
image_render_frac(gx_image_enum * penum,const byte * buffer,int data_x,uint w,int h,gx_device * dev)233 image_render_frac(gx_image_enum * penum, const byte * buffer, int data_x,
234                   uint w, int h, gx_device * dev)
235 {
236     const gs_gstate *pgs = penum->pgs;
237     gs_logical_operation_t lop = penum->log_op;
238     gx_dda_fixed_point pnext;
239     image_posture posture = penum->posture;
240     fixed xl, ytf;
241     fixed pdyx, pdyy;		/* edge of parallelogram */
242     int yt = penum->yci, iht = penum->hci;
243     const gs_color_space *pcs = penum->pcs;
244     cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
245     gs_client_color cc;
246     bool device_color = penum->device_color;
247     const gx_color_map_procs *cmap_procs = gx_get_cmap_procs(pgs, dev);
248     cmap_proc_rgb((*map_rgb)) = cmap_procs->map_rgb;
249     cmap_proc_cmyk((*map_cmyk)) = cmap_procs->map_cmyk;
250     bool use_mask_color = penum->use_mask_color;
251     gx_device_color devc1, devc2;
252     gx_device_color *pdevc = &devc1;
253     gx_device_color *pdevc_next = &devc2;
254     int spp = penum->spp;
255     const frac *psrc_initial = (const frac *)buffer + data_x * spp;
256     const frac *psrc = psrc_initial;
257     const frac *rsrc = psrc + spp; /* psrc + spp at start of run */
258     fixed xrun;			/* x at start of run */
259     int irun;			/* int xrun */
260     fixed yrun;			/* y ditto */
261     color_fracs run;		/* run value */
262     color_fracs next;		/* next sample value */
263     const frac *bufend = psrc + w;
264     int code = 0, mcode = 0;
265     int i;
266     bool is_devn = false;
267     bool is_sep = (gs_color_space_get_index(penum->pcs) ==
268                     gs_color_space_index_Separation);
269 
270     if (h == 0)
271         return 0;
272     pnext = penum->dda.pixel0;
273     xrun = xl = dda_current(pnext.x);
274     irun = fixed2int_var_rounded(xrun);
275     yrun = ytf = dda_current(pnext.y);
276     pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
277     pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
278     if_debug5m('b', penum->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
279                penum->y, data_x, w, fixed2float(xl), fixed2float(ytf));
280     memset(&run, 0, sizeof(run));
281     memset(&next, 0, sizeof(next));
282     /* Ensure that we don't get any false dev_color_eq hits. */
283     set_nonclient_dev_color(&devc1, gx_no_color_index);
284     set_nonclient_dev_color(&devc2, gx_no_color_index);
285     cs_full_init_color(&cc, pcs);
286     run.v[0] = ~psrc[0];	/* force remap */
287 
288     if (dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0)) {
289         for (i = 0; i < GS_CLIENT_COLOR_MAX_COMPONENTS; i++) {
290             pdevc->colors.devn.values[i] = 0;
291             pdevc_next->colors.devn.values[i] = 0;
292         }
293         is_devn = true;
294     }
295     while (psrc < bufend) {
296         next.v[0] = psrc[0];
297         switch (spp) {
298             case 4:		/* may be CMYK */
299                 next.v[1] = psrc[1];
300                 next.v[2] = psrc[2];
301                 next.v[3] = psrc[3];
302                 psrc += 4;
303                 if (COLOR_FRACS_4_EQ(next, run))
304                     goto inc;
305                 if (use_mask_color && mask_color12_matches(next.v, penum, 4)) {
306                     color_set_null(pdevc_next);
307                     goto f;
308                 }
309                 if (device_color) {
310                     (*map_cmyk) (next.v[0], next.v[1],
311                                  next.v[2], next.v[3],
312                                  pdevc_next, pgs, dev,
313                                  gs_color_select_source, NULL);
314                     goto f;
315                 }
316                 decode_frac(next.v[0], cc, 0);
317                 decode_frac(next.v[1], cc, 1);
318                 decode_frac(next.v[2], cc, 2);
319                 decode_frac(next.v[3], cc, 3);
320                 if_debug4m('B', penum->memory, "[B]cc[0..3]=%g,%g,%g,%g\n",
321                            cc.paint.values[0], cc.paint.values[1],
322                            cc.paint.values[2], cc.paint.values[3]);
323                 break;
324             case 3:		/* may be RGB */
325                 next.v[1] = psrc[1];
326                 next.v[2] = psrc[2];
327                 psrc += 3;
328                 if (COLOR_FRACS_4_EQ(next, run))
329                     goto inc;
330                 if (use_mask_color && mask_color12_matches(next.v, penum, 3)) {
331                     color_set_null(pdevc_next);
332                     goto f;
333                 }
334                 if (device_color) {
335                     (*map_rgb) (next.v[0], next.v[1],
336                                 next.v[2], pdevc_next, pgs, dev,
337                                 gs_color_select_source);
338                     goto f;
339                 }
340                 decode_frac(next.v[0], cc, 0);
341                 decode_frac(next.v[1], cc, 1);
342                 decode_frac(next.v[2], cc, 2);
343                 if_debug3m('B', penum->memory, "[B]cc[0..2]=%g,%g,%g\n",
344                            cc.paint.values[0], cc.paint.values[1],
345                            cc.paint.values[2]);
346                 break;
347             case 1:		/* may be Gray, but could be a separation */
348                 if (is_devn && is_sep) {
349                     psrc++;
350                     if (next.v[0] == run.v[0])
351                         goto inc;
352                     if (use_mask_color && mask_color12_matches(next.v, penum, 1)) {
353                         color_set_null(pdevc_next);
354                         goto f;
355                     }
356                     decode_frac(next.v[0], cc, 0);
357                     if_debug1m('B', penum->memory, "[B]cc[0]=%g\n",
358                                cc.paint.values[0]);
359                     break;
360                 } else {
361                     psrc++;
362                     if (next.v[0] == run.v[0])
363                         goto inc;
364                     if (use_mask_color && mask_color12_matches(next.v, penum, 1)) {
365                         color_set_null(pdevc_next);
366                         goto f;
367                     }
368                     if (device_color) {
369                         (*map_rgb) (next.v[0], next.v[0],
370                                     next.v[0], pdevc_next, pgs, dev,
371                                     gs_color_select_source);
372                         goto f;
373                     }
374                     decode_frac(next.v[0], cc, 0);
375                     if_debug1('B', "[B]cc[0]=%g\n",
376                               cc.paint.values[0]);
377                     break;
378                 }
379             default:		/* DeviceN */
380                 {
381                     int i;
382 
383                     for (i = 1; i < spp; ++i)
384                         next.v[i] = psrc[i];
385                     psrc += spp;
386                     if (!memcmp(next.v, run.v, spp * sizeof(next.v[0])))
387                         goto inc;
388                     if (use_mask_color &&
389                         mask_color12_matches(next.v, penum, spp)
390                         ) {
391                         color_set_null(pdevc_next);
392                         goto f;
393                     }
394                     for (i = 0; i < spp; ++i)
395                         decode_frac(next.v[i], cc, i);
396 #ifdef DEBUG
397                     if (gs_debug_c('B')) {
398                         dmprintf2(dev->memory, "[B]cc[0..%d]=%g", spp - 1,
399                                  cc.paint.values[0]);
400                         for (i = 1; i < spp; ++i)
401                             dmprintf1(dev->memory, ",%g", cc.paint.values[i]);
402                         dmputs(dev->memory, "\n");
403                     }
404 #endif
405                 }
406                 break;
407         }
408         mcode = remap_color(&cc, pcs, pdevc_next, pgs, dev,
409                            gs_color_select_source);
410         if (mcode < 0)
411             goto fill;
412 f:
413         if (sizeof(pdevc_next->colors.binary.color[0]) <= sizeof(ulong))
414             if_debug7m('B', penum->memory,
415                        "[B]0x%x,0x%x,0x%x,0x%x -> 0x%lx,0x%lx,0x%lx\n",
416                        next.v[0], next.v[1], next.v[2], next.v[3],
417                        (ulong)pdevc_next->colors.binary.color[0],
418                        (ulong)pdevc_next->colors.binary.color[1],
419                        (ulong)pdevc_next->type);
420         else
421             if_debug9m('B', penum->memory,
422                        "[B]0x%x,0x%x,0x%x,0x%x -> 0x%08lx%08lx,0x%08lx%08lx,0x%lx\n",
423                        next.v[0], next.v[1], next.v[2], next.v[3],
424                        (ulong)(pdevc_next->colors.binary.color[0] >>
425                                8 * (sizeof(pdevc_next->colors.binary.color[0]) - sizeof(ulong))),
426                        (ulong)pdevc_next->colors.binary.color[0],
427                        (ulong)(pdevc_next->colors.binary.color[1] >>
428                                8 * (sizeof(pdevc_next->colors.binary.color[1]) - sizeof(ulong))),
429                        (ulong)pdevc_next->colors.binary.color[1],
430                        (ulong)pdevc_next->type);
431 /* NB: sizeof gx_color_index is 4 or 8 bytes! */
432 
433         /* Even though the supplied colors don't match, */
434         /* the device colors might. */
435         if (!dev_color_eq(devc1, devc2)) {
436             /* Fill the region between xrun/irun and xl */
437             gx_device_color *ptemp;
438 
439 fill:
440             if (posture != image_portrait) {	/* Parallelogram */
441                 code = (*dev_proc(dev, fill_parallelogram))
442                     (dev, xrun, yrun,
443                      xl - xrun, ytf - yrun, pdyx, pdyy,
444                      pdevc, lop);
445             } else {		/* Rectangle */
446                 int xi = irun;
447                 int wi = (irun = fixed2int_var_rounded(xl)) - xi;
448 
449                 if (wi < 0)
450                     xi += wi, wi = -wi;
451                 code = gx_fill_rectangle_device_rop(xi, yt,
452                                                   wi, iht, pdevc, dev, lop);
453             }
454             if (code < 0)
455                 goto err;
456             rsrc = psrc;
457             if ((code = mcode) < 0)
458                 goto err;
459             ptemp = pdevc;
460             pdevc = pdevc_next;
461             pdevc_next = ptemp;
462             xrun = xl;
463             yrun = ytf;
464         }
465         run = next;
466 inc:
467         dda_next_assign(pnext.x, xl);
468         dda_next_assign(pnext.y, ytf);
469     }
470     /* Fill the final run. */
471     if (posture != image_portrait) {
472         code = (*dev_proc(dev, fill_parallelogram))
473             (dev, xrun, yrun, xl - xrun, ytf - yrun, pdyx, pdyy, pdevc, lop);
474     } else {
475         /* Same code as above near 'fill:' : */
476         int xi = irun;
477         int wi = (irun = fixed2int_var_rounded(xl)) - xi;
478 
479         if (wi < 0)
480             xi += wi, wi = -wi;
481         code = gx_fill_rectangle_device_rop(xi, yt,
482                                           wi, iht, pdevc, dev, lop);
483     }
484     return (code < 0 ? code : 1);
485 
486     /* Save position if error, in case we resume. */
487 err:
488     penum->used.x = (rsrc - spp - psrc_initial) / spp;
489     penum->used.y = 0;
490     return code;
491 }
492 
493 static inline float
rescale_input_color(gs_range range,float input)494 rescale_input_color(gs_range range, float input)
495 {
496     return((input-range.rmin)/(range.rmax-range.rmin));
497 }
498 
499 /* This one includes an extra adjustment for the CIE PS color space
500    non standard range */
501 static void
decode_row_cie16(const gx_image_enum * penum,const unsigned short * psrc,int spp,unsigned short * pdes,const unsigned short * bufend,gs_range range_array[])502 decode_row_cie16(const gx_image_enum *penum, const unsigned short *psrc,
503                  int spp, unsigned short *pdes,
504                   const unsigned short *bufend, gs_range range_array[])
505 {
506     unsigned short *curr_pos = pdes;
507     int k;
508     float temp;
509 
510     while ( curr_pos < bufend ) {
511         for ( k = 0; k < spp; k ++ ) {
512             switch ( penum->map[k].decoding ) {
513                 case sd_none:
514                     *curr_pos = *psrc;
515                     break;
516                 case sd_lookup:
517                     temp = penum->map[k].decode_lookup[(*psrc) >> 4]*65535.0;
518                     temp = rescale_input_color(range_array[k], temp);
519                     temp = temp*65535;
520                     if (temp > 65535.0) temp = 65535.0;
521                     if (temp < 0 ) temp = 0;
522                     *curr_pos = (unsigned short) temp;
523                     break;
524                 case sd_compute:
525                     temp = penum->map[k].decode_base +
526                         (*psrc) * penum->map[k].decode_factor;
527                     temp = rescale_input_color(range_array[k], temp);
528                     temp = temp*65535;
529                     if (temp > 65535) temp = 65535;
530                     if (temp < 0 ) temp = 0;
531                     *curr_pos = (unsigned short) temp;
532                 default:
533                     break;
534             }
535             curr_pos++;
536             psrc++;
537         }
538     }
539 }
540 
541 static void
decode_row16(const gx_image_enum * penum,const unsigned short * psrc,int spp,unsigned short * pdes,const unsigned short * bufend)542 decode_row16(const gx_image_enum *penum, const unsigned short *psrc, int spp,
543              unsigned short *pdes,const unsigned short *bufend)
544 {
545     unsigned short *curr_pos = pdes;
546     int k;
547     float temp;
548 
549     while ( curr_pos < bufend ) {
550         for ( k = 0; k < spp; k ++ ) {
551             switch ( penum->map[k].decoding ) {
552                 case sd_none:
553                     *curr_pos = *psrc;
554                     break;
555                 case sd_lookup:
556                     temp = penum->map[k].decode_lookup[(*psrc) >> 4]*65535;
557                     if (temp > 65535) temp = 65535;
558                     if (temp < 0 ) temp = 0;
559                     *curr_pos = (unsigned short) temp;
560                     break;
561                 case sd_compute:
562                     temp = penum->map[k].decode_base +
563                         (*psrc) * penum->map[k].decode_factor;
564                     temp *= 65535;
565                     if (temp > 65535) temp = 65535;
566                     if (temp < 0 ) temp = 0;
567                     *curr_pos = (unsigned short) temp;
568                 default:
569                     break;
570             }
571             curr_pos++;
572             psrc++;
573         }
574     }
575 }
576 
577 /* Render an image with more than 8 bits per sample where we keep the data
578    in 16 bit form and hand directly to the CMM */
579 static int
image_render_icc16(gx_image_enum * penum,const byte * buffer,int data_x,uint w,int h,gx_device * dev)580 image_render_icc16(gx_image_enum * penum, const byte * buffer, int data_x,
581                   uint w, int h, gx_device * dev)
582 {
583     const gs_gstate *pgs = penum->pgs;
584     gs_logical_operation_t lop = penum->log_op;
585     gx_dda_fixed_point pnext;
586     image_posture posture = penum->posture;
587     fixed pdyx, pdyy;		/* edge of parallelogram */
588     int vci, vdi;
589     int spp = penum->spp;
590     const unsigned short *psrc = (const unsigned short *)buffer + data_x * spp;
591     fixed xrun;			/* x at start of run */
592     int irun;			/* int xrun */
593     fixed yrun;			/* y ditto */
594     const unsigned short *bufend = psrc + w;
595     unsigned short *run;
596     int code = 0;
597     gsicc_bufferdesc_t input_buff_desc;
598     gsicc_bufferdesc_t output_buff_desc;
599     unsigned short *psrc_cm, *psrc_cm_start, *psrc_decode, *psrc_cm_initial;
600     int k;
601     int spp_cm, num_pixels;
602     bool need_decode = penum->icc_setup.need_decode;
603     bool must_halftone = penum->icc_setup.must_halftone;
604     bool has_transfer = penum->icc_setup.has_transfer;
605     int num_des_comps;
606     cmm_dev_profile_t *dev_profile;
607     gx_cmapper_t data;
608     gx_cmapper_fn *mapper;
609     gx_color_value *conc = &data.conc[0];
610     int first = 1;
611 
612     if (h == 0)
613         return 0;
614 
615     if (penum->icc_link == NULL) {
616         return gs_rethrow(-1, "ICC Link not created during image render icc16");
617     }
618     gx_get_cmapper(&data, pgs, dev, has_transfer, must_halftone, gs_color_select_source);
619     mapper = data.set_color;
620     /* Needed for device N */
621     code = dev_proc(dev, get_profile)(dev, &dev_profile);
622     num_des_comps = gsicc_get_device_profile_comps(dev_profile);
623     /* If the link is the identity, then we don't need to do any color
624        conversions except for potentially a decode. */
625     if (penum->icc_link->is_identity && !need_decode) {
626         /* Fastest case.  No decode or CM needed */
627         psrc_cm = (unsigned short *) psrc;
628         spp_cm = spp;
629         bufend = psrc_cm +  w;
630         psrc_cm_start = NULL;
631     } else {
632         spp_cm = num_des_comps;
633         psrc_cm = (unsigned short*) gs_alloc_bytes(pgs->memory,
634                         sizeof(unsigned short)  * w * spp_cm/spp,
635                         "image_render_icc16");
636         psrc_cm_start = psrc_cm;
637         bufend = psrc_cm +  w * spp_cm/spp;
638         if (penum->icc_link->is_identity) {
639             /* decode only. no CM.  This is slow but does not happen that often */
640             decode_row16(penum, psrc, spp, psrc_cm, bufend);
641         } else {
642             /* Set up the buffer descriptors. */
643             num_pixels = w/spp;
644             gsicc_init_buffer(&input_buff_desc, spp, 2,
645                           false, false, false, 0, w * 2,
646                           1, num_pixels);
647             gsicc_init_buffer(&output_buff_desc, spp_cm, 2,
648                           false, false, false, 0, num_pixels * spp_cm * 2,
649                           1, num_pixels);
650             /* For now, just blast it all through the link. If we had a significant reduction
651                we will want to repack the data first and then do this.  That will be
652                an optimization shortly.  For now just allocate a new output
653                buffer.  We can reuse the old one if the number of channels in the output is
654                less than or equal to the new one.  */
655             if (need_decode) {
656                 /* Need decode and CM.  This is slow but does not happen that often */
657                 psrc_decode = (unsigned short*) gs_alloc_bytes(pgs->memory,
658                                 sizeof(unsigned short) * w * spp_cm/spp,
659                                 "image_render_icc16");
660                 if (!penum->use_cie_range) {
661                     decode_row16(penum, psrc, spp, psrc_decode,
662                                     (const unsigned short*) (psrc_decode+w));
663                 } else {
664                     /* Decode needs to include adjustment for CIE range */
665                     decode_row_cie16(penum, psrc, spp, psrc_decode,
666                                         (const unsigned short*) (psrc_decode+w),
667                                          get_cie_range(penum->pcs));
668                 }
669                 (penum->icc_link->procs.map_buffer)(dev, penum->icc_link,
670                                                     &input_buff_desc,
671                                                     &output_buff_desc,
672                                                     (void*) psrc_decode,
673                                                     (void*) psrc_cm);
674                 gs_free_object(pgs->memory, (byte *)psrc_decode, "image_render_color_icc");
675             } else {
676                 /* CM only. No decode */
677                 (penum->icc_link->procs.map_buffer)(dev, penum->icc_link,
678                                                     &input_buff_desc,
679                                                     &output_buff_desc,
680                                                     (void*) psrc,
681                                                     (void*) psrc_cm);
682             }
683         }
684     }
685     psrc_cm_initial = psrc_cm;
686 
687     pnext = penum->dda.pixel0;
688     xrun = dda_current(pnext.x);
689     yrun = dda_current(pnext.y);
690     pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
691     pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
692     switch (posture) {
693         case image_portrait:
694             vci = penum->yci, vdi = penum->hci;
695             irun = fixed2int_var_rounded(xrun);
696             break;
697         case image_landscape:
698         default:    /* we don't handle skew -- treat as landscape */
699             vci = penum->xci, vdi = penum->wci;
700             irun = fixed2int_var_rounded(yrun);
701             break;
702     }
703     if_debug5m('b', penum->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
704                penum->y, data_x, w, fixed2float(xrun), fixed2float(yrun));
705     while (psrc_cm < bufend) {
706         /* Find the length of the next run. It will either end when we hit
707          * the end of the source data, or when the pixel data differs. */
708         run = psrc_cm + spp_cm;
709         while (1)
710         {
711             dda_next(pnext.x);
712             dda_next(pnext.y);
713             if (run >= bufend)
714                 break;
715             if (memcmp(run, psrc_cm, spp_cm * 2))
716                 break;
717             if (posture == image_skewed) {
718                 if (first) /* We always need to map the first pixel on a line */
719                     break;
720                 /* The color doesn't need remapping, but we can't handle a run */
721                 goto skewed_but_same;
722             }
723             run += spp_cm;
724         }
725         first = 0;
726         /* So we have a run of pixels from psrc_cm to run that are all the same. */
727         /* This needs to be sped up */
728         for ( k = 0; k < spp_cm; k++ ) {
729             conc[k] = psrc_cm[k];
730         }
731         mapper(&data);
732         /* Fill the region between */
733         /* xrun/irun and pnext.x/pnext.y */
734         switch(posture)
735         {
736         default: /* skew */
737 skewed_but_same:
738         {
739             fixed xprev = dda_current(pnext.x);
740             fixed yprev = dda_current(pnext.y);
741             code = (*dev_proc(dev, fill_parallelogram))
742                 (dev, xrun, yrun, xprev - xrun, yprev - yrun, pdyx, pdyy,
743                  &data.devc, lop);
744             xrun = xprev;
745             yrun = yprev;
746             break;
747         }
748         case image_portrait:
749         {
750             int xi = irun;
751             int wi = (irun = fixed2int_var_rounded(dda_current(pnext.x))) - xi;
752 
753             if (wi < 0)
754                 xi += wi, wi = -wi;
755             if (wi > 0)
756                 code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi,
757                                                     &data.devc, dev, lop);
758             break;
759         }
760         case image_landscape:
761         {
762             int yi = irun;
763             int hi = (irun = fixed2int_var_rounded(dda_current(pnext.y))) - yi;
764 
765             if (hi < 0)
766                 yi += hi, hi = -hi;
767             if (hi > 0)
768                 code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi,
769                                                     &data.devc, dev, lop);
770         }
771         }
772         if (code < 0)
773             goto err;
774         psrc_cm = run;
775     }
776     /* Free cm buffer, if it was used */
777     if (psrc_cm_start != NULL) {
778         gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_icc16");
779     }
780     return (code < 0 ? code : 1);
781 
782     /* Save position if error, in case we resume. */
783 err:
784     gs_free_object(pgs->memory, (byte *)psrc_cm_start, "image_render_icc16");
785     penum->used.x = (psrc_cm - psrc_cm_initial) / spp_cm;
786     penum->used.y = 0;
787     return code;
788 }
789