Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1998, 1999, 2000 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gdevbmpa.c,v 1.6 2002/06/16 05:48:54 lpd Exp $ */
18
/* .BMP file format output drivers: Demo of ASYNC rendering */
19
 
20
/* 2000-04-20 ghost@aladdin.com - Makes device structures const, changing
21
   makefile entry from DEV to DEV2. */
22
/* 1998/12/29 ghost@aladdin.com - Modified to use gdev_prn_render_lines,
23
   which replaces the former "overlay" calls */
24
/* 1998/11/23 ghost@aladdin.com - Removed pointless restriction to
25
   single-page output */
26
/* 1998/7/28 ghost@aladdin.com - Factored out common BMP format code
27
   to gdevbmpc.c */
28
/* Initial version 2/2/98 by John Desrosiers (soho@crl.com) */
29
 
30
#include "stdio_.h"
31
#include "gserrors.h"
32
#include "gdevprna.h"
33
#include "gdevpccm.h"
34
#include "gdevbmp.h"
35
#include "gdevppla.h"
36
#include "gpsync.h"
37
 
38
/*
39
 * The original version of this driver was restricted to producing a single
40
 * page per file.  If for some reason you want to reinstate this
41
 * restriction, uncomment the next line. 
42
 * NOTE: Even though the logic for multi-page files is straightforward,
43
 * it results in a file that most programs that process BMP format cannot
44
 * handle. Most programs will only display the first page.
45
 */
46
/*************** #define SINGLE_PAGE ****************/
47
 
48
/* ------ The device descriptors ------ */
49
 
50
/* Define data type for this device based on prn_device */
51
typedef struct gx_device_async_s {
52
    gx_device_common;
53
    gx_prn_device_common;
54
    bool UsePlanarBuffer;
55
    int buffered_page_exists;
56
    long file_offset_to_data[4];
57
} gx_device_async;
58
 
59
/* Define initializer for device */
60
#define async_device(procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, color_bits, print_page)\
61
{ prn_device_std_margins_body(gx_device_async, procs, dname,\
62
    w10, h10, xdpi, ydpi, lm, tm, lm, bm, rm, tm, color_bits, print_page),\
63
    0, 0, { 0, 0, 0, 0 }\
64
}
65
 
66
private dev_proc_open_device(bmpa_writer_open);
67
private dev_proc_open_device(bmpa_cmyk_writer_open);
68
private prn_dev_proc_open_render_device(bmpa_reader_open_render_device);
69
private dev_proc_print_page_copies(bmpa_reader_print_page_copies);
70
/* VMS limits procedure names to 31 characters. */
71
private dev_proc_print_page_copies(bmpa_cmyk_reader_print_copies);
72
private prn_dev_proc_buffer_page(bmpa_reader_buffer_page);
73
private prn_dev_proc_buffer_page(bmpa_cmyk_reader_buffer_page);
74
private dev_proc_output_page(bmpa_reader_output_page);
75
private dev_proc_get_params(bmpa_get_params);
76
private dev_proc_put_params(bmpa_put_params);
77
private dev_proc_get_hardware_params(bmpa_get_hardware_params);
78
private prn_dev_proc_start_render_thread(bmpa_reader_start_render_thread);
79
private prn_dev_proc_get_space_params(bmpa_get_space_params);
80
#define default_print_page 0	/* not needed becoz print_page_copies def'd */
81
 
82
/* Monochrome. */
83
 
84
private const gx_device_procs bmpamono_procs =
85
  prn_procs(bmpa_writer_open, gdev_prn_output_page, gdev_prn_close);
86
const gx_device_async gs_bmpamono_device =
87
  async_device(bmpamono_procs, "bmpamono",
88
	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
89
	X_DPI, Y_DPI,
90
	0,0,0,0,			/* margins */
91
	1, default_print_page);
92
 
93
/* 1-bit-per-plane separated CMYK color. */
94
 
95
#define bmpa_cmyk_procs(p_open, p_map_color_rgb, p_map_cmyk_color)\
96
    p_open, NULL, NULL, gdev_prn_output_page, gdev_prn_close,\
97
    NULL, p_map_color_rgb, NULL, NULL, NULL, NULL, NULL, NULL,\
98
    bmpa_get_params, bmpa_put_params,\
99
    p_map_cmyk_color, NULL, NULL, NULL, gx_page_device_get_page_device
100
 
101
private const gx_device_procs bmpasep1_procs = {
102
    bmpa_cmyk_procs(bmpa_cmyk_writer_open, cmyk_1bit_map_color_rgb,
103
		    cmyk_1bit_map_cmyk_color)
104
};
105
const gx_device_async gs_bmpasep1_device = {
106
  prn_device_body(gx_device_async, bmpasep1_procs, "bmpasep1",
107
	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
108
	X_DPI, Y_DPI,
109
	0,0,0,0,			/* margins */
110
	4, 4, 1, 1, 2, 2, default_print_page)
111
};
112
 
113
/* 8-bit-per-plane separated CMYK color. */
114
 
115
private const gx_device_procs bmpasep8_procs = {
116
    bmpa_cmyk_procs(bmpa_cmyk_writer_open, cmyk_8bit_map_color_rgb,
117
		    cmyk_8bit_map_cmyk_color)
118
};
119
const gx_device_async gs_bmpasep8_device = {
120
  prn_device_body(gx_device_async, bmpasep8_procs, "bmpasep8",
121
	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
122
	X_DPI, Y_DPI,
123
	0,0,0,0,			/* margins */
124
	4, 32, 255, 255, 256, 256, default_print_page)
125
};
126
 
127
/* 4-bit (EGA/VGA-style) color. */
128
 
129
private const gx_device_procs bmpa16_procs =
130
  prn_color_procs(bmpa_writer_open, gdev_prn_output_page, gdev_prn_close,
131
    pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
132
const gx_device_async gs_bmpa16_device =
133
  async_device(bmpa16_procs, "bmpa16",
134
	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
135
	X_DPI, Y_DPI,
136
	0,0,0,0,			/* margins */
137
	4, default_print_page);
138
 
139
/* 8-bit (SuperVGA-style) color. */
140
/* (Uses a fixed palette of 3,3,2 bits.) */
141
 
142
private const gx_device_procs bmpa256_procs =
143
  prn_color_procs(bmpa_writer_open, gdev_prn_output_page, gdev_prn_close,
144
    pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
145
const gx_device_async gs_bmpa256_device =
146
  async_device(bmpa256_procs, "bmpa256",
147
	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
148
	X_DPI, Y_DPI,
149
	0,0,0,0,			/* margins */
150
	8, default_print_page);
151
 
152
/* 24-bit color. */
153
 
154
private const gx_device_procs bmpa16m_procs =
155
  prn_color_procs(bmpa_writer_open, gdev_prn_output_page, gdev_prn_close,
156
    bmp_map_16m_rgb_color, bmp_map_16m_color_rgb);
157
const gx_device_async gs_bmpa16m_device =
158
  async_device(bmpa16m_procs, "bmpa16m",
159
	DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
160
	X_DPI, Y_DPI,
161
	0,0,0,0,			/* margins */
162
	24, default_print_page);
163
 
164
/* 32-bit CMYK color (outside the BMP specification). */
165
 
166
private const gx_device_procs bmpa32b_procs = {
167
    bmpa_cmyk_procs(bmpa_writer_open, gx_default_map_color_rgb,
168
		    gx_default_cmyk_map_cmyk_color)
169
};
170
const gx_device_async gs_bmpa32b_device =
171
  async_device(bmpa32b_procs, "bmpa32b",
172
	       DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
173
	       X_DPI, Y_DPI,
174
	       0, 0, 0, 0,		/* margins */
175
	       32, default_print_page);
176
 
177
/* --------- Forward declarations ---------- */
178
 
179
private void bmpa_reader_thread(void *);
180
 
181
/* ------------ Writer Instance procedures ---------- */
182
 
183
/* Writer's open procedure */
184
private int
185
bmpa_open_writer(gx_device *pdev  /* Driver instance to open */,
186
		 dev_proc_print_page_copies((*reader_print_page_copies)),
187
		 prn_dev_proc_buffer_page((*reader_buffer_page)))
188
{
189
    gx_device_async * const pwdev = (gx_device_async *)pdev;
190
    int max_width;
191
    int max_raster;
192
    int min_band_height;
193
    int max_src_image_row;
194
 
195
    /*
196
     * Set up device's printer proc vector to point to this driver, since
197
     * there are no convenient macros for setting them up in static template.
198
     */
199
    init_async_render_procs(pwdev, bmpa_reader_start_render_thread,
200
			    reader_buffer_page,
201
			    reader_print_page_copies);
202
    set_dev_proc(pdev, get_params, bmpa_get_params);	/* because not all device-init macros allow this to be defined */
203
    set_dev_proc(pdev, put_params, bmpa_put_params);	/* ibid. */
204
    set_dev_proc(pdev, get_hardware_params, bmpa_get_hardware_params);
205
    set_dev_proc(pdev, output_page, bmpa_reader_output_page);	/* hack */
206
    pwdev->printer_procs.get_space_params = bmpa_get_space_params;
207
    pwdev->printer_procs.open_render_device =
208
	bmpa_reader_open_render_device;	/* Included for tutorial value */
209
 
210
    /*
211
     * Determine MAXIMUM parameters this device will have to support over
212
     * lifetime.  See comments for bmpa_get_space_params().
213
     */
214
    max_width = DEFAULT_WIDTH_10THS * 60;   /* figure max wid = default @ 600dpi */
215
    min_band_height = max(1, (DEFAULT_HEIGHT_10THS * 60) / 100);
216
    max_raster = bitmap_raster(max_width * pwdev->color_info.depth);	/* doesn't need to be super accurate */
217
    max_src_image_row = max_width * 4 * 2;
218
 
219
    /* Set to planar buffering mode if appropriate. */
220
    if (pwdev->UsePlanarBuffer)
221
	gdev_prn_set_procs_planar(pdev);
222
 
223
    /* Special writer open routine for async interpretation */
224
    /* Starts render thread */
225
    return gdev_prn_async_write_open((gx_device_printer *)pdev,
226
				     max_raster, min_band_height,
227
				     max_src_image_row);
228
}
229
private int
230
bmpa_writer_open(gx_device *pdev  /* Driver instance to open */)
231
{
232
    return bmpa_open_writer(pdev, bmpa_reader_print_page_copies,
233
			    bmpa_reader_buffer_page);
234
}
235
private int
236
bmpa_cmyk_writer_open(gx_device *pdev  /* Driver instance to open */)
237
{
238
    return bmpa_open_writer(pdev, bmpa_cmyk_reader_print_copies,
239
			    bmpa_cmyk_reader_buffer_page);
240
}
241
 
242
/* -------------- Renderer instance procedures ----------*/
243
 
244
/* Forward declarations */
245
private int
246
    bmpa_reader_buffer_planes(gx_device_printer *pdev, FILE *prn_stream,
247
			      int num_copies, int first_plane,
248
			      int last_plane, int raster);
249
 
250
/* Thread to do rendering, started by bmpa_reader_start_render_thread */
251
private void 
252
bmpa_reader_thread(void *params)
253
{
254
    gdev_prn_async_render_thread((gdev_prn_start_render_params *)params);
255
}
256
 
257
private int	/* rets 0 ok, -ve error if couldn't start thread */
258
bmpa_reader_start_render_thread(gdev_prn_start_render_params *params)
259
{
260
    return gp_create_thread(bmpa_reader_thread, params);
261
}
262
 
263
private int
264
bmpa_reader_open_render_device(gx_device_printer *ppdev)
265
{
266
    /*
267
     * Do anything that needs to be done at open time here.
268
     * Since this implementation doesn't do anything, we don't need to
269
     * cast the device argument to the more specific type.
270
     */
271
    /*gx_device_async * const prdev = (gx_device_async *)ppdev;*/
272
 
273
    /* Cascade down to the default handler */
274
    return gdev_prn_async_render_open(ppdev);
275
}
276
 
277
/* Generic routine to send the page to the printer. */
278
private int
279
bmpa_reader_output_page(gx_device *pdev, int num_copies, int flush)
280
{
281
    /*
282
     * HACK: open the printer page with the positionable attribute since
283
     * we need to seek back & forth to support partial rendering.
284
     */
285
    if ( num_copies > 0 || !flush ) {
286
	int code = gdev_prn_open_printer_positionable(pdev, 1, 1);
287
 
288
	if ( code < 0 )
289
	    return code;
290
    }
291
    return gdev_prn_output_page(pdev, num_copies, flush);
292
}
293
 
294
private int
295
bmpa_reader_print_planes(gx_device_printer *pdev, FILE *prn_stream,
296
			 int num_copies, int first_plane, int last_plane,
297
			 int raster)
298
{
299
    gx_device_async * const prdev = (gx_device_async *)pdev;
300
    /* BMP scan lines are padded to 32 bits. */
301
    uint bmp_raster = raster + (-raster & 3);
302
    int code = 0;
303
    int y;
304
    byte *row = 0;
305
    byte *raster_data;
306
    int plane;
307
 
308
    /* If there's data in buffer, need to process w/overlays */
309
    if (prdev->buffered_page_exists) {
310
	code = bmpa_reader_buffer_planes(pdev, prn_stream, num_copies,
311
					 first_plane, last_plane, raster);
312
	goto done;
313
    }
314
#ifdef SINGLE_PAGE
315
    /* BMP format is single page, so discard all but 1st printable page */
316
    /* Since the OutputFile may have a %d, we use ftell to determine if */
317
    /* this is a zero length file, which is legal to write		*/
318
    if (ftell(prn_stream) != 0)
319
	return 0;
320
#endif
321
    row = gs_alloc_bytes(pdev->memory, bmp_raster, "bmp file buffer");
322
    if (row == 0)		/* can't allocate row buffer */
323
	return_error(gs_error_VMerror);
324
 
325
    for (plane = first_plane; plane <= last_plane; ++plane) {
326
	gx_render_plane_t render_plane;
327
 
328
	/* Write header & seek to its end */
329
	code =
330
	    (first_plane < 0 ? write_bmp_header(pdev, prn_stream) :
331
	     write_bmp_separated_header(pdev, prn_stream));
332
	if (code < 0)
333
	    goto done;
334
	/* Save the file offset where data begins */
335
	if ((prdev->file_offset_to_data[plane - first_plane] =
336
	     ftell(prn_stream)) == -1L) {
337
	    code = gs_note_error(gs_error_ioerror);
338
	    goto done;
339
	}
340
 
341
	/*
342
	 * Write out the bands top to bottom.  Finish the job even if
343
	 * num_copies == 0, to avoid invalid output file.
344
	 */
345
	if (plane >= 0)
346
	    gx_render_plane_init(&render_plane, (gx_device *)pdev, plane);
347
	for (y = prdev->height - 1; y >= 0; y--) {
348
	    uint actual_raster;
349
 
350
	    code = gdev_prn_get_lines(pdev, y, 1, row, bmp_raster,
351
				      &raster_data, &actual_raster,
352
				      (plane < 0 ? NULL : &render_plane));
353
	    if (code < 0)
354
		goto done;
355
	    if (fwrite((const char *)raster_data, actual_raster, 1, prn_stream) < 1) {
356
		code = gs_error_ioerror;
357
		goto done;
358
	    }
359
	}
360
    }
361
done:
362
    gs_free_object(pdev->memory, row, "bmp file buffer");
363
    prdev->buffered_page_exists = 0;
364
    return code;
365
}
366
private int
367
bmpa_reader_print_page_copies(gx_device_printer *pdev, FILE *prn_stream,
368
			      int num_copies)
369
{
370
    return bmpa_reader_print_planes(pdev, prn_stream, num_copies, -1, -1,
371
				    gdev_prn_raster(pdev));
372
}
373
private int
374
bmpa_cmyk_plane_raster(gx_device_printer *pdev)
375
{
376
    return bitmap_raster(pdev->width * (pdev->color_info.depth / 4));
377
}
378
private int
379
bmpa_cmyk_reader_print_copies(gx_device_printer *pdev, FILE *prn_stream,
380
			      int num_copies)
381
{
382
    return bmpa_reader_print_planes(pdev, prn_stream, num_copies, 0, 3,
383
				    bmpa_cmyk_plane_raster(pdev));
384
}
385
 
386
/* Buffer a (partial) rasterized page & optionally print result multiple times. */
387
private int
388
bmpa_reader_buffer_planes(gx_device_printer *pdev, FILE *file, int num_copies,
389
			  int first_plane, int last_plane, int raster)
390
{
391
    gx_device_async * const prdev = (gx_device_async *)pdev;
392
    gx_device * const dev = (gx_device *)pdev;
393
    int code = 0;
394
 
395
    /* If there's no data in buffer, no need to do any overlays */
396
    if (!prdev->buffered_page_exists) {
397
	code = bmpa_reader_print_planes(pdev, file, num_copies,
398
					first_plane, last_plane, raster);
399
	goto done;
400
    }
401
 
402
    /*
403
     * Continue rendering on top of the existing file. This requires setting
404
     * up a buffer of the existing bits in GS's format (except for optional
405
     * extra padding bytes at the end of each scan line, provided the scan
406
     * lines are still correctly memory-aligned) and then calling
407
     * gdev_prn_render_lines.  If the device already provides a band buffer
408
     * -- which currently is always the case -- we can use it if we want;
409
     * but if a device stores partially rendered pages in memory in a
410
     * compatible format (e.g., a printer with a hardware page buffer), it
411
     * can render directly on top of the stored bits.
412
     *
413
     * If we can render exactly one band (or N bands) at a time, this is
414
     * more efficient, since otherwise (a) band(s) will have to be rendered
415
     * more than once.
416
     */
417
 
418
    {
419
	byte *raster_data;
420
	gx_device_clist_reader *const crdev =
421
	    (gx_device_clist_reader *)pdev;
422
	int raster = gx_device_raster(dev, 1);
423
	int padding = -raster & 3; /* BMP scan lines are padded to 32 bits. */
424
	int bmp_raster = raster + padding;
425
	int plane;
426
 
427
	/*
428
	 * Get the address of the renderer's band buffer.  In the future,
429
	 * it will be possible to suppress the allocation of this buffer,
430
	 * and to use only buffers provided the driver itself (e.g., a
431
	 * hardware buffer).
432
	 */
433
	if (!pdev->buffer_space) {
434
	    /* Not banding.  Can't happen. */
435
	    code = gs_note_error(gs_error_Fatal);
436
	    goto done;
437
	}
438
	raster_data = crdev->data;
439
 
440
	for (plane = first_plane; plane <= last_plane; ++plane) {
441
	    gx_render_plane_t render_plane;
442
	    gx_device *bdev;
443
	    int y, band_base_line;
444
 
445
	    /* Seek to beginning of data portion of file */
446
	    if (fseek(file, prdev->file_offset_to_data[plane - first_plane],
447
		      SEEK_SET)) {
448
		code = gs_note_error(gs_error_ioerror);
449
		goto done;
450
	    }
451
 
452
	    if (plane >= 0)
453
		gx_render_plane_init(&render_plane, (gx_device *)pdev, plane);
454
	    else
455
		render_plane.index = -1;
456
 
457
	    /* Set up the buffer device. */
458
	    code = gdev_create_buf_device(crdev->buf_procs.create_buf_device,
459
					  &bdev, crdev->target, &render_plane,
460
					  dev->memory, true);
461
	    if (code < 0)
462
		goto done;
463
 
464
	    /*
465
	     * Iterate thru bands from top to bottom.  As noted above, we
466
	     * do this an entire band at a time for efficiency.
467
	     */
468
	    for (y = dev->height - 1; y >= 0; y = band_base_line - 1) {
469
		int band_height =
470
		    dev_proc(dev, get_band)(dev, y, &band_base_line);
471
		int line;
472
		gs_int_rect band_rect;
473
 
474
		/* Set up the buffer device for this band. */
475
		code = crdev->buf_procs.setup_buf_device
476
		    (bdev, raster_data, bmp_raster, NULL, 0, band_height,
477
		     band_height);
478
		if (code < 0)
479
		    goto done;
480
 
481
		/* Fill in the buffer with a band from the BMP file. */
482
		/* Need to do this backward since BMP is top to bottom. */
483
		for (line = band_height - 1; line >= 0; --line)
484
		    if (fread(raster_data + line * bmp_raster,
485
			      raster, 1, file) < 1 ||
486
			fseek(file, padding, SEEK_CUR)
487
			) {
488
			code = gs_note_error(gs_error_ioerror);
489
			goto done;
490
		    }
491
 
492
		/* Continue rendering on top of the existing bits. */
493
		band_rect.p.x = 0;
494
		band_rect.p.y = band_base_line;
495
		band_rect.q.x = pdev->width;
496
		band_rect.q.y = band_base_line + band_height;
497
		if ((code = clist_render_rectangle((gx_device_clist *)pdev,
498
						   &band_rect, bdev,
499
						   &render_plane, false)) < 0)
500
		    goto done;
501
 
502
		/* Rewind & write out the updated buffer. */
503
		if (fseek(file, -bmp_raster * band_height, SEEK_CUR)) {
504
		    code = gs_note_error(gs_error_ioerror);
505
		    goto done;
506
		}
507
		for (line = band_height - 1; line >= 0; --line) {
508
		    if (fwrite(raster_data + line * bmp_raster,
509
			       bmp_raster, 1, file) < 1 ||
510
			fseek(file, padding, SEEK_CUR)
511
			) {
512
			code = gs_note_error(gs_error_ioerror);
513
			goto done;
514
		    }
515
		}
516
	    }
517
	    crdev->buf_procs.destroy_buf_device(bdev);
518
	}
519
    }
520
 
521
 done:
522
    prdev->buffered_page_exists = (code >= 0);
523
    return code;
524
}
525
private int
526
bmpa_reader_buffer_page(gx_device_printer *pdev, FILE *prn_stream,
527
			int num_copies)
528
{
529
    return bmpa_reader_buffer_planes(pdev, prn_stream, num_copies, -1, -1,
530
				     gdev_prn_raster(pdev));
531
}
532
private int
533
bmpa_cmyk_reader_buffer_page(gx_device_printer *pdev, FILE *prn_stream,
534
			     int num_copies)
535
{
536
    return bmpa_reader_buffer_planes(pdev, prn_stream, num_copies, 0, 3,
537
				     bmpa_cmyk_plane_raster(pdev));
538
}
539
 
540
/*------------ Procedures common to writer & renderer -------- */
541
 
542
/* Compute space parameters */
543
private void
544
bmpa_get_space_params(const gx_device_printer *pdev,
545
 gdev_prn_space_params *space_params)
546
{
547
    /* Plug params into device before opening it
548
     *
549
     * You ask "How did you come up with these #'s?" You asked, so...
550
     *
551
     * To answer clearly, let me begin by recapitulating how command list
552
     * (clist) device memory allocation works in the non-overlapped case:
553
     * When the device is opened, a buffer is allocated. How big? For
554
     * starters, it must be >= PRN_MIN_BUFFER_SPACE, and as we'll see, must
555
     * be sufficient to satisfy the rest of the band params. If you don't
556
     * specify a size for it in space_params.band.BandBufferSpace, the open
557
     * routine will use a heuristic where it tries to use PRN_BUFFER_SPACE,
558
     * then works its way down by factors of 2 if that much memory isn't
559
     * available.
560
     *
561
     * The device proceeds to divide the buffer into several parts: one of
562
     * them is used for the same thing during writing & rasterizing; the
563
     * other parts are redivided and used differently writing and
564
     * rasterizing. The limiting factor dictating memory requirements is the
565
     * rasterizer's render buffer.  This buffer needs to be able to contain
566
     * a pixmap that covers an entire band. Memory consumption is whatever
567
     * is needed to hold N rows of data aligned on word boundaries, +
568
     * sizeof(pointer) for each of N rows. Whatever is left over in the
569
     * rasterized is allocated to a tile cache. You want to make sure that
570
     * cache is at least 50KB.
571
     *
572
     * For example, take a 600 dpi b/w device at 8.5 x 11 inches.  For the
573
     * whole device, that's 6600 rows @ 638 bytes = ~4.2 MB total.  If the
574
     * device is divided into 100 bands, each band's rasterizer buffer is
575
     * 62K. Add on a 50K tile cache, and you get a 112KB (+ add a little
576
     * slop) total device buffer size.
577
     *
578
     * Now that we've covered the rasterizer, let's switch back to the
579
     * writer. The writer must have a tile cache *exactly* the same size as
580
     * the reader. This means that the space to divide up for the writer is
581
     * equal is size to the rasterizer's band buffer.  This space is divided
582
     * into 2 sections: per-band bookeeping info and a command buffer. The
583
     * bookeeping info currently uses ~72 bytes for each band. The rest is
584
     * the command buffer.
585
     *
586
     * To continue the same 112KB example, we have 62KB to slice up.
587
     * We need 72 bytes * 100 bands = 7.2KB, leaving a 55K command buffer.
588
     *
589
     * A larger command buffer has some performance (see gxclmem.c comments)
590
     * advantages in the general case, but is critical in one special case:
591
     * high-level images. Whenever possible, images are transmitted across
592
     * the band buffer in their original resolution and bits/pixel. The
593
     * alternative fallback behavior can be very slow.  Here, the relevant
594
     * restriction is that at least one entire source image row must fit
595
     * into the command buffer. This means that, in our example, an RGB
596
     * source image would have to be <= 18K pixels wide. If the image is
597
     * sampled at the same resolution as the hardware (600 dpi), that means
598
     * the row would be limited to a very reasonable 30 inches. However, if
599
     * the source image is sampled at 2400 dpi, that limit is only 7.5
600
     * inches. The situation gets worse as bands get smaller, but the
601
     * implementor must decide on the tradeoff point.
602
     *
603
     * The moral of the story is that you should never make a band
604
     * so small that its buffer limits the command buffer excessively.
605
     * Again, Max image row bytes = band buffer size - # bands * 72. 
606
     *
607
     * In the overlapped case, everything is exactly as above, except that
608
     * two identical devices, each with an identical buffer, are allocated:
609
     * one for the writer, and one for the rasterizer. Because it's critical
610
     * to allocate identical buffers, I *strongly* recommend setting these
611
     * params in the writer's open routine:
612
     * space_params.band.BandBufferSpace, .BandWidth and .BandHeight.  If
613
     * you don't force these values to a known value, the memory allocation
614
     * heuristic may not come to the same result for both copies of the
615
     * device, since the first allocation will diminish the amount of free
616
     * memory.
617
     *
618
     * There is room for an important optimization here: allocate the
619
     * writer's space with enough memory for a generous command buffer, but
620
     * allocate the reader with only enough memory for a band rasterization
621
     * buffer and the tile cache.  To do this, observe that the space_params
622
     * struct has two sizes: BufferSpace vs. BandBufferSpace.  To start,
623
     * BandBufferSpace is always <= BufferSpace. On the reader side,
624
     * BandBufferSpace is divided between the tile cache and the rendering
625
     * buffer -- that's all the memory that's needed to rasterize. On the
626
     * writer's side, BandBufferSpace is divided the same way: the tile
627
     * cache (which must be identical to the reader's) is carved out, and
628
     * the space that would have been used for a rasterizing buffer is used
629
     * as a command buffer. However, you can further increase the cmd buf
630
     * further by setting BufferSize (not BandBufferSize) to a higher number
631
     * than BandBufferSize. In that case, the command buffer is increased by
632
     * the difference (BufferSize - BandBufferSize). There is logic in the
633
     * memory allocation for printers that will automatically use BufferSize
634
     * for writers (or non-async printers), and BandBufferSize for readers.
635
     *
636
     * Note: per the comments in gxclmem.c, the banding logic will perform
637
     * better with 1MB or better for the command list.
638
     */
639
 
640
    /* This will give us a very "ungenerous" buffer. */
641
    /* Here, my arbitrary rule for min image row is: twice the dest width */
642
    /* in full CMYK. */
643
    int render_space;
644
    int writer_space;
645
    const int tile_cache_space = 50 * 1024;
646
    const int min_image_rows = 2;
647
    int min_row_space =
648
	min_image_rows * (  4 * ( pdev->width + sizeof(int) - 1 )  );
649
    int min_band_height = max(1, pdev->height / 100);	/* make bands >= 1% of total */
650
 
651
    space_params->band.BandWidth = pdev->width;
652
    space_params->band.BandHeight = min_band_height;
653
 
654
    render_space = gdev_mem_data_size( (const gx_device_memory *)pdev,
655
				       space_params->band.BandWidth,
656
				       space_params->band.BandHeight );
657
    /* need to include minimal writer requirements to satisfy rasterizer init */
658
    writer_space = 	/* add 5K slop for good measure */
659
	5000 + (72 + 8) * ( (pdev->height / space_params->band.BandHeight) + 1 );
660
    space_params->band.BandBufferSpace =
661
	max(render_space, writer_space) + tile_cache_space;
662
    space_params->BufferSpace =
663
	max(render_space, writer_space + min_row_space) + tile_cache_space;
664
    /**************** HACK HACK HACK ****************/
665
    /* Override this computation to force reader & writer to match */
666
    space_params->BufferSpace = space_params->band.BandBufferSpace;
667
}
668
 
669
/* Get device parameters. */
670
private int
671
bmpa_get_params(gx_device * pdev, gs_param_list * plist)
672
{
673
    gx_device_async * const bdev = (gx_device_async *)pdev;
674
 
675
    return gdev_prn_get_params_planar(pdev, plist, &bdev->UsePlanarBuffer);
676
}
677
 
678
/* Put device parameters. */
679
/* IMPORTANT: async drivers must NOT CLOSE the device while doing put_params.*/
680
/* IMPORTANT: async drivers must NOT CLOSE the device while doing put_params.*/
681
/* IMPORTANT: async drivers must NOT CLOSE the device while doing put_params.*/
682
/* IMPORTANT: async drivers must NOT CLOSE the device while doing put_params.*/
683
private int
684
bmpa_put_params(gx_device *pdev, gs_param_list *plist)
685
{
686
    /*
687
     * This driver does nothing interesting except cascade down to
688
     * gdev_prn_put_params_planar, which is something it would have to do
689
     * even if it did do something interesting here.
690
     *
691
     * Note that gdev_prn_put_params[_planar] does not close the device.
692
     */
693
    gx_device_async * const bdev = (gx_device_async *)pdev;
694
 
695
    return gdev_prn_put_params_planar(pdev, plist, &bdev->UsePlanarBuffer);
696
}
697
 
698
/* Get hardware-detected parameters. */
699
/* This proc defines a only one param: a useless value for testing */
700
private int
701
bmpa_get_hardware_params(gx_device *dev, gs_param_list *plist)
702
{
703
    static const char *const test_value = "Test value";
704
    static const char *const test_name = "TestValue";
705
    int code = 0;
706
 
707
    if ( param_requested(plist, test_name) ) {
708
	gs_param_string param_str;
709
 
710
	param_string_from_string(param_str, test_value); /* value must be persistent to use this macro */
711
	code = param_write_string(plist, test_name, &param_str);
712
    }
713
    return code;
714
}