xref: /plan9/sys/src/cmd/gs/src/gdevbmp.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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