NXWidgets: cscaledbitmap.cxx Source File

NXWidgets 1.19

cscaledbitmap.cxx
Go to the documentation of this file.
1 /****************************************************************************
2 * NxWidgets/libnxwidgets/src/cscaledbitmap.hxx
3 *
4 * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved.
5 * Author: Gregory Nutt <gnutt@nuttx.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
18 * me be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 ****************************************************************************/
35
36 /****************************************************************************
37 * Included Files
38 ****************************************************************************/
39
40 #include <nuttx/config.h>
41
42 #include <stdint.h>
43 #include <stdbool.h>
44 #include <cstring>
45
46 #include <nuttx/nx/nxglib.h>
47
48 #include "cscaledbitmap.hxx"
49
50 /****************************************************************************
51 * Pre-Processor Definitions
52 ****************************************************************************/
53
54 /****************************************************************************
55 * Method Implementations
56 ****************************************************************************/
57
58 using namespace NXWidgets;
59
60 /**
61 * Constructor.
62 *
63 * @param bitmap The bitmap structure being scaled.
64 * @newSize The new, scaled size of the image
65 */
66
67 CScaledBitmap::CScaledBitmap(IBitmap *bitmap, struct nxgl_size_s &newSize)
68 : m_bitmap(bitmap), m_size(newSize)
69 {
70 // xScale will be used to convert a request X position to an X position
71 // in the contained bitmap:
72 //
73 // xImage = xRequested * oldWidth / newWidth
74 // = xRequested * xScale
75
76 m_xScale = itob16((uint32_t)m_bitmap->getWidth()) / newSize.w;
77
78 // Similarly, yScale will be used to convert a request Y position to a Y
79 // positionin the contained bitmap:
80 //
81 // yImage = yRequested * oldHeight / newHeight
82 // = yRequested * yScale
83
84 m_yScale = itob16((uint32_t)m_bitmap->getHeight()) / newSize.h;
85
86 // Allocate and initialize the row cache
87
88 size_t stride = bitmap->getStride();
89 m_rowCache[0] = new uint8_t[stride];
90 m_rowCache[1] = new uint8_t[stride];
91
92 // Read the first two rows into the cache
93
94 m_row = m_bitmap->getWidth(); // Set to an impossible value
95 cacheRows(0);
96 }
97
98 /**
99 * Destructor.
100 */
101
102 CScaledBitmap::~CScaledBitmap(void)
103 {
104 // Delete the allocated row cache memory
105
106 if (m_rowCache[0])
107 {
108 delete m_rowCache[0];
109 }
110
111 if (m_rowCache[1])
112 {
113 delete m_rowCache[1];
114 }
115
116 // We are also responsible for deleting the contained IBitmap
117
118 if (m_bitmap)
119 {
120 delete m_bitmap;
121 }
122 }
123
124 /**
125 * Get the bitmap's color format.
126 *
127 * @return The bitmap's width.
128 */
129
130 const uint8_t CScaledBitmap::getColorFormat(void) const
131 {
132 return m_bitmap->getColorFormat();
133 }
134
135 /**
136 * Get the bitmap's color format.
137 *
138 * @return The bitmap's color format.
139 */
140
141 const uint8_t CScaledBitmap::getBitsPerPixel(void) const
142 {
143 return m_bitmap->getBitsPerPixel();
144 }
145
146 /**
147 * Get the bitmap's width (in pixels/columns).
148 *
149 * @return The bitmap's pixel depth.
150 */
151
152 const nxgl_coord_t CScaledBitmap::getWidth(void) const
153 {
154 return m_size.w;
155 }
156
157 /**
158 * Get the bitmap's height (in rows).
159 *
160 * @return The bitmap's height (in rows).
161 */
162
163 const nxgl_coord_t CScaledBitmap::getHeight(void) const
164 {
165 return m_size.h;
166 }
167
168 /**
169 * Get the bitmap's width (in bytes).
170 *
171 * @return The bitmap's width (in bytes).
172 */
173
174 const size_t CScaledBitmap::getStride(void) const
175 {
176 return (m_bitmap->getBitsPerPixel() * m_size.w + 7) / 8;
177 }
178
179 /**
180 * Get one row from the bit map image.
181 *
182 * REVISIT: This algorithm is really intended to expand images. Hence,
183 * for example, interpolation is between row and row+1 and column and
184 * column+1 in the original, unscaled image. You would the interpolation
185 * differently if you really wanted to sub-sample well.
186 *
187 * @param x The offset into the row to get
188 * @param y The row number to get
189 * @param width The number of pixels to get from the row
190 * @param data The memory location provided by the caller
191 * in which to return the data. This should be at least
192 * (getWidth()*getBitsPerPixl() + 7)/8 bytes in length
193 * and properly aligned for the pixel color format.
194 * @param True if the run was returned successfully.
195 */
196
197 bool CScaledBitmap::getRun(nxgl_coord_t x, nxgl_coord_t y,
198 nxgl_coord_t width, FAR void *data)
199 {
200 #if CONFIG_NXWIDGETS_FMT == FB_FMT_RGB8_332 || CONFIG_NXWIDGETS_FMT == FB_FMT_RGB24
201 FAR uint8_t *dest = (FAR uint8_t *)data;
202 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB16_565
203 FAR uint16_t *dest = (FAR uint16_t *)data;
204 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB32
205 FAR uint32_t *dest = (FAR uint32_t *)data;
206 #else
207 # error Unsupported, invalid, or undefined color format
208 #endif
209
210 // Check ranges. Casts to unsigned int are ugly but permit one-sided comparisons
211
212 if (((unsigned int)x >= (unsigned int)m_size.w) &&
213 ((unsigned int)(x + width) > (unsigned int)m_size.w) &&
214 ((unsigned int)y <= (unsigned int)m_size.h))
215 {
216 return false;
217 }
218
219 // Get the row number in the unscaled image corresponding to the
220 // requested y position. This must be either the exact row or the
221 // closest row just before the requested position
222
223 b16_t row16 = y * m_yScale;
224 nxgl_coord_t row = b16toi(row16);
225
226 // Get that row and the one after it into the row cache. We know that
227 // the pixel value that we want is one between the two rows. This
228 // may seem wasteful to read two entire rows. However, in normal usage
229 // we will be traversal each image from top-left to bottom-right in
230 // order. In that case, the caching is most efficient.
231
232 if (!cacheRows(row))
233 {
234 return false;
235 }
236
237 // Now scale and copy the data from the cached row data
238
239 for (int i = 0; i < width; i++, x++)
240 {
241 // Get the column number in the unscaled row corresponding to the
242 // requested x position. This must be either the exact column or the
243 // closest column just before the requested position
244
245 b16_t column = x * m_xScale;
246
247 // Get the color at the position on the first row
248
249 struct rgbcolor_s color1;
250 if (!rowColor(m_rowCache[0], column, color1))
251 {
252 gerr("ERROR: rowColor failed for the first row\n");
253 return false;
254 }
255
256 // Get the color at the position on the first row
257
258 struct rgbcolor_s color2;
259 if (!rowColor(m_rowCache[1], column, color2))
260 {
261 gerr("ERROR: rowColor failed for the second row\n");
262 return false;
263 }
264
265 // Check for transparent colors
266
267 bool transparent1;
268 bool transparent2;
269
270 #if CONFIG_NXWIDGETS_FMT == FB_FMT_RGB8_332
271 uint8_t color = RGBTO8(color1.r, color1.g, color1.b);
272 transparent1 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
273
274 color = RGBTO8(color2.r, color2.g, color2.b);
275 transparent2 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
276
277 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB16_565
278 uint16_t color = RGBTO16(color1.r, color1.g, color1.b);
279 transparent1 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
280
281 color = RGBTO16(color2.r, color2.g, color2.b);
282 transparent2 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
283
284 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB24 || CONFIG_NXWIDGETS_FMT == FB_FMT_RGB32
285 uint32_t color = RGBTO24(color1.r, color1.g, color1.b);
286 transparent1 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
287
288 color = RGBTO24(color2.r, color2.g, color2.b);
289 transparent2 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
290
291 #else
292 # error Unsupported, invalid, or undefined color format
293 #endif
294
295 // Is one of the colors transparent?
296
297 struct rgbcolor_s scaledColor;
298 b16_t fraction b16frac(row16);
299
300 if (transparent1 || transparent2)
301 {
302 // Yes.. don't interpolate within transparent regions or
303 // between transparent and opaque regions.
304
305 // Get the color closest to the requested position
306
307 if (fraction < b16HALF)
308 {
309 scaledColor.r = color1.r;
310 scaledColor.g = color1.g;
311 scaledColor.b = color1.b;
312 }
313 else
314 {
315 scaledColor.r = color2.r;
316 scaledColor.g = color2.g;
317 scaledColor.b = color2.b;
318 }
319 }
320 else
321 {
322 // No.. both colors are opaque
323
324 if (!scaleColor(color1, color2, fraction, scaledColor))
325 {
326 return false;
327 }
328 }
329
330 // Write the interpolated data to the user buffer
331
332 #if CONFIG_NXWIDGETS_FMT == FB_FMT_RGB8_332
333 color = RGBTO8(scaledColor.r, scaledColor.g, scaledColor.b);
334 *dest++ = color;
335
336 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB16_565
337 color = RGBTO16(scaledColor.r, scaledColor.g, scaledColor.b);
338 *dest++ = color;
339
340 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB24
341 *dest++ = color2.b;
342 *dest++ = color2.r;
343 *dest++ = color2.g;
344
345 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB32
346 color = RGBTO24(scaledColor.r, scaledColor.g, scaledColor.b);
347 *dest++ = color;
348
349 #else
350 # error Unsupported, invalid, or undefined color format
351 #endif
352 }
353
354 return true;
355 }
356
357 /**
358 * Read two rows into the row cache
359 *
360 * @param row - The row number of the first row to cache
361 */
362
363 bool CScaledBitmap::cacheRows(unsigned int row)
364 {
365 nxgl_coord_t bitmapWidth = m_bitmap->getWidth();
366 nxgl_coord_t bitmapHeight = m_bitmap->getHeight();
367
368 // A common case is to advance by one row. In this case, we only
369 // need to read one row
370
371 if (row == m_row + 1)
372 {
373 // Swap rows
374
375 FAR uint8_t *saveRow = m_rowCache[0];
376 m_rowCache[0] = m_rowCache[1];
377 m_rowCache[1] = saveRow;
378
379 // Save number of the first row that we have in the cache
380
381 m_row = row;
382
383 // Now read the new row into the second row cache buffer
384
385 if (++row >= (unsigned int)bitmapHeight)
386 {
387 row = bitmapHeight - 1;
388 }
389
390 if (!m_bitmap->getRun(0, row, bitmapWidth, m_rowCache[1]))
391 {
392 gerr("ERROR: Failed to read bitmap row %d\n", row);
393 return false;
394 }
395 }
396
397 // Do we need to read two new rows? Or do we already have the
398 // request row in the cache?
399
400 else if (row != m_row)
401 {
402 // Read the first row into the cache
403
404 if (row >= (unsigned int)bitmapHeight)
405 {
406 row = bitmapHeight - 1;
407 }
408
409 if (!m_bitmap->getRun(0, row, bitmapWidth, m_rowCache[0]))
410 {
411 gerr("ERROR: Failed to read bitmap row %d\n", row);
412 return false;
413 }
414
415 // Save number of the first row that we have in the cache
416
417 m_row = row;
418
419 // Read the next row into the cache
420
421 if (++row >= (unsigned int)bitmapHeight)
422 {
423 row = bitmapHeight - 1;
424 }
425
426 if (!m_bitmap->getRun(0, row, bitmapWidth, m_rowCache[1]))
427 {
428 gerr("ERROR: Failed to read bitmap row %d\n", row);
429 return false;
430 }
431 }
432
433 return true;
434 }
435
436 /**
437 * Given an two RGB colors and a fractional value, return the scaled
438 * value between the two colors.
439 *
440 * @param incolor1 - The first color to be used
441 * @param incolor2 - The second color to be used
442 * @param fraction - The fractional value
443 * @param outcolor - The returned, scaled color
444 */
445
446 bool CScaledBitmap::scaleColor(FAR const struct rgbcolor_s &incolor1,
447 FAR const struct rgbcolor_s &incolor2,
448 b16_t fraction, FAR struct rgbcolor_s &outcolor)
449 {
450 uint8_t component;
451 b16_t red;
452 b16_t green;
453 b16_t blue;
454
455 // A fraction of < 0.5 would mean to use use mostly color1; a fraction
456 // greater than 0.5 would men to use mostly color2
457
458 b16_t remainder = b16ONE - fraction;
459
460 // Interpolate each color value (converting to b15)
461
462 red = (b16_t)incolor1.r * remainder + (b16_t)incolor2.r * fraction;
463 green = (b16_t)incolor1.g * remainder + (b16_t)incolor2.g * fraction;
464 blue = (b16_t)incolor1.b * remainder + (b16_t)incolor2.b * fraction;
465
466 // Return the integer, interpolated values, clipping to the range of
467 // uint8_t
468
469 component = b16toi(red);
470 outcolor.r = component < 256 ? component : 255;
471
472 component = b16toi(green);
473 outcolor.g = component < 256 ? component : 255;
474
475 component = b16toi(blue);
476 outcolor.b = component < 256 ? component : 255;
477 return true;
478 }
479
480 /**
481 * Given an image row and a non-integer column offset, return the
482 * interpolated RGB color value corresponding to that position
483 *
484 * @param row - The pointer to the row in the row cache to use
485 * @param column - The non-integer column offset
486 * @param outcolor - The returned, interpolated color
487 *
488 */
489
490 bool CScaledBitmap::rowColor(FAR uint8_t *row, b16_t column,
491 FAR struct rgbcolor_s &outcolor)
492 {
493 // This is the col at or just before the pixel of interest
494
495 nxgl_coord_t col1 = b16toi(column);
496 nxgl_coord_t col2 = col1 + 1;
497
498 nxgl_coord_t bitmapWidth = m_bitmap->getWidth();
499 if (col2 >= bitmapWidth)
500 {
501 col2 = bitmapWidth - 1;
502 }
503
504 b16_t fraction = b16frac(column);
505
506 struct rgbcolor_s color1;
507 struct rgbcolor_s color2;
508
509 bool transparent1;
510 bool transparent2;
511
512 #if CONFIG_NXWIDGETS_FMT == FB_FMT_RGB8_332
513 uint8_t color = row[col1];
514 color1.r = RGB8RED(color);
515 color1.g = RGB8GREEN(color);
516 color1.b = RGB8BLUE(color);
517
518 transparent1 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
519
520 color = row[col2];
521 color2.r = RGB8RED(color);
522 color2.g = RGB8GREEN(color);
523 color2.b = RGB8BLUE(color);
524
525 transparent2 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
526
527 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB16_565
528 FAR uint16_t *row16 = (FAR uint16_t*)row;
529 uint16_t color = row16[col1];
530 color1.r = RGB16RED(color);
531 color1.g = RGB16GREEN(color);
532 color1.b = RGB16BLUE(color);
533
534 transparent1 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
535
536 color = row16[col2];
537 color2.r = RGB16RED(color);
538 color2.g = RGB16GREEN(color);
539 color2.b = RGB16BLUE(color);
540
541 transparent2 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
542
543 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB24
544 unsigned int ndx = 3*col1;
545 color1.r = row[ndx+2];
546 color1.g = row[ndx+1];
547 color1.b = row[ndx];
548
549 uint32_t color = RGBTO24(color1.r, color1.g, color1.b);
550 transparent1 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
551
552 ndx = 3*col2;
553 color2.r = row[ndx+2];
554 color2.g = row[ndx+1];
555 color2.b = row[ndx];
556
557 color = RGBTO24(color2.r, color2.g, color2.b);
558 transparent2 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
559
560 #elif CONFIG_NXWIDGETS_FMT == FB_FMT_RGB32
561 FAR uint32_t *row32 = (FAR uint32_t*)row;
562 uint32_t color = row32[col1];
563 color1.r = RGB24RED(color);
564 color1.g = RGB24GREEN(color);
565 color1.b = RGB24BLUE(color);
566
567 transparent1 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
568
569 color = row32[col2];
570 color2.r = RGB24RED(color);
571 color2.g = RGB24GREEN(color);
572 color2.b = RGB24BLUE(color);
573
574 transparent2 = (color == CONFIG_NXWIDGETS_TRANSPARENT_COLOR);
575
576 #else
577 # error Unsupported, invalid, or undefined color format
578 #endif
579
580 // Is one of the colors transparent?
581
582 if (transparent1 || transparent2)
583 {
584 // Yes.. don't interpolate within transparent regions or
585 // between transparent and opaque regions.
586
587 // Return the color closest to the requested position
588 //
589 // A fraction of < 0.5 would mean to use use mostly color1; a fraction
590 // greater than 0.5 would men to use mostly color2
591
592 if (fraction < b16HALF)
593 {
594 outcolor.r = color1.r;
595 outcolor.g = color1.b;
596 outcolor.g = color1.g;
597 }
598 else
599 {
600 outcolor.r = color2.r;
601 outcolor.g = color2.b;
602 outcolor.g = color2.g;
603 }
604
605 return true;
606 }
607 else
608 {
609 // No.. both colors are opaque
610
611 return scaleColor(color1, color2, fraction, outcolor);
612 }
613 }
NXWidgets::IBitmap::getRun
virtual bool getRun(nxgl_coord_t x, nxgl_coord_t y, nxgl_coord_t width, FAR void *data)=0
NXWidgets::IBitmap::getHeight
virtual const nxgl_coord_t getHeight(void) const =0
NXWidgets
Definition: cbgwindow.hxx:65
NXWidgets::CScaledBitmap::getRun
bool getRun(nxgl_coord_t x, nxgl_coord_t y, nxgl_coord_t width, FAR void *data)
Definition: cscaledbitmap.cxx:197
NXWidgets::CScaledBitmap::getBitsPerPixel
const uint8_t getBitsPerPixel(void) const
Definition: cscaledbitmap.cxx:141
NXWidgets::CScaledBitmap::~CScaledBitmap
~CScaledBitmap(void)
Definition: cscaledbitmap.cxx:102
NXWidgets::CScaledBitmap::cacheRows
bool cacheRows(unsigned int row)
Definition: cscaledbitmap.cxx:363
NXWidgets::CScaledBitmap::getColorFormat
const uint8_t getColorFormat(void) const
Definition: cscaledbitmap.cxx:130
NXWidgets::IBitmap::getStride
virtual const size_t getStride(void) const =0
NXWidgets::CScaledBitmap::m_rowCache
FAR uint8_t * m_rowCache[2]
Definition: cscaledbitmap.hxx:77
cscaledbitmap.hxx
NXWidgets::CScaledBitmap::m_xScale
b16_t m_xScale
Definition: cscaledbitmap.hxx:79
NXWidgets::CScaledBitmap::m_row
unsigned int m_row
Definition: cscaledbitmap.hxx:78
NXWidgets::CScaledBitmap::rowColor
bool rowColor(FAR uint8_t *row, b16_t column, FAR struct rgbcolor_s &outcolor)
Definition: cscaledbitmap.cxx:490
NXWidgets::CScaledBitmap::m_bitmap
FAR IBitmap * m_bitmap
Definition: cscaledbitmap.hxx:75
NXWidgets::IBitmap::getWidth
virtual const nxgl_coord_t getWidth(void) const =0
NXWidgets::CScaledBitmap::CScaledBitmap
CScaledBitmap(const CScaledBitmap &bitmap)
Definition: cscaledbitmap.hxx:121
NXWidgets::CScaledBitmap::getWidth
const nxgl_coord_t getWidth(void) const
Definition: cscaledbitmap.cxx:152
NXWidgets::CScaledBitmap::getStride
const size_t getStride(void) const
Definition: cscaledbitmap.cxx:174
bitmap
static const NXWidgets::SRlePaletteBitmapEntry bitmap[]
Definition: glyph_mediaplayer24x24.cxx:85
NXWidgets::IBitmap::getBitsPerPixel
virtual const uint8_t getBitsPerPixel(void) const =0
NXWidgets::IBitmap::getColorFormat
virtual const uint8_t getColorFormat(void) const =0
NXWidgets::IBitmap
Definition: ibitmap.hxx:103
NXWidgets::CScaledBitmap::getHeight
const nxgl_coord_t getHeight(void) const
Definition: cscaledbitmap.cxx:163
NXWidgets::CScaledBitmap::scaleColor
bool scaleColor(FAR const struct rgbcolor_s &incolor1, FAR const struct rgbcolor_s &incolor2, b16_t fraction, FAR struct rgbcolor_s &outcolor)
Definition: cscaledbitmap.cxx:446
NXWidgets::CScaledBitmap::m_size
struct nxgl_size_s m_size
Definition: cscaledbitmap.hxx:76
NXWidgets::CScaledBitmap::m_yScale
b16_t m_yScale
Definition: cscaledbitmap.hxx:80