Coverage Report

Created: 2025-06-24 07:01

/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
}