blob: 1459817cfa4c67d31f6abf6f7c750214cd95abb6 [file] [log] [blame]
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001/*
2 * Raster file routines for CUPS.
3 *
Haibo Huang4c283622019-12-13 16:47:52 -08004 * Copyright 2007-2019 by Apple Inc.
Philip P. Moltmann25aee822016-12-15 12:16:46 -08005 * Copyright 1997-2006 by Easy Software Products.
6 *
7 * This file is part of the CUPS Imaging library.
8 *
Haibo Huang4c283622019-12-13 16:47:52 -08009 * Licensed under Apache License v2.0. See the file "LICENSE" for more
10 * information.
Philip P. Moltmann25aee822016-12-15 12:16:46 -080011 */
12
13/*
14 * Include necessary headers...
15 */
16
Haibo Huang4c283622019-12-13 16:47:52 -080017#include "raster-private.h"
18#include "debug-internal.h"
Philip P. Moltmann25aee822016-12-15 12:16:46 -080019#ifdef HAVE_STDINT_H
20# include <stdint.h>
21#endif /* HAVE_STDINT_H */
22
23
24/*
25 * Private structures...
26 */
27
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -070028typedef void (*_cups_copyfunc_t)(void *dst, const void *src, size_t bytes);
29
30
31/*
32 * Local globals...
33 */
34
Haibo Huang4c283622019-12-13 16:47:52 -080035static const char * const apple_media_types[] =
36{ /* media-type values for Apple Raster */
37 "auto",
38 "stationery",
39 "transparency",
40 "envelope",
41 "cardstock",
42 "labels",
43 "stationery-letterhead",
44 "disc",
45 "photographic-matte",
46 "photographic-satin",
47 "photographic-semi-gloss",
48 "photographic-glossy",
49 "photographic-high-gloss",
50 "other"
51};
52
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -070053#ifdef DEBUG
Haibo Huang4c283622019-12-13 16:47:52 -080054static const char * const cups_modes[] =
55{ /* Open modes */
56 "CUPS_RASTER_READ",
57 "CUPS_RASTER_WRITE",
58 "CUPS_RASTER_WRITE_COMPRESSED",
59 "CUPS_RASTER_WRITE_PWG",
60 "CUPS_RASTER_WRITE_APPLE"
61};
62#endif /* DEBUG */
63
64
65/*
66 * Local functions...
67 */
68
69static ssize_t cups_raster_io(cups_raster_t *r, unsigned char *buf, size_t bytes);
70static ssize_t cups_raster_read(cups_raster_t *r, unsigned char *buf, size_t bytes);
71static int cups_raster_update(cups_raster_t *r);
72static ssize_t cups_raster_write(cups_raster_t *r, const unsigned char *pixels);
73static void cups_swap(unsigned char *buf, size_t bytes);
74static void cups_swap_copy(unsigned char *dst, const unsigned char *src, size_t bytes);
75
76
77/*
78 * '_cupsRasterColorSpaceString()' - Return the colorspace name for a
79 * cupsColorSpace value.
80 */
81
82const char *
83_cupsRasterColorSpaceString(
84 cups_cspace_t cspace) /* I - cupsColorSpace value */
85{
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -070086 static const char * const cups_color_spaces[] =
87 { /* Color spaces */
Haibo Huang4c283622019-12-13 16:47:52 -080088 "W",
89 "RGB",
90 "RGBA",
91 "K",
92 "CMY",
93 "YMC",
94 "CMYK",
95 "YMCK",
96 "KCMY",
97 "KCMYcm",
98 "GMCK",
99 "GMCS",
100 "WHITE",
101 "GOLD",
102 "SILVER",
103 "CIEXYZ",
104 "CIELab",
105 "RGBW",
106 "SW",
107 "SRGB",
108 "ADOBERGB",
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700109 "21",
110 "22",
111 "23",
112 "24",
113 "25",
114 "26",
115 "27",
116 "28",
117 "29",
118 "30",
119 "31",
Haibo Huang4c283622019-12-13 16:47:52 -0800120 "ICC1",
121 "ICC2",
122 "ICC3",
123 "ICC4",
124 "ICC5",
125 "ICC6",
126 "ICC7",
127 "ICC8",
128 "ICC9",
129 "ICCA",
130 "ICCB",
131 "ICCC",
132 "ICCD",
133 "ICCE",
134 "ICCF",
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700135 "47",
Haibo Huang4c283622019-12-13 16:47:52 -0800136 "DEVICE1",
137 "DEVICE2",
138 "DEVICE3",
139 "DEVICE4",
140 "DEVICE5",
141 "DEVICE6",
142 "DEVICE7",
143 "DEVICE8",
144 "DEVICE9",
145 "DEVICEA",
146 "DEVICEB",
147 "DEVICEC",
148 "DEVICED",
149 "DEVICEE",
150 "DEVICEF"
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700151 };
Haibo Huang4c283622019-12-13 16:47:52 -0800152
153 if (cspace < CUPS_CSPACE_W || cspace > CUPS_CSPACE_DEVICEF)
154 return ("Unknown");
155 else
156 return (cups_color_spaces[cspace]);
157}
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700158
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800159
160/*
Haibo Huang4c283622019-12-13 16:47:52 -0800161 * '_cupsRasterDelete()' - Free a raster stream.
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800162 *
163 * The file descriptor associated with the raster stream must be closed
164 * separately as needed.
165 */
166
167void
Haibo Huang4c283622019-12-13 16:47:52 -0800168_cupsRasterDelete(cups_raster_t *r) /* I - Stream to free */
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800169{
170 if (r != NULL)
171 {
172 if (r->buffer)
173 free(r->buffer);
174
175 if (r->pixels)
176 free(r->pixels);
177
178 free(r);
179 }
180}
181
182
183/*
Haibo Huang4c283622019-12-13 16:47:52 -0800184 * '_cupsRasterInitPWGHeader()' - Initialize a page header for PWG Raster output.
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800185 *
186 * The "media" argument specifies the media to use.
187 *
188 * The "type" argument specifies a "pwg-raster-document-type-supported" value
189 * that controls the color space and bit depth of the raster data.
190 *
191 * The "xres" and "yres" arguments specify the raster resolution in dots per
192 * inch.
193 *
194 * The "sheet_back" argument specifies a "pwg-raster-document-sheet-back" value
195 * to apply for the back side of a page. Pass @code NULL@ for the front side.
196 *
197 * @since CUPS 2.2/macOS 10.12@
198 */
199
200int /* O - 1 on success, 0 on failure */
Haibo Huang4c283622019-12-13 16:47:52 -0800201_cupsRasterInitPWGHeader(
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800202 cups_page_header2_t *h, /* I - Page header */
203 pwg_media_t *media, /* I - PWG media information */
204 const char *type, /* I - PWG raster type string */
205 int xdpi, /* I - Cross-feed direction (horizontal) resolution */
206 int ydpi, /* I - Feed direction (vertical) resolution */
207 const char *sides, /* I - IPP "sides" option value */
208 const char *sheet_back) /* I - Transform for back side or @code NULL@ for none */
209{
210 if (!h || !media || !type || xdpi <= 0 || ydpi <= 0)
211 {
212 _cupsRasterAddError("%s", strerror(EINVAL));
213 return (0);
214 }
215
216 /*
217 * Initialize the page header...
218 */
219
220 memset(h, 0, sizeof(cups_page_header2_t));
221
222 strlcpy(h->cupsPageSizeName, media->pwg, sizeof(h->cupsPageSizeName));
223
224 h->PageSize[0] = (unsigned)(72 * media->width / 2540);
225 h->PageSize[1] = (unsigned)(72 * media->length / 2540);
226
227 /* This never gets written but is needed for some applications */
228 h->cupsPageSize[0] = 72.0f * media->width / 2540.0f;
229 h->cupsPageSize[1] = 72.0f * media->length / 2540.0f;
230
231 h->ImagingBoundingBox[2] = h->PageSize[0];
232 h->ImagingBoundingBox[3] = h->PageSize[1];
233
234 h->HWResolution[0] = (unsigned)xdpi;
235 h->HWResolution[1] = (unsigned)ydpi;
236
237 h->cupsWidth = (unsigned)(media->width * xdpi / 2540);
238 h->cupsHeight = (unsigned)(media->length * ydpi / 2540);
239
240 if (h->cupsWidth > 0x00ffffff || h->cupsHeight > 0x00ffffff)
241 {
242 _cupsRasterAddError("Raster dimensions too large.");
243 return (0);
244 }
245
246 h->cupsInteger[CUPS_RASTER_PWG_ImageBoxRight] = h->cupsWidth;
247 h->cupsInteger[CUPS_RASTER_PWG_ImageBoxBottom] = h->cupsHeight;
248
249 /*
250 * Colorspace and bytes per line...
251 */
252
253 if (!strcmp(type, "adobe-rgb_8"))
254 {
255 h->cupsBitsPerColor = 8;
256 h->cupsBitsPerPixel = 24;
257 h->cupsColorSpace = CUPS_CSPACE_ADOBERGB;
258 }
259 else if (!strcmp(type, "adobe-rgb_16"))
260 {
261 h->cupsBitsPerColor = 16;
262 h->cupsBitsPerPixel = 48;
263 h->cupsColorSpace = CUPS_CSPACE_ADOBERGB;
264 }
265 else if (!strcmp(type, "black_1"))
266 {
267 h->cupsBitsPerColor = 1;
268 h->cupsBitsPerPixel = 1;
269 h->cupsColorSpace = CUPS_CSPACE_K;
270 }
271 else if (!strcmp(type, "black_8"))
272 {
273 h->cupsBitsPerColor = 8;
274 h->cupsBitsPerPixel = 8;
275 h->cupsColorSpace = CUPS_CSPACE_K;
276 }
277 else if (!strcmp(type, "black_16"))
278 {
279 h->cupsBitsPerColor = 16;
280 h->cupsBitsPerPixel = 16;
281 h->cupsColorSpace = CUPS_CSPACE_K;
282 }
283 else if (!strcmp(type, "cmyk_8"))
284 {
285 h->cupsBitsPerColor = 8;
286 h->cupsBitsPerPixel = 32;
287 h->cupsColorSpace = CUPS_CSPACE_CMYK;
288 }
289 else if (!strcmp(type, "cmyk_16"))
290 {
291 h->cupsBitsPerColor = 16;
292 h->cupsBitsPerPixel = 64;
293 h->cupsColorSpace = CUPS_CSPACE_CMYK;
294 }
295 else if (!strncmp(type, "device", 6) && type[6] >= '1' && type[6] <= '9')
296 {
297 int ncolors, bits; /* Number of colors and bits */
298
299
300 if (sscanf(type, "device%d_%d", &ncolors, &bits) != 2 || ncolors > 15 || (bits != 8 && bits != 16))
301 {
302 _cupsRasterAddError("Unsupported raster type \'%s\'.", type);
303 return (0);
304 }
305
306 h->cupsBitsPerColor = (unsigned)bits;
307 h->cupsBitsPerPixel = (unsigned)(ncolors * bits);
308 h->cupsColorSpace = (cups_cspace_t)(CUPS_CSPACE_DEVICE1 + ncolors - 1);
309 }
310 else if (!strcmp(type, "rgb_8"))
311 {
312 h->cupsBitsPerColor = 8;
313 h->cupsBitsPerPixel = 24;
314 h->cupsColorSpace = CUPS_CSPACE_RGB;
315 }
316 else if (!strcmp(type, "rgb_16"))
317 {
318 h->cupsBitsPerColor = 16;
319 h->cupsBitsPerPixel = 48;
320 h->cupsColorSpace = CUPS_CSPACE_RGB;
321 }
322 else if (!strcmp(type, "sgray_1"))
323 {
324 h->cupsBitsPerColor = 1;
325 h->cupsBitsPerPixel = 1;
326 h->cupsColorSpace = CUPS_CSPACE_SW;
327 }
328 else if (!strcmp(type, "sgray_8"))
329 {
330 h->cupsBitsPerColor = 8;
331 h->cupsBitsPerPixel = 8;
332 h->cupsColorSpace = CUPS_CSPACE_SW;
333 }
334 else if (!strcmp(type, "sgray_16"))
335 {
336 h->cupsBitsPerColor = 16;
337 h->cupsBitsPerPixel = 16;
338 h->cupsColorSpace = CUPS_CSPACE_SW;
339 }
340 else if (!strcmp(type, "srgb_8"))
341 {
342 h->cupsBitsPerColor = 8;
343 h->cupsBitsPerPixel = 24;
344 h->cupsColorSpace = CUPS_CSPACE_SRGB;
345 }
346 else if (!strcmp(type, "srgb_16"))
347 {
348 h->cupsBitsPerColor = 16;
349 h->cupsBitsPerPixel = 48;
350 h->cupsColorSpace = CUPS_CSPACE_SRGB;
351 }
352 else
353 {
354 _cupsRasterAddError("Unsupported raster type \'%s\'.", type);
355 return (0);
356 }
357
358 h->cupsColorOrder = CUPS_ORDER_CHUNKED;
359 h->cupsNumColors = h->cupsBitsPerPixel / h->cupsBitsPerColor;
360 h->cupsBytesPerLine = (h->cupsWidth * h->cupsBitsPerPixel + 7) / 8;
361
362 /*
363 * Duplex support...
364 */
365
366 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 1;
367 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 1;
368
369 if (sides)
370 {
371 if (!strcmp(sides, "two-sided-long-edge"))
372 {
373 h->Duplex = 1;
374 }
375 else if (!strcmp(sides, "two-sided-short-edge"))
376 {
377 h->Duplex = 1;
378 h->Tumble = 1;
379 }
380 else if (strcmp(sides, "one-sided"))
381 {
382 _cupsRasterAddError("Unsupported sides value \'%s\'.", sides);
383 return (0);
384 }
385
386 if (sheet_back)
387 {
388 if (!strcmp(sheet_back, "flipped"))
389 {
390 if (h->Tumble)
391 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU;
392 else
393 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU;
394 }
395 else if (!strcmp(sheet_back, "manual-tumble"))
396 {
397 if (h->Tumble)
398 {
399 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU;
400 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU;
401 }
402 }
403 else if (!strcmp(sheet_back, "rotated"))
404 {
405 if (!h->Tumble)
406 {
407 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU;
408 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU;
409 }
410 }
411 else if (strcmp(sheet_back, "normal"))
412 {
413 _cupsRasterAddError("Unsupported sheet_back value \'%s\'.", sheet_back);
414 return (0);
415 }
416 }
417 }
418
419 return (1);
420}
421
422
423/*
Haibo Huang4c283622019-12-13 16:47:52 -0800424 * '_cupsRasterNew()' - Create a raster stream using a callback function.
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800425 *
426 * This function associates a raster stream with the given callback function and
427 * context pointer.
428 *
429 * When writing raster data, the @code CUPS_RASTER_WRITE@,
430 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
431 * be used - compressed and PWG output is generally 25-50% smaller but adds a
432 * 100-300% execution time overhead.
433 */
434
435cups_raster_t * /* O - New stream */
Haibo Huang4c283622019-12-13 16:47:52 -0800436_cupsRasterNew(
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800437 cups_raster_iocb_t iocb, /* I - Read/write callback */
438 void *ctx, /* I - Context pointer for callback */
439 cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
440 @code CUPS_RASTER_WRITE@,
441 @code CUPS_RASTER_WRITE_COMPRESSED@,
442 or @code CUPS_RASTER_WRITE_PWG@ */
443{
444 cups_raster_t *r; /* New stream */
445
446
Haibo Huang4c283622019-12-13 16:47:52 -0800447 DEBUG_printf(("_cupsRasterOpenIO(iocb=%p, ctx=%p, mode=%s)", (void *)iocb, ctx, cups_modes[mode]));
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700448
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800449 _cupsRasterClearError();
450
451 if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL)
452 {
453 _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n",
454 strerror(errno));
Haibo Huang4c283622019-12-13 16:47:52 -0800455 DEBUG_puts("1_cupsRasterOpenIO: Returning NULL.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800456 return (NULL);
457 }
458
459 r->ctx = ctx;
460 r->iocb = iocb;
461 r->mode = mode;
462
463 if (mode == CUPS_RASTER_READ)
464 {
465 /*
466 * Open for read - get sync word...
467 */
468
469 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) !=
470 sizeof(r->sync))
471 {
472 _cupsRasterAddError("Unable to read header from raster stream: %s\n",
473 strerror(errno));
474 free(r);
Haibo Huang4c283622019-12-13 16:47:52 -0800475 DEBUG_puts("1_cupsRasterOpenIO: Unable to read header, returning NULL.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800476 return (NULL);
477 }
478
479 if (r->sync != CUPS_RASTER_SYNC &&
480 r->sync != CUPS_RASTER_REVSYNC &&
481 r->sync != CUPS_RASTER_SYNCv1 &&
482 r->sync != CUPS_RASTER_REVSYNCv1 &&
483 r->sync != CUPS_RASTER_SYNCv2 &&
Philip P. Moltmann24473732017-05-11 09:37:47 -0700484 r->sync != CUPS_RASTER_REVSYNCv2 &&
485 r->sync != CUPS_RASTER_SYNCapple &&
486 r->sync != CUPS_RASTER_REVSYNCapple)
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800487 {
488 _cupsRasterAddError("Unknown raster format %08x!\n", r->sync);
489 free(r);
Haibo Huang4c283622019-12-13 16:47:52 -0800490 DEBUG_puts("1_cupsRasterOpenIO: Unknown format, returning NULL.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800491 return (NULL);
492 }
493
494 if (r->sync == CUPS_RASTER_SYNCv2 ||
Philip P. Moltmann24473732017-05-11 09:37:47 -0700495 r->sync == CUPS_RASTER_REVSYNCv2 ||
496 r->sync == CUPS_RASTER_SYNCapple ||
497 r->sync == CUPS_RASTER_REVSYNCapple)
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800498 r->compressed = 1;
499
Haibo Huang4c283622019-12-13 16:47:52 -0800500 DEBUG_printf(("1_cupsRasterOpenIO: sync=%08x", r->sync));
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700501
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800502 if (r->sync == CUPS_RASTER_REVSYNC ||
503 r->sync == CUPS_RASTER_REVSYNCv1 ||
Philip P. Moltmann24473732017-05-11 09:37:47 -0700504 r->sync == CUPS_RASTER_REVSYNCv2 ||
505 r->sync == CUPS_RASTER_REVSYNCapple)
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800506 r->swapped = 1;
507
Philip P. Moltmann24473732017-05-11 09:37:47 -0700508 if (r->sync == CUPS_RASTER_SYNCapple ||
509 r->sync == CUPS_RASTER_REVSYNCapple)
510 {
511 unsigned char header[8]; /* File header */
512
513 if (cups_raster_io(r, (unsigned char *)header, sizeof(header)) !=
514 sizeof(header))
515 {
516 _cupsRasterAddError("Unable to read header from raster stream: %s\n",
517 strerror(errno));
518 free(r);
Haibo Huang4c283622019-12-13 16:47:52 -0800519 DEBUG_puts("1_cupsRasterOpenIO: Unable to read header, returning NULL.");
Philip P. Moltmann24473732017-05-11 09:37:47 -0700520 return (NULL);
521 }
Philip P. Moltmann24473732017-05-11 09:37:47 -0700522 }
523
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700524#ifdef DEBUG
525 r->iostart = r->iocount;
526#endif /* DEBUG */
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800527 }
528 else
529 {
530 /*
531 * Open for write - put sync word...
532 */
533
534 switch (mode)
535 {
536 default :
537 case CUPS_RASTER_WRITE :
538 r->sync = CUPS_RASTER_SYNC;
539 break;
540
541 case CUPS_RASTER_WRITE_COMPRESSED :
542 r->compressed = 1;
543 r->sync = CUPS_RASTER_SYNCv2;
544 break;
545
546 case CUPS_RASTER_WRITE_PWG :
547 r->compressed = 1;
548 r->sync = htonl(CUPS_RASTER_SYNC_PWG);
549 r->swapped = r->sync != CUPS_RASTER_SYNC_PWG;
550 break;
Philip P. Moltmann24473732017-05-11 09:37:47 -0700551
552 case CUPS_RASTER_WRITE_APPLE :
553 r->compressed = 1;
554 r->sync = htonl(CUPS_RASTER_SYNCapple);
555 r->swapped = r->sync != CUPS_RASTER_SYNCapple;
556 r->apple_page_count = 0xffffffffU;
557 break;
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800558 }
559
560 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) < (ssize_t)sizeof(r->sync))
561 {
562 _cupsRasterAddError("Unable to write raster stream header: %s\n",
563 strerror(errno));
564 free(r);
Haibo Huang4c283622019-12-13 16:47:52 -0800565 DEBUG_puts("1_cupsRasterOpenIO: Unable to write header, returning NULL.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800566 return (NULL);
567 }
568 }
569
Haibo Huang4c283622019-12-13 16:47:52 -0800570 DEBUG_printf(("1_cupsRasterOpenIO: compressed=%d, swapped=%d, returning %p", r->compressed, r->swapped, (void *)r));
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700571
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800572 return (r);
573}
574
575
576/*
Haibo Huang4c283622019-12-13 16:47:52 -0800577 * '_cupsRasterReadHeader()' - Read a raster page header.
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800578 */
579
Haibo Huang4c283622019-12-13 16:47:52 -0800580unsigned /* O - 1 on success, 0 on fail */
581_cupsRasterReadHeader(
582 cups_raster_t *r) /* I - Raster stream */
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800583{
Haibo Huang4c283622019-12-13 16:47:52 -0800584 size_t len; /* Length for read/swap */
585
586
587 DEBUG_printf(("3_cupsRasterReadHeader(r=%p), r->mode=%s", (void *)r, r ? cups_modes[r->mode] : ""));
588
589 if (r == NULL || r->mode != CUPS_RASTER_READ)
590 return (0);
591
592 DEBUG_printf(("4_cupsRasterReadHeader: r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
593
594 memset(&(r->header), 0, sizeof(r->header));
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700595
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800596 /*
Haibo Huang4c283622019-12-13 16:47:52 -0800597 * Read the header...
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800598 */
599
Haibo Huang4c283622019-12-13 16:47:52 -0800600 switch (r->sync)
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800601 {
Haibo Huang4c283622019-12-13 16:47:52 -0800602 default :
603 /*
604 * Get the length of the raster header...
605 */
606
607 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
608 len = sizeof(cups_page_header_t);
609 else
610 len = sizeof(cups_page_header2_t);
611
612 DEBUG_printf(("4_cupsRasterReadHeader: len=%d", (int)len));
613
614 /*
615 * Read it...
616 */
617
618 if (cups_raster_read(r, (unsigned char *)&(r->header), len) < (ssize_t)len)
619 {
620 DEBUG_printf(("4_cupsRasterReadHeader: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
621 return (0);
622 }
623
624 /*
625 * Swap bytes as needed...
626 */
627
628 if (r->swapped)
629 {
630 unsigned *s, /* Current word */
631 temp; /* Temporary copy */
632
633
634 DEBUG_puts("4_cupsRasterReadHeader: Swapping header bytes.");
635
636 for (len = 81, s = &(r->header.AdvanceDistance);
637 len > 0;
638 len --, s ++)
639 {
640 temp = *s;
641 *s = ((temp & 0xff) << 24) |
642 ((temp & 0xff00) << 8) |
643 ((temp & 0xff0000) >> 8) |
644 ((temp & 0xff000000) >> 24);
645
646 DEBUG_printf(("4_cupsRasterReadHeader: %08x => %08x", temp, *s));
647 }
648 }
649 break;
650
651 case CUPS_RASTER_SYNCapple :
652 case CUPS_RASTER_REVSYNCapple :
653 {
654 unsigned char appleheader[32]; /* Raw header */
655 static const unsigned rawcspace[] =
656 {
657 CUPS_CSPACE_SW,
658 CUPS_CSPACE_SRGB,
659 CUPS_CSPACE_CIELab,
660 CUPS_CSPACE_ADOBERGB,
661 CUPS_CSPACE_W,
662 CUPS_CSPACE_RGB,
663 CUPS_CSPACE_CMYK
664 };
665 static const unsigned rawnumcolors[] =
666 {
667 1,
668 3,
669 3,
670 3,
671 1,
672 3,
673 4
674 };
675
676 if (cups_raster_read(r, appleheader, sizeof(appleheader)) < (ssize_t)sizeof(appleheader))
677 {
678 DEBUG_printf(("4_cupsRasterReadHeader: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
679 return (0);
680 }
681
682 strlcpy(r->header.MediaClass, "PwgRaster", sizeof(r->header.MediaClass));
683 /* PwgRaster */
684 r->header.cupsBitsPerPixel = appleheader[0];
685 r->header.cupsColorSpace = appleheader[1] >= (sizeof(rawcspace) / sizeof(rawcspace[0])) ? CUPS_CSPACE_DEVICE1 : rawcspace[appleheader[1]];
686 r->header.cupsNumColors = appleheader[1] >= (sizeof(rawnumcolors) / sizeof(rawnumcolors[0])) ? 1 : rawnumcolors[appleheader[1]];
687 r->header.cupsBitsPerColor = r->header.cupsBitsPerPixel / r->header.cupsNumColors;
688 r->header.cupsWidth = ((((((unsigned)appleheader[12] << 8) | (unsigned)appleheader[13]) << 8) | (unsigned)appleheader[14]) << 8) | (unsigned)appleheader[15];
689 r->header.cupsHeight = ((((((unsigned)appleheader[16] << 8) | (unsigned)appleheader[17]) << 8) | (unsigned)appleheader[18]) << 8) | (unsigned)appleheader[19];
690 r->header.cupsBytesPerLine = r->header.cupsWidth * r->header.cupsBitsPerPixel / 8;
691 r->header.cupsColorOrder = CUPS_ORDER_CHUNKED;
692 r->header.HWResolution[0] = r->header.HWResolution[1] = ((((((unsigned)appleheader[20] << 8) | (unsigned)appleheader[21]) << 8) | (unsigned)appleheader[22]) << 8) | (unsigned)appleheader[23];
693
694 if (r->header.HWResolution[0] > 0)
695 {
696 r->header.PageSize[0] = (unsigned)(r->header.cupsWidth * 72 / r->header.HWResolution[0]);
697 r->header.PageSize[1] = (unsigned)(r->header.cupsHeight * 72 / r->header.HWResolution[1]);
698 r->header.cupsPageSize[0] = (float)(r->header.cupsWidth * 72.0 / r->header.HWResolution[0]);
699 r->header.cupsPageSize[1] = (float)(r->header.cupsHeight * 72.0 / r->header.HWResolution[1]);
700 }
701
702 r->header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = r->apple_page_count;
703 r->header.cupsInteger[CUPS_RASTER_PWG_AlternatePrimary] = 0xffffff;
704 r->header.cupsInteger[CUPS_RASTER_PWG_PrintQuality] = appleheader[3];
705
706 if (appleheader[2] >= 2)
707 r->header.Duplex = 1;
708 if (appleheader[2] == 2)
709 r->header.Tumble = 1;
710
711 r->header.MediaPosition = appleheader[5];
712
713 if (appleheader[4] < (int)(sizeof(apple_media_types) / sizeof(apple_media_types[0])))
714 strlcpy(r->header.MediaType, apple_media_types[appleheader[4]], sizeof(r->header.MediaType));
715 else
716 strlcpy(r->header.MediaType, "other", sizeof(r->header.MediaType));
717 }
718 break;
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800719 }
720
721 /*
Haibo Huang4c283622019-12-13 16:47:52 -0800722 * Update the header and row count...
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800723 */
724
Haibo Huang4c283622019-12-13 16:47:52 -0800725 if (!cups_raster_update(r))
726 return (0);
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800727
Haibo Huang4c283622019-12-13 16:47:52 -0800728 DEBUG_printf(("4_cupsRasterReadHeader: cupsColorSpace=%s", _cupsRasterColorSpaceString(r->header.cupsColorSpace)));
729 DEBUG_printf(("4_cupsRasterReadHeader: cupsBitsPerColor=%u", r->header.cupsBitsPerColor));
730 DEBUG_printf(("4_cupsRasterReadHeader: cupsBitsPerPixel=%u", r->header.cupsBitsPerPixel));
731 DEBUG_printf(("4_cupsRasterReadHeader: cupsBytesPerLine=%u", r->header.cupsBytesPerLine));
732 DEBUG_printf(("4_cupsRasterReadHeader: cupsWidth=%u", r->header.cupsWidth));
733 DEBUG_printf(("4_cupsRasterReadHeader: cupsHeight=%u", r->header.cupsHeight));
734 DEBUG_printf(("4_cupsRasterReadHeader: r->bpp=%d", r->bpp));
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700735
Haibo Huang4c283622019-12-13 16:47:52 -0800736 return (r->header.cupsBitsPerPixel > 0 && r->header.cupsBitsPerPixel <= 240 && r->header.cupsBitsPerColor > 0 && r->header.cupsBitsPerColor <= 16 && r->header.cupsBytesPerLine > 0 && r->header.cupsBytesPerLine <= 0x7fffffff && r->header.cupsHeight != 0 && (r->header.cupsBytesPerLine % r->bpp) == 0);
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800737}
738
739
740/*
Haibo Huang4c283622019-12-13 16:47:52 -0800741 * '_cupsRasterReadPixels()' - Read raster pixels.
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800742 *
743 * For best performance, filters should read one or more whole lines.
744 * The "cupsBytesPerLine" value from the page header can be used to allocate
745 * the line buffer and as the number of bytes to read.
746 */
747
748unsigned /* O - Number of bytes read */
Haibo Huang4c283622019-12-13 16:47:52 -0800749_cupsRasterReadPixels(
750 cups_raster_t *r, /* I - Raster stream */
751 unsigned char *p, /* I - Pointer to pixel buffer */
752 unsigned len) /* I - Number of bytes to read */
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800753{
754 ssize_t bytes; /* Bytes read */
755 unsigned cupsBytesPerLine; /* cupsBytesPerLine value */
756 unsigned remaining; /* Bytes remaining */
757 unsigned char *ptr, /* Pointer to read buffer */
758 byte, /* Byte from file */
759 *temp; /* Pointer into buffer */
760 unsigned count; /* Repetition count */
761
762
Haibo Huang4c283622019-12-13 16:47:52 -0800763 DEBUG_printf(("_cupsRasterReadPixels(r=%p, p=%p, len=%u)", (void *)r, (void *)p, len));
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800764
765 if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0 ||
766 r->header.cupsBytesPerLine == 0)
767 {
Haibo Huang4c283622019-12-13 16:47:52 -0800768 DEBUG_puts("1_cupsRasterReadPixels: Returning 0.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800769 return (0);
770 }
771
Haibo Huang4c283622019-12-13 16:47:52 -0800772 DEBUG_printf(("1_cupsRasterReadPixels: compressed=%d, remaining=%u", r->compressed, r->remaining));
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800773
774 if (!r->compressed)
775 {
776 /*
777 * Read without compression...
778 */
779
780 r->remaining -= len / r->header.cupsBytesPerLine;
781
782 if (cups_raster_io(r, p, len) < (ssize_t)len)
783 {
Haibo Huang4c283622019-12-13 16:47:52 -0800784 DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800785 return (0);
786 }
787
788 /*
789 * Swap bytes as needed...
790 */
791
792 if (r->swapped &&
793 (r->header.cupsBitsPerColor == 16 ||
794 r->header.cupsBitsPerPixel == 12 ||
795 r->header.cupsBitsPerPixel == 16))
796 cups_swap(p, len);
797
798 /*
799 * Return...
800 */
801
Haibo Huang4c283622019-12-13 16:47:52 -0800802 DEBUG_printf(("1_cupsRasterReadPixels: Returning %u", len));
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800803
804 return (len);
805 }
806
807 /*
808 * Read compressed data...
809 */
810
811 remaining = len;
812 cupsBytesPerLine = r->header.cupsBytesPerLine;
813
814 while (remaining > 0 && r->remaining > 0)
815 {
816 if (r->count == 0)
817 {
818 /*
819 * Need to read a new row...
820 */
821
822 if (remaining == cupsBytesPerLine)
823 ptr = p;
824 else
825 ptr = r->pixels;
826
827 /*
828 * Read using a modified PackBits compression...
829 */
830
831 if (!cups_raster_read(r, &byte, 1))
832 {
Haibo Huang4c283622019-12-13 16:47:52 -0800833 DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800834 return (0);
835 }
836
837 r->count = (unsigned)byte + 1;
838
839 if (r->count > 1)
840 ptr = r->pixels;
841
842 temp = ptr;
843 bytes = (ssize_t)cupsBytesPerLine;
844
845 while (bytes > 0)
846 {
847 /*
848 * Get a new repeat count...
849 */
850
851 if (!cups_raster_read(r, &byte, 1))
852 {
Haibo Huang4c283622019-12-13 16:47:52 -0800853 DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800854 return (0);
855 }
856
Philip P. Moltmann24473732017-05-11 09:37:47 -0700857 if (byte == 128)
858 {
859 /*
860 * Clear to end of line...
861 */
862
863 switch (r->header.cupsColorSpace)
864 {
865 case CUPS_CSPACE_W :
866 case CUPS_CSPACE_RGB :
867 case CUPS_CSPACE_SW :
868 case CUPS_CSPACE_SRGB :
869 case CUPS_CSPACE_RGBW :
870 case CUPS_CSPACE_ADOBERGB :
871 memset(temp, 0xff, (size_t)bytes);
872 break;
873 default :
874 memset(temp, 0x00, (size_t)bytes);
875 break;
876 }
877
878 temp += bytes;
879 bytes = 0;
880 }
881 else if (byte & 128)
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800882 {
883 /*
884 * Copy N literal pixels...
885 */
886
887 count = (unsigned)(257 - byte) * r->bpp;
888
889 if (count > (unsigned)bytes)
890 count = (unsigned)bytes;
891
892 if (!cups_raster_read(r, temp, count))
893 {
Haibo Huang4c283622019-12-13 16:47:52 -0800894 DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800895 return (0);
896 }
897
898 temp += count;
899 bytes -= (ssize_t)count;
900 }
901 else
902 {
903 /*
904 * Repeat the next N bytes...
905 */
906
907 count = ((unsigned)byte + 1) * r->bpp;
908 if (count > (unsigned)bytes)
909 count = (unsigned)bytes;
910
911 if (count < r->bpp)
912 break;
913
914 bytes -= (ssize_t)count;
915
916 if (!cups_raster_read(r, temp, r->bpp))
917 {
Haibo Huang4c283622019-12-13 16:47:52 -0800918 DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800919 return (0);
920 }
921
922 temp += r->bpp;
923 count -= r->bpp;
924
925 while (count > 0)
926 {
927 memcpy(temp, temp - r->bpp, r->bpp);
928 temp += r->bpp;
929 count -= r->bpp;
930 }
931 }
932 }
933
934 /*
935 * Swap bytes as needed...
936 */
937
938 if ((r->header.cupsBitsPerColor == 16 ||
939 r->header.cupsBitsPerPixel == 12 ||
940 r->header.cupsBitsPerPixel == 16) &&
941 r->swapped)
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700942 {
Haibo Huang4c283622019-12-13 16:47:52 -0800943 DEBUG_puts("1_cupsRasterReadPixels: Swapping bytes.");
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -0700944 cups_swap(ptr, (size_t)cupsBytesPerLine);
945 }
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800946
947 /*
948 * Update pointers...
949 */
950
951 if (remaining >= cupsBytesPerLine)
952 {
953 bytes = (ssize_t)cupsBytesPerLine;
954 r->pcurrent = r->pixels;
955 r->count --;
956 r->remaining --;
957 }
958 else
959 {
960 bytes = (ssize_t)remaining;
961 r->pcurrent = r->pixels + bytes;
962 }
963
964 /*
965 * Copy data as needed...
966 */
967
968 if (ptr != p)
969 memcpy(p, ptr, (size_t)bytes);
970 }
971 else
972 {
973 /*
974 * Copy fragment from buffer...
975 */
976
977 if ((unsigned)(bytes = (int)(r->pend - r->pcurrent)) > remaining)
978 bytes = (ssize_t)remaining;
979
980 memcpy(p, r->pcurrent, (size_t)bytes);
981 r->pcurrent += bytes;
982
983 if (r->pcurrent >= r->pend)
984 {
985 r->pcurrent = r->pixels;
986 r->count --;
987 r->remaining --;
988 }
989 }
990
991 remaining -= (unsigned)bytes;
992 p += bytes;
993 }
994
Haibo Huang4c283622019-12-13 16:47:52 -0800995 DEBUG_printf(("1_cupsRasterReadPixels: Returning %u", len));
Philip P. Moltmann25aee822016-12-15 12:16:46 -0800996
997 return (len);
998}
999
1000
1001/*
Haibo Huang4c283622019-12-13 16:47:52 -08001002 * '_cupsRasterWriteHeader()' - Write a raster page header.
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001003 */
1004
1005unsigned /* O - 1 on success, 0 on failure */
Haibo Huang4c283622019-12-13 16:47:52 -08001006_cupsRasterWriteHeader(
1007 cups_raster_t *r) /* I - Raster stream */
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001008{
Haibo Huang4c283622019-12-13 16:47:52 -08001009 DEBUG_printf(("_cupsRasterWriteHeader(r=%p)", (void *)r));
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001010
Haibo Huang4c283622019-12-13 16:47:52 -08001011 DEBUG_printf(("1_cupsRasterWriteHeader: cupsColorSpace=%s", _cupsRasterColorSpaceString(r->header.cupsColorSpace)));
1012 DEBUG_printf(("1_cupsRasterWriteHeader: cupsBitsPerColor=%u", r->header.cupsBitsPerColor));
1013 DEBUG_printf(("1_cupsRasterWriteHeader: cupsBitsPerPixel=%u", r->header.cupsBitsPerPixel));
1014 DEBUG_printf(("1_cupsRasterWriteHeader: cupsBytesPerLine=%u", r->header.cupsBytesPerLine));
1015 DEBUG_printf(("1_cupsRasterWriteHeader: cupsWidth=%u", r->header.cupsWidth));
1016 DEBUG_printf(("1_cupsRasterWriteHeader: cupsHeight=%u", r->header.cupsHeight));
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001017
1018 /*
Haibo Huang4c283622019-12-13 16:47:52 -08001019 * Compute the number of raster lines in the page image...
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001020 */
1021
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001022 if (!cups_raster_update(r))
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001023 {
Haibo Huang4c283622019-12-13 16:47:52 -08001024 DEBUG_puts("1_cupsRasterWriteHeader: Unable to update parameters, returning 0.");
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001025 return (0);
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001026 }
1027
1028 if (r->mode == CUPS_RASTER_WRITE_APPLE)
1029 {
Haibo Huang4c283622019-12-13 16:47:52 -08001030 r->rowheight = r->header.HWResolution[0] / r->header.HWResolution[1];
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001031
Haibo Huang4c283622019-12-13 16:47:52 -08001032 if (r->header.HWResolution[0] != (r->rowheight * r->header.HWResolution[1]))
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001033 return (0);
1034 }
1035 else
1036 r->rowheight = 1;
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001037
1038 /*
1039 * Write the raster header...
1040 */
1041
1042 if (r->mode == CUPS_RASTER_WRITE_PWG)
1043 {
1044 /*
1045 * PWG raster data is always network byte order with much of the page header
1046 * zeroed.
1047 */
1048
1049 cups_page_header2_t fh; /* File page header */
1050
1051 memset(&fh, 0, sizeof(fh));
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001052 strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass));
1053 strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor));
1054 strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType));
1055 strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType));
1056 strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent,
1057 sizeof(fh.cupsRenderingIntent));
1058 strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName,
1059 sizeof(fh.cupsPageSizeName));
1060
1061 fh.CutMedia = htonl(r->header.CutMedia);
1062 fh.Duplex = htonl(r->header.Duplex);
1063 fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
1064 fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
1065 fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]);
1066 fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]);
1067 fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]);
1068 fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]);
1069 fh.InsertSheet = htonl(r->header.InsertSheet);
1070 fh.Jog = htonl(r->header.Jog);
1071 fh.LeadingEdge = htonl(r->header.LeadingEdge);
1072 fh.ManualFeed = htonl(r->header.ManualFeed);
1073 fh.MediaPosition = htonl(r->header.MediaPosition);
1074 fh.MediaWeight = htonl(r->header.MediaWeight);
1075 fh.NumCopies = htonl(r->header.NumCopies);
1076 fh.Orientation = htonl(r->header.Orientation);
1077 fh.PageSize[0] = htonl(r->header.PageSize[0]);
1078 fh.PageSize[1] = htonl(r->header.PageSize[1]);
1079 fh.Tumble = htonl(r->header.Tumble);
1080 fh.cupsWidth = htonl(r->header.cupsWidth);
1081 fh.cupsHeight = htonl(r->header.cupsHeight);
1082 fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
1083 fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
1084 fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
1085 fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
1086 fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
1087 fh.cupsNumColors = htonl(r->header.cupsNumColors);
1088 fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]);
1089 fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]);
1090 fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]);
1091 fh.cupsInteger[3] = htonl((unsigned)(r->header.cupsImagingBBox[0] * r->header.HWResolution[0] / 72.0));
1092 fh.cupsInteger[4] = htonl((unsigned)(r->header.cupsImagingBBox[1] * r->header.HWResolution[1] / 72.0));
1093 fh.cupsInteger[5] = htonl((unsigned)(r->header.cupsImagingBBox[2] * r->header.HWResolution[0] / 72.0));
1094 fh.cupsInteger[6] = htonl((unsigned)(r->header.cupsImagingBBox[3] * r->header.HWResolution[1] / 72.0));
1095 fh.cupsInteger[7] = htonl(0xffffff);
1096
1097 return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
1098 }
Philip P. Moltmann24473732017-05-11 09:37:47 -07001099 else if (r->mode == CUPS_RASTER_WRITE_APPLE)
1100 {
1101 /*
1102 * Raw raster data is always network byte order with most of the page header
1103 * zeroed.
1104 */
1105
Haibo Huang4c283622019-12-13 16:47:52 -08001106 int i; /* Looping var */
1107 unsigned char appleheader[32];/* Raw page header */
1108 unsigned height = r->header.cupsHeight * r->rowheight;
Philip P. Moltmann24473732017-05-11 09:37:47 -07001109 /* Computed page height */
1110
1111 if (r->apple_page_count == 0xffffffffU)
1112 {
1113 /*
1114 * Write raw page count from raster page header...
1115 */
1116
1117 r->apple_page_count = r->header.cupsInteger[0];
1118
1119 appleheader[0] = 'A';
1120 appleheader[1] = 'S';
1121 appleheader[2] = 'T';
1122 appleheader[3] = 0;
1123 appleheader[4] = (unsigned char)(r->apple_page_count >> 24);
1124 appleheader[5] = (unsigned char)(r->apple_page_count >> 16);
1125 appleheader[6] = (unsigned char)(r->apple_page_count >> 8);
1126 appleheader[7] = (unsigned char)(r->apple_page_count);
1127
1128 if (cups_raster_io(r, appleheader, 8) != 8)
1129 return (0);
1130 }
1131
1132 memset(appleheader, 0, sizeof(appleheader));
1133
1134 appleheader[0] = (unsigned char)r->header.cupsBitsPerPixel;
1135 appleheader[1] = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 :
Haibo Huang4c283622019-12-13 16:47:52 -08001136 r->header.cupsColorSpace == CUPS_CSPACE_CIELab ? 2 :
Philip P. Moltmann24473732017-05-11 09:37:47 -07001137 r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 :
1138 r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 :
1139 r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 :
1140 r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0;
Haibo Huang4c283622019-12-13 16:47:52 -08001141 appleheader[2] = r->header.Duplex ? (r->header.Tumble ? 2 : 3) : 1;
1142 appleheader[3] = (unsigned char)(r->header.cupsInteger[CUPS_RASTER_PWG_PrintQuality]);
1143 appleheader[5] = (unsigned char)(r->header.MediaPosition);
Philip P. Moltmann24473732017-05-11 09:37:47 -07001144 appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24);
1145 appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16);
1146 appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8);
1147 appleheader[15] = (unsigned char)(r->header.cupsWidth);
1148 appleheader[16] = (unsigned char)(height >> 24);
1149 appleheader[17] = (unsigned char)(height >> 16);
1150 appleheader[18] = (unsigned char)(height >> 8);
1151 appleheader[19] = (unsigned char)(height);
1152 appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24);
1153 appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16);
1154 appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8);
1155 appleheader[23] = (unsigned char)(r->header.HWResolution[0]);
1156
Haibo Huang4c283622019-12-13 16:47:52 -08001157 for (i = 0; i < (int)(sizeof(apple_media_types) / sizeof(apple_media_types[0])); i ++)
1158 {
1159 if (!strcmp(r->header.MediaType, apple_media_types[i]))
1160 {
1161 appleheader[4] = (unsigned char)i;
1162 break;
1163 }
1164 }
1165
Philip P. Moltmann24473732017-05-11 09:37:47 -07001166 return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader));
1167 }
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001168 else
1169 return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
1170 == sizeof(r->header));
1171}
1172
1173
1174/*
Haibo Huang4c283622019-12-13 16:47:52 -08001175 * '_cupsRasterWritePixels()' - Write raster pixels.
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001176 *
1177 * For best performance, filters should write one or more whole lines.
1178 * The "cupsBytesPerLine" value from the page header can be used to allocate
1179 * the line buffer and as the number of bytes to write.
1180 */
1181
1182unsigned /* O - Number of bytes written */
Haibo Huang4c283622019-12-13 16:47:52 -08001183_cupsRasterWritePixels(
1184 cups_raster_t *r, /* I - Raster stream */
1185 unsigned char *p, /* I - Bytes to write */
1186 unsigned len) /* I - Number of bytes to write */
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001187{
1188 ssize_t bytes; /* Bytes read */
1189 unsigned remaining; /* Bytes remaining */
1190
1191
Haibo Huang4c283622019-12-13 16:47:52 -08001192 DEBUG_printf(("_cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u", (void *)r, (void *)p, len, r->remaining));
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001193
1194 if (r == NULL || r->mode == CUPS_RASTER_READ || r->remaining == 0)
1195 return (0);
1196
1197 if (!r->compressed)
1198 {
1199 /*
1200 * Without compression, just write the raster data raw unless the data needs
1201 * to be swapped...
1202 */
1203
1204 r->remaining -= len / r->header.cupsBytesPerLine;
1205
1206 if (r->swapped &&
1207 (r->header.cupsBitsPerColor == 16 ||
1208 r->header.cupsBitsPerPixel == 12 ||
1209 r->header.cupsBitsPerPixel == 16))
1210 {
1211 unsigned char *bufptr; /* Pointer into write buffer */
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001212
1213 /*
1214 * Allocate a write buffer as needed...
1215 */
1216
1217 if ((size_t)len > r->bufsize)
1218 {
1219 if (r->buffer)
1220 bufptr = realloc(r->buffer, len);
1221 else
1222 bufptr = malloc(len);
1223
1224 if (!bufptr)
1225 return (0);
1226
1227 r->buffer = bufptr;
1228 r->bufsize = len;
1229 }
1230
1231 /*
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001232 * Byte swap the pixels and write them...
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001233 */
1234
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001235 cups_swap_copy(r->buffer, p, len);
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001236
1237 bytes = cups_raster_io(r, r->buffer, len);
1238 }
1239 else
1240 bytes = cups_raster_io(r, p, len);
1241
Haibo Huang4c283622019-12-13 16:47:52 -08001242 if (bytes < (ssize_t)len)
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001243 return (0);
1244 else
1245 return (len);
1246 }
1247
1248 /*
1249 * Otherwise, compress each line...
1250 */
1251
1252 for (remaining = len; remaining > 0; remaining -= (unsigned)bytes, p += bytes)
1253 {
1254 /*
1255 * Figure out the number of remaining bytes on the current line...
1256 */
1257
1258 if ((bytes = (ssize_t)remaining) > (ssize_t)(r->pend - r->pcurrent))
1259 bytes = (ssize_t)(r->pend - r->pcurrent);
1260
1261 if (r->count > 0)
1262 {
1263 /*
1264 * Check to see if this line is the same as the previous line...
1265 */
1266
1267 if (memcmp(p, r->pcurrent, (size_t)bytes))
1268 {
1269 if (cups_raster_write(r, r->pixels) <= 0)
1270 return (0);
1271
1272 r->count = 0;
1273 }
1274 else
1275 {
1276 /*
1277 * Mark more bytes as the same...
1278 */
1279
1280 r->pcurrent += bytes;
1281
1282 if (r->pcurrent >= r->pend)
1283 {
1284 /*
1285 * Increase the repeat count...
1286 */
1287
Philip P. Moltmann24473732017-05-11 09:37:47 -07001288 r->count += r->rowheight;
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001289 r->pcurrent = r->pixels;
1290
1291 /*
1292 * Flush out this line if it is the last one...
1293 */
1294
1295 r->remaining --;
1296
1297 if (r->remaining == 0)
1298 {
1299 if (cups_raster_write(r, r->pixels) <= 0)
1300 return (0);
1301 else
1302 return (len);
1303 }
Philip P. Moltmann24473732017-05-11 09:37:47 -07001304 else if (r->count > (256 - r->rowheight))
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001305 {
1306 if (cups_raster_write(r, r->pixels) <= 0)
1307 return (0);
1308
1309 r->count = 0;
1310 }
1311 }
1312
1313 continue;
1314 }
1315 }
1316
1317 if (r->count == 0)
1318 {
1319 /*
1320 * Copy the raster data to the buffer...
1321 */
1322
1323 memcpy(r->pcurrent, p, (size_t)bytes);
1324
1325 r->pcurrent += bytes;
1326
1327 if (r->pcurrent >= r->pend)
1328 {
1329 /*
1330 * Increase the repeat count...
1331 */
1332
Philip P. Moltmann24473732017-05-11 09:37:47 -07001333 r->count += r->rowheight;
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001334 r->pcurrent = r->pixels;
1335
1336 /*
1337 * Flush out this line if it is the last one...
1338 */
1339
1340 r->remaining --;
1341
1342 if (r->remaining == 0)
1343 {
1344 if (cups_raster_write(r, r->pixels) <= 0)
1345 return (0);
1346 }
1347 }
1348 }
1349 }
1350
1351 return (len);
1352}
1353
1354
1355/*
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001356 * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions.
1357 */
1358
1359static ssize_t /* O - Bytes read/write or -1 */
1360cups_raster_io(cups_raster_t *r, /* I - Raster stream */
1361 unsigned char *buf, /* I - Buffer for read/write */
1362 size_t bytes) /* I - Number of bytes to read/write */
1363{
1364 ssize_t count, /* Number of bytes read/written */
1365 total; /* Total bytes read/written */
1366
1367
1368 DEBUG_printf(("5cups_raster_io(r=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)r, (void *)buf, CUPS_LLCAST bytes));
1369
1370 for (total = 0; total < (ssize_t)bytes; total += count, buf += count)
1371 {
1372 count = (*r->iocb)(r->ctx, buf, bytes - (size_t)total);
1373
1374 DEBUG_printf(("6cups_raster_io: count=%d, total=%d", (int)count, (int)total));
1375 if (count == 0)
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001376 break;
Haibo Huang4c283622019-12-13 16:47:52 -08001377// {
1378// DEBUG_puts("6cups_raster_io: Returning 0.");
1379// return (0);
1380// }
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001381 else if (count < 0)
1382 {
1383 DEBUG_puts("6cups_raster_io: Returning -1 on error.");
1384 return (-1);
1385 }
1386
1387#ifdef DEBUG
1388 r->iocount += (size_t)count;
1389#endif /* DEBUG */
1390 }
1391
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001392 DEBUG_printf(("6cups_raster_io: iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001393 DEBUG_printf(("6cups_raster_io: Returning " CUPS_LLFMT ".", CUPS_LLCAST total));
1394
1395 return (total);
1396}
1397
1398
1399/*
1400 * 'cups_raster_read()' - Read through the raster buffer.
1401 */
1402
1403static ssize_t /* O - Number of bytes read */
1404cups_raster_read(cups_raster_t *r, /* I - Raster stream */
1405 unsigned char *buf, /* I - Buffer */
1406 size_t bytes) /* I - Number of bytes to read */
1407{
1408 ssize_t count, /* Number of bytes read */
1409 remaining, /* Remaining bytes in buffer */
1410 total; /* Total bytes read */
1411
1412
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001413 DEBUG_printf(("4cups_raster_read(r=%p, buf=%p, bytes=" CUPS_LLFMT "), offset=" CUPS_LLFMT, (void *)r, (void *)buf, CUPS_LLCAST bytes, CUPS_LLCAST (r->iostart + r->bufptr - r->buffer)));
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001414
1415 if (!r->compressed)
1416 return (cups_raster_io(r, buf, bytes));
1417
1418 /*
1419 * Allocate a read buffer as needed...
1420 */
1421
1422 count = (ssize_t)(2 * r->header.cupsBytesPerLine);
1423 if (count < 65536)
1424 count = 65536;
1425
1426 if ((size_t)count > r->bufsize)
1427 {
1428 ssize_t offset = r->bufptr - r->buffer;
1429 /* Offset to current start of buffer */
1430 ssize_t end = r->bufend - r->buffer;/* Offset to current end of buffer */
1431 unsigned char *rptr; /* Pointer in read buffer */
1432
1433 if (r->buffer)
1434 rptr = realloc(r->buffer, (size_t)count);
1435 else
1436 rptr = malloc((size_t)count);
1437
1438 if (!rptr)
1439 return (0);
1440
1441 r->buffer = rptr;
1442 r->bufptr = rptr + offset;
1443 r->bufend = rptr + end;
1444 r->bufsize = (size_t)count;
1445 }
1446
1447 /*
1448 * Loop until we have read everything...
1449 */
1450
1451 for (total = 0, remaining = (int)(r->bufend - r->bufptr);
1452 total < (ssize_t)bytes;
1453 total += count, buf += count)
1454 {
1455 count = (ssize_t)bytes - total;
1456
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001457 DEBUG_printf(("5cups_raster_read: count=" CUPS_LLFMT ", remaining=" CUPS_LLFMT ", buf=%p, bufptr=%p, bufend=%p", CUPS_LLCAST count, CUPS_LLCAST remaining, (void *)buf, (void *)r->bufptr, (void *)r->bufend));
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001458
1459 if (remaining == 0)
1460 {
1461 if (count < 16)
1462 {
1463 /*
1464 * Read into the raster buffer and then copy...
1465 */
1466
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001467#ifdef DEBUG
1468 r->iostart += (size_t)(r->bufend - r->buffer);
1469#endif /* DEBUG */
1470
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001471 remaining = (*r->iocb)(r->ctx, r->buffer, r->bufsize);
1472 if (remaining <= 0)
1473 return (0);
1474
1475 r->bufptr = r->buffer;
1476 r->bufend = r->buffer + remaining;
1477
1478#ifdef DEBUG
1479 r->iocount += (size_t)remaining;
1480#endif /* DEBUG */
1481 }
1482 else
1483 {
1484 /*
1485 * Read directly into "buf"...
1486 */
1487
1488 count = (*r->iocb)(r->ctx, buf, (size_t)count);
1489
1490 if (count <= 0)
1491 return (0);
1492
1493#ifdef DEBUG
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001494 r->iostart += (size_t)count;
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001495 r->iocount += (size_t)count;
1496#endif /* DEBUG */
1497
1498 continue;
1499 }
1500 }
1501
1502 /*
1503 * Copy bytes from raster buffer to "buf"...
1504 */
1505
1506 if (count > remaining)
1507 count = remaining;
1508
1509 if (count == 1)
1510 {
1511 /*
1512 * Copy 1 byte...
1513 */
1514
1515 *buf = *(r->bufptr)++;
1516 remaining --;
1517 }
1518 else if (count < 128)
1519 {
1520 /*
1521 * Copy up to 127 bytes without using memcpy(); this is
1522 * faster because it avoids an extra function call and is
1523 * often further optimized by the compiler...
1524 */
1525
1526 unsigned char *bufptr; /* Temporary buffer pointer */
1527
1528 remaining -= count;
1529
1530 for (bufptr = r->bufptr; count > 0; count --, total ++)
1531 *buf++ = *bufptr++;
1532
1533 r->bufptr = bufptr;
1534 }
1535 else
1536 {
1537 /*
1538 * Use memcpy() for a large read...
1539 */
1540
1541 memcpy(buf, r->bufptr, (size_t)count);
1542 r->bufptr += count;
1543 remaining -= count;
1544 }
1545 }
1546
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001547 DEBUG_printf(("5cups_raster_read: Returning %ld", (long)total));
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001548
1549 return (total);
1550}
1551
1552
1553/*
1554 * 'cups_raster_update()' - Update the raster header and row count for the
1555 * current page.
1556 */
1557
1558static int /* O - 1 on success, 0 on failure */
1559cups_raster_update(cups_raster_t *r) /* I - Raster stream */
1560{
1561 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 ||
1562 r->header.cupsNumColors == 0)
1563 {
1564 /*
1565 * Set the "cupsNumColors" field according to the colorspace...
1566 */
1567
1568 switch (r->header.cupsColorSpace)
1569 {
1570 case CUPS_CSPACE_W :
1571 case CUPS_CSPACE_K :
1572 case CUPS_CSPACE_WHITE :
1573 case CUPS_CSPACE_GOLD :
1574 case CUPS_CSPACE_SILVER :
1575 case CUPS_CSPACE_SW :
1576 r->header.cupsNumColors = 1;
1577 break;
1578
1579 case CUPS_CSPACE_RGB :
1580 case CUPS_CSPACE_CMY :
1581 case CUPS_CSPACE_YMC :
1582 case CUPS_CSPACE_CIEXYZ :
1583 case CUPS_CSPACE_CIELab :
1584 case CUPS_CSPACE_SRGB :
1585 case CUPS_CSPACE_ADOBERGB :
1586 case CUPS_CSPACE_ICC1 :
1587 case CUPS_CSPACE_ICC2 :
1588 case CUPS_CSPACE_ICC3 :
1589 case CUPS_CSPACE_ICC4 :
1590 case CUPS_CSPACE_ICC5 :
1591 case CUPS_CSPACE_ICC6 :
1592 case CUPS_CSPACE_ICC7 :
1593 case CUPS_CSPACE_ICC8 :
1594 case CUPS_CSPACE_ICC9 :
1595 case CUPS_CSPACE_ICCA :
1596 case CUPS_CSPACE_ICCB :
1597 case CUPS_CSPACE_ICCC :
1598 case CUPS_CSPACE_ICCD :
1599 case CUPS_CSPACE_ICCE :
1600 case CUPS_CSPACE_ICCF :
1601 r->header.cupsNumColors = 3;
1602 break;
1603
1604 case CUPS_CSPACE_RGBA :
1605 case CUPS_CSPACE_RGBW :
1606 case CUPS_CSPACE_CMYK :
1607 case CUPS_CSPACE_YMCK :
1608 case CUPS_CSPACE_KCMY :
1609 case CUPS_CSPACE_GMCK :
1610 case CUPS_CSPACE_GMCS :
1611 r->header.cupsNumColors = 4;
1612 break;
1613
1614 case CUPS_CSPACE_KCMYcm :
1615 if (r->header.cupsBitsPerPixel < 8)
1616 r->header.cupsNumColors = 6;
1617 else
1618 r->header.cupsNumColors = 4;
1619 break;
1620
1621 case CUPS_CSPACE_DEVICE1 :
1622 case CUPS_CSPACE_DEVICE2 :
1623 case CUPS_CSPACE_DEVICE3 :
1624 case CUPS_CSPACE_DEVICE4 :
1625 case CUPS_CSPACE_DEVICE5 :
1626 case CUPS_CSPACE_DEVICE6 :
1627 case CUPS_CSPACE_DEVICE7 :
1628 case CUPS_CSPACE_DEVICE8 :
1629 case CUPS_CSPACE_DEVICE9 :
1630 case CUPS_CSPACE_DEVICEA :
1631 case CUPS_CSPACE_DEVICEB :
1632 case CUPS_CSPACE_DEVICEC :
1633 case CUPS_CSPACE_DEVICED :
1634 case CUPS_CSPACE_DEVICEE :
1635 case CUPS_CSPACE_DEVICEF :
1636 r->header.cupsNumColors = r->header.cupsColorSpace -
1637 CUPS_CSPACE_DEVICE1 + 1;
1638 break;
1639
1640 default :
1641 /* Unknown color space */
1642 return (0);
1643 }
1644 }
1645
1646 /*
1647 * Set the number of bytes per pixel/color...
1648 */
1649
1650 if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED)
1651 r->bpp = (r->header.cupsBitsPerPixel + 7) / 8;
1652 else
1653 r->bpp = (r->header.cupsBitsPerColor + 7) / 8;
1654
1655 if (r->bpp == 0)
1656 r->bpp = 1;
1657
1658 /*
1659 * Set the number of remaining rows...
1660 */
1661
1662 if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR)
1663 r->remaining = r->header.cupsHeight * r->header.cupsNumColors;
1664 else
1665 r->remaining = r->header.cupsHeight;
1666
1667 /*
1668 * Allocate the compression buffer...
1669 */
1670
1671 if (r->compressed)
1672 {
1673 if (r->pixels != NULL)
1674 free(r->pixels);
1675
1676 if ((r->pixels = calloc(r->header.cupsBytesPerLine, 1)) == NULL)
1677 {
1678 r->pcurrent = NULL;
1679 r->pend = NULL;
1680 r->count = 0;
1681
1682 return (0);
1683 }
1684
1685 r->pcurrent = r->pixels;
1686 r->pend = r->pixels + r->header.cupsBytesPerLine;
1687 r->count = 0;
1688 }
1689
1690 return (1);
1691}
1692
1693
1694/*
1695 * 'cups_raster_write()' - Write a row of compressed raster data...
1696 */
1697
1698static ssize_t /* O - Number of bytes written */
1699cups_raster_write(
1700 cups_raster_t *r, /* I - Raster stream */
1701 const unsigned char *pixels) /* I - Pixel data to write */
1702{
1703 const unsigned char *start, /* Start of sequence */
1704 *ptr, /* Current pointer in sequence */
1705 *pend, /* End of raster buffer */
1706 *plast; /* Pointer to last pixel */
1707 unsigned char *wptr; /* Pointer into write buffer */
1708 unsigned bpp, /* Bytes per pixel */
1709 count; /* Count */
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001710 _cups_copyfunc_t cf; /* Copy function */
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001711
1712
1713 DEBUG_printf(("3cups_raster_write(r=%p, pixels=%p)", (void *)r, (void *)pixels));
1714
1715 /*
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001716 * Determine whether we need to swap bytes...
1717 */
1718
1719 if (r->swapped && (r->header.cupsBitsPerColor == 16 || r->header.cupsBitsPerPixel == 12 || r->header.cupsBitsPerPixel == 16))
1720 {
1721 DEBUG_puts("4cups_raster_write: Swapping bytes when writing.");
1722 cf = (_cups_copyfunc_t)cups_swap_copy;
1723 }
1724 else
1725 cf = (_cups_copyfunc_t)memcpy;
1726
1727 /*
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001728 * Allocate a write buffer as needed...
1729 */
1730
1731 count = r->header.cupsBytesPerLine * 2;
1732 if (count < 65536)
1733 count = 65536;
1734
1735 if ((size_t)count > r->bufsize)
1736 {
1737 if (r->buffer)
1738 wptr = realloc(r->buffer, count);
1739 else
1740 wptr = malloc(count);
1741
1742 if (!wptr)
1743 {
1744 DEBUG_printf(("4cups_raster_write: Unable to allocate " CUPS_LLFMT " bytes for raster buffer: %s", CUPS_LLCAST count, strerror(errno)));
1745 return (-1);
1746 }
1747
1748 r->buffer = wptr;
1749 r->bufsize = count;
1750 }
1751
1752 /*
1753 * Write the row repeat count...
1754 */
1755
1756 bpp = r->bpp;
1757 pend = pixels + r->header.cupsBytesPerLine;
1758 plast = pend - bpp;
1759 wptr = r->buffer;
1760 *wptr++ = (unsigned char)(r->count - 1);
1761
1762 /*
1763 * Write using a modified PackBits compression...
1764 */
1765
1766 for (ptr = pixels; ptr < pend;)
1767 {
1768 start = ptr;
1769 ptr += bpp;
1770
1771 if (ptr == pend)
1772 {
1773 /*
1774 * Encode a single pixel at the end...
1775 */
1776
1777 *wptr++ = 0;
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001778 (*cf)(wptr, start, bpp);
1779 wptr += bpp;
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001780 }
1781 else if (!memcmp(start, ptr, bpp))
1782 {
1783 /*
1784 * Encode a sequence of repeating pixels...
1785 */
1786
1787 for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp)
1788 if (memcmp(ptr, ptr + bpp, bpp))
1789 break;
1790
1791 *wptr++ = (unsigned char)(count - 1);
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001792 (*cf)(wptr, ptr, bpp);
1793 wptr += bpp;
1794 ptr += bpp;
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001795 }
1796 else
1797 {
1798 /*
1799 * Encode a sequence of non-repeating pixels...
1800 */
1801
1802 for (count = 1; count < 128 && ptr < plast; count ++, ptr += bpp)
1803 if (!memcmp(ptr, ptr + bpp, bpp))
1804 break;
1805
1806 if (ptr >= plast && count < 128)
1807 {
1808 count ++;
1809 ptr += bpp;
1810 }
1811
1812 *wptr++ = (unsigned char)(257 - count);
1813
1814 count *= bpp;
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001815 (*cf)(wptr, start, count);
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001816 wptr += count;
1817 }
1818 }
1819
1820 DEBUG_printf(("4cups_raster_write: Writing " CUPS_LLFMT " bytes.", CUPS_LLCAST (wptr - r->buffer)));
1821
1822 return (cups_raster_io(r, r->buffer, (size_t)(wptr - r->buffer)));
1823}
1824
1825
1826/*
Philip P. Moltmann25aee822016-12-15 12:16:46 -08001827 * 'cups_swap()' - Swap bytes in raster data...
1828 */
1829
1830static void
1831cups_swap(unsigned char *buf, /* I - Buffer to swap */
1832 size_t bytes) /* I - Number of bytes to swap */
1833{
1834 unsigned char even, odd; /* Temporary variables */
1835
1836
1837 bytes /= 2;
1838
1839 while (bytes > 0)
1840 {
1841 even = buf[0];
1842 odd = buf[1];
1843 buf[0] = odd;
1844 buf[1] = even;
1845
1846 buf += 2;
1847 bytes --;
1848 }
1849}
1850
1851
1852/*
Bryan Ferris5fb2ccd2019-06-21 10:49:26 -07001853 * 'cups_swap_copy()' - Copy and swap bytes in raster data...
1854 */
1855
1856static void
1857cups_swap_copy(
1858 unsigned char *dst, /* I - Destination */
1859 const unsigned char *src, /* I - Source */
1860 size_t bytes) /* I - Number of bytes to swap */
1861{
1862 bytes /= 2;
1863
1864 while (bytes > 0)
1865 {
1866 dst[0] = src[1];
1867 dst[1] = src[0];
1868
1869 dst += 2;
1870 src += 2;
1871 bytes --;
1872 }
1873}