/src/libwpg/src/lib/WPGBitmap.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwpg |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * Major Contributor(s): |
10 | | * Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) |
11 | | * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) |
12 | | * |
13 | | * For minor contributions see the git repository. |
14 | | * |
15 | | * Alternatively, the contents of this file may be used under the terms |
16 | | * of the GNU Lesser General Public License Version 2.1 or later |
17 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
18 | | * applicable instead of those above. |
19 | | * |
20 | | * For further information visit http://libwpg.sourceforge.net |
21 | | */ |
22 | | |
23 | | /* "This product is not manufactured, approved, or supported by |
24 | | * Corel Corporation or Corel Corporation Limited." |
25 | | */ |
26 | | |
27 | | #include "WPGBitmap.h" |
28 | | |
29 | | #include <cassert> |
30 | | #include <vector> |
31 | | |
32 | | #include "libwpg_utils.h" |
33 | | |
34 | | #define DUMP_BITMAP 0 |
35 | | |
36 | | #if DUMP_BITMAP |
37 | | static unsigned bitmapId = 0; |
38 | | #include <sstream> |
39 | | #endif |
40 | | |
41 | | namespace |
42 | | { |
43 | | |
44 | | void writeU8(std::vector<unsigned char> &buffer, const int value) |
45 | 0 | { |
46 | 0 | buffer.push_back(static_cast<unsigned char>(value & 0xFF)); |
47 | 0 | } |
48 | | |
49 | | void writeU16(std::vector<unsigned char> &buffer, const int value) |
50 | 0 | { |
51 | 0 | writeU8(buffer, value & 0xFF); |
52 | 0 | writeU8(buffer, (value >> 8) & 0xFF); |
53 | 0 | } |
54 | | |
55 | | void writeU32(std::vector<unsigned char> &buffer, const int value) |
56 | 0 | { |
57 | 0 | writeU8(buffer, value & 0xFF); |
58 | 0 | writeU8(buffer, (value >> 8) & 0xFF); |
59 | 0 | writeU8(buffer, (value >> 16) & 0xFF); |
60 | 0 | writeU8(buffer, (value >> 24) & 0xFF); |
61 | 0 | } |
62 | | |
63 | | } |
64 | | |
65 | | class libwpg::WPGBitmap::Private |
66 | | { |
67 | | public: |
68 | | int width; |
69 | | int height; |
70 | | int vRes; |
71 | | int hRes; |
72 | | bool vFlip; |
73 | | bool hFlip; |
74 | | std::unique_ptr<WPGColor[]> pixels; |
75 | | librevenge::RVNGBinaryData dib; |
76 | | |
77 | 0 | Private(int w, int h): width(w), height(h), vRes(72), hRes(72), vFlip(false), hFlip(false), pixels(nullptr), dib() {} |
78 | | private: |
79 | | // Unimplemented to prevent compiler from creating crasher ones |
80 | | Private(const Private &); |
81 | | Private &operator=(const Private &); |
82 | | }; |
83 | | |
84 | | libwpg::WPGBitmap::WPGBitmap(int w, int h, int verticalResolution, int horizontalResolution, bool verticalFlip, bool horizontalFlip) : |
85 | 0 | d(new Private(w, h)) |
86 | 0 | { |
87 | 0 | assert(w >= 0); |
88 | 0 | assert(h >= 0); |
89 | 0 | d->vRes = verticalResolution; |
90 | 0 | d->hRes = horizontalResolution; |
91 | 0 | d->vFlip = verticalFlip; |
92 | 0 | d->hFlip = horizontalFlip; |
93 | 0 | d->pixels.reset(new WPGColor[unsigned(w) * unsigned(h)]); |
94 | 0 | } |
95 | | |
96 | | libwpg::WPGBitmap::~WPGBitmap() |
97 | 0 | { |
98 | 0 | } |
99 | | |
100 | 0 | libwpg::WPGBitmap::WPGBitmap(const WPGBitmap &bitmap): d(new Private(0,0)) |
101 | 0 | { |
102 | 0 | copyFrom(bitmap); |
103 | 0 | } |
104 | | |
105 | | libwpg::WPGBitmap &libwpg::WPGBitmap::operator=(const WPGBitmap &bitmap) |
106 | 0 | { |
107 | 0 | if (this != &bitmap) |
108 | 0 | copyFrom(bitmap); |
109 | 0 | return *this; |
110 | 0 | } |
111 | | |
112 | | void libwpg::WPGBitmap::copyFrom(const WPGBitmap &bitmap) |
113 | 0 | { |
114 | 0 | d->width = bitmap.d->width; |
115 | 0 | d->height = bitmap.d->height; |
116 | 0 | d->pixels.reset(new WPGColor[d->width*d->height]); |
117 | 0 | for (int i=0; i < d->width*d->height; i++) |
118 | 0 | d->pixels[i] = bitmap.d->pixels[i]; |
119 | 0 | } |
120 | | |
121 | | int libwpg::WPGBitmap::width() const |
122 | 0 | { |
123 | 0 | return d->width; |
124 | 0 | } |
125 | | |
126 | | int libwpg::WPGBitmap::height() const |
127 | 0 | { |
128 | 0 | return d->height; |
129 | 0 | } |
130 | | |
131 | | int libwpg::WPGBitmap::vres() const |
132 | 0 | { |
133 | 0 | return d->vRes; |
134 | 0 | } |
135 | | |
136 | | int libwpg::WPGBitmap::hres() const |
137 | 0 | { |
138 | 0 | return d->hRes; |
139 | 0 | } |
140 | | |
141 | | void libwpg::WPGBitmap::setPixel(int x, int y, const libwpg::WPGColor &color) |
142 | 0 | { |
143 | 0 | if ((x < 0) || (y <0) || (x >= d->width) || (y >= d->height)) |
144 | 0 | return; |
145 | | |
146 | 0 | d->pixels[y *d->width + x] = color; |
147 | 0 | } |
148 | | |
149 | | const librevenge::RVNGBinaryData &libwpg::WPGBitmap::getDIB() const |
150 | 0 | { |
151 | 0 | if (d->dib.size() || d->height <= 0 || d->width <= 0) |
152 | 0 | return d->dib; |
153 | | |
154 | 0 | auto tmpPixelSize = (unsigned)(d->height * d->width); |
155 | 0 | if (tmpPixelSize < (unsigned)d->height) // overflow |
156 | 0 | return d->dib; |
157 | | |
158 | 0 | unsigned tmpDIBImageSize = tmpPixelSize * 4; |
159 | 0 | if (tmpPixelSize > tmpDIBImageSize) // overflow !!! |
160 | 0 | return d->dib; |
161 | | |
162 | 0 | unsigned tmpDIBOffsetBits = 14 + 40; |
163 | 0 | unsigned tmpDIBFileSize = tmpDIBOffsetBits + tmpDIBImageSize; |
164 | 0 | if (tmpDIBImageSize > tmpDIBFileSize) // overflow !!! |
165 | 0 | return d->dib; |
166 | | |
167 | 0 | std::vector<unsigned char> tmpDIBBuffer; |
168 | 0 | tmpDIBBuffer.reserve(tmpDIBFileSize); |
169 | | |
170 | | // Create DIB file header |
171 | 0 | writeU16(tmpDIBBuffer, 0x4D42); // Type |
172 | 0 | writeU32(tmpDIBBuffer, (int) tmpDIBFileSize); // Size |
173 | 0 | writeU16(tmpDIBBuffer, 0); // Reserved1 |
174 | 0 | writeU16(tmpDIBBuffer, 0); // Reserved2 |
175 | 0 | writeU32(tmpDIBBuffer, (int) tmpDIBOffsetBits); // OffsetBits |
176 | |
|
177 | 0 | WPG_DEBUG_MSG(("WPGBitmap: DIB file header end = %lu\n", static_cast<unsigned long>(tmpDIBBuffer.size() - 1))); |
178 | | |
179 | | // Create DIB Info header |
180 | 0 | writeU32(tmpDIBBuffer, 40); // Size |
181 | 0 | writeU32(tmpDIBBuffer, width()); // Width |
182 | 0 | writeU32(tmpDIBBuffer, height()); // Height |
183 | 0 | writeU16(tmpDIBBuffer, 1); // Planes |
184 | 0 | writeU16(tmpDIBBuffer, 32); // BitCount |
185 | 0 | writeU32(tmpDIBBuffer, 0); // Compression |
186 | 0 | writeU32(tmpDIBBuffer, (int)tmpDIBImageSize); // SizeImage |
187 | 0 | writeU32(tmpDIBBuffer, (int)(hres()*100.0/2.54)); // XPelsPerMeter |
188 | 0 | writeU32(tmpDIBBuffer, (int)(vres()*100.0/2.54)); // YPelsPerMeter |
189 | 0 | writeU32(tmpDIBBuffer, 0); // ColorsUsed |
190 | 0 | writeU32(tmpDIBBuffer, 0); // ColorsImportant |
191 | |
|
192 | 0 | WPG_DEBUG_MSG(("WPGBitmap: DIB info header end = %lu\n", static_cast<unsigned long>(tmpDIBBuffer.size() - 1))); |
193 | | |
194 | | // Write DIB Image data |
195 | |
|
196 | 0 | int i = 0; |
197 | 0 | int j = 0; |
198 | 0 | if (d->vFlip) |
199 | 0 | for (i = 0; i < d->height && tmpDIBBuffer.size() < tmpDIBFileSize; i++) |
200 | 0 | { |
201 | 0 | if (d->hFlip) |
202 | 0 | for (j = d->width - 1; j >= 0 && tmpDIBBuffer.size() < tmpDIBFileSize; j--) |
203 | 0 | { |
204 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].blue); |
205 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].green); |
206 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].red); |
207 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].alpha); |
208 | 0 | } |
209 | 0 | else |
210 | 0 | for (j = 0; j < d->width && tmpDIBBuffer.size() < tmpDIBFileSize; j++) |
211 | 0 | { |
212 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].blue); |
213 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].green); |
214 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].red); |
215 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].alpha); |
216 | 0 | } |
217 | 0 | } |
218 | 0 | else |
219 | 0 | for (i = d->height - 1; i >= 0 && tmpDIBBuffer.size() < tmpDIBFileSize; i--) |
220 | 0 | { |
221 | 0 | if (d->hFlip) |
222 | 0 | for (j = d->width - 1; j >= 0 && tmpDIBBuffer.size() < tmpDIBFileSize; j--) |
223 | 0 | { |
224 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].blue); |
225 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].green); |
226 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].red); |
227 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].alpha); |
228 | 0 | } |
229 | 0 | else |
230 | 0 | for (j = 0; j < d->width && tmpDIBBuffer.size() < tmpDIBFileSize; j++) |
231 | 0 | { |
232 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].blue); |
233 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].green); |
234 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].red); |
235 | 0 | writeU8(tmpDIBBuffer, d->pixels[i*d->width + j].alpha); |
236 | 0 | } |
237 | 0 | } |
238 | |
|
239 | 0 | WPG_DEBUG_MSG(("WPGBitmap: DIB file size = %lu\n", static_cast<unsigned long>(tmpDIBBuffer.size() - 1))); |
240 | |
|
241 | 0 | d->dib.append(tmpDIBBuffer.data(), tmpDIBBuffer.size()); |
242 | | |
243 | | // temporary for debug - dump the binary bmp (need to have write access in the current directory |
244 | | #if DUMP_BITMAP |
245 | | std::ostringstream filename; |
246 | | filename << "binarydump" << bitmapId++ << ".bmp"; |
247 | | FILE *f = fopen(filename.str().c_str(), "wb"); |
248 | | if (f) |
249 | | { |
250 | | for (size_t k = 0; k < tmpDIBBuffer.size(); k++) |
251 | | fprintf(f, "%c",tmpDIBBuffer[k]); |
252 | | fclose(f); |
253 | | } |
254 | | #endif |
255 | |
|
256 | 0 | return d->dib; |
257 | 0 | } |
258 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |