~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/gdevbmpa.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

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