Skip to content

Commit c53e9d2

Browse files
added support in GFXcanvas* classes to access pixel values
Alsp added and example for GFXcanvas that demonstrates the impact of rotation on pixel layout and also demonstrates getting a pixel based on raw physical coordinates.
1 parent 1232016 commit c53e9d2

File tree

5 files changed

+305
-15
lines changed

5 files changed

+305
-15
lines changed

Adafruit_GFX.cpp

100755100644
Lines changed: 162 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,12 @@ boolean Adafruit_GFX_Button::justReleased() {
17361736
// scanline pad).
17371737
// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
17381738

1739+
#ifdef __AVR__
1740+
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
1741+
const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
1742+
const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE };
1743+
#endif
1744+
17391745
/**************************************************************************/
17401746
/*!
17411747
@brief Instatiate a GFX 1-bit canvas context for graphics
@@ -1765,18 +1771,10 @@ GFXcanvas1::~GFXcanvas1(void) {
17651771
@brief Draw a pixel to the canvas framebuffer
17661772
@param x x coordinate
17671773
@param y y coordinate
1768-
@param color 16-bit 5-6-5 Color to fill with
1774+
@param color Binary (on or off) color to fill with
17691775
*/
17701776
/**************************************************************************/
17711777
void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
1772-
#ifdef __AVR__
1773-
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
1774-
static const uint8_t PROGMEM GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
1775-
0x08, 0x04, 0x02, 0x01},
1776-
GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
1777-
0xF7, 0xFB, 0xFD, 0xFE};
1778-
#endif
1779-
17801778
if (buffer) {
17811779
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
17821780
return;
@@ -1814,10 +1812,66 @@ void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
18141812
}
18151813
}
18161814

1815+
/**********************************************************************/
1816+
/*!
1817+
@brief Get the pixel color value at a given coordinate
1818+
@param x x coordinate
1819+
@param y y coordinate
1820+
@returns The desired pixel's binary color value, either 0x1 (on) or 0x0 (off)
1821+
*/
1822+
/**********************************************************************/
1823+
bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
1824+
int16_t t;
1825+
switch(rotation) {
1826+
case 1:
1827+
t = x;
1828+
x = WIDTH - 1 - y;
1829+
y = t;
1830+
break;
1831+
case 2:
1832+
x = WIDTH - 1 - x;
1833+
y = HEIGHT - 1 - y;
1834+
break;
1835+
case 3:
1836+
t = x;
1837+
x = y;
1838+
y = HEIGHT - 1 - t;
1839+
break;
1840+
}
1841+
return getRawPixel(x, y);
1842+
}
1843+
1844+
/**********************************************************************/
1845+
/*!
1846+
@brief Get the pixel color value at a given, unrotated coordinate.
1847+
This method is intended for hardware drivers to get pixel value
1848+
in physical coordinates.
1849+
@param x x coordinate
1850+
@param y y coordinate
1851+
@returns The desired pixel's binary color value, either 0x1 (on) or 0x0 (off)
1852+
*/
1853+
/**********************************************************************/
1854+
bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
1855+
if((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) return 0;
1856+
if(this->getBuffer()) {
1857+
uint8_t *buffer = this->getBuffer();
1858+
uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
1859+
1860+
#ifdef __AVR__
1861+
return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0;
1862+
#else
1863+
return ((*ptr) & (0x80 >> (x & 7))) != 0;
1864+
#endif
1865+
}
1866+
return 0;
1867+
}
1868+
1869+
1870+
18171871
/**************************************************************************/
18181872
/*!
18191873
@brief Fill the framebuffer completely with one color
1820-
@param color 16-bit 5-6-5 Color to fill with
1874+
@param color Binary (on or off) color to fill with
18211875
*/
18221876
/**************************************************************************/
18231877
void GFXcanvas1::fillScreen(uint16_t color) {
@@ -1856,7 +1910,7 @@ GFXcanvas8::~GFXcanvas8(void) {
18561910
@brief Draw a pixel to the canvas framebuffer
18571911
@param x x coordinate
18581912
@param y y coordinate
1859-
@param color 16-bit 5-6-5 Color to fill with
1913+
@param color 8-bit Color to fill with. Only lower byte of uint16_t is used.
18601914
*/
18611915
/**************************************************************************/
18621916
void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
@@ -1886,10 +1940,58 @@ void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
18861940
}
18871941
}
18881942

1943+
/**********************************************************************/
1944+
/*!
1945+
@brief Get the pixel color value at a given coordinate
1946+
@param x x coordinate
1947+
@param y y coordinate
1948+
@returns The desired pixel's 8-bit color value
1949+
*/
1950+
/**********************************************************************/
1951+
uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const {
1952+
int16_t t;
1953+
switch(rotation) {
1954+
case 1:
1955+
t = x;
1956+
x = WIDTH - 1 - y;
1957+
y = t;
1958+
break;
1959+
case 2:
1960+
x = WIDTH - 1 - x;
1961+
y = HEIGHT - 1 - y;
1962+
break;
1963+
case 3:
1964+
t = x;
1965+
x = y;
1966+
y = HEIGHT - 1 - t;
1967+
break;
1968+
}
1969+
return getRawPixel(x, y);
1970+
}
1971+
1972+
/**********************************************************************/
1973+
/*!
1974+
@brief Get the pixel color value at a given, unrotated coordinate.
1975+
This method is intended for hardware drivers to get pixel value
1976+
in physical coordinates.
1977+
@param x x coordinate
1978+
@param y y coordinate
1979+
@returns The desired pixel's 8-bit color value
1980+
*/
1981+
/**********************************************************************/
1982+
uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const {
1983+
if((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) return 0;
1984+
if(buffer) {
1985+
return buffer[x + y * WIDTH];
1986+
}
1987+
return 0;
1988+
}
1989+
1990+
18891991
/**************************************************************************/
18901992
/*!
18911993
@brief Fill the framebuffer completely with one color
1892-
@param color 16-bit 5-6-5 Color to fill with
1994+
@param color 8-bit Color to fill with. Only lower byte of uint16_t is used.
18931995
*/
18941996
/**************************************************************************/
18951997
void GFXcanvas8::fillScreen(uint16_t color) {
@@ -1995,6 +2097,54 @@ void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
19952097
}
19962098
}
19972099

2100+
/**********************************************************************/
2101+
/*!
2102+
@brief Get the pixel color value at a given coordinate
2103+
@param x x coordinate
2104+
@param y y coordinate
2105+
@returns The desired pixel's 16-bit 5-6-5 color value
2106+
*/
2107+
/**********************************************************************/
2108+
uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const {
2109+
int16_t t;
2110+
switch(rotation) {
2111+
case 1:
2112+
t = x;
2113+
x = WIDTH - 1 - y;
2114+
y = t;
2115+
break;
2116+
case 2:
2117+
x = WIDTH - 1 - x;
2118+
y = HEIGHT - 1 - y;
2119+
break;
2120+
case 3:
2121+
t = x;
2122+
x = y;
2123+
y = HEIGHT - 1 - t;
2124+
break;
2125+
}
2126+
return getRawPixel(x, y);
2127+
}
2128+
2129+
/**********************************************************************/
2130+
/*!
2131+
@brief Get the pixel color value at a given, unrotated coordinate.
2132+
This method is intended for hardware drivers to get pixel value
2133+
in physical coordinates.
2134+
@param x x coordinate
2135+
@param y y coordinate
2136+
@returns The desired pixel's 16-bit 5-6-5 color value
2137+
*/
2138+
/**********************************************************************/
2139+
uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const {
2140+
if((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) return 0;
2141+
if(buffer) {
2142+
return buffer[x + y * WIDTH];
2143+
}
2144+
return 0;
2145+
}
2146+
2147+
19982148
/**************************************************************************/
19992149
/*!
20002150
@brief Fill the framebuffer completely with one color

Adafruit_GFX.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,16 +310,23 @@ class GFXcanvas1 : public Adafruit_GFX {
310310
~GFXcanvas1(void);
311311
void drawPixel(int16_t x, int16_t y, uint16_t color);
312312
void fillScreen(uint16_t color);
313+
bool getPixel(int16_t x, int16_t y) const;
313314
/**********************************************************************/
314315
/*!
315316
@brief Get a pointer to the internal buffer memory
316317
@returns A pointer to the allocated buffer
317318
*/
318319
/**********************************************************************/
319320
uint8_t *getBuffer(void) const { return buffer; }
320-
321+
protected:
322+
bool getRawPixel(int16_t x, int16_t y) const;
321323
private:
322324
uint8_t *buffer;
325+
326+
#ifdef __AVR__
327+
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
328+
static const uint8_t PROGMEM GFXsetBit[], GFXclrBit[];
329+
#endif
323330
};
324331

325332
/// A GFX 8-bit canvas context for graphics
@@ -330,14 +337,16 @@ class GFXcanvas8 : public Adafruit_GFX {
330337
void drawPixel(int16_t x, int16_t y, uint16_t color);
331338
void fillScreen(uint16_t color);
332339
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
340+
uint8_t getPixel(int16_t x, int16_t y) const;
333341
/**********************************************************************/
334342
/*!
335343
@brief Get a pointer to the internal buffer memory
336344
@returns A pointer to the allocated buffer
337345
*/
338346
/**********************************************************************/
339347
uint8_t *getBuffer(void) const { return buffer; }
340-
348+
protected:
349+
uint8_t getRawPixel(int16_t x, int16_t y) const;
341350
private:
342351
uint8_t *buffer;
343352
};
@@ -350,14 +359,16 @@ class GFXcanvas16 : public Adafruit_GFX {
350359
void drawPixel(int16_t x, int16_t y, uint16_t color);
351360
void fillScreen(uint16_t color);
352361
void byteSwap(void);
362+
uint16_t getPixel(int16_t x, int16_t y) const;
353363
/**********************************************************************/
354364
/*!
355365
@brief Get a pointer to the internal buffer memory
356366
@returns A pointer to the allocated buffer
357367
*/
358368
/**********************************************************************/
359369
uint16_t *getBuffer(void) const { return buffer; }
360-
370+
protected:
371+
uint16_t getRawPixel(int16_t x, int16_t y) const;
361372
private:
362373
uint16_t *buffer;
363374
};

examples/GFXcanvas/GFXcanvas.ino

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/***
2+
This example is intended to demonstrate the use of getPixel() versus
3+
getRawPixel() in the GFXcanvas family of classes.
4+
5+
When using the GFXcanvas* classes as the image buffer for a hardware driver,
6+
there is a need to get individual pixel color values at given physical
7+
coordinates. Rather than subclasses or client classes call getBuffer() and
8+
reinterpret the byte layout of the buffer, two methods are added to each of the
9+
GFXcanvas* classes that allow fetching of specific pixel values.
10+
11+
* getPixel(x, y) : Gets the pixel color value at the rotated coordinates in
12+
the image.
13+
* getRawPixel(x,y) : Gets the pixel color value at the unrotated coordinates
14+
in the image. This is useful for getting the pixel value to map to a hardware
15+
pixel location. This method was made protected as only the hardware driver
16+
should be accessing it.
17+
18+
The GFXcanvasSerialDemo class in this example will print to Serial the contents
19+
of the underlying GFXcanvas buffer in both the current rotated layout and the
20+
underlying physical layout.
21+
***/
22+
23+
#include "GFXcanvasSerialDemo.h"
24+
#include <Arduino.h>
25+
26+
void setup() {
27+
Serial.begin(115200);
28+
29+
// first create a rectangular GFXcanvasSerialDemo object and draw to it
30+
GFXcanvasSerialDemo demo(21, 11);
31+
32+
demo.fillScreen(0x00);
33+
demo.setRotation(1); // now canvas is 11x21
34+
demo.fillCircle(5, 10, 5, 0xAA);
35+
demo.writeLine(0, 0, 10, 0, 0x11);
36+
demo.writeLine(0, 10, 10, 10, 0x22);
37+
demo.writeLine(0, 20, 10, 20, 0x33);
38+
demo.writeLine(0, 0, 0, 20, 0x44);
39+
demo.writeLine(10, 0, 10, 20, 0x55);
40+
41+
Serial.println("Demonstrating GFXcanvas rotated and raw pixels.\n");
42+
43+
// print it out rotated
44+
45+
Serial.println("The canvas's content in the rotation of '0':\n");
46+
demo.setRotation(0);
47+
demo.print(true);
48+
Serial.println("\n");
49+
50+
Serial.println("The canvas's content in the rotation of '1' (which is what "
51+
"it was drawn in):\n");
52+
demo.setRotation(1);
53+
demo.print(true);
54+
Serial.println("\n");
55+
56+
Serial.println("The canvas's content in the rotation of '2':\n");
57+
demo.setRotation(2);
58+
demo.print(true);
59+
Serial.println("\n");
60+
61+
Serial.println("The canvas's content in the rotation of '3':\n");
62+
demo.setRotation(3);
63+
demo.print(true);
64+
Serial.println("\n");
65+
66+
// print it out unrotated
67+
Serial.println("The canvas's content in it's raw, physical layout:\n");
68+
demo.print(false);
69+
Serial.println("\n");
70+
}
71+
72+
void loop() {}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "GFXcanvasSerialDemo.h"
2+
#include <Arduino.h>
3+
4+
GFXcanvasSerialDemo::GFXcanvasSerialDemo(uint16_t w, uint16_t h)
5+
: GFXcanvas8(w, h) {}
6+
7+
void GFXcanvasSerialDemo::print(bool rotated) {
8+
char pixel_buffer[8];
9+
uint16_t width, height;
10+
11+
if (rotated) {
12+
width = this->width();
13+
height = this->height();
14+
} else {
15+
width = this->WIDTH;
16+
height = this->HEIGHT;
17+
}
18+
19+
for (uint16_t y = 0; y < height; y++) {
20+
for (uint16_t x = 0; x < width; x++) {
21+
uint8_t pixel;
22+
if (rotated) {
23+
pixel = this->getPixel(x, y);
24+
} else {
25+
pixel = this->getRawPixel(x, y);
26+
}
27+
sprintf(pixel_buffer, " %02x", pixel);
28+
Serial.print(pixel_buffer);
29+
}
30+
Serial.print("\n");
31+
}
32+
}

0 commit comments

Comments
 (0)