Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : /*
4 : : MIT License
5 : :
6 : : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7 : :
8 : : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : of this software and associated documentation files (the "Software"), to deal
10 : : in the Software without restriction, including without limitation the rights
11 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : copies of the Software, and to permit persons to whom the Software is
13 : : furnished to do so, subject to the following conditions:
14 : :
15 : : The above copyright notice and this permission notice shall be included in all
16 : : copies or substantial portions of the Software.
17 : :
18 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : : SOFTWARE.
25 : : */
26 : :
27 : : // ezBmp is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 : :
29 : : #ifndef EZ_BMP
30 : : #define EZ_BMP
31 : : #endif // EZ_BMP
32 : :
33 : : #include <fstream>
34 : : #include <vector>
35 : : #include <cstdint>
36 : : #include <stdexcept>
37 : : #include <string>
38 : :
39 : : namespace ez {
40 : : namespace img {
41 : :
42 : : /*
43 : : Bitmap picture file saver
44 : :
45 : : ez::img::Bmp()
46 : : .setSize(10,10) // width, height 10
47 : : .setPixel(0,0,255,100,200) // byte form
48 : : .setPixel(5,5,0.5,0.2,0.8) // linear float form
49 : : .save("test.bmp"); // save to file test.bmp
50 : : */
51 : :
52 : : class Bmp {
53 : : friend class TestBmp;
54 : :
55 : : private:
56 : : uint32_t m_width{};
57 : : uint32_t m_height{};
58 : : std::vector<uint8_t> m_pixels;
59 : :
60 : : public:
61 : 1 : Bmp() = default;
62 : 1 : ~Bmp() = default;
63 : :
64 : 1 : Bmp& setSize(uint32_t vWidth, uint32_t vHeight) {
65 : 1 : m_width = std::move(vWidth);
66 : 1 : m_height = std::move(vHeight);
67 : 1 : m_pixels.resize(m_width * m_height * 3U);
68 : 1 : return *this;
69 : 1 : }
70 : :
71 : 0 : Bmp& clear() {
72 : 0 : m_width = 0U;
73 : 0 : m_height = 0U;
74 : 0 : m_pixels.clear();
75 : 0 : return *this;
76 : 0 : }
77 : :
78 : 10000 : Bmp& setPixel(int32_t vX, int32_t vY, int32_t vRed, int32_t vGreen, int32_t vBlue) {
79 : 10000 : auto x = static_cast<uint32_t>(vX);
80 : 10000 : auto y = static_cast<uint32_t>(vY);
81 [ + - ][ + - ]: 10000 : if (x >= 0 && y < m_width && y >= 0U && x < m_height) {
[ + - ][ + - ]
82 : 10000 : size_t index = static_cast<size_t>((vY * m_width + vX) * 3);
83 : : // BMP save color in BGR
84 : 10000 : m_pixels[index++] = m_getByteFromInt32(vBlue);
85 : 10000 : m_pixels[index++] = m_getByteFromInt32(vGreen);
86 : 10000 : m_pixels[index] = m_getByteFromInt32(vRed);
87 : 10000 : }
88 : 10000 : return *this;
89 : 10000 : }
90 : :
91 : 0 : Bmp& setPixel(int32_t vX, int32_t vY, float vRed, float vGreen, float vBlue) {
92 : 0 : return setPixel(vX, //
93 : 0 : vY,
94 : 0 : m_getByteFromLinearFloat(vRed),
95 : 0 : m_getByteFromLinearFloat(vGreen),
96 : 0 : m_getByteFromLinearFloat(vBlue));
97 : 0 : }
98 : :
99 : : // Sauvegarde l'image en tant que fichier BMP
100 : 1 : Bmp& write(const std::string& filename) {
101 : 1 : std::ofstream file(filename, std::ios::binary);
102 [ - + ]: 1 : if (!file) {
103 : 0 : throw std::runtime_error("Impossible d'ouvrir le fichier.");
104 : 0 : }
105 : :
106 : 1 : int paddingSize = (4 - (m_width * 3) % 4) % 4;
107 : 1 : int fileSize = 54 + (m_width * m_height * 3) + (m_height * paddingSize);
108 : :
109 : : // En-t�te de fichier BMP
110 : 1 : uint8_t fileHeader[14] = {
111 : 1 : 'B',
112 : 1 : 'M', // Signature
113 : 1 : 0,
114 : 1 : 0,
115 : 1 : 0,
116 : 1 : 0, // Taille du fichier
117 : 1 : 0,
118 : 1 : 0,
119 : 1 : 0,
120 : 1 : 0, // R�serv�
121 : 1 : 54,
122 : 1 : 0,
123 : 1 : 0,
124 : 1 : 0 // Offset vers les donn�es d'image
125 : 1 : };
126 : :
127 : : // Ins�rer la taille du fichier dans l'en-t�te
128 : 1 : fileHeader[2] = fileSize;
129 : 1 : fileHeader[3] = fileSize >> 8;
130 : 1 : fileHeader[4] = fileSize >> 16;
131 : 1 : fileHeader[5] = fileSize >> 24;
132 : :
133 : : // En-t�te d'information BMP
134 : 1 : uint8_t infoHeader[40] = {
135 : 1 : 40, 0, 0, 0, // Taille de l'en-t�te d'information
136 : 1 : 0, 0, 0, 0, // Largeur
137 : 1 : 0, 0, 0, 0, // Hauteur
138 : 1 : 1, 0, // Nombre de plans (1)
139 : 1 : 24, 0, // Bits par pixel (24 bits)
140 : 1 : 0, 0, 0, 0, // Compression (aucune)
141 : 1 : 0, 0, 0, 0, // Taille de l'image (non compress�e)
142 : 1 : 0, 0, 0, 0, // R�solution horizontale (pixels par m�tre)
143 : 1 : 0, 0, 0, 0, // R�solution verticale (pixels par m�tre)
144 : 1 : 0, 0, 0, 0, // Couleurs dans la palette
145 : 1 : 0, 0, 0, 0 // Couleurs importantes
146 : 1 : };
147 : :
148 : : // Ins�rer la largeur et la hauteur dans l'en-t�te d'information
149 : 1 : infoHeader[4] = m_width;
150 : 1 : infoHeader[5] = m_width >> 8;
151 : 1 : infoHeader[6] = m_width >> 16;
152 : 1 : infoHeader[7] = m_width >> 24;
153 : 1 : infoHeader[8] = m_height;
154 : 1 : infoHeader[9] = m_height >> 8;
155 : 1 : infoHeader[10] = m_height >> 16;
156 : 1 : infoHeader[11] = m_height >> 24;
157 : :
158 : : // �crire les en-t�tes dans le fichier
159 : 1 : file.write(reinterpret_cast<char*>(fileHeader), sizeof(fileHeader));
160 : 1 : file.write(reinterpret_cast<char*>(infoHeader), sizeof(infoHeader));
161 : :
162 : : // �crire les donn�es des pixels
163 [ + + ]: 101 : for (int32_t y = static_cast<int32_t>(m_height - 1); y >= 0; --y) { // BMP commence du bas vers le haut
164 [ + + ]: 10100 : for (int32_t x = 0; x < static_cast<int32_t>(m_width); ++x) {
165 : 10000 : size_t index = static_cast<size_t>((y * m_width + x) * 3);
166 : 10000 : file.write(reinterpret_cast<char*>(&m_pixels[index]), 3);
167 : 10000 : }
168 : : // Ajout de padding si n�cessaire
169 : 100 : uint8_t padding[3] = {0, 0, 0};
170 : 100 : file.write(reinterpret_cast<char*>(padding), paddingSize);
171 : 100 : }
172 : :
173 : 1 : file.close();
174 : 1 : return *this;
175 : 1 : }
176 : :
177 : : private:
178 : 30000 : uint8_t m_getByteFromInt32(int32_t vValue) {
179 [ - + ]: 30000 : if (vValue < 0) {
180 : 0 : vValue = 0;
181 : 0 : }
182 [ - + ]: 30000 : if (vValue > 255) {
183 : 0 : vValue = 255;
184 : 0 : }
185 : 30000 : return static_cast<uint8_t>(vValue);
186 : 30000 : }
187 : 0 : uint8_t m_getByteFromLinearFloat(float vValue) {
188 : 0 : if (vValue < 0.0f) {
189 : 0 : vValue = 0.0f;
190 : 0 : }
191 : 0 : if (vValue > 1.0f) {
192 : 0 : vValue = 1.0f;
193 : 0 : }
194 : 0 : return static_cast<uint8_t>(vValue * 255.0f);
195 : 0 : }
196 : : };
197 : :
198 : : } // namespace img
199 : : } // namespace ez
|