Merge pull request #237 from michaelkamprath/master

Added support in GFXcanvas* classes to access pixel values
This commit is contained in:
Melissa LeBlanc-Williams 2020-06-16 16:02:58 -07:00 committed by GitHub
commit e4fcdba2b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 311 additions and 12 deletions

177
Adafruit_GFX.cpp Executable file → Normal file
View File

@ -1734,6 +1734,14 @@ bool Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }
// scanline pad).
// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
#ifdef __AVR__
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
0x08, 0x04, 0x02, 0x01};
const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
0xF7, 0xFB, 0xFD, 0xFE};
#endif
/**************************************************************************/
/*!
@brief Instatiate a GFX 1-bit canvas context for graphics
@ -1763,18 +1771,10 @@ GFXcanvas1::~GFXcanvas1(void) {
@brief Draw a pixel to the canvas framebuffer
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to fill with
@param color Binary (on or off) color to fill with
*/
/**************************************************************************/
void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
#ifdef __AVR__
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
static const uint8_t PROGMEM GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
0x08, 0x04, 0x02, 0x01},
GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
0xF7, 0xFB, 0xFD, 0xFE};
#endif
if (buffer) {
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
return;
@ -1812,10 +1812,67 @@ void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
}
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given coordinate
@param x x coordinate
@param y y coordinate
@returns The desired pixel's binary color value, either 0x1 (on) or 0x0
(off)
*/
/**********************************************************************/
bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
int16_t t;
switch (rotation) {
case 1:
t = x;
x = WIDTH - 1 - y;
y = t;
break;
case 2:
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
break;
case 3:
t = x;
x = y;
y = HEIGHT - 1 - t;
break;
}
return getRawPixel(x, y);
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given, unrotated coordinate.
This method is intended for hardware drivers to get pixel value
in physical coordinates.
@param x x coordinate
@param y y coordinate
@returns The desired pixel's binary color value, either 0x1 (on) or 0x0
(off)
*/
/**********************************************************************/
bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
return 0;
if (this->getBuffer()) {
uint8_t *buffer = this->getBuffer();
uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
#ifdef __AVR__
return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0;
#else
return ((*ptr) & (0x80 >> (x & 7))) != 0;
#endif
}
return 0;
}
/**************************************************************************/
/*!
@brief Fill the framebuffer completely with one color
@param color 16-bit 5-6-5 Color to fill with
@param color Binary (on or off) color to fill with
*/
/**************************************************************************/
void GFXcanvas1::fillScreen(uint16_t color) {
@ -1854,7 +1911,7 @@ GFXcanvas8::~GFXcanvas8(void) {
@brief Draw a pixel to the canvas framebuffer
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to fill with
@param color 8-bit Color to fill with. Only lower byte of uint16_t is used.
*/
/**************************************************************************/
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) {
}
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given coordinate
@param x x coordinate
@param y y coordinate
@returns The desired pixel's 8-bit color value
*/
/**********************************************************************/
uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const {
int16_t t;
switch (rotation) {
case 1:
t = x;
x = WIDTH - 1 - y;
y = t;
break;
case 2:
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
break;
case 3:
t = x;
x = y;
y = HEIGHT - 1 - t;
break;
}
return getRawPixel(x, y);
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given, unrotated coordinate.
This method is intended for hardware drivers to get pixel value
in physical coordinates.
@param x x coordinate
@param y y coordinate
@returns The desired pixel's 8-bit color value
*/
/**********************************************************************/
uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const {
if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
return 0;
if (buffer) {
return buffer[x + y * WIDTH];
}
return 0;
}
/**************************************************************************/
/*!
@brief Fill the framebuffer completely with one color
@param color 16-bit 5-6-5 Color to fill with
@param color 8-bit Color to fill with. Only lower byte of uint16_t is used.
*/
/**************************************************************************/
void GFXcanvas8::fillScreen(uint16_t color) {
@ -1993,6 +2098,54 @@ void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
}
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given coordinate
@param x x coordinate
@param y y coordinate
@returns The desired pixel's 16-bit 5-6-5 color value
*/
/**********************************************************************/
uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const {
int16_t t;
switch (rotation) {
case 1:
t = x;
x = WIDTH - 1 - y;
y = t;
break;
case 2:
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
break;
case 3:
t = x;
x = y;
y = HEIGHT - 1 - t;
break;
}
return getRawPixel(x, y);
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given, unrotated coordinate.
This method is intended for hardware drivers to get pixel value
in physical coordinates.
@param x x coordinate
@param y y coordinate
@returns The desired pixel's 16-bit 5-6-5 color value
*/
/**********************************************************************/
uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const {
if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
return 0;
if (buffer) {
return buffer[x + y * WIDTH];
}
return 0;
}
/**************************************************************************/
/*!
@brief Fill the framebuffer completely with one color

View File

@ -310,6 +310,7 @@ public:
~GFXcanvas1(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
bool getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
/*!
@brief Get a pointer to the internal buffer memory
@ -318,8 +319,16 @@ public:
/**********************************************************************/
uint8_t *getBuffer(void) const { return buffer; }
protected:
bool getRawPixel(int16_t x, int16_t y) const;
private:
uint8_t *buffer;
#ifdef __AVR__
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
static const uint8_t PROGMEM GFXsetBit[], GFXclrBit[];
#endif
};
/// A GFX 8-bit canvas context for graphics
@ -330,6 +339,7 @@ public:
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint8_t getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
/*!
@brief Get a pointer to the internal buffer memory
@ -338,6 +348,9 @@ public:
/**********************************************************************/
uint8_t *getBuffer(void) const { return buffer; }
protected:
uint8_t getRawPixel(int16_t x, int16_t y) const;
private:
uint8_t *buffer;
};
@ -350,6 +363,7 @@ public:
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
void byteSwap(void);
uint16_t getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
/*!
@brief Get a pointer to the internal buffer memory
@ -358,6 +372,9 @@ public:
/**********************************************************************/
uint16_t *getBuffer(void) const { return buffer; }
protected:
uint16_t getRawPixel(int16_t x, int16_t y) const;
private:
uint16_t *buffer;
};

View File

@ -0,0 +1,72 @@
/***
This example is intended to demonstrate the use of getPixel() versus
getRawPixel() in the GFXcanvas family of classes.
When using the GFXcanvas* classes as the image buffer for a hardware driver,
there is a need to get individual pixel color values at given physical
coordinates. Rather than subclasses or client classes call getBuffer() and
reinterpret the byte layout of the buffer, two methods are added to each of the
GFXcanvas* classes that allow fetching of specific pixel values.
* getPixel(x, y) : Gets the pixel color value at the rotated coordinates in
the image.
* getRawPixel(x,y) : Gets the pixel color value at the unrotated coordinates
in the image. This is useful for getting the pixel value to map to a hardware
pixel location. This method was made protected as only the hardware driver
should be accessing it.
The GFXcanvasSerialDemo class in this example will print to Serial the contents
of the underlying GFXcanvas buffer in both the current rotated layout and the
underlying physical layout.
***/
#include "GFXcanvasSerialDemo.h"
#include <Arduino.h>
void setup() {
Serial.begin(115200);
// first create a rectangular GFXcanvasSerialDemo object and draw to it
GFXcanvasSerialDemo demo(21, 11);
demo.fillScreen(0x00);
demo.setRotation(1); // now canvas is 11x21
demo.fillCircle(5, 10, 5, 0xAA);
demo.writeLine(0, 0, 10, 0, 0x11);
demo.writeLine(0, 10, 10, 10, 0x22);
demo.writeLine(0, 20, 10, 20, 0x33);
demo.writeLine(0, 0, 0, 20, 0x44);
demo.writeLine(10, 0, 10, 20, 0x55);
Serial.println("Demonstrating GFXcanvas rotated and raw pixels.\n");
// print it out rotated
Serial.println("The canvas's content in the rotation of '0':\n");
demo.setRotation(0);
demo.print(true);
Serial.println("\n");
Serial.println("The canvas's content in the rotation of '1' (which is what "
"it was drawn in):\n");
demo.setRotation(1);
demo.print(true);
Serial.println("\n");
Serial.println("The canvas's content in the rotation of '2':\n");
demo.setRotation(2);
demo.print(true);
Serial.println("\n");
Serial.println("The canvas's content in the rotation of '3':\n");
demo.setRotation(3);
demo.print(true);
Serial.println("\n");
// print it out unrotated
Serial.println("The canvas's content in it's raw, physical layout:\n");
demo.print(false);
Serial.println("\n");
}
void loop() {}

View File

@ -0,0 +1,32 @@
#include "GFXcanvasSerialDemo.h"
#include <Arduino.h>
GFXcanvasSerialDemo::GFXcanvasSerialDemo(uint16_t w, uint16_t h)
: GFXcanvas8(w, h) {}
void GFXcanvasSerialDemo::print(bool rotated) {
char pixel_buffer[8];
uint16_t width, height;
if (rotated) {
width = this->width();
height = this->height();
} else {
width = this->WIDTH;
height = this->HEIGHT;
}
for (uint16_t y = 0; y < height; y++) {
for (uint16_t x = 0; x < width; x++) {
uint8_t pixel;
if (rotated) {
pixel = this->getPixel(x, y);
} else {
pixel = this->getRawPixel(x, y);
}
sprintf(pixel_buffer, " %02x", pixel);
Serial.print(pixel_buffer);
}
Serial.print("\n");
}
}

View File

@ -0,0 +1,25 @@
#ifndef __GFXcanvasSerialDemo__
#define __GFXcanvasSerialDemo__
#include <Adafruit_GFX.h>
/**********************************************************************/
/*!
@brief Demonstrates using the GFXconvas classes as the backing store
for a device driver.
*/
/**********************************************************************/
class GFXcanvasSerialDemo : public GFXcanvas8 {
public:
GFXcanvasSerialDemo(uint16_t w, uint16_t h);
/**********************************************************************/
/*!
@brief Prints the current contents of the canvas to Serial
@param rotated true to print according to the current GFX rotation,
false to print to the native rotation of the canvas (or unrotated).
*/
/**********************************************************************/
void print(bool rotated);
};
#endif // __GFXcanvasSerialDemo__