~ubuntu-branches/ubuntu/vivid/ghostscript/vivid-security

« back to all changes in this revision

Viewing changes to devices/gdevbmpa.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2013-08-09 20:01:36 UTC
  • mfrom: (1.1.37)
  • Revision ID: package-import@ubuntu.com-20130809200136-amb6zrr7hnjb5jq9
Tags: 9.08~rc1~dfsg-0ubuntu1
* New upstream release
   - Ghostscript 9.08rc1.
   - We are using the system's liblcms2 and libopenjpeg now.
* debian/patches/020130401-852e545-pxl-xl-driver-produced-drawing-commands-without-setting-color-space.patch:
  Removed patch backported from upstream.
* debian/patches/ojdk-8007925+8007926.patch,
  debian/patches/ojdk-8007927.patch,
  debian/patches/ojdk-8007929.patch,
  debian/patches/ojdk-8009654.patch: Removed patches on build in liblcms2, we
  use the system's liblcms2 now.
* debian/patches/2001_docdir_fix_for_debian.patch: Manually updated to new
  upstream source code.
* debian/patches/2003_support_multiarch.patch: Refreshed with quilt.
* debian/control: Added build dependencies on liblcms2-dev and
  libopenjpeg-dev.
* debian/rules: Check for removed lcms2/ and openjpeg/ subdirectories in
  the repackaging check again, also set build options for shared liblcms2
  and libopenjpeg libraries.
* debian/rules: Makefile.in and configure.ac are in the root directory of
  the source now and do not need to get linked from base/. Also there is no
  gstoraster and gstopxl CUPS filter in the package any more and no
  "install-cups" make target any more.
* debian/control, debian/rules, debian/ghostscript-cups.install,
  debian/ghostscript-cups.ppd-updater: Removed the ghostscript-cups binary
  package. The files are now provided by cups-filters.
* debian/symbols.common: Updated for new upstream source. Applied patch
  which dpkg-gensymbols generated for debian/libgs9.symbols to this file.

Show diffs side-by-side

added added

removed removed

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