OpenTTD Source 20250522-master-g467f832c2f
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(std::string_view name, const ScreenshotCallback &callb, uint w, uint h, int pixelformat, const Colour *palette) override
45 {
46 uint maxlines;
47 uint y;
48 bool success;
49
50 if (pixelformat == 32) {
51 Debug(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick another format.");
52 return false;
53 }
54 if (pixelformat != 8 || w == 0) return false;
55
56 auto of = FileHandle::Open(name, "wb");
57 if (!of.has_value()) return false;
58 auto &f = *of;
59
60 /* setup pcx header */
61 PcxHeader pcx{};
62 pcx.manufacturer = 10;
63 pcx.version = 5;
64 pcx.rle = 1;
65 pcx.bpp = 8;
66 pcx.xmax = TO_LE16(w - 1);
67 pcx.ymax = TO_LE16(h - 1);
68 pcx.hdpi = TO_LE16(320);
69 pcx.vdpi = TO_LE16(320);
70
71 pcx.planes = 1;
72 pcx.cpal = TO_LE16(1);
73 pcx.width = pcx.pitch = TO_LE16(w);
74 pcx.height = TO_LE16(h);
75
76 /* write pcx header */
77 if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
78 return false;
79 }
80
81 /* use by default 64k temp memory */
82 maxlines = Clamp(65536 / w, 16, 128);
83
84 /* now generate the bitmap bits */
85 std::vector<uint8_t> buff(static_cast<size_t>(w) * maxlines); // by default generate 128 lines at a time.
86
87 y = 0;
88 do {
89 /* determine # lines to write */
90 uint n = std::min(h - y, maxlines);
91 uint i;
92
93 /* render the pixels into the buffer */
94 callb(buff.data(), y, w, n);
95 y += n;
96
97 /* write them to pcx */
98 for (i = 0; i != n; i++) {
99 const uint8_t *bufp = buff.data() + i * w;
100 uint8_t runchar = bufp[0];
101 uint runcount = 1;
102 uint j;
103
104 /* for each pixel... */
105 for (j = 1; j < w; j++) {
106 uint8_t ch = bufp[j];
107
108 if (ch != runchar || runcount >= 0x3f) {
109 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
110 if (fputc(0xC0 | runcount, f) == EOF) {
111 return false;
112 }
113 }
114 if (fputc(runchar, f) == EOF) {
115 return false;
116 }
117 runcount = 0;
118 runchar = ch;
119 }
120 runcount++;
121 }
122
123 /* write remaining bytes.. */
124 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
125 if (fputc(0xC0 | runcount, f) == EOF) {
126 return false;
127 }
128 }
129 if (fputc(runchar, f) == EOF) {
130 return false;
131 }
132 }
133 } while (y != h);
134
135 /* write 8-bit colour palette */
136 if (fputc(12, f) == EOF) {
137 return false;
138 }
139
140 /* Palette is word-aligned, copy it to a temporary byte array */
141 uint8_t tmp[256 * 3];
142
143 for (uint i = 0; i < 256; i++) {
144 tmp[i * 3 + 0] = palette[i].r;
145 tmp[i * 3 + 1] = palette[i].g;
146 tmp[i * 3 + 2] = palette[i].b;
147 }
148 success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
149
150 return success;
151 }
152};
153
154static const ScreenshotProvider_Pcx s_screenshot_provider_pcx;
static std::optional< FileHandle > Open(const std::string &filename, std::string_view mode)
Open an RAII file handle if possible.
Definition fileio.cpp:1168
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.
std::function< void(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.