2 Copyright 1993-2001 by Easy Software Products.
3 Copyright 1990, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
5 This file is part of GNU Ghostscript.
7 GNU Ghostscript is distributed in the hope that it will be useful, but
8 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
9 to anyone for the consequences of using it or for whether it serves any
10 particular purpose or works at all, unless he says so in writing. Refer
11 to the GNU General Public License for full details.
13 Everyone is granted permission to copy, modify and redistribute GNU
14 Ghostscript, but only under the conditions described in the GNU General
15 Public License. A copy of this license is supposed to have been given
16 to you along with GNU Ghostscript so you can know your rights and
17 responsibilities. It should be in a file named COPYING. Among other
18 things, the copyright notice and this notice must be preserved on all
21 Aladdin Enterprises supports the work of the GNU Project, but is not
22 affiliated with the Free Software Foundation or the GNU Project. GNU
23 Ghostscript, as distributed by Aladdin Enterprises, does not require any
24 GNU software to build or run it.
27 /*$Id: gdevprn.c,v 1.13 2001/03/27 15:45:20 mike Exp $ */
28 /* Generic printer driver support */
36 /* ---------------- Standard device procedures ---------------- */
38 /* Define the standard printer procedure vector. */
39 const gx_device_procs prn_std_procs
=
40 prn_procs(gdev_prn_open
, gdev_prn_output_page
, gdev_prn_close
);
42 /* Forward references */
43 int gdev_prn_maybe_reallocate_memory(P4(gx_device_printer
*pdev
,
44 gdev_prn_space_params
*old_space
,
45 int old_width
, int old_height
));
47 /* ------ Open/close ------ */
49 /* Open a generic printer device. */
50 /* Specific devices may wish to extend this. */
52 gdev_prn_open(gx_device
* pdev
)
54 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
58 code
= gdev_prn_allocate_memory(pdev
, NULL
, 0, 0);
61 if (ppdev
->OpenOutputFile
)
62 code
= gdev_prn_open_printer(pdev
, 1);
66 /* Generic closing for the printer device. */
67 /* Specific devices may wish to extend this. */
69 gdev_prn_close(gx_device
* pdev
)
71 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
73 gdev_prn_free_memory(pdev
);
74 if (ppdev
->file
!= NULL
) {
75 if (ppdev
->file
!= stdout
)
76 gp_close_printer(ppdev
->file
, ppdev
->fname
);
82 private int /* returns 0 ok, else -ve error cde */
83 gdev_prn_setup_as_command_list(gx_device
*pdev
, gs_memory_t
*buffer_memory
,
85 const gdev_prn_space_params
*space_params
,
86 bool bufferSpace_is_exact
)
88 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
91 gx_device_clist
*const pclist_dev
= (gx_device_clist
*)pdev
;
92 gx_device_clist_common
* const pcldev
= &pclist_dev
->common
;
93 bool reallocate
= *the_memory
!= 0;
96 /* Try to allocate based simply on param-requested buffer size */
97 for ( space
= space_params
->BufferSpace
; ; ) {
99 gs_resize_object(buffer_memory
, *the_memory
, space
,
101 gs_alloc_bytes(buffer_memory
, space
,
105 if (bufferSpace_is_exact
|| (space
>>= 1) < PRN_MIN_BUFFER_SPACE
)
109 return_error(gs_error_VMerror
);
112 /* Try opening the command list, to see if we allocated */
113 /* enough buffer space. */
116 ppdev
->buffer_space
= space
;
117 clist_init_params(pclist_dev
, base
, space
, pdev
,
118 ppdev
->printer_procs
.make_buffer_device
,
119 space_params
->band
, ppdev
->is_async_renderer
,
120 (ppdev
->bandlist_memory
== 0 ? &gs_memory_default
:
121 ppdev
->bandlist_memory
),
122 ppdev
->free_up_bandlist_memory
,
123 ppdev
->clist_disable_mask
);
124 code
= (*gs_clist_device_procs
.open_device
)( (gx_device
*)pcldev
);
126 /* If there wasn't enough room, and we haven't */
127 /* already shrunk the buffer, try enlarging it. */
128 if ( code
== gs_error_limitcheck
&&
129 space
>= space_params
->BufferSpace
&&
130 !bufferSpace_is_exact
134 base
= gs_resize_object(buffer_memory
,
136 "cmd list buf(retry open)");
140 gs_free_object(buffer_memory
, base
,
141 "cmd list buf(retry open)");
143 gs_alloc_bytes(buffer_memory
, space
,
144 "cmd list buf(retry open)");
146 ppdev
->buf
= *the_memory
;
152 gs_free_object(buffer_memory
, base
, "cmd list buf");
153 ppdev
->buffer_space
= 0;
160 private bool /* ret true if device was cmd list, else false */
161 gdev_prn_tear_down(gx_device
*pdev
, byte
**the_memory
)
163 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
164 gx_device_memory
* const pmemdev
= (gx_device_memory
*)pdev
;
165 gx_device_clist
*const pclist_dev
= (gx_device_clist
*)pdev
;
166 gx_device_clist_common
* const pcldev
= &pclist_dev
->common
;
167 bool is_command_list
;
169 if (ppdev
->buffer_space
!= 0) {
170 /* Close cmd list device & point to the storage */
171 (*gs_clist_device_procs
.close_device
)( (gx_device
*)pcldev
);
172 *the_memory
= ppdev
->buf
;
174 ppdev
->buffer_space
= 0;
175 is_command_list
= true;
177 /* point at the device bitmap, no need to close mem dev */
178 *the_memory
= pmemdev
->base
;
180 is_command_list
= false;
183 /* Reset device proc vector to default */
184 if (ppdev
->orig_procs
.open_device
!= 0)
185 pdev
->procs
= ppdev
->orig_procs
;
186 ppdev
->orig_procs
.open_device
= 0; /* prevent uninit'd restore of procs */
188 return is_command_list
;
192 gdev_prn_allocate(gx_device
*pdev
, gdev_prn_space_params
*new_space_params
,
193 int new_width
, int new_height
, bool reallocate
)
195 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
196 gx_device_memory
* const pmemdev
= (gx_device_memory
*)pdev
;
197 byte
*the_memory
= 0;
198 gdev_prn_space_params save_params
;
199 int save_width
, save_height
;
200 bool is_command_list
= false;
201 bool save_is_command_list
;
204 gs_memory_t
*buffer_memory
=
205 (ppdev
->buffer_memory
== 0 ? &gs_memory_default
:
206 ppdev
->buffer_memory
);
208 /* If reallocate, find allocated memory & tear down buffer device */
210 save_is_command_list
= gdev_prn_tear_down(pdev
, &the_memory
);
212 /* Re/allocate memory */
213 ppdev
->orig_procs
= pdev
->procs
;
214 for ( pass
= 1; pass
<= (reallocate
? 2 : 1); ++pass
) {
217 bool bufferSpace_is_default
= false;
218 gdev_prn_space_params space_params
;
224 /* Setup device to get reallocated */
225 save_params
= ppdev
->space_params
;
226 ppdev
->space_params
= *new_space_params
;
227 save_width
= ppdev
->width
;
228 ppdev
->width
= new_width
;
229 save_height
= ppdev
->height
;
230 ppdev
->height
= new_height
;
232 case 2: /* only comes here if reallocate */
233 /* Restore device to previous contents */
234 ppdev
->space_params
= save_params
;
235 ppdev
->width
= save_width
;
236 ppdev
->height
= save_height
;
240 /* Init clist/mem device-specific fields */
241 memset(ppdev
->skip
, 0, sizeof(ppdev
->skip
));
242 mem_space
= gdev_mem_bitmap_size(pmemdev
);
244 /* Compute desired space params: never use the space_params as-is. */
245 /* Rather, give the dev-specific driver a chance to adjust them. */
246 space_params
= ppdev
->space_params
;
247 space_params
.BufferSpace
= 0;
248 (*ppdev
->printer_procs
.get_space_params
)(ppdev
, &space_params
);
249 if (ppdev
->is_async_renderer
&& space_params
.band
.BandBufferSpace
!= 0)
250 space_params
.BufferSpace
= space_params
.band
.BandBufferSpace
;
251 else if (space_params
.BufferSpace
== 0) {
252 if (space_params
.band
.BandBufferSpace
> 0)
253 space_params
.BufferSpace
= space_params
.band
.BandBufferSpace
;
255 space_params
.BufferSpace
= ppdev
->space_params
.BufferSpace
;
256 bufferSpace_is_default
= true;
260 /* Determine if we can use a full bitmap buffer, or have to use banding */
262 is_command_list
= save_is_command_list
;
264 is_command_list
= space_params
.banding_type
== BandingAlways
||
265 mem_space
>= space_params
.MaxBitmap
||
266 mem_space
!= (uint
)mem_space
; /* too big to allocate */
268 if (!is_command_list
) {
269 /* Try to allocate memory for full memory buffer */
271 ? gs_resize_object( buffer_memory
, the_memory
,
272 (uint
)mem_space
, "printer buffer" )
273 : gs_alloc_bytes( buffer_memory
, (uint
)mem_space
,
276 is_command_list
= true;
280 if (!is_command_list
&& pass
== 1 && PRN_MIN_MEMORY_LEFT
!= 0
281 && buffer_memory
== &gs_memory_default
) {
282 /* before using full memory buffer, ensure enough working mem left */
283 byte
* left
= gs_alloc_bytes( buffer_memory
,
284 PRN_MIN_MEMORY_LEFT
, "printer mem left");
286 is_command_list
= true;
288 gs_free_object(buffer_memory
, left
, "printer mem left");
291 if (is_command_list
) {
292 /* Buffer the image in a command list. */
293 /* Release the buffer if we allocated it. */
296 gs_free_object(buffer_memory
, the_memory
,
297 "printer buffer(open)");
300 if (space_params
.banding_type
== BandingNever
) {
301 ecode
= gs_note_error(gs_error_VMerror
);
304 code
= gdev_prn_setup_as_command_list(pdev
, buffer_memory
,
305 &the_memory
, &space_params
,
306 !bufferSpace_is_default
);
310 if ( code
>= 0 || (reallocate
&& pass
> 1) )
311 ppdev
->procs
= gs_clist_device_procs
;
313 /* Render entirely in memory. */
316 ppdev
->buffer_space
= 0;
317 code
= (*ppdev
->printer_procs
.make_buffer_device
)
318 (pmemdev
, pdev
, buffer_memory
, false);
319 if (code
< 0) { /* Catastrophic. Shouldn't ever happen */
320 gs_free_object(buffer_memory
, base
, "printer buffer");
321 pdev
->procs
= ppdev
->orig_procs
;
322 ppdev
->orig_procs
.open_device
= 0; /* prevent uninit'd restore of procs */
325 pmemdev
->base
= base
;
331 if (ecode
>= 0 || reallocate
) { /* even if realloc failed */
332 /* Synthesize the procedure vector. */
333 /* Rendering operations come from the memory or clist device, */
334 /* non-rendering come from the printer device. */
335 #define COPY_PROC(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p)
336 COPY_PROC(get_initial_matrix
);
337 COPY_PROC(output_page
);
338 COPY_PROC(close_device
);
339 COPY_PROC(map_rgb_color
);
340 COPY_PROC(map_color_rgb
);
341 COPY_PROC(get_params
);
342 COPY_PROC(put_params
);
343 COPY_PROC(map_cmyk_color
);
344 COPY_PROC(get_xfont_procs
);
345 COPY_PROC(get_xfont_device
);
346 COPY_PROC(map_rgb_alpha_color
);
347 /* All printers are page devices, even if they didn't use the */
348 /* standard macros for generating their procedure vectors. */
349 set_dev_proc(ppdev
, get_page_device
, gx_page_device_get_page_device
);
350 COPY_PROC(get_alpha_bits
);
351 COPY_PROC(get_clipping_box
);
352 COPY_PROC(map_color_rgb_alpha
);
353 COPY_PROC(get_hardware_params
);
355 /* If using a command list, already opened the device. */
359 return (*dev_proc(pdev
, open_device
))(pdev
);
361 pdev
->procs
= ppdev
->orig_procs
;
362 ppdev
->orig_procs
.open_device
= 0; /* prevent uninit'd restore of procs */
368 gdev_prn_allocate_memory(gx_device
*pdev
,
369 gdev_prn_space_params
*new_space_params
,
370 int new_width
, int new_height
)
372 return gdev_prn_allocate(pdev
, new_space_params
,
373 new_width
, new_height
, false);
377 gdev_prn_reallocate_memory(gx_device
*pdev
,
378 gdev_prn_space_params
*new_space_params
,
379 int new_width
, int new_height
)
381 return gdev_prn_allocate(pdev
, new_space_params
,
382 new_width
, new_height
, true);
386 gdev_prn_free_memory(gx_device
*pdev
)
388 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
389 byte
*the_memory
= 0;
390 gs_memory_t
*buffer_memory
=
391 (ppdev
->buffer_memory
== 0 ? &gs_memory_default
:
392 ppdev
->buffer_memory
);
394 gdev_prn_tear_down(pdev
, &the_memory
);
395 gs_free_object(buffer_memory
, the_memory
, "gdev_prn_free_memory");
399 /* ------------- Stubs related only to async rendering ------- */
401 int /* rets 0 ok, -ve error if couldn't start thread */
402 gx_default_start_render_thread(gdev_prn_start_render_params
*params
)
404 return gs_error_unknownerror
;
407 /* Open the renderer's copy of a device. */
408 /* This is overriden in gdevprna.c */
410 gx_default_open_render_device(gx_device_printer
*pdev
)
412 return gs_error_unknownerror
;
415 /* Close the renderer's copy of a device. */
417 gx_default_close_render_device(gx_device_printer
*pdev
)
419 return gdev_prn_close( (gx_device
*)pdev
);
422 /* ------ Get/put parameters ------ */
424 /* Get parameters. Printer devices add several more parameters */
425 /* to the default set. */
427 gdev_prn_get_params(gx_device
* pdev
, gs_param_list
* plist
)
429 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
430 int code
= gx_default_get_params(pdev
, plist
);
433 (ppdev
->Duplex_set
>= 0 &&
434 (code
= (ppdev
->Duplex_set
?
435 param_write_bool(plist
, "Duplex", &ppdev
->Duplex
) :
436 param_write_null(plist
, "Duplex"))) < 0)
443 /* Put parameters. */
445 gdev_prn_put_params(gx_device
* pdev
, gs_param_list
* plist
)
447 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
450 const char *param_name
;
451 bool is_open
= pdev
->is_open
;
452 bool oof
= ppdev
->OpenOutputFile
;
453 bool rpp
= ppdev
->ReopenPerPage
;
456 int width
= pdev
->width
;
457 int height
= pdev
->height
;
458 gdev_prn_space_params sp
, save_sp
;
461 sp
= ppdev
->space_params
;
464 switch (code
= param_read_bool(plist
, (param_name
= "OpenOutputFile"), &oof
)) {
467 param_signal_error(plist
, param_name
, ecode
);
473 switch (code
= param_read_bool(plist
, (param_name
= "ReopenPerPage"), &rpp
)) {
476 param_signal_error(plist
, param_name
, ecode
);
482 if (ppdev
->Duplex_set
>= 0) /* i.e., Duplex is supported */
483 switch (code
= param_read_bool(plist
, (param_name
= "Duplex"),
489 if ((code
= param_read_null(plist
, param_name
)) == 0) {
494 param_signal_error(plist
, param_name
, ecode
);
498 #define CHECK_PARAM_CASES(member, bad, label)\
500 if ((sp.params_are_read_only ? sp.member != save_sp.member : bad))\
501 ecode = gs_error_rangecheck;\
508 param_signal_error(plist, param_name, ecode);\
512 /* Read InputAttributes and OutputAttributes just for the type */
513 /* check and to indicate that they aren't undefined. */
514 #define read_media(pname)\
515 switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\
518 param_end_read_dict(plist, pname, &mdict);\
522 param_signal_error(plist, param_name, ecode);\
527 read_media("InputAttributes");
528 read_media("OutputAttributes");
532 /* Prevent gx_default_put_params from closing the printer. */
533 pdev
->is_open
= false;
534 code
= gx_default_put_params(pdev
, plist
);
535 pdev
->is_open
= is_open
;
539 ppdev
->OpenOutputFile
= oof
;
540 ppdev
->ReopenPerPage
= rpp
;
541 if (duplex_set
>= 0) {
542 ppdev
->Duplex
= duplex
;
543 ppdev
->Duplex_set
= duplex_set
;
545 ppdev
->space_params
= sp
;
547 /* If necessary, free and reallocate the printer memory. */
548 /* Formerly, would not reallocate if device is not open: */
549 /* we had to patch this out (see News for 5.50). */
550 code
= gdev_prn_maybe_reallocate_memory(ppdev
, &save_sp
, width
, height
);
557 /* ------ Others ------ */
559 #define TILE_SIZE 256
561 /* Default routine to override current space_params. */
563 gdev_prn_default_get_space_params(const gx_device_printer
*printer_dev
,
564 gdev_prn_space_params
*space_params
)
566 int cache_size
; /* Size of tile cache in bytes */
567 char *cache_env
, /* Cache size environment variable */
568 cache_units
[255]; /* Cache size units */
571 if ((cache_env
= getenv("RIP_MAX_CACHE")) != NULL
)
573 switch (sscanf(cache_env
, "%d%254s", &cache_size
, cache_units
))
576 cache_size
= 8 * 1024 * 1024;
579 cache_size
*= 4 * TILE_SIZE
* TILE_SIZE
;
582 if (tolower(cache_units
[0]) == 'g')
583 cache_size
*= 1024 * 1024 * 1024;
584 else if (tolower(cache_units
[0]) == 'm')
585 cache_size
*= 1024 * 1024;
586 else if (tolower(cache_units
[0]) == 'k')
588 else if (tolower(cache_units
[0]) == 't')
589 cache_size
*= 4 * TILE_SIZE
* TILE_SIZE
;
594 cache_size
= 8 * 1024 * 1024;
596 space_params
->MaxBitmap
= cache_size
;
597 space_params
->BufferSpace
= cache_size
/ 10;
600 /* Generic routine to send the page to the printer. */
601 int /* 0 ok, -ve error, or 1 if successfully upgraded to buffer_page */
602 gdev_prn_output_page(gx_device
* pdev
, int num_copies
, int flush
)
604 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
605 int outcode
= 0, closecode
= 0, errcode
= 0, endcode
;
606 bool upgraded_copypage
= false;
608 if (num_copies
> 0 || !flush
) {
609 int code
= gdev_prn_open_printer(pdev
, 1);
614 /* If copypage request, try to do it using buffer_page */
616 (*ppdev
->printer_procs
.buffer_page
)
617 (ppdev
, ppdev
->file
, num_copies
) >= 0
619 upgraded_copypage
= true;
622 else if (num_copies
> 0)
623 /* Print the accumulated page description. */
625 (*ppdev
->printer_procs
.print_page_copies
)(ppdev
, ppdev
->file
,
631 (ferror(ppdev
->file
) ? gs_note_error(gs_error_ioerror
) : 0);
636 if (!upgraded_copypage
)
637 closecode
= gdev_prn_close_printer(pdev
);
639 endcode
= (ppdev
->buffer_space
? clist_finish_page(pdev
, flush
) : 0);
649 return (upgraded_copypage
? 1 : 0);
652 /* Print multiple copies of a page by calling print_page multiple times. */
654 gx_default_print_page_copies(gx_device_printer
* pdev
, FILE * prn_stream
,
660 while (code
>= 0 && i
-- > 0)
661 code
= (*pdev
->printer_procs
.print_page
) (pdev
, prn_stream
);
666 * Buffer a (partial) rasterized page & optionally print result multiple times.
667 * The default implementation returns error, since the driver needs to override
668 * this (in procedure vector) in configurations where this call may occur.
671 gx_default_buffer_page(gx_device_printer
*pdev
, FILE *prn_stream
,
674 return gs_error_unknownerror
;
677 /* ---------------- Driver services ---------------- */
679 /* Return the number of scan lines that should actually be passed */
682 gdev_prn_print_scan_lines(gx_device
* pdev
)
684 int height
= pdev
->height
;
687 int top
, bottom
, offset
, end
;
689 (*dev_proc(pdev
, get_initial_matrix
)) (pdev
, &imat
);
690 yscale
= imat
.yy
* 72.0; /* Y dpi, may be negative */
691 top
= (int)(dev_t_margin(pdev
) * yscale
);
692 bottom
= (int)(dev_b_margin(pdev
) * yscale
);
693 offset
= (int)(dev_y_offset(pdev
) * yscale
);
694 if (yscale
< 0) { /* Y=0 is top of page */
695 end
= -offset
+ height
+ bottom
;
696 } else { /* Y=0 is bottom of page */
697 end
= offset
+ height
- top
;
699 return min(height
, end
);
702 /* Open the current page for printing. */
704 gdev_prn_open_printer_positionable(gx_device
*pdev
, bool binary_mode
,
707 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
709 if (ppdev
->file
!= 0) {
710 ppdev
->file_is_new
= false;
714 int code
= gx_device_open_output_file(pdev
, ppdev
->fname
,
715 binary_mode
, positionable
,
720 ppdev
->file_is_new
= true;
724 gdev_prn_open_printer(gx_device
*pdev
, bool binary_mode
)
726 return gdev_prn_open_printer_positionable(pdev
, binary_mode
, false);
729 /* Copy a scan line from the buffer to the printer. */
731 gdev_prn_get_bits(gx_device_printer
* pdev
, int y
, byte
* str
, byte
** actual_data
)
733 int code
= (*dev_proc(pdev
, get_bits
)) ((gx_device
*) pdev
, y
, str
, actual_data
);
734 uint line_size
= gdev_prn_raster(pdev
);
735 int last_bits
= -(pdev
->width
* pdev
->color_info
.depth
) & 7;
739 if (last_bits
!= 0) {
740 byte
*dest
= (actual_data
!= 0 ? *actual_data
: str
);
742 dest
[line_size
- 1] &= 0xff << last_bits
;
746 /* Copy scan lines to a buffer. Return the number of scan lines, */
747 /* or <0 if error. */
749 gdev_prn_copy_scan_lines(gx_device_printer
* pdev
, int y
, byte
* str
, uint size
)
751 uint line_size
= gdev_prn_raster(pdev
);
752 int count
= size
/ line_size
;
756 count
= min(count
, pdev
->height
- y
);
757 for (i
= 0; i
< count
; i
++, dest
+= line_size
) {
758 int code
= gdev_prn_get_bits(pdev
, y
+ i
, dest
, NULL
);
766 /* Like get_bits, but accepts initial raster contents */
768 gdev_prn_get_overlay_bits(gx_device_printer
*pdev
, int y
, int lineCount
,
771 if (pdev
->buffer_space
) {
772 /* Command lists have built-in support for this function */
773 return clist_get_overlay_bits(pdev
, y
, lineCount
, data
);
775 /* Memory devices cannot support this function. */
776 return_error(gs_error_unknownerror
);
780 /* Find out where the band buffer for a given line is going to fall on the */
781 /* next call to get_bits. */
782 int /* rets # lines from y till end of buffer, or -ve error code */
783 gdev_prn_locate_overlay_buffer(gx_device_printer
*pdev
, int y
, byte
**data
)
785 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
787 if (ppdev
->buffer_space
) {
788 /* Command lists have built-in support for this function */
789 return clist_locate_overlay_buffer(pdev
, y
, data
);
791 /* Memory devices cannot support this function. */
792 return_error(gs_error_unknownerror
);
796 /* Close the current page. */
798 gdev_prn_close_printer(gx_device
* pdev
)
800 gx_device_printer
* const ppdev
= (gx_device_printer
*)pdev
;
802 if (strchr(ppdev
->fname
, '%') /* file per page */ ||
803 ppdev
->ReopenPerPage
/* close and reopen for each page */
805 gp_close_printer(ppdev
->file
, ppdev
->fname
);
811 /* If necessary, free and reallocate the printer memory after changing params */
813 gdev_prn_maybe_reallocate_memory(gx_device_printer
*prdev
,
814 gdev_prn_space_params
*old_sp
,
815 int old_width
, int old_height
)
818 gx_device
*const pdev
= (gx_device
*)prdev
;
820 if (prdev
->is_open
&&
821 (memcmp(&prdev
->space_params
, old_sp
, sizeof(*old_sp
)) != 0 ||
822 prdev
->width
!= old_width
|| prdev
->height
!= old_height
)
824 int new_width
= prdev
->width
;
825 int new_height
= prdev
->height
;
826 gdev_prn_space_params new_sp
= prdev
->space_params
;
828 prdev
->width
= old_width
;
829 prdev
->height
= old_height
;
830 prdev
->space_params
= *old_sp
;
831 code
= gdev_prn_reallocate_memory(pdev
, &new_sp
,
832 new_width
, new_height
);
833 /* If this fails, device should be usable w/old params, but */
834 /* band files may not be open. */