Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support in GFXcanvas* classes to access pixel values #237

Merged
merged 2 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 165 additions & 12 deletions Adafruit_GFX.cpp
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,14 @@ boolean Adafruit_GFX_Button::justReleased() {
// 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
Expand Down Expand Up @@ -1765,18 +1773,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;
Expand Down Expand Up @@ -1814,10 +1814,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) {
Expand Down Expand Up @@ -1856,7 +1913,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) {
Expand Down Expand Up @@ -1886,10 +1943,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) {
Expand Down Expand Up @@ -1995,6 +2100,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
Expand Down
17 changes: 17 additions & 0 deletions Adafruit_GFX.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ class GFXcanvas1 : public Adafruit_GFX {
~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
Expand All @@ -318,8 +319,16 @@ class GFXcanvas1 : public Adafruit_GFX {
/**********************************************************************/
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
Expand All @@ -330,6 +339,7 @@ class GFXcanvas8 : public Adafruit_GFX {
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
Expand All @@ -338,6 +348,9 @@ class GFXcanvas8 : public Adafruit_GFX {
/**********************************************************************/
uint8_t *getBuffer(void) const { return buffer; }

protected:
uint8_t getRawPixel(int16_t x, int16_t y) const;

private:
uint8_t *buffer;
};
Expand All @@ -350,6 +363,7 @@ class GFXcanvas16 : public Adafruit_GFX {
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
Expand All @@ -358,6 +372,9 @@ class GFXcanvas16 : public Adafruit_GFX {
/**********************************************************************/
uint16_t *getBuffer(void) const { return buffer; }

protected:
uint16_t getRawPixel(int16_t x, int16_t y) const;

private:
uint16_t *buffer;
};
Expand Down
72 changes: 72 additions & 0 deletions examples/GFXcanvas/GFXcanvas.ino
Original file line number Diff line number Diff line change
@@ -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() {}
32 changes: 32 additions & 0 deletions examples/GFXcanvas/GFXcanvasSerialDemo.cpp
Original file line number Diff line number Diff line change
@@ -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");
}
}
Loading