Lumitronix_Iflex_Pro_Workshop
Library to interact with the iFlexPro
NeoBitmapFile.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2 NeoBitmapFile
3 
4 Written by Michael C. Miller.
5 
6 I invest time and resources providing this open source code,
7 please support me by dontating (see https://github.com/Makuna)
8 
9 -------------------------------------------------------------------------
10 This file is part of the LUMITRONIX_iFlex_Workshop library.
11 
12 LumitronixIFlexBus is free software: you can redistribute it and/or modify
13 it under the terms of the GNU Lesser General Public License as
14 published by the Free Software Foundation, either version 3 of
15 the License, or (at your option) any later version.
16 
17 LumitronixIFlexBus is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU Lesser General Public License for more details.
21 
22 You should have received a copy of the GNU Lesser General Public
23 License along with LumitronixIFlex. If not, see
24 <http://www.gnu.org/licenses/>.
25 -------------------------------------------------------------------------*/
26 #pragma once
27 
28 const uint16_t c_BitmapFileId = 0x4d42; // "BM"
29 
30 #pragma pack(push, 2)
32 {
33  uint16_t FileId; // only c_BitmapFileId is supported
34  uint32_t FileSize;
35  uint16_t Reserved0;
36  uint16_t Reserved1;
37  uint32_t PixelAddress;
38 };
39 
41 {
42  uint32_t Size;
43  int32_t Width;
44  int32_t Height;
45  uint16_t Planes; // only support 1
46  uint16_t BitsPerPixel; // only support 24 and 32
47  uint32_t Compression; // only support BI_Rgb
48  uint32_t RawDateSize; // can be zero
49  int32_t XPpm;
50  int32_t YPpm;
51  uint32_t PaletteLength;
53 };
54 #pragma pack(pop)
55 
57 {
65  BI_Cmyk = 11,
68 };
69 
70 // T_COLOR_FEATURE - one of the Features
71 // T_FILE_METHOD - any standard File object following Arduino File methods/members
72 //
73 template<typename T_COLOR_FEATURE, typename T_FILE_METHOD> class NeoBitmapFile
74 {
75 public:
77  _fileAddressPixels(0),
78  _width(0),
79  _height(0),
80  _sizeRow(0),
81  _bytesPerPixel(0),
82  _bottomToTop(true)
83  {
84  }
85 
87  {
88  _file.close();
89  }
90 
91  bool Begin(T_FILE_METHOD file)
92  {
93  if (_file)
94  {
95  _file.close();
96  }
97 
98  if (!file || !file.seek(0))
99  {
100  goto error;
101  }
102 
103  _file = file;
104 
105  BitmapFileHeader bmpHeader;
106  BitmapInfoHeader bmpInfoHeader;
107  size_t result;
108 
109  result = _file.read((uint8_t*)(&bmpHeader), sizeof(bmpHeader));
110 
111  if (result != sizeof(bmpHeader) ||
112  bmpHeader.FileId != c_BitmapFileId ||
113  bmpHeader.FileSize != _file.size())
114  {
115  goto error;
116  }
117 
118  result = _file.read((uint8_t*)(&bmpInfoHeader), sizeof(bmpInfoHeader));
119 
120  if (result != sizeof(bmpInfoHeader) ||
121  result != bmpInfoHeader.Size ||
122  1 != bmpInfoHeader.Planes ||
123  BI_Rgb != bmpInfoHeader.Compression)
124  {
125  goto error;
126  }
127 
128  if (!(24 == bmpInfoHeader.BitsPerPixel ||
129  32 == bmpInfoHeader.BitsPerPixel))
130  {
131  goto error;
132  }
133 
134  // save the interesting information
135  _width = abs(bmpInfoHeader.Width);
136  _height = abs(bmpInfoHeader.Height);
137  _fileAddressPixels = bmpHeader.PixelAddress;
138  // negative height means rows are top to bottom
139  _bottomToTop = (bmpInfoHeader.Height > 0);
140  // rows are 32 bit aligned so they may have padding on each row
141  _sizeRow = (bmpInfoHeader.BitsPerPixel * _width + 31) / 32 * 4;
142  _bytesPerPixel = bmpInfoHeader.BitsPerPixel / 8;
143 
144  return true;
145 
146  error:
147  _fileAddressPixels = 0;
148  _width = 0;
149  _height = 0;
150  _sizeRow = 0;
151  _bytesPerPixel = 0;
152 
153  _file.close();
154  return false;
155  };
156 
157  size_t PixelSize() const
158  {
159  return T_COLOR_FEATURE::PixelSize;
160  };
161 
162  uint16_t PixelCount() const
163  {
164  return _width * _height;
165  };
166 
167  uint16_t Width() const
168  {
169  return _width;
170  };
171 
172  uint16_t Height() const
173  {
174  return _height;
175  };
176 
177  typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y)
178  {
179  if (x < 0 || x >= _width || y < 0 || y >= _height)
180  {
181  // Pixel # is out of bounds, this will get converted to a
182  // color object type initialized to 0 (black)
183  return 0;
184  }
185 
186  typename T_COLOR_FEATURE::ColorObject color;
187  if (!seek(x, y) || !readPixel(&color))
188  {
189  return 0;
190  }
191 
192  return color;
193  };
194 
195 
196  template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
197  T_SHADER& shader,
198  uint16_t indexPixel,
199  int16_t xSrc,
200  int16_t ySrc,
201  int16_t wSrc)
202  {
203  const uint16_t destPixelCount = destBuffer.PixelCount();
204  typename T_COLOR_FEATURE::ColorObject color(0);
205  xSrc = constrainX(xSrc);
206  ySrc = constrainY(ySrc);
207 
208  if (seek(xSrc, ySrc))
209  {
210  for (int16_t x = 0; x < wSrc && indexPixel < destPixelCount; x++, indexPixel++)
211  {
212  if (static_cast<uint16_t>(xSrc) < _width)
213  {
214  if (readPixel(&color))
215  {
216  color = shader.Apply(indexPixel, color);
217  xSrc++;
218  }
219  }
220 
221  T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexPixel, color);
222  }
223  }
224  }
225 
227  uint16_t indexPixel,
228  int16_t xSrc,
229  int16_t ySrc,
230  int16_t wSrc)
231  {
233 
234  Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer, shaderNop, indexPixel, xSrc, ySrc, wSrc);
235  };
236 
237  template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
238  T_SHADER& shader,
239  int16_t xDest,
240  int16_t yDest,
241  int16_t xSrc,
242  int16_t ySrc,
243  int16_t wSrc,
244  int16_t hSrc,
245  LayoutMapCallback layoutMap)
246  {
247  const uint16_t destPixelCount = destBuffer.PixelCount();
248  typename T_COLOR_FEATURE::ColorObject color(0);
249 
250  for (int16_t y = 0; y < hSrc; y++)
251  {
252  int16_t xFile = constrainX(xSrc);
253  int16_t yFile = constrainY(ySrc + y);
254 
255  if (seek(xFile, yFile))
256  {
257  for (int16_t x = 0; x < wSrc; x++)
258  {
259  uint16_t indexDest = layoutMap(xDest + x, yDest + y);
260 
261  if (static_cast<uint16_t>(xFile) < _width)
262  {
263  if (readPixel(&color))
264  {
265  color = shader.Apply(indexDest, color);
266  xFile++;
267  }
268  }
269 
270  if (indexDest < destPixelCount)
271  {
272  T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexDest, color);
273  }
274  }
275  }
276  }
277  };
278 
280  int16_t xDest,
281  int16_t yDest,
282  int16_t xSrc,
283  int16_t ySrc,
284  int16_t wSrc,
285  int16_t hSrc,
286  LayoutMapCallback layoutMap)
287  {
289 
290  Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer,
291  shaderNop,
292  xDest,
293  yDest,
294  xSrc,
295  ySrc,
296  wSrc,
297  hSrc,
298  layoutMap);
299  };
300 
301 
302 private:
303  T_FILE_METHOD _file;
304  uint32_t _fileAddressPixels;
305  uint16_t _width;
306  uint16_t _height;
307  uint32_t _sizeRow;
308  uint8_t _bytesPerPixel;
309  bool _bottomToTop;
310 
311  int16_t constrainX(int16_t x) const
312  {
313  if (x < 0)
314  {
315  x = 0;
316  }
317  else if (static_cast<uint16_t>(x) >= _width)
318  {
319  x = _width - 1;
320  }
321  return x;
322  };
323 
324  int16_t constrainY(int16_t y) const
325  {
326  if (y < 0)
327  {
328  y = 0;
329  }
330  else if (static_cast<uint16_t>(y) >= _height)
331  {
332  y = _height - 1;
333  }
334  return y;
335  };
336 
337  bool seek(int16_t x, int16_t y)
338  {
339  if (_bottomToTop)
340  {
341  y = (_height - 1) - y;
342  }
343 
344  uint32_t pos = y * _sizeRow + x * _bytesPerPixel;
345  pos += _fileAddressPixels;
346 
347  return _file.seek(pos);
348  };
349 
350  bool readPixel(RgbColor* color)
351  {
352  uint8_t bgr[4];
353  int result;
354 
355  result = _file.read(bgr, _bytesPerPixel);
356 
357  if (result != _bytesPerPixel)
358  {
359  *color = 0;
360  return false;
361  }
362 
363  color->B = bgr[0];
364  color->G = bgr[1];
365  color->R = bgr[2];
366 
367  return true;
368  };
369 
370  bool readPixel(RgbwColor* color)
371  {
372  uint8_t bgr[4];
373  int result;
374 
375  bgr[3] = 0; // init white channel as read maybe only 3 bytes
376  result = _file.read(bgr, _bytesPerPixel);
377 
378  if (result != _bytesPerPixel)
379  {
380  *color = 0;
381  return false;
382  }
383 
384  color->B = bgr[0];
385  color->G = bgr[1];
386  color->R = bgr[2];
387  color->W = bgr[3];
388 
389  return true;
390  };
391 };
std::function< uint16_t(int16_t x, int16_t y)> LayoutMapCallback
Definition: LayoutMapCallback.h:39
BmpCompression
Definition: NeoBitmapFile.h:57
@ BI_Bitfields
Definition: NeoBitmapFile.h:61
@ BI_CmykRle4
Definition: NeoBitmapFile.h:67
@ BI_Jpeg
Definition: NeoBitmapFile.h:62
@ BI_CmykRle8
Definition: NeoBitmapFile.h:66
@ BI_Rle4
Definition: NeoBitmapFile.h:60
@ BI_AlphaBitfields
Definition: NeoBitmapFile.h:64
@ BI_Rle8
Definition: NeoBitmapFile.h:59
@ BI_Png
Definition: NeoBitmapFile.h:63
@ BI_Cmyk
Definition: NeoBitmapFile.h:65
@ BI_Rgb
Definition: NeoBitmapFile.h:58
const uint16_t c_BitmapFileId
Definition: NeoBitmapFile.h:28
Definition: NeoBitmapFile.h:74
uint16_t Height() const
Definition: NeoBitmapFile.h:172
size_t PixelSize() const
Definition: NeoBitmapFile.h:157
T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y)
Definition: NeoBitmapFile.h:177
~NeoBitmapFile()
Definition: NeoBitmapFile.h:86
uint16_t Width() const
Definition: NeoBitmapFile.h:167
uint16_t PixelCount() const
Definition: NeoBitmapFile.h:162
void Blt(NeoBufferContext< T_COLOR_FEATURE > destBuffer, int16_t xDest, int16_t yDest, int16_t xSrc, int16_t ySrc, int16_t wSrc, int16_t hSrc, LayoutMapCallback layoutMap)
Definition: NeoBitmapFile.h:279
void Render(NeoBufferContext< T_COLOR_FEATURE > destBuffer, T_SHADER &shader, uint16_t indexPixel, int16_t xSrc, int16_t ySrc, int16_t wSrc)
Definition: NeoBitmapFile.h:196
void Blt(NeoBufferContext< T_COLOR_FEATURE > destBuffer, uint16_t indexPixel, int16_t xSrc, int16_t ySrc, int16_t wSrc)
Definition: NeoBitmapFile.h:226
NeoBitmapFile()
Definition: NeoBitmapFile.h:76
bool Begin(T_FILE_METHOD file)
Definition: NeoBitmapFile.h:91
void Render(NeoBufferContext< T_COLOR_FEATURE > destBuffer, T_SHADER &shader, int16_t xDest, int16_t yDest, int16_t xSrc, int16_t ySrc, int16_t wSrc, int16_t hSrc, LayoutMapCallback layoutMap)
Definition: NeoBitmapFile.h:237
Definition: NeoShaderNop.h:29
Definition: NeoBitmapFile.h:32
uint16_t Reserved0
Definition: NeoBitmapFile.h:35
uint32_t FileSize
Definition: NeoBitmapFile.h:34
uint32_t PixelAddress
Definition: NeoBitmapFile.h:37
uint16_t Reserved1
Definition: NeoBitmapFile.h:36
uint16_t FileId
Definition: NeoBitmapFile.h:33
Definition: NeoBitmapFile.h:41
uint32_t Size
Definition: NeoBitmapFile.h:42
uint32_t PaletteLength
Definition: NeoBitmapFile.h:51
int32_t XPpm
Definition: NeoBitmapFile.h:49
int32_t YPpm
Definition: NeoBitmapFile.h:50
int32_t Width
Definition: NeoBitmapFile.h:43
uint32_t ImportantColorCount
Definition: NeoBitmapFile.h:52
uint32_t RawDateSize
Definition: NeoBitmapFile.h:48
uint16_t Planes
Definition: NeoBitmapFile.h:45
int32_t Height
Definition: NeoBitmapFile.h:44
uint32_t Compression
Definition: NeoBitmapFile.h:47
uint16_t BitsPerPixel
Definition: NeoBitmapFile.h:46
Definition: NeoBufferContext.h:32
uint8_t * Pixels
Definition: NeoBufferContext.h:43
uint16_t PixelCount() const
Definition: NeoBufferContext.h:40
Definition: RgbColor.h:36
uint8_t G
Definition: RgbColor.h:247
uint8_t B
Definition: RgbColor.h:248
uint8_t R
Definition: RgbColor.h:246
Definition: RgbwColor.h:38
uint8_t R
Definition: RgbwColor.h:271
uint8_t W
Definition: RgbwColor.h:274
uint8_t B
Definition: RgbwColor.h:273
uint8_t G
Definition: RgbwColor.h:272