Quellcode durchsuchen

Merge pull request #237 from michaelkamprath/master

Added support in GFXcanvas* classes to access pixel values
Melissa LeBlanc-Williams vor 5 Jahren
Ursprung
Commit
e4fcdba2b2

+ 165 - 12
Adafruit_GFX.cpp

@@ -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

+ 17 - 0
Adafruit_GFX.h

@@ -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;
 };

+ 72 - 0
examples/GFXcanvas/GFXcanvas.ino

@@ -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 - 0
examples/GFXcanvas/GFXcanvasSerialDemo.cpp

@@ -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");
+  }
+}

+ 25 - 0
examples/GFXcanvas/GFXcanvasSerialDemo.h

@@ -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__