Coverage Report

Created: 2025-06-24 07:01

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