OpenTTD Source 20250312-master-gcdcc6b491d
screenshot_pcx.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "core/endian_func.hpp"
12#include "core/math_func.hpp"
13#include "debug.h"
14#include "fileio_func.h"
15#include "screenshot_type.h"
16
17#include "safeguards.h"
18
19
21struct PcxHeader {
22 uint8_t manufacturer;
23 uint8_t version;
24 uint8_t rle;
25 uint8_t bpp;
26 uint32_t unused;
27 uint16_t xmax, ymax;
28 uint16_t hdpi, vdpi;
29 uint8_t pal_small[16 * 3];
30 uint8_t reserved;
31 uint8_t planes;
32 uint16_t pitch;
33 uint16_t cpal;
34 uint16_t width;
35 uint16_t height;
36 uint8_t filler[54];
37};
38static_assert(sizeof(PcxHeader) == 128);
39
41public:
42 ScreenshotProvider_Pcx() : ScreenshotProvider("pcx", "PCX", 20) {}
43
44 bool MakeImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) override
45 {
46 uint maxlines;
47 uint y;
48 PcxHeader pcx;
49 bool success;
50
51 if (pixelformat == 32) {
52 Debug(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick another format.");
53 return false;
54 }
55 if (pixelformat != 8 || w == 0) return false;
56
57 auto of = FileHandle::Open(name, "wb");
58 if (!of.has_value()) return false;
59 auto &f = *of;
60
61 memset(&pcx, 0, sizeof(pcx));
62
63 /* setup pcx header */
64 pcx.manufacturer = 10;
65 pcx.version = 5;
66 pcx.rle = 1;
67 pcx.bpp = 8;
68 pcx.xmax = TO_LE16(w - 1);
69 pcx.ymax = TO_LE16(h - 1);
70 pcx.hdpi = TO_LE16(320);
71 pcx.vdpi = TO_LE16(320);
72
73 pcx.planes = 1;
74 pcx.cpal = TO_LE16(1);
75 pcx.width = pcx.pitch = TO_LE16(w);
76 pcx.height = TO_LE16(h);
77
78 /* write pcx header */
79 if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
80 return false;
81 }
82
83 /* use by default 64k temp memory */
84 maxlines = Clamp(65536 / w, 16, 128);
85
86 /* now generate the bitmap bits */
87 std::vector<uint8_t> buff(static_cast<size_t>(w) * maxlines); // by default generate 128 lines at a time.
88
89 y = 0;
90 do {
91 /* determine # lines to write */
92 uint n = std::min(h - y, maxlines);
93 uint i;
94
95 /* render the pixels into the buffer */
96 callb(userdata, buff.data(), y, w, n);
97 y += n;
98
99 /* write them to pcx */
100 for (i = 0; i != n; i++) {
101 const uint8_t *bufp = buff.data() + i * w;
102 uint8_t runchar = bufp[0];
103 uint runcount = 1;
104 uint j;
105
106 /* for each pixel... */
107 for (j = 1; j < w; j++) {
108 uint8_t ch = bufp[j];
109
110 if (ch != runchar || runcount >= 0x3f) {
111 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
112 if (fputc(0xC0 | runcount, f) == EOF) {
113 return false;
114 }
115 }
116 if (fputc(runchar, f) == EOF) {
117 return false;
118 }
119 runcount = 0;
120 runchar = ch;
121 }
122 runcount++;
123 }
124
125 /* write remaining bytes.. */
126 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
127 if (fputc(0xC0 | runcount, f) == EOF) {
128 return false;
129 }
130 }
131 if (fputc(runchar, f) == EOF) {
132 return false;
133 }
134 }
135 } while (y != h);
136
137 /* write 8-bit colour palette */
138 if (fputc(12, f) == EOF) {
139 return false;
140 }
141
142 /* Palette is word-aligned, copy it to a temporary byte array */
143 uint8_t tmp[256 * 3];
144
145 for (uint i = 0; i < 256; i++) {
146 tmp[i * 3 + 0] = palette[i].r;
147 tmp[i * 3 + 1] = palette[i].g;
148 tmp[i * 3 + 2] = palette[i].b;
149 }
150 success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
151
152 return success;
153 }
154};
155
156static ScreenshotProvider_Pcx s_screenshot_provider_pcx;
static std::optional< FileHandle > Open(const std::string &filename, const std::string &mode)
Open an RAII file handle if possible.
Definition fileio.cpp:1170
Base interface for a SoundLoader implementation.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Function to handling different endian machines.
Functions for Standard In/Out file operations.
Integer math functions.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
A number of safeguards to prevent using unsafe methods.
Types related to screenshot providers.
void(void *userdata, void *buf, uint y, uint pitch, uint n) ScreenshotCallback
Callback function signature for generating lines of pixel data to be written to the screenshot file.
Definition of base types and functions in a cross-platform compatible way.
Definition of a PCX file header.