/src/ghostpdl/devices/gdevbmp.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, 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 | | /* The print_page proc is compatible with allowing bg printing */ |
30 | | prn_device(gdev_prn_initialize_device_procs_mono_bg, "bmpmono", |
31 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
32 | | X_DPI, Y_DPI, |
33 | | 0, 0, 0, 0, /* margins */ |
34 | | 1, bmp_print_page); |
35 | | |
36 | | /* 8-bit (SuperVGA-style) grayscale . */ |
37 | | /* (Uses a fixed palette of 256 gray levels.) */ |
38 | | |
39 | | /* Since the print_page doesn't alter the device, this device can print in the background */ |
40 | | static void |
41 | | bmpgray_initialize_device_procs(gx_device *dev) |
42 | 0 | { |
43 | 0 | gdev_prn_initialize_device_procs_gray_bg(dev); |
44 | |
|
45 | 0 | set_dev_proc(dev, encode_color, gx_default_8bit_map_gray_color); |
46 | 0 | set_dev_proc(dev, decode_color, gx_default_8bit_map_color_gray); |
47 | 0 | } |
48 | | |
49 | | const gx_device_printer gs_bmpgray_device = { |
50 | | prn_device_body(gx_device_printer, bmpgray_initialize_device_procs, "bmpgray", |
51 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
52 | | X_DPI, Y_DPI, |
53 | | 0, 0, 0, 0, /* margins */ |
54 | | 1, 8, 255, 0, 256, 0, bmp_print_page) |
55 | | }; |
56 | | |
57 | | /* 1-bit-per-plane separated CMYK color. */ |
58 | | |
59 | | /* Since the print_page doesn't alter the device, this device can print in the background */ |
60 | | static void |
61 | | bmpsep1_initialize_device_procs(gx_device *dev) |
62 | 0 | { |
63 | 0 | gdev_prn_initialize_device_procs_cmyk1_bg(dev); |
64 | 0 | } |
65 | | |
66 | | const gx_device_printer gs_bmpsep1_device = { |
67 | | prn_device_body(gx_device_printer, bmpsep1_initialize_device_procs, "bmpsep1", |
68 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
69 | | X_DPI, Y_DPI, |
70 | | 0,0,0,0, /* margins */ |
71 | | 4, 4, 1, 1, 2, 2, bmp_cmyk_print_page) |
72 | | }; |
73 | | |
74 | | /* 8-bit-per-plane separated CMYK color. */ |
75 | | static void |
76 | | bmpsep8_initialize_device_procs(gx_device *dev) |
77 | 0 | { |
78 | 0 | gdev_prn_initialize_device_procs_cmyk8_bg(dev); |
79 | 0 | } |
80 | | |
81 | | const gx_device_printer gs_bmpsep8_device = { |
82 | | prn_device_body(gx_device_printer, bmpsep8_initialize_device_procs, "bmpsep8", |
83 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
84 | | X_DPI, Y_DPI, |
85 | | 0,0,0,0, /* margins */ |
86 | | 4, 32, 255, 255, 256, 256, bmp_cmyk_print_page) |
87 | | }; |
88 | | |
89 | | /* 4-bit planar (EGA/VGA-style) color. */ |
90 | | |
91 | | /* Since the print_page doesn't alter the device, this device can print in the background */ |
92 | | static void |
93 | | bmp16_initialize_device_procs(gx_device *dev) |
94 | 0 | { |
95 | 0 | gdev_prn_initialize_device_procs_cmyk8_bg(dev); |
96 | |
|
97 | 0 | set_dev_proc(dev, map_rgb_color, pc_4bit_map_rgb_color); |
98 | 0 | set_dev_proc(dev, map_color_rgb, pc_4bit_map_color_rgb); |
99 | 0 | set_dev_proc(dev, encode_color, pc_4bit_map_rgb_color); |
100 | 0 | set_dev_proc(dev, decode_color, pc_4bit_map_color_rgb); |
101 | 0 | } |
102 | | |
103 | | const gx_device_printer gs_bmp16_device = { |
104 | | prn_device_body(gx_device_printer, bmp16_initialize_device_procs, "bmp16", |
105 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
106 | | X_DPI, Y_DPI, |
107 | | 0, 0, 0, 0, /* margins */ |
108 | | 3, 4, 1, 1, 2, 2, bmp_print_page) |
109 | | }; |
110 | | |
111 | | /* 8-bit (SuperVGA-style) color. */ |
112 | | /* (Uses a fixed palette of 3,3,2 bits.) */ |
113 | | |
114 | | /* Since the print_page doesn't alter the device, this device can print in the background */ |
115 | | static void |
116 | | bmp256_initialize_device_procs(gx_device *dev) |
117 | 0 | { |
118 | 0 | gdev_prn_initialize_device_procs_bg(dev); |
119 | |
|
120 | 0 | set_dev_proc(dev, map_rgb_color, pc_8bit_map_rgb_color); |
121 | 0 | set_dev_proc(dev, map_color_rgb, pc_8bit_map_color_rgb); |
122 | 0 | set_dev_proc(dev, encode_color, pc_8bit_map_rgb_color); |
123 | 0 | set_dev_proc(dev, decode_color, pc_8bit_map_color_rgb); |
124 | 0 | } |
125 | | |
126 | | const gx_device_printer gs_bmp256_device = { |
127 | | prn_device_body(gx_device_printer, bmp256_initialize_device_procs, "bmp256", |
128 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
129 | | X_DPI, Y_DPI, |
130 | | 0, 0, 0, 0, /* margins */ |
131 | | 3, 8, 5, 5, 6, 6, bmp_print_page) |
132 | | }; |
133 | | |
134 | | /* 24-bit color. */ |
135 | | |
136 | | /* Since the print_page doesn't alter the device, this device can print in the background */ |
137 | | static void |
138 | | bmp16m_initialize_device_procs(gx_device *dev) |
139 | 0 | { |
140 | 0 | gdev_prn_initialize_device_procs_bg(dev); |
141 | |
|
142 | 0 | set_dev_proc(dev, map_rgb_color, bmp_map_16m_rgb_color); |
143 | 0 | set_dev_proc(dev, map_color_rgb, bmp_map_16m_color_rgb); |
144 | 0 | set_dev_proc(dev, encode_color, bmp_map_16m_rgb_color); |
145 | 0 | set_dev_proc(dev, decode_color, bmp_map_16m_color_rgb); |
146 | 0 | } |
147 | | |
148 | | const gx_device_printer gs_bmp16m_device = |
149 | | prn_device(bmp16m_initialize_device_procs, "bmp16m", |
150 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
151 | | X_DPI, Y_DPI, |
152 | | 0, 0, 0, 0, /* margins */ |
153 | | 24, bmp_print_page); |
154 | | |
155 | | /* 32-bit CMYK color (outside the BMP specification). */ |
156 | | static void |
157 | | bmp32b_initialize_device_procs(gx_device *dev) |
158 | 0 | { |
159 | 0 | gdev_prn_initialize_device_procs_cmyk8_bg(dev); |
160 | 0 | } |
161 | | |
162 | | const gx_device_printer gs_bmp32b_device = |
163 | | prn_device(bmp32b_initialize_device_procs, "bmp32b", |
164 | | DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, |
165 | | X_DPI, Y_DPI, |
166 | | 0, 0, 0, 0, /* margins */ |
167 | | 32, bmp_print_page); |
168 | | |
169 | | /* ------ Private definitions ------ */ |
170 | | |
171 | | /* Write out a page in BMP format. */ |
172 | | /* This routine is used for all non-separated formats. */ |
173 | | static int |
174 | | bmp_print_page(gx_device_printer * pdev, gp_file * file) |
175 | 8.36k | { |
176 | 8.36k | uint raster = gdev_prn_raster(pdev); |
177 | | /* BMP scan lines are padded to 32 bits. */ |
178 | 8.36k | uint bmp_raster = raster + (-(int)raster & 3); |
179 | 8.36k | byte *row = gs_alloc_bytes(pdev->memory, bmp_raster, "bmp file buffer"); |
180 | 8.36k | int y; |
181 | 8.36k | int code; /* return code */ |
182 | | |
183 | 8.36k | if (row == 0) /* can't allocate row buffer */ |
184 | 0 | return_error(gs_error_VMerror); |
185 | 8.36k | memset(row+raster, 0, bmp_raster - raster); /* clear the padding bytes */ |
186 | | |
187 | | /* Write the file header. */ |
188 | | |
189 | 8.36k | code = write_bmp_header(pdev, file); |
190 | 8.36k | if (code < 0) |
191 | 0 | goto done; |
192 | | |
193 | | /* Write the contents of the image. */ |
194 | | /* BMP files want the image in bottom-to-top order! */ |
195 | | |
196 | 18.0M | for (y = pdev->height - 1; y >= 0; y--) { |
197 | 18.0M | code = gdev_prn_copy_scan_lines(pdev, y, row, raster); |
198 | 18.0M | if (code < 0) |
199 | 3 | goto done; |
200 | 18.0M | gp_fwrite((const char *)row, bmp_raster, 1, file); |
201 | 18.0M | } |
202 | | |
203 | 8.36k | done: |
204 | 8.36k | gs_free_object(pdev->memory, row, "bmp file buffer"); |
205 | | |
206 | 8.36k | return code; |
207 | 8.36k | } |
208 | | |
209 | | /* Write out a page in separated CMYK format. */ |
210 | | /* This routine is used for all formats. */ |
211 | | static int |
212 | | bmp_cmyk_print_page(gx_device_printer * pdev, gp_file * file) |
213 | 0 | { |
214 | 0 | int plane_depth = pdev->color_info.depth / 4; |
215 | 0 | uint raster = (pdev->width * plane_depth + 7) >> 3; |
216 | | /* BMP scan lines are padded to 32 bits. */ |
217 | 0 | uint bmp_raster = raster + (-(int)raster & 3); |
218 | 0 | byte *row = gs_alloc_bytes(pdev->memory, bmp_raster, "bmp file buffer"); |
219 | 0 | int y; |
220 | 0 | int code = 0; /* return code */ |
221 | 0 | int plane; |
222 | |
|
223 | 0 | if (row == 0) /* can't allocate row buffer */ |
224 | 0 | return_error(gs_error_VMerror); |
225 | 0 | memset(row+raster, 0, bmp_raster - raster); /* clear the padding bytes */ |
226 | |
|
227 | 0 | for (plane = 0; plane <= 3; ++plane) { |
228 | 0 | gx_render_plane_t render_plane; |
229 | | |
230 | | /* Write the page header. */ |
231 | |
|
232 | 0 | code = write_bmp_separated_header(pdev, file); |
233 | 0 | if (code < 0) |
234 | 0 | break; |
235 | | |
236 | | /* Write the contents of the image. */ |
237 | | /* BMP files want the image in bottom-to-top order! */ |
238 | | |
239 | 0 | gx_render_plane_init(&render_plane, (gx_device *)pdev, plane); |
240 | 0 | for (y = pdev->height - 1; y >= 0; y--) { |
241 | 0 | byte *actual_data; |
242 | 0 | uint actual_raster; |
243 | |
|
244 | 0 | code = gdev_prn_get_lines(pdev, y, 1, row, bmp_raster, |
245 | 0 | &actual_data, &actual_raster, |
246 | 0 | &render_plane); |
247 | 0 | if (code < 0) |
248 | 0 | goto done; |
249 | 0 | gp_fwrite((const char *)actual_data, bmp_raster, 1, file); |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | 0 | done: |
254 | 0 | gs_free_object(pdev->memory, row, "bmp file buffer"); |
255 | |
|
256 | 0 | return code; |
257 | 0 | } |