gdevbmpa.c 27 KB

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