1 /* Copyright (C) 1998, 1999 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: gdevbmpc.c,v 1.8 2005/08/04 17:38:45 alexcher Exp $ */
18 /* .BMP file format driver utilities */
19 #include "gdevprn.h"
20 #include "gdevbmp.h"
21
22 /*
23 * Define BMP file format structures.
24 * All multi-byte quantities are stored LSB-first!
25 */
26
27 typedef ushort word;
28 #if arch_sizeof_int == 4
29 typedef uint dword;
30 #else
31 # if arch_sizeof_long == 4
32 typedef ulong dword;
33 # endif
34 #endif
35 #if arch_is_big_endian
36 # define BMP_ASSIGN_WORD(a,v) a = ((v) >> 8) + ((v) << 8)
37 # define BMP_ASSIGN_DWORD(a,v)\
38 a = ((v) >> 24) + (((v) >> 8) & 0xff00L) +\
39 (((dword)(v) << 8) & 0xff0000L) + ((dword)(v) << 24)
40 #else
41 # define BMP_ASSIGN_WORD(a,v) a = (v)
42 # define BMP_ASSIGN_DWORD(a,v) a = (v)
43 #endif
44
45 typedef struct bmp_file_header_s {
46
47 /* BITMAPFILEHEADER */
48
49 /*
50 * This structure actually begins with two bytes
51 * containing the characters 'BM', but we must omit them,
52 * because some compilers would insert padding to force
53 * the size member to a 32- or 64-bit boundary.
54 */
55
56 /*byte typeB, typeM; *//* always 'BM' */
57 dword size; /* total size of file */
58 word reserved1;
59 word reserved2;
60 dword offBits; /* offset of bits from start of file */
61
62 } bmp_file_header;
63
64 #define sizeof_bmp_file_header (2 + sizeof(bmp_file_header))
65
66 typedef struct bmp_info_header_s {
67
68 /* BITMAPINFOHEADER */
69
70 dword size; /* size of info header in bytes */
71 dword width; /* width in pixels */
72 dword height; /* height in pixels */
73 word planes; /* # of planes, always 1 */
74 word bitCount; /* bits per pixel */
75 dword compression; /* compression scheme, always 0 */
76 dword sizeImage; /* size of bits */
77 dword xPelsPerMeter; /* X pixels per meter */
78 dword yPelsPerMeter; /* Y pixels per meter */
79 dword clrUsed; /* # of colors used */
80 dword clrImportant; /* # of important colors */
81
82 /* This is followed by (1 << bitCount) bmp_quad structures, */
83 /* unless bitCount == 24. */
84
85 } bmp_info_header;
86
87 typedef struct bmp_quad_s {
88
89 /* RGBQUAD */
90
91 byte blue, green, red, reserved;
92
93 } bmp_quad;
94
95 /* Write the BMP file header. */
96 private int
write_bmp_depth_header(gx_device_printer * pdev,FILE * file,int depth,const byte * palette,int raster)97 write_bmp_depth_header(gx_device_printer *pdev, FILE *file, int depth,
98 const byte *palette /* [4 << depth] */,
99 int raster)
100 {
101 /* BMP scan lines are padded to 32 bits. */
102 ulong bmp_raster = raster + (-raster & 3);
103 int height = pdev->height;
104 int quads = (depth <= 8 ? sizeof(bmp_quad) << depth : 0);
105
106 /* Write the file header. */
107
108 fputc('B', file);
109 fputc('M', file);
110 {
111 bmp_file_header fhdr;
112
113 BMP_ASSIGN_DWORD(fhdr.size,
114 sizeof_bmp_file_header +
115 sizeof(bmp_info_header) + quads +
116 bmp_raster * height);
117 BMP_ASSIGN_WORD(fhdr.reserved1, 0);
118 BMP_ASSIGN_WORD(fhdr.reserved2, 0);
119 BMP_ASSIGN_DWORD(fhdr.offBits,
120 sizeof_bmp_file_header +
121 sizeof(bmp_info_header) + quads);
122 if (fwrite((const char *)&fhdr, 1, sizeof(fhdr), file) != sizeof(fhdr))
123 return_error(gs_error_ioerror);
124 }
125
126 /* Write the info header. */
127
128 {
129 bmp_info_header ihdr;
130
131 BMP_ASSIGN_DWORD(ihdr.size, sizeof(ihdr));
132 BMP_ASSIGN_DWORD(ihdr.width, pdev->width);
133 BMP_ASSIGN_DWORD(ihdr.height, height);
134 BMP_ASSIGN_WORD(ihdr.planes, 1);
135 BMP_ASSIGN_WORD(ihdr.bitCount, depth);
136 BMP_ASSIGN_DWORD(ihdr.compression, 0);
137 BMP_ASSIGN_DWORD(ihdr.sizeImage, bmp_raster * height);
138 /*
139 * Earlier versions of this driver set the PelsPerMeter values
140 * to zero. At a user's request, we now set them correctly,
141 * but we suspect this will cause problems other places.
142 */
143 #define INCHES_PER_METER (100 /*cm/meter*/ / 2.54 /*cm/inch*/)
144 BMP_ASSIGN_DWORD(ihdr.xPelsPerMeter,
145 (dword)(pdev->x_pixels_per_inch * INCHES_PER_METER + 0.5));
146 BMP_ASSIGN_DWORD(ihdr.yPelsPerMeter,
147 (dword)(pdev->y_pixels_per_inch * INCHES_PER_METER + 0.5));
148 #undef INCHES_PER_METER
149 BMP_ASSIGN_DWORD(ihdr.clrUsed, 0);
150 BMP_ASSIGN_DWORD(ihdr.clrImportant, 0);
151 if (fwrite((const char *)&ihdr, 1, sizeof(ihdr), file) != sizeof(ihdr))
152 return_error(gs_error_ioerror);
153 }
154
155 /* Write the palette. */
156
157 if (depth <= 8)
158 fwrite(palette, sizeof(bmp_quad), 1 << depth, file);
159
160 return 0;
161 }
162
163 /* Write the BMP file header. */
164 int
write_bmp_header(gx_device_printer * pdev,FILE * file)165 write_bmp_header(gx_device_printer *pdev, FILE *file)
166 {
167 int depth = pdev->color_info.depth;
168 bmp_quad palette[256];
169
170 if (depth <= 8) {
171 int i;
172 gx_color_value rgb[3];
173 bmp_quad q;
174
175 q.reserved = 0;
176 for (i = 0; i != 1 << depth; i++) {
177 /* Note that the use of map_color_rgb is deprecated in
178 favor of decode_color. This should work, though, because
179 backwards compatibility is preserved. */
180 (*dev_proc(pdev, map_color_rgb))((gx_device *)pdev,
181 (gx_color_index)i, rgb);
182 q.red = gx_color_value_to_byte(rgb[0]);
183 q.green = gx_color_value_to_byte(rgb[1]);
184 q.blue = gx_color_value_to_byte(rgb[2]);
185 palette[i] = q;
186 }
187 }
188 return write_bmp_depth_header(pdev, file, depth, (const byte *)palette,
189 gdev_prn_raster(pdev));
190 }
191
192 /* Write a BMP header for separated CMYK output. */
193 int
write_bmp_separated_header(gx_device_printer * pdev,FILE * file)194 write_bmp_separated_header(gx_device_printer *pdev, FILE *file)
195 {
196 int depth = pdev->color_info.depth;
197 int plane_depth = depth / 4;
198 bmp_quad palette[256];
199 bmp_quad q;
200 int i;
201
202 q.reserved = 0;
203 for (i = 0; i < 1 << plane_depth; i++) {
204 q.red = q.green = q.blue =
205 255 - i * 255 / ((1 << plane_depth) - 1);
206 palette[i] = q;
207 }
208 return write_bmp_depth_header(pdev, file, plane_depth,
209 (const byte *)palette,
210 (pdev->width*plane_depth + 7) >> 3);
211 }
212
213 /* 24-bit color mappers (taken from gdevmem2.c). */
214 /* Note that Windows expects RGB values in the order B,G,R. */
215
216 /* Map a r-g-b color to a color index. */
217 gx_color_index
bmp_map_16m_rgb_color(gx_device * dev,const gx_color_value cv[])218 bmp_map_16m_rgb_color(gx_device * dev, const gx_color_value cv[])
219 {
220
221 gx_color_value r, g, b;
222 r = cv[0]; g = cv[1]; b = cv[2];
223 return gx_color_value_to_byte(r) +
224 ((uint) gx_color_value_to_byte(g) << 8) +
225 ((ulong) gx_color_value_to_byte(b) << 16);
226 }
227
228 /* Map a color index to a r-g-b color. */
229 int
bmp_map_16m_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])230 bmp_map_16m_color_rgb(gx_device * dev, gx_color_index color,
231 gx_color_value prgb[3])
232 {
233 prgb[2] = gx_color_value_from_byte(color >> 16);
234 prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
235 prgb[0] = gx_color_value_from_byte(color & 0xff);
236 return 0;
237 }
238