1 //--------------------------------------------------------------------------
2 // Name: src/bitmap_ex.h
3 // Purpose: Helper functions and etc. for copying bitmap data to/from
4 // buffer objects. This file is included in etg/bitmap.py and
5 // used in the wxBitmap wrapper.
6 //
7 // Author: Robin Dunn
8 //
9 // Created: 27-Apr-2012
10 // Copyright: (c) 2012-2018 by Total Control Software
11 // Licence: wxWindows license
12 //--------------------------------------------------------------------------
13
14
15 #include <wx/rawbmp.h>
16
17 // TODO: Switch these APIs to use the new wxPyBuffer class
18
wxPyCopyBitmapFromBuffer(wxBitmap * bmp,buffer data,Py_ssize_t DATASIZE,wxBitmapBufferFormat format,int stride)19 void wxPyCopyBitmapFromBuffer(wxBitmap* bmp,
20 buffer data, Py_ssize_t DATASIZE,
21 wxBitmapBufferFormat format, int stride)
22 {
23 int height = bmp->GetHeight();
24 int width = bmp->GetWidth();
25
26 switch (format) {
27 // A simple sequence of RGB bytes
28 case wxBitmapBufferFormat_RGB:
29 {
30 if (DATASIZE < width * height * 3) {
31 wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
32 return;
33 }
34 wxNativePixelData pixData(*bmp, wxPoint(0,0), wxSize(width, height));
35 if (! pixData) {
36 wxPyErr_SetString(PyExc_RuntimeError,
37 "Failed to gain raw access to bitmap data.");
38 return;
39 }
40
41 wxNativePixelData::Iterator p(pixData);
42 for (int y=0; y<height; y++) {
43 wxNativePixelData::Iterator rowStart = p;
44 for (int x=0; x<width; x++) {
45 p.Red() = *(data++);
46 p.Green() = *(data++);
47 p.Blue() = *(data++);
48 ++p;
49 }
50 p = rowStart;
51 p.OffsetY(pixData, 1);
52 }
53 break;
54 }
55
56 // A simple sequence of RGBA bytes
57 case wxBitmapBufferFormat_RGBA:
58 {
59 if (DATASIZE < width * height * 4) {
60 wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
61 return;
62 }
63 wxAlphaPixelData pixData(*bmp, wxPoint(0,0), wxSize(width, height));
64 if (! pixData) {
65 wxPyErr_SetString(PyExc_RuntimeError,
66 "Failed to gain raw access to bitmap data.");
67 return;
68 }
69 wxAlphaPixelData::Iterator p(pixData);
70 for (int y=0; y<height; y++) {
71 wxAlphaPixelData::Iterator rowStart = p;
72 for (int x=0; x<width; x++) {
73 byte a = data[3];
74 p.Red() = wxPy_premultiply(*(data++), a);
75 p.Green() = wxPy_premultiply(*(data++), a);
76 p.Blue() = wxPy_premultiply(*(data++), a);
77 p.Alpha() = a; data++;
78 ++p;
79 }
80 p = rowStart;
81 p.OffsetY(pixData, 1);
82 }
83 break;
84 }
85
86 // A sequence of 32-bit values in native endian order,
87 // where the alpha is in the upper 8 bits, then red, then
88 // green, then blue. The stride is the distance in bytes
89 // from the beginning of one row of the image data to the
90 // beginning of the next row. This may not be the same as
91 // width*4 if alignment or platform specific optimizations
92 // have been utilized.
93
94 // NOTE: This is normally used with Cairo, which seems to
95 // already have the values premultiplied. Should we have
96 // a way to optionally do it anyway?
97
98 case wxBitmapBufferFormat_RGB32:
99 case wxBitmapBufferFormat_ARGB32:
100 {
101 bool useAlpha = (format == wxBitmapBufferFormat_ARGB32);
102 byte* rowStart = data;
103 wxUint32* bufptr;
104 wxUint32 value;
105
106 if (stride == -1)
107 stride = width * 4;
108
109 if (DATASIZE < stride * height) {
110 wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
111 return;
112 }
113
114 wxAlphaPixelData pixData(*bmp, wxPoint(0,0), wxSize(width,height));
115 if (! pixData) {
116 wxPyErr_SetString(PyExc_RuntimeError,
117 "Failed to gain raw access to bitmap data.");
118 return;
119 }
120
121 wxAlphaPixelData::Iterator pix(pixData);
122 for (int y=0; y<height; y++) {
123 pix.MoveTo(pixData, 0, y);
124 bufptr = (wxUint32*)rowStart;
125 for (int x=0; x<width; x++) {
126 value = *bufptr;
127 pix.Alpha() = useAlpha ? (value >> 24) & 0xFF : 255;
128 pix.Red() = (value >> 16) & 0xFF;
129 pix.Green() = (value >> 8) & 0xFF;
130 pix.Blue() = (value >> 0) & 0xFF;
131 ++pix;
132 ++bufptr;
133 }
134 rowStart += stride;
135 }
136 break;
137 }
138 }
139 }
140
141
142 // Some helper macros used below to help declutter the code
143 #define MAKE_PIXDATA(type) \
144 type pixData(*bmp, wxPoint(0,0), wxSize(width, height)); \
145 if (! pixData) { \
146 wxPyErr_SetString(PyExc_RuntimeError, "Failed to gain raw access to bitmap data."); \
147 return; \
148 } \
149 type::Iterator p(pixData); \
150 type::Iterator rowStart
151
152 #define CHECK_BUFFERSIZE(size_needed) \
153 if (DATASIZE < size_needed) { \
154 wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size."); \
155 return; \
156 }
157
158
wxPyCopyBitmapToBuffer(wxBitmap * bmp,buffer data,Py_ssize_t DATASIZE,wxBitmapBufferFormat format,int stride)159 void wxPyCopyBitmapToBuffer(wxBitmap* bmp,
160 buffer data, Py_ssize_t DATASIZE,
161 wxBitmapBufferFormat format, int stride)
162 {
163 int height = bmp->GetHeight();
164 int width = bmp->GetWidth();
165 int depth = bmp->GetDepth();
166
167 // images loaded from a file may not have set the depth, at least on Mac...
168 if (depth == -1) {
169 if (bmp->HasAlpha())
170 depth = 32;
171 else
172 depth = 24;
173 }
174
175 switch (format) {
176 // A simple sequence of RGB bytes
177 case wxBitmapBufferFormat_RGB:
178 {
179 CHECK_BUFFERSIZE(width * height * 3);
180 if (depth == 24) {
181 MAKE_PIXDATA(wxNativePixelData);
182
183 for (int y=0; y<height; y++) {
184 rowStart = p;
185 for (int x=0; x<width; x++) {
186 *(data++) = p.Red();
187 *(data++) = p.Green();
188 *(data++) = p.Blue();
189 ++p;
190 }
191 p = rowStart;
192 p.OffsetY(pixData, 1);
193 }
194 }
195 if (depth == 32) {
196 // Source has alpha, but we won't be using it because the
197 // destination buffer doesn't
198 MAKE_PIXDATA(wxAlphaPixelData);
199
200 for (int y=0; y<height; y++) {
201 rowStart = p;
202 for (int x=0; x<width; x++) {
203 *(data++) = p.Red();
204 *(data++) = p.Green();
205 *(data++) = p.Blue();
206 ++p;
207 }
208 p = rowStart;
209 p.OffsetY(pixData, 1);
210 }
211 }
212 break;
213 }
214
215 // A simple sequence of RGBA bytes
216 case wxBitmapBufferFormat_RGBA:
217 {
218 CHECK_BUFFERSIZE(width * height * 4);
219 if (depth == 24) {
220 MAKE_PIXDATA(wxNativePixelData);
221 for (int y=0; y<height; y++) {
222 rowStart = p;
223 for (int x=0; x<width; x++) {
224 byte a = wxALPHA_OPAQUE;
225 *(data++) = wxPy_unpremultiply(p.Red(), a);
226 *(data++) = wxPy_unpremultiply(p.Green(), a);
227 *(data++) = wxPy_unpremultiply(p.Blue(), a);
228 *(data++) = a;
229 ++p;
230 }
231 p = rowStart;
232 p.OffsetY(pixData, 1);
233 }
234 }
235 if (depth == 32) {
236 MAKE_PIXDATA(wxAlphaPixelData);
237 for (int y=0; y<height; y++) {
238 rowStart = p;
239 for (int x=0; x<width; x++) {
240 byte a = p.Alpha();
241 *(data++) = wxPy_unpremultiply(p.Red(), a);
242 *(data++) = wxPy_unpremultiply(p.Green(), a);
243 *(data++) = wxPy_unpremultiply(p.Blue(), a);
244 *(data++) = a;
245 ++p;
246 }
247 p = rowStart;
248 p.OffsetY(pixData, 1);
249 }
250 }
251 break;
252 }
253
254 // A sequence of 32-bit values in native endian order,
255 // where the alpha is in the upper 8 bits, then red, then
256 // green, then blue. The stride is the distance in bytes
257 // from the beginning of one row of the image data to the
258 // beginning of the next row. This may not be the same as
259 // width*4 if alignment or platform specific optimizations
260 // have been utilized.
261
262 // NOTE: This is normally used with Cairo, which seems to
263 // already have the values premultiplied. Should we have
264 // a way to optionally do it anyway?
265
266 case wxBitmapBufferFormat_RGB32:
267 case wxBitmapBufferFormat_ARGB32:
268 {
269 bool useAlpha = (format == wxBitmapBufferFormat_ARGB32);
270 byte* dataRow = data;
271 wxUint32* bufptr;
272 wxUint32 value;
273
274 if (stride == -1)
275 stride = width * 4;
276
277 CHECK_BUFFERSIZE(stride * height);
278
279 if (useAlpha && depth == 32) {
280 MAKE_PIXDATA(wxAlphaPixelData);
281 for (int y=0; y<height; y++) {
282 p.MoveTo(pixData, 0, y);
283 bufptr = (wxUint32*)dataRow;
284 for (int x=0; x<width; x++) {
285 value =
286 (p.Alpha() << 24) |
287 (p.Red() << 16) |
288 (p.Green() << 8) |
289 (p.Blue());
290 *bufptr = value;
291 ++p;
292 ++bufptr;
293 }
294 dataRow += stride;
295 }
296 }
297 else // if (!useAlpha /*depth == 24*/)
298 {
299 MAKE_PIXDATA(wxNativePixelData);
300 for (int y=0; y<height; y++) {
301 p.MoveTo(pixData, 0, y);
302 bufptr = (wxUint32*)dataRow;
303 for (int x=0; x<width; x++) {
304 value =
305 (wxALPHA_OPAQUE << 24) |
306 (p.Red() << 16) |
307 (p.Green() << 8) |
308 (p.Blue());
309 *bufptr = value;
310 ++p;
311 ++bufptr;
312 }
313 dataRow += stride;
314 }
315 }
316 break;
317 }
318 }
319 }
320
321 //--------------------------------------------------------------------------
322