1 /* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16 /* .BMP file format output drivers */
17 #include "gdevprn.h"
18 #include "gdevpccm.h"
19 #include "gdevbmp.h"
20
21 /* ------ The device descriptors ------ */
22
23 static dev_proc_print_page(bmp_print_page);
24 static dev_proc_print_page(bmp_cmyk_print_page);
25
26 /* Monochrome. */
27
28 const gx_device_printer gs_bmpmono_device =
29 prn_device(prn_bg_procs, "bmpmono", /* The print_page proc is compatible with allowing bg printing */
30 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
31 X_DPI, Y_DPI,
32 0, 0, 0, 0, /* margins */
33 1, bmp_print_page);
34
35 /* 8-bit (SuperVGA-style) grayscale . */
36 /* (Uses a fixed palette of 256 gray levels.) */
37
38 /* Since the print_page doesn't alter the device, this device can print in the background */
39 static const gx_device_procs bmpgray_procs =
40 prn_color_procs(gdev_prn_open, gdev_prn_bg_output_page, gdev_prn_close,
41 gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
42 const gx_device_printer gs_bmpgray_device = {
43 prn_device_body(gx_device_printer, bmpgray_procs, "bmpgray",
44 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
45 X_DPI, Y_DPI,
46 0, 0, 0, 0, /* margins */
47 1, 8, 255, 0, 256, 0, bmp_print_page)
48 };
49
50 /* 1-bit-per-plane separated CMYK color. */
51
52 /* Since the print_page doesn't alter the device, this device can print in the background */
53 #define bmp_cmyk_procs(p_map_color_rgb, p_map_cmyk_color)\
54 gdev_prn_open, NULL, NULL, gdev_prn_bg_output_page, gdev_prn_close,\
55 NULL, p_map_color_rgb, NULL, NULL, NULL, NULL, NULL, NULL,\
56 gdev_prn_get_params, gdev_prn_put_params,\
57 p_map_cmyk_color, NULL, NULL, NULL, gx_page_device_get_page_device
58
59 static const gx_device_procs bmpsep1_procs = {
60 bmp_cmyk_procs(cmyk_1bit_map_color_rgb, cmyk_1bit_map_cmyk_color)
61 };
62 const gx_device_printer gs_bmpsep1_device = {
63 prn_device_body(gx_device_printer, bmpsep1_procs, "bmpsep1",
64 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
65 X_DPI, Y_DPI,
66 0,0,0,0, /* margins */
67 4, 4, 1, 1, 2, 2, bmp_cmyk_print_page)
68 };
69
70 /* 8-bit-per-plane separated CMYK color. */
71
72 static const gx_device_procs bmpsep8_procs = {
73 bmp_cmyk_procs(cmyk_8bit_map_color_rgb, cmyk_8bit_map_cmyk_color)
74 };
75 const gx_device_printer gs_bmpsep8_device = {
76 prn_device_body(gx_device_printer, bmpsep8_procs, "bmpsep8",
77 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
78 X_DPI, Y_DPI,
79 0,0,0,0, /* margins */
80 4, 32, 255, 255, 256, 256, bmp_cmyk_print_page)
81 };
82
83 /* 4-bit planar (EGA/VGA-style) color. */
84
85 /* Since the print_page doesn't alter the device, this device can print in the background */
86 static const gx_device_procs bmp16_procs =
87 prn_color_procs(gdev_prn_open, gdev_prn_bg_output_page, gdev_prn_close,
88 pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
89 const gx_device_printer gs_bmp16_device = {
90 prn_device_body(gx_device_printer, bmp16_procs, "bmp16",
91 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
92 X_DPI, Y_DPI,
93 0, 0, 0, 0, /* margins */
94 3, 4, 1, 1, 2, 2, bmp_print_page)
95 };
96
97 /* 8-bit (SuperVGA-style) color. */
98 /* (Uses a fixed palette of 3,3,2 bits.) */
99
100 /* Since the print_page doesn't alter the device, this device can print in the background */
101 static const gx_device_procs bmp256_procs =
102 prn_color_procs(gdev_prn_open, gdev_prn_bg_output_page, gdev_prn_close,
103 pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
104 const gx_device_printer gs_bmp256_device = {
105 prn_device_body(gx_device_printer, bmp256_procs, "bmp256",
106 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
107 X_DPI, Y_DPI,
108 0, 0, 0, 0, /* margins */
109 3, 8, 5, 5, 6, 6, bmp_print_page)
110 };
111
112 /* 24-bit color. */
113
114 /* Since the print_page doesn't alter the device, this device can print in the background */
115 static const gx_device_procs bmp16m_procs =
116 prn_color_procs(gdev_prn_open, gdev_prn_bg_output_page, gdev_prn_close,
117 bmp_map_16m_rgb_color, bmp_map_16m_color_rgb);
118 const gx_device_printer gs_bmp16m_device =
119 prn_device(bmp16m_procs, "bmp16m",
120 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
121 X_DPI, Y_DPI,
122 0, 0, 0, 0, /* margins */
123 24, bmp_print_page);
124
125 /* 32-bit CMYK color (outside the BMP specification). */
126
127 static const gx_device_procs bmp32b_procs = {
128 bmp_cmyk_procs(cmyk_8bit_map_color_rgb, gx_default_cmyk_map_cmyk_color)
129 };
130 const gx_device_printer gs_bmp32b_device =
131 prn_device(bmp32b_procs, "bmp32b",
132 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
133 X_DPI, Y_DPI,
134 0, 0, 0, 0, /* margins */
135 32, bmp_print_page);
136
137 /* ------ Private definitions ------ */
138
139 /* Write out a page in BMP format. */
140 /* This routine is used for all non-separated formats. */
141 static int
bmp_print_page(gx_device_printer * pdev,gp_file * file)142 bmp_print_page(gx_device_printer * pdev, gp_file * file)
143 {
144 uint raster = gdev_prn_raster(pdev);
145 /* BMP scan lines are padded to 32 bits. */
146 uint bmp_raster = raster + (-(int)raster & 3);
147 byte *row = gs_alloc_bytes(pdev->memory, bmp_raster, "bmp file buffer");
148 int y;
149 int code; /* return code */
150
151 if (row == 0) /* can't allocate row buffer */
152 return_error(gs_error_VMerror);
153 memset(row+raster, 0, bmp_raster - raster); /* clear the padding bytes */
154
155 /* Write the file header. */
156
157 code = write_bmp_header(pdev, file);
158 if (code < 0)
159 goto done;
160
161 /* Write the contents of the image. */
162 /* BMP files want the image in bottom-to-top order! */
163
164 for (y = pdev->height - 1; y >= 0; y--) {
165 code = gdev_prn_copy_scan_lines(pdev, y, row, raster);
166 if (code < 0)
167 goto done;
168 gp_fwrite((const char *)row, bmp_raster, 1, file);
169 }
170
171 done:
172 gs_free_object(pdev->memory, row, "bmp file buffer");
173
174 return code;
175 }
176
177 /* Write out a page in separated CMYK format. */
178 /* This routine is used for all formats. */
179 static int
bmp_cmyk_print_page(gx_device_printer * pdev,gp_file * file)180 bmp_cmyk_print_page(gx_device_printer * pdev, gp_file * file)
181 {
182 int plane_depth = pdev->color_info.depth / 4;
183 uint raster = (pdev->width * plane_depth + 7) >> 3;
184 /* BMP scan lines are padded to 32 bits. */
185 uint bmp_raster = raster + (-(int)raster & 3);
186 byte *row = gs_alloc_bytes(pdev->memory, bmp_raster, "bmp file buffer");
187 int y;
188 int code = 0; /* return code */
189 int plane;
190
191 if (row == 0) /* can't allocate row buffer */
192 return_error(gs_error_VMerror);
193 memset(row+raster, 0, bmp_raster - raster); /* clear the padding bytes */
194
195 for (plane = 0; plane <= 3; ++plane) {
196 gx_render_plane_t render_plane;
197
198 /* Write the page header. */
199
200 code = write_bmp_separated_header(pdev, file);
201 if (code < 0)
202 break;
203
204 /* Write the contents of the image. */
205 /* BMP files want the image in bottom-to-top order! */
206
207 gx_render_plane_init(&render_plane, (gx_device *)pdev, plane);
208 for (y = pdev->height - 1; y >= 0; y--) {
209 byte *actual_data;
210 uint actual_raster;
211
212 code = gdev_prn_get_lines(pdev, y, 1, row, bmp_raster,
213 &actual_data, &actual_raster,
214 &render_plane);
215 if (code < 0)
216 goto done;
217 gp_fwrite((const char *)actual_data, bmp_raster, 1, file);
218 }
219 }
220
221 done:
222 gs_free_object(pdev->memory, row, "bmp file buffer");
223
224 return code;
225 }
226