Skip to content

Commit e4fcdba

Browse files
authored
Merge pull request #237 from michaelkamprath/master
Added support in GFXcanvas* classes to access pixel values
2 parents aa3ecbd + 6791eac commit e4fcdba

File tree

5 files changed

+311
-12
lines changed

5 files changed

+311
-12
lines changed

Adafruit_GFX.cpp

100755100644
Lines changed: 165 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,6 +1734,14 @@ bool Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }
17341734
// scanline pad).
17351735
// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
17361736

1737+
#ifdef __AVR__
1738+
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
1739+
const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
1740+
0x08, 0x04, 0x02, 0x01};
1741+
const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
1742+
0xF7, 0xFB, 0xFD, 0xFE};
1743+
#endif
1744+
17371745
/**************************************************************************/
17381746
/*!
17391747
@brief Instatiate a GFX 1-bit canvas context for graphics
@@ -1763,18 +1771,10 @@ GFXcanvas1::~GFXcanvas1(void) {
17631771
@brief Draw a pixel to the canvas framebuffer
17641772
@param x x coordinate
17651773
@param y y coordinate
1766-
@param color 16-bit 5-6-5 Color to fill with
1774+
@param color Binary (on or off) color to fill with
17671775
*/
17681776
/**************************************************************************/
17691777
void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
1770-
#ifdef __AVR__
1771-
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
1772-
static const uint8_t PROGMEM GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
1773-
0x08, 0x04, 0x02, 0x01},
1774-
GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
1775-
0xF7, 0xFB, 0xFD, 0xFE};
1776-
#endif
1777-
17781778
if (buffer) {
17791779
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
17801780
return;
@@ -1812,10 +1812,67 @@ void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
18121812
}
18131813
}
18141814

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
1821+
(off)
1822+
*/
1823+
/**********************************************************************/
1824+
bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
1825+
int16_t t;
1826+
switch (rotation) {
1827+
case 1:
1828+
t = x;
1829+
x = WIDTH - 1 - y;
1830+
y = t;
1831+
break;
1832+
case 2:
1833+
x = WIDTH - 1 - x;
1834+
y = HEIGHT - 1 - y;
1835+
break;
1836+
case 3:
1837+
t = x;
1838+
x = y;
1839+
y = HEIGHT - 1 - t;
1840+
break;
1841+
}
1842+
return getRawPixel(x, y);
1843+
}
1844+
1845+
/**********************************************************************/
1846+
/*!
1847+
@brief Get the pixel color value at a given, unrotated coordinate.
1848+
This method is intended for hardware drivers to get pixel value
1849+
in physical coordinates.
1850+
@param x x coordinate
1851+
@param y y coordinate
1852+
@returns The desired pixel's binary color value, either 0x1 (on) or 0x0
1853+
(off)
1854+
*/
1855+
/**********************************************************************/
1856+
bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
1857+
if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
1858+
return 0;
1859+
if (this->getBuffer()) {
1860+
uint8_t *buffer = this->getBuffer();
1861+
uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
1862+
1863+
#ifdef __AVR__
1864+
return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0;
1865+
#else
1866+
return ((*ptr) & (0x80 >> (x & 7))) != 0;
1867+
#endif
1868+
}
1869+
return 0;
1870+
}
1871+
18151872
/**************************************************************************/
18161873
/*!
18171874
@brief Fill the framebuffer completely with one color
1818-
@param color 16-bit 5-6-5 Color to fill with
1875+
@param color Binary (on or off) color to fill with
18191876
*/
18201877
/**************************************************************************/
18211878
void GFXcanvas1::fillScreen(uint16_t color) {
@@ -1854,7 +1911,7 @@ GFXcanvas8::~GFXcanvas8(void) {
18541911
@brief Draw a pixel to the canvas framebuffer
18551912
@param x x coordinate
18561913
@param y y coordinate
1857-
@param color 16-bit 5-6-5 Color to fill with
1914+
@param color 8-bit Color to fill with. Only lower byte of uint16_t is used.
18581915
*/
18591916
/**************************************************************************/
18601917
void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
@@ -1884,10 +1941,58 @@ void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
18841941
}
18851942
}
18861943

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

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

Adafruit_GFX.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ 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
@@ -318,8 +319,16 @@ class GFXcanvas1 : public Adafruit_GFX {
318319
/**********************************************************************/
319320
uint8_t *getBuffer(void) const { return buffer; }
320321

322+
protected:
323+
bool getRawPixel(int16_t x, int16_t y) const;
324+
321325
private:
322326
uint8_t *buffer;
327+
328+
#ifdef __AVR__
329+
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
330+
static const uint8_t PROGMEM GFXsetBit[], GFXclrBit[];
331+
#endif
323332
};
324333

325334
/// A GFX 8-bit canvas context for graphics
@@ -330,6 +339,7 @@ class GFXcanvas8 : public Adafruit_GFX {
330339
void drawPixel(int16_t x, int16_t y, uint16_t color);
331340
void fillScreen(uint16_t color);
332341
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
342+
uint8_t getPixel(int16_t x, int16_t y) const;
333343
/**********************************************************************/
334344
/*!
335345
@brief Get a pointer to the internal buffer memory
@@ -338,6 +348,9 @@ class GFXcanvas8 : public Adafruit_GFX {
338348
/**********************************************************************/
339349
uint8_t *getBuffer(void) const { return buffer; }
340350

351+
protected:
352+
uint8_t getRawPixel(int16_t x, int16_t y) const;
353+
341354
private:
342355
uint8_t *buffer;
343356
};
@@ -350,6 +363,7 @@ class GFXcanvas16 : public Adafruit_GFX {
350363
void drawPixel(int16_t x, int16_t y, uint16_t color);
351364
void fillScreen(uint16_t color);
352365
void byteSwap(void);
366+
uint16_t getPixel(int16_t x, int16_t y) const;
353367
/**********************************************************************/
354368
/*!
355369
@brief Get a pointer to the internal buffer memory
@@ -358,6 +372,9 @@ class GFXcanvas16 : public Adafruit_GFX {
358372
/**********************************************************************/
359373
uint16_t *getBuffer(void) const { return buffer; }
360374

375+
protected:
376+
uint16_t getRawPixel(int16_t x, int16_t y) const;
377+
361378
private:
362379
uint16_t *buffer;
363380
};

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)