1 /* Copyright (C) 1992, 1993, 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevbmp.c,v 1.12 2005/10/20 19:42:18 ray Exp $ */
18 /* .BMP file format output drivers */
19 #include "gdevprn.h"
20 #include "gdevpccm.h"
21 #include "gdevbmp.h"
22
23 /* ------ The device descriptors ------ */
24
25 private dev_proc_print_page(bmp_print_page);
26 private dev_proc_print_page(bmp_cmyk_print_page);
27
28 /* Monochrome. */
29
30 const gx_device_printer gs_bmpmono_device =
31 prn_device(prn_std_procs, "bmpmono",
32 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
33 X_DPI, Y_DPI,
34 0, 0, 0, 0, /* margins */
35 1, bmp_print_page);
36
37 /* 8-bit (SuperVGA-style) grayscale . */
38 /* (Uses a fixed palette of 256 gray levels.) */
39
40 private const gx_device_procs bmpgray_procs =
41 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
42 gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
43 const gx_device_printer gs_bmpgray_device = {
44 prn_device_body(gx_device_printer, bmpgray_procs, "bmpgray",
45 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
46 X_DPI, Y_DPI,
47 0, 0, 0, 0, /* margins */
48 1, 8, 255, 0, 256, 0, bmp_print_page)
49 };
50
51 /* 1-bit-per-plane separated CMYK color. */
52
53 #define bmp_cmyk_procs(p_map_color_rgb, p_map_cmyk_color)\
54 gdev_prn_open, NULL, NULL, gdev_prn_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 private 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 private 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 private const gx_device_procs bmp16_procs =
86 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
87 pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
88 const gx_device_printer gs_bmp16_device = {
89 prn_device_body(gx_device_printer, bmp16_procs, "bmp16",
90 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
91 X_DPI, Y_DPI,
92 0, 0, 0, 0, /* margins */
93 3, 4, 1, 1, 2, 2, bmp_print_page)
94 };
95
96 /* 8-bit (SuperVGA-style) color. */
97 /* (Uses a fixed palette of 3,3,2 bits.) */
98
99 private const gx_device_procs bmp256_procs =
100 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
101 pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
102 const gx_device_printer gs_bmp256_device = {
103 prn_device_body(gx_device_printer, bmp256_procs, "bmp256",
104 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
105 X_DPI, Y_DPI,
106 0, 0, 0, 0, /* margins */
107 3, 8, 5, 5, 6, 6, bmp_print_page)
108 };
109
110 /* 24-bit color. */
111
112 private const gx_device_procs bmp16m_procs =
113 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
114 bmp_map_16m_rgb_color, bmp_map_16m_color_rgb);
115 const gx_device_printer gs_bmp16m_device =
116 prn_device(bmp16m_procs, "bmp16m",
117 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
118 X_DPI, Y_DPI,
119 0, 0, 0, 0, /* margins */
120 24, bmp_print_page);
121
122 /* 32-bit CMYK color (outside the BMP specification). */
123
124 private const gx_device_procs bmp32b_procs = {
125 bmp_cmyk_procs(cmyk_8bit_map_color_rgb, gx_default_cmyk_map_cmyk_color)
126 };
127 const gx_device_printer gs_bmp32b_device =
128 prn_device(bmp32b_procs, "bmp32b",
129 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
130 X_DPI, Y_DPI,
131 0, 0, 0, 0, /* margins */
132 32, bmp_print_page);
133
134 /* ------ Private definitions ------ */
135
136 /* Write out a page in BMP format. */
137 /* This routine is used for all non-separated formats. */
138 private int
bmp_print_page(gx_device_printer * pdev,FILE * file)139 bmp_print_page(gx_device_printer * pdev, FILE * file)
140 {
141 uint raster = gdev_prn_raster(pdev);
142 /* BMP scan lines are padded to 32 bits. */
143 uint bmp_raster = raster + (-(int)raster & 3);
144 byte *row = gs_alloc_bytes(pdev->memory, bmp_raster, "bmp file buffer");
145 int y;
146 int code; /* return code */
147
148 if (row == 0) /* can't allocate row buffer */
149 return_error(gs_error_VMerror);
150 memset(row+raster, 0, bmp_raster - raster); /* clear the padding bytes */
151
152 /* Write the file header. */
153
154 code = write_bmp_header(pdev, file);
155 if (code < 0)
156 goto done;
157
158 /* Write the contents of the image. */
159 /* BMP files want the image in bottom-to-top order! */
160
161 for (y = pdev->height - 1; y >= 0; y--) {
162 gdev_prn_copy_scan_lines(pdev, y, row, raster);
163 fwrite((const char *)row, bmp_raster, 1, file);
164 }
165
166 done:
167 gs_free_object(pdev->memory, row, "bmp file buffer");
168
169 return code;
170 }
171
172 /* Write out a page in separated CMYK format. */
173 /* This routine is used for all formats. */
174 private int
bmp_cmyk_print_page(gx_device_printer * pdev,FILE * file)175 bmp_cmyk_print_page(gx_device_printer * pdev, FILE * file)
176 {
177 int plane_depth = pdev->color_info.depth / 4;
178 uint raster = (pdev->width * plane_depth + 7) >> 3;
179 /* BMP scan lines are padded to 32 bits. */
180 uint bmp_raster = raster + (-(int)raster & 3);
181 byte *row = gs_alloc_bytes(pdev->memory, bmp_raster, "bmp file buffer");
182 int y;
183 int code = 0; /* return code */
184 int plane;
185
186 if (row == 0) /* can't allocate row buffer */
187 return_error(gs_error_VMerror);
188 memset(row+raster, 0, bmp_raster - raster); /* clear the padding bytes */
189
190 for (plane = 0; plane <= 3; ++plane) {
191 gx_render_plane_t render_plane;
192
193 /* Write the page header. */
194
195 code = write_bmp_separated_header(pdev, file);
196 if (code < 0)
197 break;
198
199 /* Write the contents of the image. */
200 /* BMP files want the image in bottom-to-top order! */
201
202 gx_render_plane_init(&render_plane, (gx_device *)pdev, plane);
203 for (y = pdev->height - 1; y >= 0; y--) {
204 byte *actual_data;
205 uint actual_raster;
206
207 code = gdev_prn_get_lines(pdev, y, 1, row, bmp_raster,
208 &actual_data, &actual_raster,
209 &render_plane);
210 if (code < 0)
211 goto done;
212 fwrite((const char *)actual_data, bmp_raster, 1, file);
213 }
214 }
215
216 done:
217 gs_free_object(pdev->memory, row, "bmp file buffer");
218
219 return code;
220 }
221