1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied,
8
modified or distributed except as expressly authorized under the terms
9
of the license contained in the file LICENSE in this distribution.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
17
/* H-P PCL XL driver */
25
#include "gxcspace.h" /* for color mapping for images */
39
#include "gdevpcl.h" /* for gdev_pcl_mode3compress() */
40
#include "gsicc_manage.h"
41
#include "gsicc_cache.h"
42
#include <stdlib.h> /* abs() */
44
/* ---------------- Device definition ---------------- */
46
/* Define the default resolution. */
54
/* Structure definition */
55
#define NUM_POINTS 40 /* must be >= 3 and <= 255 */
61
typedef struct gx_device_pclxl_s {
62
gx_device_vector_common;
63
/* Additional state information */
64
pxeMediaSize_t media_size;
65
bool ManualFeed; /* map ps setpage commands to pxl */
67
int MediaPosition_old; /* old Position attribute - for duplex detection */
68
int MediaPosition; /* MediaPosition attribute */
69
int MediaPosition_set;
70
char MediaType_old[64]; /* old MediaType attribute - for duplex detection */
71
char MediaType[64]; /* MediaType attribute */
73
int page; /* Page number starting at 0 */
74
bool Duplex; /* Duplex attribute */
75
bool Tumble; /* Tumble attribute */
76
gx_path_type_t fill_rule; /* ...winding_number or ...even_odd */
77
gx_path_type_t clip_rule; /* ditto */
78
pxeColorSpace_t color_space;
80
int size; /* # of bytes */
81
byte data[256 * 3]; /* up to 8-bit samples */
83
struct pts_ { /* buffer for accumulating path points */
84
gs_int_point current; /* current point as of start of data */
87
gs_int_point data[NUM_POINTS];
89
struct ch_ { /* cache for downloaded characters */
90
#define MAX_CACHED_CHARS 400
91
#define MAX_CHAR_DATA 500000
92
#define MAX_CHAR_SIZE 5000
93
#define CHAR_HASH_FACTOR 247
94
ushort table[MAX_CACHED_CHARS * 3 / 2];
98
} data[MAX_CACHED_CHARS];
99
int next_in; /* next data element to fill in */
100
int next_out; /* next data element to discard */
101
int count; /* of occupied data elements */
105
int state_rotated; /* 0, 1, 2, -1, mutiple of 90 deg */
106
int CompressMode; /* std PXL enum: None=0, RLE=1, JPEG=2, DeltaRow=3 */
108
floatp x_scale; /* chosen so that max(x) is scaled to 0x7FFF, to give max distinction between x values */
115
gs_public_st_suffix_add0_final(st_device_pclxl, gx_device_pclxl,
117
device_pclxl_enum_ptrs, device_pclxl_reloc_ptrs,
118
gx_device_finalize, st_device_vector);
120
#define pclxl_device_body(dname, depth)\
121
std_device_dci_type_body(gx_device_pclxl, 0, dname, &st_device_pclxl,\
122
DEFAULT_WIDTH_10THS * X_DPI / 10,\
123
DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
125
(depth > 8 ? 3 : 1), depth,\
126
(depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0),\
127
(depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
129
/* Driver procedures */
130
static dev_proc_open_device(pclxl_open_device);
131
static dev_proc_output_page(pclxl_output_page);
132
static dev_proc_close_device(pclxl_close_device);
133
static dev_proc_copy_mono(pclxl_copy_mono);
134
static dev_proc_copy_color(pclxl_copy_color);
135
static dev_proc_fill_mask(pclxl_fill_mask);
137
static dev_proc_get_params(pclxl_get_params);
138
static dev_proc_put_params(pclxl_put_params);
140
/*static dev_proc_draw_thin_line(pclxl_draw_thin_line); */
141
static dev_proc_begin_image(pclxl_begin_image);
142
static dev_proc_strip_copy_rop(pclxl_strip_copy_rop);
144
#define pclxl_device_procs(map_rgb_color, map_color_rgb)\
147
NULL, /* get_initial_matrix */\
148
NULL, /* sync_output */\
151
map_rgb_color, /* differs */\
152
map_color_rgb, /* differs */\
153
gdev_vector_fill_rectangle,\
154
NULL, /* tile_rectangle */\
157
NULL, /* draw_line */\
158
NULL, /* get_bits */\
161
NULL, /* map_cmyk_color */\
162
NULL, /* get_xfont_procs */\
163
NULL, /* get_xfont_device */\
164
NULL, /* map_rgb_alpha_color */\
165
gx_page_device_get_page_device,\
166
NULL, /* get_alpha_bits */\
167
NULL, /* copy_alpha */\
168
NULL, /* get_band */\
169
NULL, /* copy_rop */\
170
gdev_vector_fill_path,\
171
gdev_vector_stroke_path,\
173
gdev_vector_fill_trapezoid,\
174
gdev_vector_fill_parallelogram,\
175
gdev_vector_fill_triangle,\
176
NULL /****** WRONG ******/, /* draw_thin_line */\
178
NULL, /* image_data */\
179
NULL, /* end_image */\
180
NULL, /* strip_tile_rectangle */\
181
pclxl_strip_copy_rop\
184
const gx_device_pclxl gs_pxlmono_device = {
185
pclxl_device_body("pxlmono", 8),
186
pclxl_device_procs(gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb)
189
const gx_device_pclxl gs_pxlcolor_device = {
190
pclxl_device_body("pxlcolor", 24),
191
pclxl_device_procs(gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb)
194
/* ---------------- Other utilities ---------------- */
196
static inline stream *
197
pclxl_stream(gx_device_pclxl *xdev)
199
return gdev_vector_stream((gx_device_vector *)xdev);
202
/* Initialize for a page. */
204
pclxl_page_init(gx_device_pclxl * xdev)
206
gdev_vector_init((gx_device_vector *)xdev);
207
xdev->in_page = false;
208
xdev->fill_rule = gx_path_type_winding_number;
209
xdev->clip_rule = gx_path_type_winding_number;
210
xdev->color_space = eNoColorSpace;
211
xdev->palette.size = 0;
212
xdev->font_set = false;
213
xdev->state_rotated = 0;
214
xdev->scaled = false;
217
xdev->pen_null = false;
218
xdev->brush_null = false;
221
/* Test whether a RGB color is actually a gray shade. */
222
#define RGB_IS_GRAY(ci) ((ci) >> 8 == ((ci) & 0xffff))
224
/* Set the color space and (optionally) palette. */
226
pclxl_set_color_space(gx_device_pclxl * xdev, pxeColorSpace_t color_space)
228
if (xdev->color_space != color_space) {
229
stream *s = pclxl_stream(xdev);
231
px_put_ub(s, (byte)color_space);
232
px_put_ac(s, pxaColorSpace, pxtSetColorSpace);
233
xdev->color_space = color_space;
234
xdev->palette.size = 0; /* purge the cached palette */
238
pclxl_set_color_palette(gx_device_pclxl * xdev, pxeColorSpace_t color_space,
239
const byte * palette, uint palette_size)
241
if (xdev->color_space != color_space ||
242
xdev->palette.size != palette_size ||
243
memcmp(xdev->palette.data, palette, palette_size)
245
stream *s = pclxl_stream(xdev);
246
static const byte csp_[] = {
248
DUB(e8Bit), DA(pxaPaletteDepth),
252
px_put_ub(s, (byte)color_space);
254
px_put_u(s, palette_size);
255
px_put_bytes(s, palette, palette_size);
256
px_put_ac(s, pxaPaletteData, pxtSetColorSpace);
257
xdev->color_space = color_space;
258
xdev->palette.size = palette_size;
259
memcpy(xdev->palette.data, palette, palette_size);
263
/* For caching either NullPen or NullBrush, which happens a lot for
264
* drawing masks in the PS3 CET test set.
266
* The expected null_source/op combos are:
267
* pxaNullPen/pxtSetPenSource and pxaNullBrush/pxtSetBrushSource
270
pclxl_set_cached_nulls(gx_device_pclxl * xdev, px_attribute_t null_source, px_tag_t op)
272
stream *s = pclxl_stream(xdev);
273
if (op == pxtSetPenSource) {
277
xdev->pen_null = true;
279
if (op == pxtSetBrushSource) {
280
if (xdev->brush_null)
283
xdev->brush_null = true;
285
px_put_uba(s, 0, (byte)null_source);
290
/* Set a drawing RGB color. */
292
pclxl_set_color(gx_device_pclxl * xdev, const gx_drawing_color * pdc,
293
px_attribute_t null_source, px_tag_t op)
295
stream *s = pclxl_stream(xdev);
297
if (gx_dc_is_pure(pdc)) {
298
gx_color_index color = gx_dc_pure_color(pdc);
300
if (op == pxtSetPenSource) xdev->pen_null = false;
301
if (op == pxtSetBrushSource) xdev->brush_null = false;
303
if (xdev->color_info.num_components == 1 || RGB_IS_GRAY(color)) {
304
pclxl_set_color_space(xdev, eGray);
305
px_put_uba(s, (byte) color, pxaGrayLevel);
307
pclxl_set_color_space(xdev, eRGB);
308
spputc(s, pxt_ubyte_array);
310
spputc(s, (byte) (color >> 16));
311
spputc(s, (byte) (color >> 8));
312
spputc(s, (byte) color);
313
px_put_a(s, pxaRGBColor);
315
} else if (gx_dc_is_null(pdc) || !color_is_set(pdc)) {
316
if (op == pxtSetPenSource || op == pxtSetBrushSource)
317
return pclxl_set_cached_nulls(xdev, null_source, op);
319
px_put_uba(s, 0, null_source);
321
return_error(gs_error_rangecheck);
326
/* Test whether we can handle a given color space in an image. */
327
/* We cannot handle ICCBased color spaces. */
329
pclxl_can_handle_color_space(const gs_color_space * pcs)
331
gs_color_space_index index;
332
/* an image with no colorspace info arrived; cannot handle */
335
index = gs_color_space_get_index(pcs);
337
if (index == gs_color_space_index_Indexed) {
338
if (pcs->params.indexed.use_proc)
341
gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
343
else if (index == gs_color_space_index_ICC)
345
index = gsicc_get_default_type(pcs->cmm_icc_profile_data);
346
return ((index < gs_color_space_index_DevicePixel) ? true : false);
349
return !(index == gs_color_space_index_Separation ||
350
index == gs_color_space_index_Pattern ||
351
index == gs_color_space_index_ICC);
354
/* Test whether we can icclink-transform an image. */
356
pclxl_can_icctransform(const gs_image_t * pim)
358
const gs_color_space *pcs = pim->ColorSpace;
360
(pim->ImageMask ? 1 :
361
pim->BitsPerComponent * gs_color_space_num_components(pcs));
363
if ((gs_color_space_get_index(pcs) == gs_color_space_index_ICC)
364
&& (bits_per_pixel == 24))
370
/* Set brush, pen, and mode for painting a path. */
372
pclxl_set_paints(gx_device_pclxl * xdev, gx_path_type_t type)
374
stream *s = pclxl_stream(xdev);
375
gx_path_type_t rule = type & gx_path_type_rule;
377
if (!(type & gx_path_type_fill) &&
378
(color_is_set(&xdev->saved_fill_color.saved_dev_color) ||
379
!gx_dc_is_null(&xdev->saved_fill_color.saved_dev_color)
382
pclxl_set_cached_nulls(xdev, pxaNullBrush, pxtSetBrushSource);
383
color_set_null(&xdev->saved_fill_color.saved_dev_color);
384
if (rule != xdev->fill_rule) {
385
px_put_ub(s, (byte)(rule == gx_path_type_even_odd ? eEvenOdd :
387
px_put_ac(s, pxaFillMode, pxtSetFillMode);
388
xdev->fill_rule = rule;
391
if (!(type & gx_path_type_stroke) &&
392
(color_is_set(&xdev->saved_stroke_color.saved_dev_color) ||
393
!gx_dc_is_null(&xdev->saved_stroke_color.saved_dev_color)
396
pclxl_set_cached_nulls(xdev, pxaNullPen, pxtSetPenSource);
397
color_set_null(&xdev->saved_stroke_color.saved_dev_color);
402
pclxl_set_page_origin(stream *s, int x, int y)
405
px_put_ac(s, pxaPageOrigin, pxtSetPageOrigin);
410
pclxl_set_page_scale(gx_device_pclxl * xdev, floatp x_scale, floatp y_scale)
412
stream *s = pclxl_stream(xdev);
414
xdev->x_scale = x_scale;
415
xdev->y_scale = y_scale;
416
px_put_rp(s, x_scale, y_scale);
417
px_put_ac(s, pxaPageScale, pxtSetPageScale);
423
pclxl_unset_page_scale(gx_device_pclxl * xdev)
425
stream *s = pclxl_stream(xdev);
427
px_put_rp(s, 1/xdev->x_scale, 1/xdev->y_scale);
428
px_put_ac(s, pxaPageScale, pxtSetPageScale);
429
xdev->scaled = false;
436
/* Set the cursor. */
438
pclxl_set_cursor(gx_device_pclxl * xdev, int x, int y)
440
stream *s = pclxl_stream(xdev);
443
/* Points must be one of ubyte/uint16/sint16;
444
Here we play with PageScale (one of ubyte/uint16/real32_xy) to go higher.
445
This gives us 32768 x 3.4e38 in UnitsPerMeasure.
446
If we ever need to go higher, we play with UnitsPerMeasure. */
447
if (abs(x) > 0x7FFF) {
448
x_scale = ((floatp) abs(x))/0x7FFF;
449
x = (x > 0 ? 0x7FFF : -0x7FFF);
452
if (abs(y) > 0x7FFF) {
453
y_scale = ((floatp) abs(y))/0x7FFF;
454
y = (y > 0 ? 0x7FFF : -0x7FFF);
457
pclxl_set_page_scale(xdev, x_scale, y_scale);
459
px_put_ac(s, pxaPoint, pxtSetCursor);
460
pclxl_unset_page_scale(xdev);
464
/* ------ Paths ------ */
466
/* Flush any buffered path points. */
468
px_put_np(stream * s, int count, pxeDataType_t dtype)
470
px_put_uba(s, (byte)count, pxaNumberOfPoints);
471
px_put_uba(s, (byte)dtype, pxaPointType);
474
pclxl_flush_points(gx_device_pclxl * xdev)
476
int count = xdev->points.count;
479
stream *s = pclxl_stream(xdev);
481
int x = xdev->points.current.x, y = xdev->points.current.y;
482
int uor = 0, sor = 0;
483
pxeDataType_t data_type;
485
byte diffs[NUM_POINTS * 2];
488
int temp_origin_x = 0, temp_origin_y = 0;
489
int count_smalls = 0;
491
if (xdev->points.type != POINTS_NONE) {
492
for (i = 0; i < count; ++i) {
493
if ((abs(xdev->points.data[i].x) > 0x7FFF) || (abs(xdev->points.data[i].y) > 0x7FFF))
495
if ((abs(xdev->points.data[i].x) < 0x8000) && (abs(xdev->points.data[i].y) < 0x8000)) {
496
if ((temp_origin_x != xdev->points.data[i].x) || (temp_origin_y != xdev->points.data[i].y)) {
497
temp_origin_x = xdev->points.data[i].x;
498
temp_origin_y = xdev->points.data[i].y;
504
/* if there are some points with small co-ordinates, we set origin to it
505
before scaling, an unset afterwards. This works around problems
506
for small co-ordinates being moved snapped to 32767 x 32767 grid points;
507
if there are more than 1, the other points
508
will be in-accurate, unfortunately */
510
pclxl_set_page_origin(s, temp_origin_x, temp_origin_y);
512
for (i = 0; i < count; ++i) {
513
x_scale = max(((floatp) abs(xdev->points.data[i].x - temp_origin_x))/0x7FFF , x_scale);
514
y_scale = max(((floatp) abs(xdev->points.data[i].y - temp_origin_y))/0x7FFF , y_scale);
516
for (i = 0; i < count; ++i) {
517
xdev->points.data[i].x = (int)((xdev->points.data[i].x - temp_origin_x)/x_scale + 0.5);
518
xdev->points.data[i].y = (int)((xdev->points.data[i].y - temp_origin_y)/y_scale + 0.5);
520
x = (int)((x - temp_origin_x)/x_scale + 0.5);
521
y = (int)((y - temp_origin_y)/y_scale + 0.5);
522
pclxl_set_page_scale(xdev, x_scale, y_scale);
524
/* don't reset origin if we did not scale */
529
* Writing N lines using a point list requires 11 + 4*N or 11 +
530
* 2*N bytes, as opposed to 8*N bytes using separate commands;
531
* writing N curves requires 11 + 12*N or 11 + 6*N bytes
532
* vs. 22*N. So it's always shorter to write curves with a
533
* list (except for N = 1 with full-size coordinates, but since
534
* the difference is only 1 byte, we don't bother to ever use
535
* the non-list form), but lines are shorter only if N >= 3
536
* (again, with a 1-byte difference if N = 2 and byte
539
switch (xdev->points.type) {
545
for (i = 0; i < count; ++i) {
546
px_put_ssp(s, xdev->points.data[i].x,
547
xdev->points.data[i].y);
548
px_put_a(s, pxaEndPoint);
551
pclxl_unset_page_scale(xdev);
553
pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
556
/* See if we can use byte values. */
557
for (i = di = 0; i < count; ++i, di += 2) {
558
int dx = xdev->points.data[i].x - x;
559
int dy = xdev->points.data[i].y - y;
561
diffs[di] = (byte) dx;
562
diffs[di + 1] = (byte) dy;
564
sor |= (dx + 0x80) | (dy + 0x80);
569
else if (!(sor & ~0xff))
574
/* Use byte values. */
575
useb:px_put_np(s, count, data_type);
577
px_put_data_length(s, count * 2); /* 2 bytes per point */
578
px_put_bytes(s, diffs, count * 2);
579
pclxl_unset_page_scale(xdev);
581
pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
585
/* See if we can use byte values. */
586
for (i = di = 0; i < count; i += 3, di += 6) {
587
int dx1 = xdev->points.data[i].x - x;
588
int dy1 = xdev->points.data[i].y - y;
589
int dx2 = xdev->points.data[i + 1].x - x;
590
int dy2 = xdev->points.data[i + 1].y - y;
591
int dx = xdev->points.data[i + 2].x - x;
592
int dy = xdev->points.data[i + 2].y - y;
594
diffs[di] = (byte) dx1;
595
diffs[di + 1] = (byte) dy1;
596
diffs[di + 2] = (byte) dx2;
597
diffs[di + 3] = (byte) dy2;
598
diffs[di + 4] = (byte) dx;
599
diffs[di + 5] = (byte) dy;
600
uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
601
sor |= (dx1 + 0x80) | (dy1 + 0x80) |
602
(dx2 + 0x80) | (dy2 + 0x80) |
603
(dx + 0x80) | (dy + 0x80);
608
else if (!(sor & ~0xff))
612
op = pxtBezierRelPath;
614
default: /* can't happen */
615
return_error(gs_error_unknownerror);
617
px_put_np(s, count, eSInt16);
619
px_put_data_length(s, count * 4); /* 2 UInt16s per point */
620
for (i = 0; i < count; ++i) {
621
px_put_s(s, xdev->points.data[i].x);
622
px_put_s(s, xdev->points.data[i].y);
624
pclxl_unset_page_scale(xdev);
626
pclxl_set_page_origin(s, -temp_origin_x, -temp_origin_y);
627
zap:xdev->points.type = POINTS_NONE;
628
xdev->points.count = 0;
633
/* ------ Images ------ */
635
static image_enum_proc_plane_data(pclxl_image_plane_data);
636
static image_enum_proc_end_image(pclxl_image_end_image);
637
static const gx_image_enum_procs_t pclxl_image_enum_procs = {
638
pclxl_image_plane_data, pclxl_image_end_image
641
/* Begin an image. */
643
pclxl_write_begin_image(gx_device_pclxl * xdev, uint width, uint height,
644
uint dest_width, uint dest_height)
646
stream *s = pclxl_stream(xdev);
648
px_put_usa(s, width, pxaSourceWidth);
649
px_put_usa(s, height, pxaSourceHeight);
650
px_put_usp(s, dest_width, dest_height);
651
px_put_ac(s, pxaDestinationSize, pxtBeginImage);
654
/* Write rows of an image. */
655
/****** IGNORES data_bit ******/
656
/* 2009: we try to cope with the case of data_bit being multiple of 8 now */
659
pclxl_write_image_data_RLE(gx_device_pclxl * xdev, const byte * base, int data_bit,
660
uint raster, uint width_bits, int y, int height)
662
stream *s = pclxl_stream(xdev);
663
uint width_bytes = (width_bits + 7) >> 3;
664
uint num_bytes = ROUND_UP(width_bytes, 4) * height;
665
bool compress = num_bytes >= 8;
667
/* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
668
int offset = data_bit >> 3;
669
const byte *data = base + offset;
671
px_put_usa(s, y, pxaStartLine);
672
px_put_usa(s, height, pxaBlockHeight);
674
stream_RLE_state rlstate;
675
stream_cursor_write w;
676
stream_cursor_read r;
679
* H-P printers require that all the data for an operator be
680
* contained in a single data block. Thus, we must allocate a
681
* temporary buffer for the compressed data. Currently we don't go
682
* to the trouble of doing two passes if we can't allocate a buffer
683
* large enough for the entire transfer.
685
byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
686
"pclxl_write_image_data");
690
s_RLE_set_defaults_inline(&rlstate);
691
rlstate.EndOfData = false;
692
s_RLE_init_inline(&rlstate);
694
w.limit = w.ptr + num_bytes;
696
* If we ever overrun the buffer, it means that the compressed
697
* data was larger than the uncompressed. If this happens,
698
* write the data uncompressed.
700
for (i = 0; i < height; ++i) {
701
r.ptr = data + i * raster - 1;
702
r.limit = r.ptr + width_bytes;
703
if ((*s_RLE_template.process)
704
((stream_state *) & rlstate, &r, &w, true) != 0 ||
708
r.ptr = (const byte *)"\000\000\000\000\000";
709
r.limit = r.ptr + (-(int)width_bytes & 3);
710
if ((*s_RLE_template.process)
711
((stream_state *) & rlstate, &r, &w, true) != 0 ||
717
if ((*s_RLE_template.process)
718
((stream_state *) & rlstate, &r, &w, true) != 0
722
uint count = w.ptr + 1 - buf;
724
px_put_ub(s, eRLECompression);
725
px_put_ac(s, pxaCompressMode, pxtReadImage);
726
px_put_data_length(s, count);
727
px_put_bytes(s, buf, count);
729
gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
731
ncfree:gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
734
/* Write the data uncompressed. */
735
px_put_ub(s, eNoCompression);
736
px_put_ac(s, pxaCompressMode, pxtReadImage);
737
px_put_data_length(s, num_bytes);
738
for (i = 0; i < height; ++i) {
739
px_put_bytes(s, data + i * raster, width_bytes);
740
px_put_bytes(s, (const byte *)"\000\000\000\000", -(int)width_bytes & 3);
745
pclxl_write_image_data_JPEG(gx_device_pclxl * xdev, const byte * base,
746
int data_bit, uint raster, uint width_bits, int y,
749
stream *s = pclxl_stream(xdev);
750
uint width_bytes = (width_bits + 7) >> 3;
755
/* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
756
int offset = data_bit >> 3;
757
const byte *data = base + offset;
758
jpeg_compress_data *jcdp =
759
gs_alloc_struct_immovable(xdev->v_memory, jpeg_compress_data,
760
&st_jpeg_compress_data,
761
"pclxl_write_image_data_JPEG(jpeg_compress_data)");
762
stream_DCT_state state;
763
stream_cursor_read r;
764
stream_cursor_write w;
765
/* Approx. The worse case is ~ header + width_bytes * height.
766
Apparently minimal SOI/DHT/DQT/SOS/EOI is 341 bytes. TO CHECK. */
767
int buffersize = 341 + width_bytes * height;
769
byte *buf = gs_alloc_bytes(xdev->v_memory, buffersize,
770
"pclxl_write_image_data_JPEG(buf)");
771
/* RLE can write uncompressed without extra-allocation */
772
if ((buf == 0) || (jcdp == 0)) {
773
goto failed_so_use_rle_instead;
775
/* Create the DCT encoder state. */
776
jcdp->templat = s_DCTE_template;
777
s_init_state((stream_state *) & state, &jcdp->templat, 0);
778
if (state.templat->set_defaults) {
779
state.memory = xdev->v_memory;
780
(*state.templat->set_defaults) ((stream_state *) & state);
783
state.ColorTransform = (xdev->color_info.num_components == 3 ? 1 : 0);
784
state.data.compress = jcdp;
785
state.icc_profile = NULL;
786
jcdp->memory = state.jpeg_memory = xdev->v_memory;
787
if ((code = gs_jpeg_create_compress(&state)) < 0)
788
goto cleanup_and_use_rle;
789
/* image-specific info */
790
jcdp->cinfo.image_width = width_bytes / xdev->color_info.num_components;
791
jcdp->cinfo.image_height = height;
792
switch (xdev->color_info.num_components) {
794
jcdp->cinfo.input_components = 3;
795
jcdp->cinfo.in_color_space = JCS_RGB;
798
jcdp->cinfo.input_components = 1;
799
jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
802
goto cleanup_and_use_rle;
805
/* Set compression parameters. */
806
if ((code = gs_jpeg_set_defaults(&state)) < 0)
807
goto cleanup_and_use_rle;
809
if (state.templat->init)
810
(*state.templat->init) ((stream_state *)&state);
811
state.scan_line_size = jcdp->cinfo.input_components *
812
jcdp->cinfo.image_width;
813
jcdp->templat.min_in_size =
814
max(s_DCTE_template.min_in_size, state.scan_line_size);
815
jcdp->templat.min_out_size =
816
max(s_DCTE_template.min_out_size, state.Markers.size);
819
w.limit = w.ptr + buffersize;
820
for (i = 0; i < height; ++i) {
821
r.ptr = data + i * raster - 1;
822
r.limit = r.ptr + width_bytes;
823
if (((code = (*state.templat->process)
824
((stream_state *) & state, &r, &w, false)) != 0 && code != EOFC) || r.ptr != r.limit)
825
goto cleanup_and_use_rle;
827
count = w.ptr + 1 - buf;
828
px_put_usa(s, y, pxaStartLine);
829
px_put_usa(s, height, pxaBlockHeight);
830
px_put_ub(s, eJPEGCompression);
831
px_put_ac(s, pxaCompressMode, pxtReadImage);
832
px_put_data_length(s, count);
833
px_put_bytes(s, buf, count);
835
gs_free_object(xdev->v_memory, buf,
836
"pclxl_write_image_data_JPEG(buf)");
838
gs_jpeg_destroy(&state); /* frees *jcdp */
842
/* cleans up - something went wrong after allocation */
843
gs_free_object(xdev->v_memory, buf,
844
"pclxl_write_image_data_JPEG(buf)");
846
gs_jpeg_destroy(&state); /* frees *jcdp */
847
/* fall through to redo in RLE */
848
failed_so_use_rle_instead:
849
/* the RLE routine can write without new allocation - use as fallback. */
850
pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits, y,
855
/* DeltaRow compression (also called "mode 3"):
856
drawn heavily from gdevcljc.c:cljc_print_page(),
857
This is simplier since PCL XL does not allow
858
compression mix-and-match.
860
Worse case of RLE is + 1/128, but worse case of DeltaRow is + 1/8
863
pclxl_write_image_data_DeltaRow(gx_device_pclxl * xdev, const byte * base, int data_bit,
864
uint raster, uint width_bits, int y, int height)
866
stream *s = pclxl_stream(xdev);
867
uint width_bytes = (width_bits + 7) >> 3;
868
int worst_case_comp_size = width_bytes + (width_bytes / 8) + 1;
873
/* cannot handle data_bit not multiple of 8, but we don't invoke this routine that way */
874
int offset = data_bit >> 3;
875
const byte *data = base + offset;
877
/* allocate the worst case scenario; PCL XL has an extra 2 byte per row compared to PCL5 */
878
byte *buf = gs_alloc_bytes(xdev->v_memory, (worst_case_comp_size + 2)* height,
879
"pclxl_write_image_data_DeltaRow(buf)");
880
prow = gs_alloc_bytes(xdev->v_memory, width_bytes, "pclxl_write_image_data_DeltaRow(prow)");
881
/* the RLE routine can write uncompressed without extra-allocation */
882
if ((buf == 0) || (prow == 0)) {
883
pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits, y, height);
886
/* initialize the seed row */
887
memset(prow, 0, width_bytes);
889
for (i = 0; i < height; i++) {
890
int compressed_size = gdev_pcl_mode3compress(width_bytes, data + i * raster, prow, cdata + 2);
891
/* PCL XL prepends row data with byte count */
892
*cdata = compressed_size & 0xff;
893
*(cdata+1) = compressed_size >> 8;
894
cdata += compressed_size + 2;
896
px_put_usa(s, y, pxaStartLine);
897
px_put_usa(s, height, pxaBlockHeight);
898
px_put_ub(s, eDeltaRowCompression);
899
px_put_ac(s, pxaCompressMode, pxtReadImage);
901
px_put_data_length(s, count);
902
px_put_bytes(s, buf, count);
904
gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data_DeltaRow(buf)");
905
gs_free_object(xdev->v_memory, prow, "pclxl_write_image_data_DeltaRow(prow)");
909
/* calling from copy_mono/copy_color/fill_mask should never do lossy compression */
911
pclxl_write_image_data(gx_device_pclxl * xdev, const byte * data,
912
int data_bit, uint raster, uint width_bits, int y,
913
int height, bool allow_lossy)
915
/* If we only have 1 line, it does not make sense to do JPEG/DeltaRow */
917
pclxl_write_image_data_RLE(xdev, data, data_bit, raster, width_bits,
922
switch (xdev->CompressMode) {
923
case eDeltaRowCompression:
924
pclxl_write_image_data_DeltaRow(xdev, data, data_bit, raster,
925
width_bits, y, height);
927
case eJPEGCompression:
928
/* JPEG should not be used for mask or other data */
930
pclxl_write_image_data_JPEG(xdev, data, data_bit, raster,
931
width_bits, y, height);
933
pclxl_write_image_data_RLE(xdev, data, data_bit, raster,
934
width_bits, y, height);
936
case eRLECompression:
938
pclxl_write_image_data_RLE(xdev, data, data_bit, raster,
939
width_bits, y, height);
946
pclxl_write_end_image(gx_device_pclxl * xdev)
948
spputc(xdev->strm, pxtEndImage);
951
/* ------ Fonts ------ */
953
/* Write a string (single- or double-byte). */
955
px_put_string(stream * s, const byte * data, uint len, bool wide)
958
spputc(s, pxt_uint16_array);
960
px_put_bytes(s, data, len * 2);
962
spputc(s, pxt_ubyte_array);
964
px_put_bytes(s, data, len);
968
/* Write a 16-bit big-endian value. */
970
px_put_us_be(stream * s, uint i)
972
spputc(s, (byte) (i >> 8));
976
/* Define a bitmap font. The client must call px_put_string */
977
/* with the font name immediately before calling this procedure. */
979
pclxl_define_bitmap_font(gx_device_pclxl * xdev)
981
stream *s = pclxl_stream(xdev);
982
static const byte bfh_[] = {
983
DA(pxaFontName), DUB(0), DA(pxaFontFormat),
985
DUS(8 + 6 + 4 + 6), DA(pxaFontHeaderLength),
987
pxt_dataLengthByte, 8 + 6 + 4 + 6,
989
254, 0, (MAX_CACHED_CHARS + 255) >> 8, 0,
992
static const byte efh_[] = {
993
0xff, 0xff, 0, 0, 0, 0,
998
px_put_us_be(s, (uint) (xdev->HWResolution[0] + 0.5));
999
px_put_us_be(s, (uint) (xdev->HWResolution[1] + 0.5));
1000
PX_PUT_LIT(s, efh_);
1003
/* Set the font. The client must call px_put_string */
1004
/* with the font name immediately before calling this procedure. */
1006
pclxl_set_font(gx_device_pclxl * xdev)
1008
stream *s = pclxl_stream(xdev);
1009
static const byte sf_[] = {
1010
DA(pxaFontName), DUB(1), DA(pxaCharSize), DUS(0), DA(pxaSymbolSet),
1017
/* Define a character in a bitmap font. The client must call px_put_string */
1018
/* with the font name immediately before calling this procedure. */
1020
pclxl_define_bitmap_char(gx_device_pclxl * xdev, uint ccode,
1021
const byte * data, uint raster, uint width_bits, uint height)
1023
stream *s = pclxl_stream(xdev);
1024
uint width_bytes = (width_bits + 7) >> 3;
1025
uint size = 10 + width_bytes * height;
1028
px_put_ac(s, pxaFontName, pxtBeginChar);
1030
px_put_a(s, pxaCharCode);
1031
if (size > 0xffff) {
1032
spputc(s, pxt_uint32);
1033
px_put_l(s, (ulong) size);
1036
px_put_ac(s, pxaCharDataSize, pxtReadChar);
1037
px_put_data_length(s, size);
1038
px_put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
1039
px_put_us_be(s, width_bits);
1040
px_put_us_be(s, height);
1041
for (i = 0; i < height; ++i)
1042
px_put_bytes(s, data + i * raster, width_bytes);
1043
spputc(s, pxtEndChar);
1046
/* Write the name of the only font we define. */
1048
pclxl_write_font_name(gx_device_pclxl * xdev)
1050
stream *s = pclxl_stream(xdev);
1052
px_put_string(s, (const byte *)"@", 1, false);
1055
/* Look up a bitmap id, return the index in the character table. */
1056
/* If the id is missing, return an index for inserting. */
1058
pclxl_char_index(gx_device_pclxl * xdev, gs_id id)
1060
int i, i_empty = -1;
1063
for (i = (id * CHAR_HASH_FACTOR) % countof(xdev->chars.table);;
1064
i = (i == 0 ? countof(xdev->chars.table) : i) - 1
1066
ccode = xdev->chars.table[i];
1068
return (i_empty >= 0 ? i_empty : i);
1069
else if (ccode == 1) {
1072
else if (i == i_empty) /* full table */
1074
} else if (xdev->chars.data[ccode].id == id)
1079
/* Remove the character table entry at a given index. */
1081
pclxl_remove_char(gx_device_pclxl * xdev, int index)
1083
uint ccode = xdev->chars.table[index];
1088
xdev->chars.count--;
1089
xdev->chars.used -= xdev->chars.data[ccode].size;
1090
xdev->chars.table[index] = 1; /* mark as deleted */
1091
i = (index == 0 ? countof(xdev->chars.table) : index) - 1;
1092
if (xdev->chars.table[i] == 0) {
1093
/* The next slot in probe order is empty. */
1094
/* Mark this slot and any deleted predecessors as empty. */
1095
for (i = index; xdev->chars.table[i] == 1;
1096
i = (i == countof(xdev->chars.table) - 1 ? 0 : i + 1)
1098
xdev->chars.table[i] = 0;
1102
/* Write a bitmap as a text character if possible. */
1103
/* The caller must set the color, cursor, and RasterOp. */
1104
/* We know id != gs_no_id. */
1106
pclxl_copy_text_char(gx_device_pclxl * xdev, const byte * data,
1107
int raster, gx_bitmap_id id, int w, int h)
1109
uint width_bytes = (w + 7) >> 3;
1110
uint size = width_bytes * h;
1113
stream *s = pclxl_stream(xdev);
1115
if (size > MAX_CHAR_SIZE)
1117
index = pclxl_char_index(xdev, id);
1118
if ((ccode = xdev->chars.table[index]) < 2) {
1119
/* Enter the character in the table. */
1120
while (xdev->chars.used + size > MAX_CHAR_DATA ||
1121
xdev->chars.count >= MAX_CACHED_CHARS - 2
1123
ccode = xdev->chars.next_out;
1124
index = pclxl_char_index(xdev, xdev->chars.data[ccode].id);
1125
pclxl_remove_char(xdev, index);
1126
xdev->chars.next_out =
1127
(ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
1129
index = pclxl_char_index(xdev, id);
1130
ccode = xdev->chars.next_in;
1131
xdev->chars.data[ccode].id = id;
1132
xdev->chars.data[ccode].size = size;
1133
xdev->chars.table[index] = ccode;
1134
xdev->chars.next_in =
1135
(ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
1136
if (!xdev->chars.count++) {
1137
/* This is the very first character. */
1138
pclxl_write_font_name(xdev);
1139
pclxl_define_bitmap_font(xdev);
1141
xdev->chars.used += size;
1142
pclxl_write_font_name(xdev);
1143
pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
1145
if (!xdev->font_set) {
1146
pclxl_write_font_name(xdev);
1147
pclxl_set_font(xdev);
1148
xdev->font_set = true;
1152
cc_bytes[0] = (byte) ccode;
1153
cc_bytes[1] = ccode >> 8;
1154
px_put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
1156
px_put_ac(s, pxaTextData, pxtText);
1160
/* ---------------- Vector implementation procedures ---------------- */
1163
pclxl_beginpage(gx_device_vector * vdev)
1165
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1167
* We can't use gdev_vector_stream here, because this may be called
1168
* from there before in_page is set.
1170
stream *s = vdev->strm;
1171
byte media_source = eAutoSelect; /* default */
1173
xdev->page ++; /* even/odd for duplex front/back */
1176
errprintf(vdev->memory, "PAGE: %d %d\n", xdev->page, xdev->NumCopies);
1177
errprintf(vdev->memory, "INFO: Printing page %d...\n", xdev->page);
1178
errflush(vdev->memory);
1181
px_write_page_header(s, (const gx_device *)vdev);
1183
if (xdev->ManualFeed_set && xdev->ManualFeed)
1185
else if (xdev->MediaPosition_set && xdev->MediaPosition >= 0 )
1186
media_source = xdev->MediaPosition;
1188
px_write_select_media(s, (const gx_device *)vdev, &xdev->media_size,
1190
xdev->page, xdev->Duplex, xdev->Tumble,
1191
xdev->MediaType_set, xdev->MediaType);
1193
spputc(s, pxtBeginPage);
1198
pclxl_setlinewidth(gx_device_vector * vdev, floatp width)
1200
stream *s = gdev_vector_stream(vdev);
1202
px_put_us(s, (uint) (width+0.5));
1203
px_put_ac(s, pxaPenWidth, pxtSetPenWidth);
1208
pclxl_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
1210
stream *s = gdev_vector_stream(vdev);
1212
/* The PCL XL cap styles just happen to be identical to PostScript. */
1213
px_put_ub(s, (byte) cap);
1214
px_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
1219
pclxl_setlinejoin(gx_device_vector * vdev, gs_line_join join)
1221
stream *s = gdev_vector_stream(vdev);
1223
if ((join < 0) || (join > 3)) {
1224
emprintf1(vdev->memory,
1225
"Igoring invalid linejoin enumerator %d\n",
1229
/* The PCL XL join styles just happen to be identical to PostScript. */
1230
px_put_ub(s, (byte) join);
1231
px_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
1236
pclxl_setmiterlimit(gx_device_vector * vdev, floatp limit)
1238
stream *s = gdev_vector_stream(vdev);
1240
* Amazingly enough, the PCL XL specification doesn't allow real
1241
* numbers for the miter limit.
1243
int i_limit = (int)(limit + 0.5);
1245
px_put_u(s, max(i_limit, 1));
1246
px_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
1251
pclxl_setdash(gx_device_vector * vdev, const float *pattern, uint count,
1254
stream *s = gdev_vector_stream(vdev);
1257
static const byte nac_[] = {
1258
DUB(0), DA(pxaSolidLine)
1261
PX_PUT_LIT(s, nac_);
1262
} else if (count > 255)
1263
return_error(gs_error_limitcheck);
1268
* Astoundingly, PCL XL doesn't allow real numbers here.
1269
* Do the best we can.
1271
spputc(s, pxt_uint16_array);
1272
px_put_ub(s, (byte)count);
1273
for (i = 0; i < count; ++i)
1274
px_put_s(s, (uint)pattern[i]);
1275
px_put_a(s, pxaLineDashStyle);
1277
px_put_usa(s, (uint)offset, pxaDashOffset);
1279
spputc(s, pxtSetLineDash);
1284
pclxl_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
1285
gs_logical_operation_t diff)
1287
stream *s = gdev_vector_stream(vdev);
1289
if (diff & lop_S_transparent) {
1290
px_put_ub(s, (byte)(lop & lop_S_transparent ? 1 : 0));
1291
px_put_ac(s, pxaTxMode, pxtSetSourceTxMode);
1293
if (diff & lop_T_transparent) {
1294
px_put_ub(s, (byte)(lop & lop_T_transparent ? 1 : 0));
1295
px_put_ac(s, pxaTxMode, pxtSetPaintTxMode);
1297
if (lop_rop(diff)) {
1298
px_put_ub(s, (byte)lop_rop(lop));
1299
px_put_ac(s, pxaROP3, pxtSetROP);
1305
pclxl_can_handle_hl_color(gx_device_vector * vdev, const gs_imager_state * pis,
1306
const gx_drawing_color * pdc)
1312
pclxl_setfillcolor(gx_device_vector * vdev, const gs_imager_state * pis,
1313
const gx_drawing_color * pdc)
1315
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1317
return pclxl_set_color(xdev, pdc, pxaNullBrush, pxtSetBrushSource);
1321
pclxl_setstrokecolor(gx_device_vector * vdev, const gs_imager_state * pis,
1322
const gx_drawing_color * pdc)
1324
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1326
return pclxl_set_color(xdev, pdc, pxaNullPen, pxtSetPenSource);
1330
pclxl_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
1331
fixed y1, gx_path_type_t type)
1333
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1334
stream *s = gdev_vector_stream(vdev);
1336
/* Check for out-of-range points. */
1337
#define OUT_OF_RANGE(v) (v < 0 || v >= int2fixed(0x10000))
1338
if (OUT_OF_RANGE(x0) || OUT_OF_RANGE(y0) ||
1339
OUT_OF_RANGE(x1) || OUT_OF_RANGE(y1)
1341
return_error(gs_error_rangecheck);
1343
if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1344
pclxl_set_paints(xdev, type);
1345
px_put_usq_fixed(s, x0, y0, x1, y1);
1346
px_put_ac(s, pxaBoundingBox, pxtRectangle);
1348
if (type & gx_path_type_clip) {
1349
static const byte cr_[] = {
1351
DUB(eInterior), DA(pxaClipRegion),
1355
px_put_usq_fixed(s, x0, y0, x1, y1);
1362
pclxl_beginpath(gx_device_vector * vdev, gx_path_type_t type)
1364
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1365
stream *s = gdev_vector_stream(vdev);
1367
spputc(s, pxtNewPath);
1368
xdev->points.type = POINTS_NONE;
1369
xdev->points.count = 0;
1374
pclxl_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
1375
gx_path_type_t type)
1377
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1378
int code = pclxl_flush_points(xdev);
1382
return pclxl_set_cursor(xdev,
1383
xdev->points.current.x = (int)(x+0.5),
1384
xdev->points.current.y = (int)(y+0.5));
1388
pclxl_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
1389
gx_path_type_t type)
1391
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1393
if (xdev->points.type != POINTS_LINES ||
1394
xdev->points.count >= NUM_POINTS
1396
if (xdev->points.type != POINTS_NONE) {
1397
int code = pclxl_flush_points(xdev);
1402
xdev->points.current.x = (int)(x0+0.5);
1403
xdev->points.current.y = (int)(y0+0.5);
1404
xdev->points.type = POINTS_LINES;
1406
gs_int_point *ppt = &xdev->points.data[xdev->points.count++];
1408
ppt->x = (int)(x+0.5), ppt->y = (int)(y+0.5);
1414
pclxl_curveto(gx_device_vector * vdev, floatp x0, floatp y0,
1415
floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3,
1416
gx_path_type_t type)
1418
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1420
if (xdev->points.type != POINTS_CURVES ||
1421
xdev->points.count >= NUM_POINTS - 2
1423
if (xdev->points.type != POINTS_NONE) {
1424
int code = pclxl_flush_points(xdev);
1429
xdev->points.current.x = (int)(x0+0.5);
1430
xdev->points.current.y = (int)(y0+0.5);
1431
xdev->points.type = POINTS_CURVES;
1434
gs_int_point *ppt = &xdev->points.data[xdev->points.count];
1436
ppt->x = (int)(x1+0.5), ppt->y = (int)(y1+0.5), ++ppt;
1437
ppt->x = (int)(x2+0.5), ppt->y = (int)(y2+0.5), ++ppt;
1438
ppt->x = (int)(x3+0.5), ppt->y = (int)(y3+0.5);
1440
xdev->points.count += 3;
1445
pclxl_closepath(gx_device_vector * vdev, floatp x, floatp y,
1446
floatp x_start, floatp y_start, gx_path_type_t type)
1448
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1449
stream *s = gdev_vector_stream(vdev);
1450
int code = pclxl_flush_points(xdev);
1454
spputc(s, pxtCloseSubPath);
1455
xdev->points.current.x = (int)(x_start+0.5);
1456
xdev->points.current.y = (int)(y_start+0.5);
1461
pclxl_endpath(gx_device_vector * vdev, gx_path_type_t type)
1463
gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
1464
stream *s = gdev_vector_stream(vdev);
1465
int code = pclxl_flush_points(xdev);
1466
gx_path_type_t rule = type & gx_path_type_rule;
1470
if (type & (gx_path_type_fill | gx_path_type_stroke)) {
1471
if (rule != xdev->fill_rule) {
1472
px_put_ub(s, (byte)(rule == gx_path_type_even_odd ? eEvenOdd :
1474
px_put_ac(s, pxaFillMode, pxtSetFillMode);
1475
xdev->fill_rule = rule;
1477
pclxl_set_paints(xdev, type);
1478
spputc(s, pxtPaintPath);
1480
if (type & gx_path_type_clip) {
1481
static const byte scr_[] = {
1482
DUB(eInterior), DA(pxaClipRegion), pxtSetClipReplace
1485
if (rule != xdev->clip_rule) {
1486
px_put_ub(s, (byte)(rule == gx_path_type_even_odd ? eEvenOdd :
1488
px_put_ac(s, pxaClipMode, pxtSetClipMode);
1489
xdev->clip_rule = rule;
1491
PX_PUT_LIT(s, scr_);
1496
/* Vector implementation procedures */
1498
static const gx_device_vector_procs pclxl_vector_procs = {
1499
/* Page management */
1505
pclxl_setmiterlimit,
1507
gdev_vector_setflat,
1510
pclxl_can_handle_hl_color,
1512
pclxl_setstrokecolor,
1524
/* ---------------- Driver procedures ---------------- */
1526
/* ------ Open/close/page ------ */
1528
/* Open the device. */
1530
pclxl_open_device(gx_device * dev)
1532
gx_device_vector *const vdev = (gx_device_vector *)dev;
1533
gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
1536
vdev->v_memory = dev->memory; /****** WRONG ******/
1537
vdev->vec_procs = &pclxl_vector_procs;
1538
code = gdev_vector_open_file_options(vdev, 512,
1539
VECTOR_OPEN_FILE_SEQUENTIAL);
1543
pclxl_page_init(xdev);
1544
px_write_file_header(vdev->strm, dev);
1545
xdev->media_size = pxeMediaSize_next; /* no size selected */
1546
memset(&xdev->chars, 0, sizeof(xdev->chars));
1547
xdev->chars.next_in = xdev->chars.next_out = 2;
1548
xdev->MediaPosition_set = false;
1549
xdev->MediaType_set = false;
1550
xdev->MediaPosition_old = eAutoSelect;
1551
xdev->MediaPosition = eAutoSelect;
1552
xdev->MediaType_old[0] = '\0';
1553
xdev->MediaType[0] = '\0';
1554
/* xdev->iccTransform = false; */ /* set true/false here to ignore command line */
1558
/* Wrap up ("output") a page. */
1559
/* We only support flush = true */
1561
pclxl_output_page(gx_device * dev, int num_copies, int flush)
1563
gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
1567
/* Note that unlike close_device, end_page must not omit blank pages. */
1569
pclxl_beginpage((gx_device_vector *)dev);
1571
px_put_usa(s, (uint)num_copies, pxaPageCopies); /* num_copies */
1572
spputc(s, pxtEndPage);
1574
pclxl_page_init(xdev);
1575
if (ferror(xdev->file))
1576
return_error(gs_error_ioerror);
1577
if ((code = gx_finish_output_page(dev, num_copies, flush)) < 0)
1579
/* Check if we need to change the output file for separate pages */
1580
if (gx_outputfile_is_separate_pages(((gx_device_vector *)dev)->fname, dev->memory)) {
1581
if ((code = pclxl_close_device(dev)) < 0)
1583
code = pclxl_open_device(dev);
1588
/* Close the device. */
1589
/* Note that if this is being called as a result of finalization, */
1590
/* the stream may no longer exist. */
1592
pclxl_close_device(gx_device * dev)
1594
gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
1595
FILE *file = xdev->file;
1597
if (xdev->strm != NULL)
1600
fputc(pxtEndPage, file);
1601
px_write_file_trailer(file);
1602
return gdev_vector_close_file((gx_device_vector *)dev);
1605
/* ------ One-for-one images ------ */
1607
static const byte eBit_values[] = {
1608
0, e1Bit, 0, 0, e4Bit, 0, 0, 0, e8Bit
1611
/* Copy a monochrome bitmap. */
1613
pclxl_copy_mono(gx_device * dev, const byte * data, int data_x, int raster,
1614
gx_bitmap_id id, int x, int y, int w, int h,
1615
gx_color_index zero, gx_color_index one)
1617
gx_device_vector *const vdev = (gx_device_vector *)dev;
1618
gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
1621
gx_color_index color0 = zero, color1 = one;
1622
gx_color_index white = (1 << dev->color_info.depth) - 1;
1623
gx_color_index black = 0;
1624
gs_logical_operation_t lop;
1625
byte palette[2 * 3];
1627
pxeColorSpace_t color_space;
1629
fit_copy(dev, data, data_x, raster, id, x, y, w, h);
1630
code = gdev_vector_update_clip_path(vdev, NULL);
1634
/* write_image_data() needs byte-alignment,
1635
* and gx_default_copy_* is more efficient than pxlcl_*
1636
* for small rasters. See details in copy_color().
1638
if ( ((data_x & 7) != 0) || (h == 1) || (w == 1) )
1639
return gx_default_copy_mono(dev, data, data_x, raster, id,
1640
x, y, w, h, zero, one);
1642
pclxl_set_cursor(xdev, x, y);
1643
if (id != gs_no_id && zero == gx_no_color_index &&
1644
one != gx_no_color_index && data_x == 0
1646
gx_drawing_color dcolor;
1648
code = gdev_vector_update_log_op(vdev, rop3_T|lop_T_transparent);
1652
set_nonclient_dev_color(&dcolor, one);
1653
pclxl_setfillcolor(vdev, NULL, &dcolor);
1654
if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1658
* The following doesn't work if we're writing white with a mask.
1659
* We'll fix it eventually.
1661
* The logic goes like this: non-white + mask (transparent)
1662
* works by setting the mask color to white and also declaring
1663
* white-is-transparent. This doesn't work for drawing white + mask,
1664
* since everything is then white+white-and-transparent. So instead
1665
* we set mask color to black, invert and draw the destination/background
1666
* through it, as well as drawing the white color.
1668
* In rop3 terms, this is (D & ~S) | S
1670
* This also only works in the case of the drawing color is white,
1671
* because we need the inversion to not draw anything, (especially
1672
* not the complimentary color/shade). So we have two different code paths,
1673
* white + mask and non-whites + mask.
1675
* There is a further refinement to this algorithm - it appears that
1676
* black+mask is treated specially by the vector driver core (rendered
1677
* as transparent on white), and does not work as non-white + mask.
1678
* So Instead we set mask color to white and do (S & D) (i.e. draw
1679
* background on mask, instead of transparent on mask).
1682
if (zero == gx_no_color_index) {
1683
if (one == gx_no_color_index)
1687
lop = (rop3_S & rop3_D);
1689
lop = rop3_S | lop_S_transparent;
1693
lop = rop3_S | (rop3_D & rop3_not(rop3_S));
1696
} else if (one == gx_no_color_index) {
1697
if (zero != white) {
1698
if (zero == black) {
1699
lop = (rop3_S & rop3_D);
1701
lop = rop3_S | lop_S_transparent;
1705
lop = rop3_S | (rop3_D & rop3_not(rop3_S));
1712
if (dev->color_info.num_components == 1 ||
1713
(RGB_IS_GRAY(color0) && RGB_IS_GRAY(color1))
1715
palette[0] = (byte) color0;
1716
palette[1] = (byte) color1;
1718
color_space = eGray;
1719
if_debug2m('b', dev->memory, "color palette %02X %02X\n",
1720
palette[0], palette[1]);
1722
palette[0] = (byte) (color0 >> 16);
1723
palette[1] = (byte) (color0 >> 8);
1724
palette[2] = (byte) color0;
1725
palette[3] = (byte) (color1 >> 16);
1726
palette[4] = (byte) (color1 >> 8);
1727
palette[5] = (byte) color1;
1731
code = gdev_vector_update_log_op(vdev, lop);
1734
pclxl_set_color_palette(xdev, color_space, palette, palette_size);
1735
s = pclxl_stream(xdev);
1737
static const byte mi_[] = {
1738
DUB(e1Bit), DA(pxaColorDepth),
1739
DUB(eIndexedPixel), DA(pxaColorMapping)
1744
pclxl_write_begin_image(xdev, w, h, w, h);
1745
pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h, false);
1746
pclxl_write_end_image(xdev);
1750
/* Copy a color bitmap. */
1752
pclxl_copy_color(gx_device * dev,
1753
const byte * base, int sourcex, int raster, gx_bitmap_id id,
1754
int x, int y, int w, int h)
1756
gx_device_vector *const vdev = (gx_device_vector *)dev;
1757
gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
1762
fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
1763
code = gdev_vector_update_clip_path(vdev, NULL);
1767
source_bit = sourcex * dev->color_info.depth;
1769
/* side-effect from fill/stroke may have set color space to eGray */
1770
if (dev->color_info.num_components == 3)
1771
pclxl_set_color_space(xdev, eRGB);
1772
else if (dev->color_info.num_components == 1)
1773
pclxl_set_color_space(xdev, eGray);
1775
/* write_image_data() needs byte-alignment,
1776
* and gx_default_copy_* is more efficient than pxlcl_*
1777
* for small rasters.
1779
* SetBrushSource + Rectangle = 21 byte for 1x1 RGB
1780
* SetCursor+ BeginImage + ReadImage + EndImage = 56 bytes for 1x1 RGB
1781
* 3x1 RGB at 3 different colors takes 62 bytes for pxlcl_*
1782
* but gx_default_copy_* uses 63 bytes. Below 3 pixels, gx_default_copy_*
1783
* is better than pxlcl_*; above 3 pixels, it is less clear;
1784
* in practice, single-lines seems better coded as painted rectangles
1787
if ( ((source_bit & 7) != 0) || (w == 1) || (h == 1) )
1788
return gx_default_copy_color(dev, base, sourcex, raster, id,
1790
code = gdev_vector_update_log_op(vdev, rop3_S);
1793
pclxl_set_cursor(xdev, x, y);
1794
s = pclxl_stream(xdev);
1796
static const byte ci_[] = {
1798
DUB(eDirectPixel), DA(pxaColorMapping)
1801
px_put_ub(s, eBit_values[dev->color_info.depth /
1802
dev->color_info.num_components]);
1805
pclxl_write_begin_image(xdev, w, h, w, h);
1806
pclxl_write_image_data(xdev, base, source_bit, raster,
1807
w * dev->color_info.depth, 0, h, false);
1808
pclxl_write_end_image(xdev);
1814
pclxl_fill_mask(gx_device * dev,
1815
const byte * data, int data_x, int raster, gx_bitmap_id id,
1816
int x, int y, int w, int h,
1817
const gx_drawing_color * pdcolor, int depth,
1818
gs_logical_operation_t lop, const gx_clip_path * pcpath)
1820
gx_device_vector *const vdev = (gx_device_vector *)dev;
1821
gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
1824
gx_color_index foreground;
1826
fit_copy(dev, data, data_x, raster, id, x, y, w, h);
1827
/* write_image_data() needs byte-alignment,
1828
* and gx_default_copy_* is more efficient than pxlcl_*
1829
* for small rasters. See details in copy_color().
1831
if ((data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1 || (w == 1) || (h == 1) )
1832
return gx_default_fill_mask(dev, data, data_x, raster, id,
1833
x, y, w, h, pdcolor, depth,
1835
code = gdev_vector_update_clip_path(vdev, pcpath);
1836
foreground = gx_dc_pure_color(pdcolor);
1839
code = gdev_vector_update_fill_color(vdev, NULL, pdcolor);
1842
pclxl_set_cursor(xdev, x, y);
1843
if (id != gs_no_id && data_x == 0) {
1844
code = gdev_vector_update_log_op(vdev, lop);
1847
if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
1850
/* This is similiar to the copy_mono white-on-mask,
1851
* except we are drawing white on the black of a black/white mask,
1852
* so we invert source, compared to copy_mono */
1853
if (foreground == (1 << dev->color_info.depth) - 1) { /* white */
1854
lop = rop3_not(rop3_S) | (rop3_D & rop3_S);
1855
}else if (foreground == 0) { /* black */
1856
lop = (rop3_S & rop3_D);
1857
}else lop |= rop3_S | lop_S_transparent;
1859
code = gdev_vector_update_log_op(vdev,
1863
pclxl_set_color_palette(xdev, eGray, (const byte *)"\377\000", 2);
1864
s = pclxl_stream(xdev);
1866
static const byte mi_[] = {
1867
DUB(e1Bit), DA(pxaColorDepth),
1868
DUB(eIndexedPixel), DA(pxaColorMapping)
1873
pclxl_write_begin_image(xdev, w, h, w, h);
1874
pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h, false);
1875
pclxl_write_end_image(xdev);
1879
/* Do a RasterOp. */
1881
pclxl_strip_copy_rop(gx_device * dev, const byte * sdata, int sourcex,
1882
uint sraster, gx_bitmap_id id,
1883
const gx_color_index * scolors,
1884
const gx_strip_bitmap * textures,
1885
const gx_color_index * tcolors,
1886
int x, int y, int width, int height,
1887
int phase_x, int phase_y, gs_logical_operation_t lop)
1889
/* Improvements possible here using PXL ROP3
1890
for some combinations of args; use gx_default for now */
1891
if (!rop3_uses_D(lop)) /* gx_default() cannot cope with D ops */
1892
return gx_default_strip_copy_rop(dev, sdata, sourcex,
1897
x, y, width, height,
1898
phase_x, phase_y, lop);
1902
/* ------ High-level images ------ */
1904
#define MAX_ROW_DATA 500000 /* arbitrary */
1905
typedef struct pclxl_image_enum_s {
1906
gdev_vector_image_enum_common;
1910
int num_rows; /* # of allocated rows */
1915
gsicc_link_t *icclink;
1916
} pclxl_image_enum_t;
1917
gs_private_st_suffix_add1(st_pclxl_image_enum, pclxl_image_enum_t,
1918
"pclxl_image_enum_t", pclxl_image_enum_enum_ptrs,
1919
pclxl_image_enum_reloc_ptrs, st_vector_image_enum,
1922
/* Start processing an image. */
1924
pclxl_begin_image(gx_device * dev,
1925
const gs_imager_state * pis, const gs_image_t * pim,
1926
gs_image_format_t format, const gs_int_rect * prect,
1927
const gx_drawing_color * pdcolor,
1928
const gx_clip_path * pcpath, gs_memory_t * mem,
1929
gx_image_enum_common_t ** pinfo)
1931
gx_device_vector *const vdev = (gx_device_vector *)dev;
1932
gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
1933
const gs_color_space *pcs = pim->ColorSpace;
1934
pclxl_image_enum_t *pie;
1939
* Following should divide by num_planes, but we only handle chunky
1940
* images, i.e., num_planes = 1.
1942
int bits_per_pixel =
1943
(pim->ImageMask ? 1 :
1944
pim->BitsPerComponent * gs_color_space_num_components(pcs));
1949
* Check whether we can handle this image. PCL XL 1.0 and 2.0 only
1950
* handle orthogonal transformations.
1952
gs_matrix_invert(&pim->ImageMatrix, &mat);
1953
gs_matrix_multiply(&mat, &ctm_only(pis), &mat);
1954
/* We can handle rotations of 90 degs + scaling + reflections.
1955
* These have one of the diagonals being zeros
1956
* (and the other diagonals having non-zeros).
1958
if ((!((mat.xx * mat.yy != 0) && (mat.xy == 0) && (mat.yx == 0)) &&
1959
!((mat.xx == 0) && (mat.yy == 0) && (mat.xy * mat.yx != 0))) ||
1961
(!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
1962
((!pclxl_can_handle_color_space(pcs) ||
1963
(bits_per_pixel != 1 && bits_per_pixel != 4 &&
1964
bits_per_pixel != 8 && bits_per_pixel !=24))
1965
&& !(pclxl_can_icctransform(pim) && xdev->iccTransform) )) ||
1966
format != gs_image_format_chunky || pim->Interpolate ||
1970
row_raster = (bits_per_pixel * pim->Width + 7) >> 3;
1971
num_rows = MAX_ROW_DATA / row_raster;
1972
if (num_rows > pim->Height)
1973
num_rows = pim->Height;
1976
pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
1977
"pclxl_begin_image");
1978
row_data = gs_alloc_bytes(mem, num_rows * row_raster,
1979
"pclxl_begin_image(rows)");
1980
if (pie == 0 || row_data == 0) {
1981
code = gs_note_error(gs_error_VMerror);
1984
code = gdev_vector_begin_image(vdev, pis, pim, format, prect,
1985
pdcolor, pcpath, mem,
1986
&pclxl_image_enum_procs,
1987
(gdev_vector_image_enum_t *)pie);
1991
/* emit a PXL XL rotation and adjust mat correspondingly */
1992
pie->flipped = false;
1993
if (mat.xx * mat.yy > 0) {
1995
stream *s = pclxl_stream(xdev);
2001
xdev->state_rotated = 2;
2002
px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2004
/* leave the matrix alone if it is portrait */
2005
} else if (mat.xx * mat.yy < 0) {
2006
pie->flipped = true;
2008
stream *s = pclxl_stream(xdev);
2012
xdev->state_rotated = +2;
2013
px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2018
} else if (mat.xy * mat.yx < 0) {
2019
/* rotate +90 or -90 */
2021
stream *s = pclxl_stream(xdev);
2029
xdev->state_rotated = -1;
2037
xdev->state_rotated = +1;
2039
mat.xy = mat.yx = 0;
2040
px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2041
} else if (mat.xy * mat.yx > 0) {
2043
stream *s = pclxl_stream(xdev);
2044
pie->flipped = true;
2052
xdev->state_rotated = -1;
2060
xdev->state_rotated = +1;
2062
mat.xy = mat.yx = 0;
2063
px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2067
pie->rows.data = row_data;
2068
pie->rows.num_rows = num_rows;
2069
pie->rows.first_y = 0;
2070
pie->rows.raster = row_raster;
2071
if (!pim->ImageMask && !pclxl_can_handle_color_space(pcs)
2072
&& pclxl_can_icctransform(pim) && pcs->cmm_icc_profile_data) {
2073
gsicc_rendering_param_t rendering_params;
2075
rendering_params.black_point_comp = pis->blackptcomp;
2076
rendering_params.graphics_type_tag = GS_IMAGE_TAG;
2077
rendering_params.rendering_intent = pis->renderingintent;
2078
pie->icclink = gsicc_get_link(pis, dev, pcs, NULL /*des */ ,
2079
&rendering_params, pis->memory);
2081
pie->icclink = NULL;
2082
*pinfo = (gx_image_enum_common_t *) pie;
2084
gs_logical_operation_t lop = pis->log_op;
2086
if (pim->ImageMask) {
2087
const byte *palette = (const byte *)
2088
(pim->Decode[0] ? "\377\000" : "\000\377");
2089
gx_color_index foreground = gx_dc_pure_color(pdcolor);
2091
code = gdev_vector_update_fill_color(vdev,
2092
NULL, /* use process color */
2096
/* This is similiar to the copy_mono white-on-mask,
2097
* except we are drawing white on the black of a black/white mask,
2098
* so we invert source, compared to copy_mono */
2099
if (foreground == (1 << dev->color_info.depth) - 1) { /* white */
2100
lop = rop3_not(rop3_S) | (rop3_D & rop3_S);
2101
}else if (foreground == 0) { /* black */
2102
lop = (rop3_S & rop3_D);
2103
}else lop |= rop3_S | lop_S_transparent;
2105
code = gdev_vector_update_log_op
2109
pclxl_set_color_palette(xdev, eGray, palette, 2);
2111
if (bits_per_pixel == 24 ) {
2112
code = gdev_vector_update_log_op
2113
(vdev, (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2116
if (dev->color_info.num_components == 1) {
2117
pclxl_set_color_space(xdev, eGray);
2119
pclxl_set_color_space(xdev, eRGB);
2122
int bpc = pim->BitsPerComponent;
2123
int num_components = pie->plane_depths[0] * pie->num_planes / bpc;
2124
int sample_max = (1 << bpc) - 1;
2125
byte palette[256 * 3];
2128
code = gdev_vector_update_log_op
2129
(vdev, (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
2132
for (i = 0; i < 1 << bits_per_pixel; ++i) {
2134
gx_device_color devc;
2138
for (j = num_components - 1; j >= 0; cv >>= bpc, --j)
2139
cc.paint.values[j] = pim->Decode[j * 2] +
2141
(pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
2143
(*pcs->type->remap_color)
2144
(&cc, pcs, &devc, pis, dev, gs_color_select_source);
2145
if (!gx_dc_is_pure(&devc))
2146
return_error(gs_error_Fatal);
2147
ci = gx_dc_pure_color(&devc);
2148
if (dev->color_info.num_components == 1) {
2149
palette[i] = (byte)ci;
2151
byte *ppal = &palette[i * 3];
2153
ppal[0] = (byte) (ci >> 16);
2154
ppal[1] = (byte) (ci >> 8);
2155
ppal[2] = (byte) ci;
2158
if (dev->color_info.num_components == 1)
2159
pclxl_set_color_palette(xdev, eGray, palette,
2160
1 << bits_per_pixel);
2162
pclxl_set_color_palette(xdev, eRGB, palette,
2163
3 << bits_per_pixel);
2169
gs_free_object(mem, row_data, "pclxl_begin_image(rows)");
2170
gs_free_object(mem, pie, "pclxl_begin_image");
2172
if (dev->color_info.num_components == 1)
2173
pclxl_set_color_space(xdev, eGray);
2175
pclxl_set_color_space(xdev, eRGB);
2176
return gx_default_begin_image(dev, pis, pim, format, prect,
2177
pdcolor, pcpath, mem, pinfo);
2180
/* Write one strip of an image, from pie->rows.first_y to pie->y. */
2182
image_transform_x(const pclxl_image_enum_t *pie, int sx)
2184
return (int)((pie->mat.tx + sx * pie->mat.xx + 0.5) /
2185
((const gx_device_pclxl *)pie->dev)->scale.x);
2188
image_transform_y(const pclxl_image_enum_t *pie, int sy)
2190
return (int)((pie->mat.ty + sy * pie->mat.yy + 0.5) /
2191
((const gx_device_pclxl *)pie->dev)->scale.y);
2195
pclxl_image_write_rows(pclxl_image_enum_t *pie)
2197
gx_device_pclxl *const xdev = (gx_device_pclxl *)pie->dev;
2198
stream *s = pclxl_stream(xdev);
2199
int y = pie->rows.first_y;
2201
int xo = image_transform_x(pie, 0);
2202
int yo = image_transform_y(pie, y);
2203
int dw = image_transform_x(pie, pie->width) - xo;
2204
int dh = image_transform_y(pie, y + h) - yo;
2205
int rows_raster=pie->rows.raster;
2206
int offset_lastflippedstrip = 0;
2208
if (pie->flipped) yo = -yo -dh;
2210
offset_lastflippedstrip = pie->rows.raster * (pie->rows.num_rows - h);
2211
if (dw <= 0 || dh <= 0)
2213
pclxl_set_cursor(xdev, xo, yo);
2214
if (pie->bits_per_pixel==24) {
2215
static const byte ci_[] = {
2217
DUB(eDirectPixel), DA(pxaColorMapping)
2220
px_put_ub(s, eBit_values[8]);
2222
if (xdev->color_info.depth==8) {
2224
if (!pie->icclink) {
2225
byte *in=pie->rows.data + offset_lastflippedstrip;
2226
byte *out=pie->rows.data + offset_lastflippedstrip;
2229
for (j=0; j<h; j++) {
2230
for (i=0; i<rows_raster; i++) {
2231
*out = (byte)( ((*(in+0) * (ulong) lum_red_weight) +
2232
(*(in+1) * (ulong) lum_green_weight) +
2233
(*(in+2) * (ulong) lum_blue_weight) +
2234
(lum_all_weights / 2)) / lum_all_weights);
2242
static const byte ii_[] = {
2244
DUB(eIndexedPixel), DA(pxaColorMapping)
2246
px_put_ub(s, eBit_values[pie->bits_per_pixel]);
2249
pclxl_write_begin_image(xdev, pie->width, h, dw, dh);
2250
/* 8-bit gray image may compress with jpeg, but we
2251
cannot tell if it is 8-bit gray or 8-bit indexed */
2252
pclxl_write_image_data(xdev, pie->rows.data + offset_lastflippedstrip, 0, rows_raster,
2253
rows_raster << 3, 0, h, (pie->bits_per_pixel==24 ? true : false));
2254
pclxl_write_end_image(xdev);
2258
/* Process the next piece of an image. */
2260
pclxl_image_plane_data(gx_image_enum_common_t * info,
2261
const gx_image_plane_t * planes, int height,
2264
pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2265
int data_bit = planes[0].data_x * info->plane_depths[0];
2266
int width_bits = pie->width * info->plane_depths[0];
2269
/****** SHOULD HANDLE NON-BYTE-ALIGNED DATA ******/
2270
if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
2271
return_error(gs_error_rangecheck);
2272
if (height > pie->height - pie->y)
2273
height = pie->height - pie->y;
2274
for (i = 0; i < height; pie->y++, ++i) {
2275
if (pie->y - pie->rows.first_y == pie->rows.num_rows) {
2276
int code = pclxl_image_write_rows(pie);
2280
pie->rows.first_y = pie->y;
2283
memcpy(pie->rows.data +
2284
pie->rows.raster * (pie->flipped ? (pie->rows.num_rows - (pie->y - pie->rows.first_y) -1) :(pie->y - pie->rows.first_y)),
2285
planes[0].data + planes[0].raster * i + (data_bit >> 3),
2288
gsicc_bufferdesc_t input_buff_desc;
2289
gsicc_bufferdesc_t output_buff_desc;
2290
int pixels_per_row = pie->rows.raster / 3 ;
2291
int out_raster_stride = pixels_per_row * info->dev->color_info.num_components;
2292
gsicc_init_buffer(&input_buff_desc, 3 /*num_chan*/, 1 /*bytes_per_chan*/,
2293
false/*has_alpha*/, false/*alpha_first*/, false /*is_planar*/,
2294
0 /*plane_stride*/, pie->rows.raster /*row_stride*/,
2295
1/*num_rows*/, pixels_per_row /*pixels_per_row*/);
2296
gsicc_init_buffer(&output_buff_desc, info->dev->color_info.num_components, 1,
2297
false, false, false,
2298
0, out_raster_stride,
2300
gscms_transform_color_buffer(info->dev, pie->icclink,
2303
(void *)(planes[0].data + planes[0].raster * i + (data_bit >> 3)), /*src*/
2305
out_raster_stride * (pie->flipped ? (pie->rows.num_rows - (pie->y - pie->rows.first_y) -1) : (pie->y - pie->rows.first_y)) /*des*/
2309
*rows_used = height;
2310
return pie->y >= pie->height;
2313
/* Clean up by releasing the buffers. */
2315
pclxl_image_end_image(gx_image_enum_common_t * info, bool draw_last)
2317
pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
2320
/* Write the final strip, if any. */
2321
if (pie->y > pie->rows.first_y && draw_last)
2322
code = pclxl_image_write_rows(pie);
2324
gx_device_pclxl *xdev = (gx_device_pclxl *)info->dev;
2325
stream *s = pclxl_stream(xdev);
2326
switch(xdev->state_rotated) {
2328
xdev->state_rotated = 0;
2330
px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2333
xdev->state_rotated = 0;
2335
px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2338
xdev->state_rotated = 0;
2340
px_put_ac(s, pxaPageAngle, pxtSetPageRotation);
2348
gs_free_object(pie->memory, pie->rows.data, "pclxl_end_image(rows)");
2349
gx_image_free_enum(&info);
2354
* 'pclxl_get_params()' - Get pagedevice parameters.
2357
static int /* O - Error status */
2358
pclxl_get_params(gx_device *dev, /* I - Device info */
2359
gs_param_list *plist) /* I - Parameter list */
2361
gx_device_pclxl *xdev; /* PCL XL device */
2362
int code; /* Return code */
2363
gs_param_string s; /* Temporary string value */
2366
* First process the "standard" page device parameters...
2369
if ((code = gdev_vector_get_params(dev, plist)) < 0)
2373
* Then write the PCL-XL parameters...
2376
xdev = (gx_device_pclxl *)dev;
2378
if ((code = param_write_bool(plist, "Duplex", &(xdev->Duplex))) < 0)
2381
if (xdev->MediaPosition_set)
2382
if ((code = param_write_int(plist, "MediaPosition",
2383
&(xdev->MediaPosition))) < 0)
2386
if (xdev->MediaType_set) {
2387
if ((code = param_string_from_string(s, xdev->MediaType)) < 0)
2389
if ((code = param_write_string(plist, "MediaType", &s)) < 0)
2393
if ((code = param_write_bool(plist, "Tumble", &(xdev->Tumble))) < 0)
2396
if ((code = param_write_int(plist, "CompressMode",
2397
&(xdev->CompressMode))) < 0)
2400
if ((code = param_write_bool(plist, "iccTransform", &(xdev->iccTransform))) < 0)
2407
* 'pclxl_put_params()' - Set pagedevice parameters.
2410
static int /* O - Error status */
2411
pclxl_put_params(gx_device *dev, /* I - Device info */
2412
gs_param_list *plist) /* I - Parameter list */
2414
gx_device_pclxl *xdev; /* PCL XL device */
2415
int code; /* Error code */
2416
int intval; /* Integer value */
2417
bool boolval; /* Boolean value */
2418
gs_param_string stringval; /* String value */
2421
* Process PCL-XL driver parameters...
2424
xdev = (gx_device_pclxl *)dev;
2426
#define intoption(name, sname, type) \
2427
if ((code = param_read_int(plist, sname, &intval)) < 0) \
2429
if_debug1('|', "Error setting %s\n", sname); \
2430
param_signal_error(plist, sname, code); \
2433
else if (code == 0) \
2435
if_debug2('|', "setting %s to %d\n", sname, intval); \
2436
xdev->name = (type)intval; \
2439
#define booloption(name, sname) \
2440
if ((code = param_read_bool(plist, sname, &boolval)) < 0) \
2442
if_debug1('|', "Error setting bool %s\n", sname); \
2443
if ((code = param_read_null(plist, sname)) < 0) \
2445
if_debug1('|', "Error setting bool %s null\n", sname); \
2446
param_signal_error(plist, sname, code); \
2450
xdev->name = false; \
2452
else if (code == 0) { \
2453
if_debug2('|', "setting %s to %d\n", sname, boolval); \
2454
xdev->name = (bool)boolval; \
2457
#define stringoption(name, sname) \
2458
if ((code = param_read_string(plist, sname, &stringval)) < 0) \
2460
if_debug1('|', "Error setting %s string\n", sname); \
2461
if ((code = param_read_null(plist, sname)) < 0) \
2463
if_debug1('|', "Error setting %s null\n", sname); \
2464
param_signal_error(plist, sname, code); \
2468
if_debug1('|', "setting %s to empty\n", sname); \
2469
xdev->name[0] = '\0'; \
2472
else if (code == 0) { \
2473
strncpy(xdev->name, (const char *)(stringval.data), \
2475
xdev->name[stringval.size] = '\0'; \
2476
if_debug2('|', "setting %s to %s\n", sname, xdev->name); \
2479
/* We need to have *_set to distinguish defaults from explicitly sets */
2480
booloption(Duplex, "Duplex")
2483
if_debug0('|', "round up page count\n");
2484
xdev->page = (xdev->page+1) & ~1 ;
2486
intoption(MediaPosition, "MediaPosition", int)
2488
xdev->MediaPosition_set = true;
2489
/* round up for duplex */
2490
if (xdev->MediaPosition_old != xdev->MediaPosition) {
2491
if_debug0('|', "round up page count\n");
2492
xdev->page = (xdev->page+1) & ~1 ;
2493
xdev->MediaPosition_old = xdev->MediaPosition;
2496
stringoption(MediaType, "MediaType")
2498
xdev->MediaType_set = true;
2499
/* round up for duplex */
2500
if (strcmp(xdev->MediaType_old, xdev->MediaType)) {
2501
if_debug0('|', "round up page count\n");
2502
xdev->page = (xdev->page+1) & ~1 ;
2503
strcpy(xdev->MediaType_old, xdev->MediaType);
2506
booloption(Tumble, "Tumble")
2507
intoption(CompressMode, "CompressMode", int)
2508
booloption(iccTransform, "iccTransform")
2511
* Then process standard page device parameters...
2514
if ((code = gdev_vector_put_params(dev, plist)) < 0)