Преглед на файлове

fixed fast line drawing in GFXcanvas* classes

Michael Kamprath преди 5 години
родител
ревизия
18eec8bb9e
променени са 5 файла, в които са добавени 582 реда и са изтрити 50 реда
  1. 402 22
      Adafruit_GFX.cpp
  2. 12 1
      Adafruit_GFX.h
  3. 64 23
      examples/GFXcanvas/GFXcanvas.ino
  4. 62 2
      examples/GFXcanvas/GFXcanvasSerialDemo.cpp
  5. 42 2
      examples/GFXcanvas/GFXcanvasSerialDemo.h

+ 402 - 22
Adafruit_GFX.cpp

@@ -1882,6 +1882,191 @@ void GFXcanvas1::fillScreen(uint16_t color) {
   }
   }
 }
 }
 
 
+/**************************************************************************/
+/*!
+   @brief    Speed optimized vertical line drawing
+   @param    x   Line horizontal start point
+   @param    y   Line vertical start point
+   @param    h   length of vertical line to be drawn, including first point
+   @param    color   Binary (on or off) color to fill with
+*/
+/**************************************************************************/
+void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h,
+                               uint16_t color) {
+  if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) {
+    return;
+  }
+
+  if (y + h > height()) {
+    h = height() - y;
+  } else if (h < 0) {
+    // convert negative heights to their postive equivalent
+    h *= -1;
+    y -= h - 1;
+    if (y < 0) {
+      h += y;
+      y = 0;
+    }
+  }
+
+  if (getRotation() == 0) {
+    drawFastRawVLine(x, y, h, color);
+  } else if (getRotation() == 1) {
+    int16_t t = x;
+    x = WIDTH - 1 - y;
+    y = t;
+    x -= h - 1;
+    drawFastRawHLine(x, y, h, color);
+  } else if (getRotation() == 2) {
+    x = WIDTH - 1 - x;
+    y = HEIGHT - 1 - y;
+
+    y -= h - 1;
+    drawFastRawVLine(x, y, h, color);
+  } else if (getRotation() == 3) {
+    int16_t t = x;
+    x = y;
+    y = HEIGHT - 1 - t;
+    drawFastRawHLine(x, y, h, color);
+  }
+}
+
+/**************************************************************************/
+/*!
+   @brief    Speed optimized horizontal line drawing
+   @param    x   Line horizontal start point
+   @param    y   Line vertical start point
+   @param    w   length of horizontal line to be drawn, including first point
+   @param    color   Binary (on or off) color to fill with
+*/
+/**************************************************************************/
+void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w,
+                               uint16_t color) {
+  if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) {
+    return;
+  }
+
+  if (x + w > width()) {
+    w = width() - x;
+  } else if (w < 0) {
+    // convert negative widths to their postive equivalent
+    w *= -1;
+    x -= w - 1;
+    if (x < 0) {
+      w += x;
+      x = 0;
+    }
+  }
+
+  if (getRotation() == 0) {
+    drawFastRawHLine(x, y, w, color);
+  } else if (getRotation() == 1) {
+    int16_t t = x;
+    x = WIDTH - 1 - y;
+    y = t;
+    drawFastRawVLine(x, y, w, color);
+  } else if (getRotation() == 2) {
+    x = WIDTH - 1 - x;
+    y = HEIGHT - 1 - y;
+
+    x -= w - 1;
+    drawFastRawHLine(x, y, w, color);
+  } else if (getRotation() == 3) {
+    int16_t t = x;
+    x = y;
+    y = HEIGHT - 1 - t;
+    y -= w - 1;
+    drawFastRawVLine(x, y, w, color);
+  }
+}
+
+void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
+                                  uint16_t color) {
+  // x & y already in raw (rotation 0) coordinates, no need to transform.
+  int16_t row_bytes = ((WIDTH + 7) / 8);
+  uint8_t *buffer = this->getBuffer();
+  uint8_t *ptr = &buffer[(x / 8) + y * row_bytes];
+
+  if (color > 0) {
+#ifdef __AVR__
+    uint8_t bit_mask = pgm_read_byte(&GFXsetBit[x & 7]);
+#else
+    uint8_t bit_mask = (0x80 >> (x & 7));
+#endif
+    for (int16_t i = 0; i < h; i++) {
+      *ptr |= bit_mask;
+      ptr += row_bytes;
+    }
+  } else {
+#ifdef __AVR__
+    uint8_t bit_mask = pgm_read_byte(&GFXclrBit[x & 7]);
+#else
+    uint8_t bit_mask = ~(0x80 >> (x & 7));
+#endif
+    for (int16_t i = 0; i < h; i++) {
+      *ptr &= bit_mask;
+      ptr += row_bytes;
+    }
+  }
+}
+
+void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
+                                  uint16_t color) {
+  // x & y already in raw (rotation 0) coordinates, no need to transform.
+  int16_t rowBytes = ((WIDTH + 7) / 8);
+  uint8_t *buffer = this->getBuffer();
+  uint8_t *ptr = &buffer[(x / 8) + y * rowBytes];
+  size_t remainingWidthBits = w;
+
+  // check to see if first byte needs to be partially filled
+  if ((x & 7) > 0) {
+    // create bit mask for first byte
+    uint8_t startByteBitMask = 0x00;
+    for (int8_t i = (x & 7); ((i < 8) && (remainingWidthBits > 0)); i++) {
+#ifdef __AVR__
+      startByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
+#else
+      startByteBitMask |= (0x80 >> i);
+#endif
+      remainingWidthBits--;
+    }
+    if (color > 0) {
+      *ptr |= startByteBitMask;
+    } else {
+      *ptr &= ~startByteBitMask;
+    }
+
+    ptr++;
+  }
+
+  // do the next remainingWidthBits bits
+  if (remainingWidthBits > 0) {
+    size_t remainingWholeBytes = remainingWidthBits / 8;
+    size_t lastByteBits = remainingWidthBits % 8;
+    uint8_t wholeByteColor = color > 0 ? 0xFF : 0x00;
+
+    memset(ptr, wholeByteColor, remainingWholeBytes);
+
+    if (lastByteBits > 0) {
+      uint8_t lastByteBitMask = 0x00;
+      for (int8_t i = 0; i < lastByteBits; i++) {
+#ifdef __AVR__
+        lastByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
+#else
+        lastByteBitMask |= (0x80 >> i);
+#endif
+      }
+      ptr += remainingWholeBytes;
+
+      if (color > 0) {
+        *ptr |= lastByteBitMask;
+      } else {
+        *ptr &= ~lastByteBitMask;
+      }
+    }
+  }
+}
+
 /**************************************************************************/
 /**************************************************************************/
 /*!
 /*!
    @brief    Instatiate a GFX 8-bit canvas context for graphics
    @brief    Instatiate a GFX 8-bit canvas context for graphics
@@ -2001,41 +2186,119 @@ void GFXcanvas8::fillScreen(uint16_t color) {
   }
   }
 }
 }
 
 
-void GFXcanvas8::writeFastHLine(int16_t x, int16_t y, int16_t w,
-                                uint16_t color) {
-
-  if ((x >= _width) || (y < 0) || (y >= _height))
+/**************************************************************************/
+/*!
+   @brief    Speed optimized vertical line drawing
+   @param    x   Line horizontal start point
+   @param    y   Line vertical start point
+   @param    h   length of vertical line to be drawn, including first point
+   @param    color   8-bit Color to fill with. Only lower byte of uint16_t is
+   used.
+*/
+/**************************************************************************/
+void GFXcanvas8::drawFastVLine(int16_t x, int16_t y, int16_t h,
+                               uint16_t color) {
+  if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) {
     return;
     return;
-  int16_t x2 = x + w - 1;
-  if (x2 < 0)
+  }
+
+  if (y + h > height()) {
+    h = height() - y;
+  } else if (h < 0) {
+    // convert negative heights to their postive equivalent
+    h *= -1;
+    y -= h - 1;
+    if (y < 0) {
+      h += y;
+      y = 0;
+    }
+  }
+
+  if (getRotation() == 0) {
+    drawFastRawVLine(x, y, h, color);
+  } else if (getRotation() == 1) {
+    int16_t t = x;
+    x = WIDTH - 1 - y;
+    y = t;
+    x -= h - 1;
+    drawFastRawHLine(x, y, h, color);
+  } else if (getRotation() == 2) {
+    x = WIDTH - 1 - x;
+    y = HEIGHT - 1 - y;
+
+    y -= h - 1;
+    drawFastRawVLine(x, y, h, color);
+  } else if (getRotation() == 3) {
+    int16_t t = x;
+    x = y;
+    y = HEIGHT - 1 - t;
+    drawFastRawHLine(x, y, h, color);
+  }
+}
+
+/**************************************************************************/
+/*!
+   @brief    Speed optimized horizontal line drawing
+   @param    x   Line horizontal start point
+   @param    y   Line vertical start point
+   @param    w   length of horizontal line to be drawn, including first point
+   @param    color   8-bit Color to fill with. Only lower byte of uint16_t is
+   used.
+*/
+/**************************************************************************/
+void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w,
+                               uint16_t color) {
+  if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) {
     return;
     return;
+  }
 
 
-  // Clip left/right
-  if (x < 0) {
-    x = 0;
-    w = x2 + 1;
+  if (x + w > width()) {
+    w = width() - x;
+  } else if (w < 0) {
+    // convert negative widths to their postive equivalent
+    w *= -1;
+    x -= w - 1;
+    if (x < 0) {
+      w += x;
+      x = 0;
+    }
   }
   }
-  if (x2 >= _width)
-    w = _width - x;
 
 
-  int16_t t;
-  switch (rotation) {
-  case 1:
-    t = x;
+  if (getRotation() == 0) {
+    drawFastRawHLine(x, y, w, color);
+  } else if (getRotation() == 1) {
+    int16_t t = x;
     x = WIDTH - 1 - y;
     x = WIDTH - 1 - y;
     y = t;
     y = t;
-    break;
-  case 2:
+    drawFastRawVLine(x, y, w, color);
+  } else if (getRotation() == 2) {
     x = WIDTH - 1 - x;
     x = WIDTH - 1 - x;
     y = HEIGHT - 1 - y;
     y = HEIGHT - 1 - y;
-    break;
-  case 3:
-    t = x;
+
+    x -= w - 1;
+    drawFastRawHLine(x, y, w, color);
+  } else if (getRotation() == 3) {
+    int16_t t = x;
     x = y;
     x = y;
     y = HEIGHT - 1 - t;
     y = HEIGHT - 1 - t;
-    break;
+    y -= w - 1;
+    drawFastRawVLine(x, y, w, color);
   }
   }
+}
 
 
+void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
+                                  uint16_t color) {
+  // x & y already in raw (rotation 0) coordinates, no need to transform.
+  uint8_t *buffer_ptr = buffer + y * WIDTH + x;
+  for (int16_t i = 0; i < h; i++) {
+    (*buffer_ptr) = color;
+    buffer_ptr += WIDTH;
+  }
+}
+
+void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
+                                  uint16_t color) {
+  // x & y already in raw (rotation 0) coordinates, no need to transform.
   memset(buffer + y * WIDTH + x, color, w);
   memset(buffer + y * WIDTH + x, color, w);
 }
 }
 
 
@@ -2185,3 +2448,120 @@ void GFXcanvas16::byteSwap(void) {
       buffer[i] = __builtin_bswap16(buffer[i]);
       buffer[i] = __builtin_bswap16(buffer[i]);
   }
   }
 }
 }
+
+/**************************************************************************/
+/*!
+   @brief    Speed optimized vertical line drawing
+   @param    x   Line horizontal start point
+   @param    y   Line vertical start point
+   @param    h   length of vertical line to be drawn, including first point
+   @param    color   color 16-bit 5-6-5 Color to draw line with
+*/
+/**************************************************************************/
+void GFXcanvas16::drawFastVLine(int16_t x, int16_t y, int16_t h,
+                                uint16_t color) {
+  if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) {
+    return;
+  }
+
+  if (y + h > height()) {
+    h = height() - y;
+  } else if (h < 0) {
+    // convert negative heights to their postive equivalent
+    h *= -1;
+    y -= h - 1;
+    if (y < 0) {
+      h += y;
+      y = 0;
+    }
+  }
+
+  if (getRotation() == 0) {
+    drawFastRawVLine(x, y, h, color);
+  } else if (getRotation() == 1) {
+    int16_t t = x;
+    x = WIDTH - 1 - y;
+    y = t;
+    x -= h - 1;
+    drawFastRawHLine(x, y, h, color);
+  } else if (getRotation() == 2) {
+    x = WIDTH - 1 - x;
+    y = HEIGHT - 1 - y;
+
+    y -= h - 1;
+    drawFastRawVLine(x, y, h, color);
+  } else if (getRotation() == 3) {
+    int16_t t = x;
+    x = y;
+    y = HEIGHT - 1 - t;
+    drawFastRawHLine(x, y, h, color);
+  }
+}
+
+/**************************************************************************/
+/*!
+   @brief    Speed optimized horizontal line drawing
+   @param    x   Line horizontal start point
+   @param    y   Line vertical start point
+   @param    w   length of horizontal line to be drawn, including first point
+   @param    color   color 16-bit 5-6-5 Color to draw line with
+*/
+/**************************************************************************/
+void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w,
+                                uint16_t color) {
+  if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) {
+    return;
+  }
+
+  if (x + w > width()) {
+    w = width() - x;
+  } else if (w < 0) {
+    // convert negative widths to their postive equivalent
+    w *= -1;
+    x -= w - 1;
+    if (x < 0) {
+      w += x;
+      x = 0;
+    }
+  }
+
+  if (getRotation() == 0) {
+    drawFastRawHLine(x, y, w, color);
+  } else if (getRotation() == 1) {
+    int16_t t = x;
+    x = WIDTH - 1 - y;
+    y = t;
+    drawFastRawVLine(x, y, w, color);
+  } else if (getRotation() == 2) {
+    x = WIDTH - 1 - x;
+    y = HEIGHT - 1 - y;
+
+    x -= w - 1;
+    drawFastRawHLine(x, y, w, color);
+  } else if (getRotation() == 3) {
+    int16_t t = x;
+    x = y;
+    y = HEIGHT - 1 - t;
+    y -= w - 1;
+    drawFastRawVLine(x, y, w, color);
+  }
+}
+
+void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
+                                   uint16_t color) {
+  // x & y already in raw (rotation 0) coordinates, no need to transform.
+  uint16_t *buffer_ptr = buffer + y * WIDTH + x;
+  for (int16_t i = 0; i < h; i++) {
+    (*buffer_ptr) = color;
+    buffer_ptr += WIDTH;
+  }
+}
+
+void GFXcanvas16::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
+                                   uint16_t color) {
+  // x & y already in raw (rotation 0) coordinates, no need to transform.
+  size_t buffer_index = y * WIDTH + x;
+  for (int16_t i = buffer_index; i < buffer_index + w; i++) {
+    buffer[i] = color;
+  }
+}

+ 12 - 1
Adafruit_GFX.h

@@ -310,6 +310,8 @@ public:
   ~GFXcanvas1(void);
   ~GFXcanvas1(void);
   void drawPixel(int16_t x, int16_t y, uint16_t color);
   void drawPixel(int16_t x, int16_t y, uint16_t color);
   void fillScreen(uint16_t color);
   void fillScreen(uint16_t color);
+  void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+  void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
   bool getPixel(int16_t x, int16_t y) const;
   bool getPixel(int16_t x, int16_t y) const;
   /**********************************************************************/
   /**********************************************************************/
   /*!
   /*!
@@ -321,6 +323,8 @@ public:
 
 
 protected:
 protected:
   bool getRawPixel(int16_t x, int16_t y) const;
   bool getRawPixel(int16_t x, int16_t y) const;
+  void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+  void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
 
 
 private:
 private:
   uint8_t *buffer;
   uint8_t *buffer;
@@ -338,7 +342,8 @@ public:
   ~GFXcanvas8(void);
   ~GFXcanvas8(void);
   void drawPixel(int16_t x, int16_t y, uint16_t color);
   void drawPixel(int16_t x, int16_t y, uint16_t color);
   void fillScreen(uint16_t color);
   void fillScreen(uint16_t color);
-  void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
+  void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+  void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
   uint8_t getPixel(int16_t x, int16_t y) const;
   uint8_t getPixel(int16_t x, int16_t y) const;
   /**********************************************************************/
   /**********************************************************************/
   /*!
   /*!
@@ -350,6 +355,8 @@ public:
 
 
 protected:
 protected:
   uint8_t getRawPixel(int16_t x, int16_t y) const;
   uint8_t getRawPixel(int16_t x, int16_t y) const;
+  void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+  void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
 
 
 private:
 private:
   uint8_t *buffer;
   uint8_t *buffer;
@@ -363,6 +370,8 @@ public:
   void drawPixel(int16_t x, int16_t y, uint16_t color);
   void drawPixel(int16_t x, int16_t y, uint16_t color);
   void fillScreen(uint16_t color);
   void fillScreen(uint16_t color);
   void byteSwap(void);
   void byteSwap(void);
+  void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+  void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
   uint16_t getPixel(int16_t x, int16_t y) const;
   uint16_t getPixel(int16_t x, int16_t y) const;
   /**********************************************************************/
   /**********************************************************************/
   /*!
   /*!
@@ -374,6 +383,8 @@ public:
 
 
 protected:
 protected:
   uint16_t getRawPixel(int16_t x, int16_t y) const;
   uint16_t getRawPixel(int16_t x, int16_t y) const;
+  void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+  void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
 
 
 private:
 private:
   uint16_t *buffer;
   uint16_t *buffer;

+ 64 - 23
examples/GFXcanvas/GFXcanvas.ino

@@ -1,6 +1,7 @@
 /***
 /***
 This example is intended to demonstrate the use of getPixel() versus
 This example is intended to demonstrate the use of getPixel() versus
-getRawPixel() in the GFXcanvas family of classes.
+getRawPixel() and the fast horizontal and vertical drawing routines
+in the GFXcanvas family of classes,
 
 
 When using the GFXcanvas* classes as the image buffer for a hardware driver,
 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
 there is a need to get individual pixel color values at given physical
@@ -15,9 +16,9 @@ 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
 pixel location. This method was made protected as only the hardware driver
 should be accessing it.
 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.
+The GFXcanvas*SerialDemo classes 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 "GFXcanvasSerialDemo.h"
@@ -26,46 +27,86 @@ underlying physical layout.
 void setup() {
 void setup() {
   Serial.begin(115200);
   Serial.begin(115200);
 
 
-  // first create a rectangular GFXcanvasSerialDemo object and draw to it
-  GFXcanvasSerialDemo demo(21, 11);
+  // first create a rectangular GFXcanvas8SerialDemo object and draw to it
+  GFXcanvas8SerialDemo demo8(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);
+  demo8.fillScreen(0x00);
+  demo8.setRotation(1); // now canvas is 11x21
+  demo8.fillCircle(5, 10, 5, 0xAA);
+  demo8.writeFastHLine(0, 0, 11, 0x11);
+  demo8.writeFastHLine(10, 10, -11, 0x22);
+  demo8.writeFastHLine(0, 20, 11, 0x33);
+  demo8.writeFastVLine(0, 0, 21, 0x44);
+  demo8.writeFastVLine(10, 20, -21, 0x55);
 
 
   Serial.println("Demonstrating GFXcanvas rotated and raw pixels.\n");
   Serial.println("Demonstrating GFXcanvas rotated and raw pixels.\n");
 
 
   // print it out rotated
   // print it out rotated
 
 
   Serial.println("The canvas's content in the rotation of '0':\n");
   Serial.println("The canvas's content in the rotation of '0':\n");
-  demo.setRotation(0);
-  demo.print(true);
+  demo8.setRotation(0);
+  demo8.print(true);
   Serial.println("\n");
   Serial.println("\n");
 
 
   Serial.println("The canvas's content in the rotation of '1' (which is what "
   Serial.println("The canvas's content in the rotation of '1' (which is what "
                  "it was drawn in):\n");
                  "it was drawn in):\n");
-  demo.setRotation(1);
-  demo.print(true);
+  demo8.setRotation(1);
+  demo8.print(true);
   Serial.println("\n");
   Serial.println("\n");
 
 
   Serial.println("The canvas's content in the rotation of '2':\n");
   Serial.println("The canvas's content in the rotation of '2':\n");
-  demo.setRotation(2);
-  demo.print(true);
+  demo8.setRotation(2);
+  demo8.print(true);
   Serial.println("\n");
   Serial.println("\n");
 
 
   Serial.println("The canvas's content in the rotation of '3':\n");
   Serial.println("The canvas's content in the rotation of '3':\n");
-  demo.setRotation(3);
-  demo.print(true);
+  demo8.setRotation(3);
+  demo8.print(true);
   Serial.println("\n");
   Serial.println("\n");
 
 
   // print it out unrotated
   // print it out unrotated
   Serial.println("The canvas's content in it's raw, physical layout:\n");
   Serial.println("The canvas's content in it's raw, physical layout:\n");
-  demo.print(false);
+  demo8.print(false);
+  Serial.println("\n");
+
+  // Demonstrate GFXcanvas1SerialDemo
+
+  GFXcanvas1SerialDemo demo1(21, 11);
+  demo1.fillScreen(0);
+  demo1.setRotation(0);
+  demo1.writeFastHLine(0, 0, 9, 1);
+  demo1.setRotation(1);
+  demo1.writeFastHLine(0, 0, 9, 1);
+  demo1.setRotation(2);
+  demo1.writeFastHLine(0, 0, 9, 1);
+  demo1.setRotation(3);
+  demo1.writeFastHLine(0, 0, 9, 1);
+  demo1.setRotation(1);
+  demo1.fillRect(3, 8, 5, 5, 1);
+
+  Serial.println("\nThe GFXcanvas1 raw content after drawing a fast horizontal "
+                 "line in each rotation:\n");
+  demo1.print(false);
+  Serial.println("\n");
+
+  // Demonstrate GFXcanvas16SerialDemo
+
+  GFXcanvas16SerialDemo demo16(21, 11);
+  demo16.fillScreen(0);
+  demo16.setRotation(0);
+  demo16.writeFastHLine(0, 0, 9, 0x1111);
+  demo16.setRotation(1);
+  demo16.writeFastHLine(0, 0, 9, 0x2222);
+  demo16.setRotation(2);
+  demo16.writeFastHLine(0, 0, 9, 0x3333);
+  demo16.setRotation(3);
+  demo16.writeFastHLine(0, 0, 9, 0x4444);
+  demo16.setRotation(1);
+  demo16.fillRect(3, 8, 5, 5, 0x8888);
+
+  Serial.println("\nThe GFXcanvas16 raw content after drawing a fast "
+                 "horizontal line in each rotation:\n");
+  demo16.print(false);
   Serial.println("\n");
   Serial.println("\n");
 }
 }
 
 

+ 62 - 2
examples/GFXcanvas/GFXcanvasSerialDemo.cpp

@@ -1,10 +1,40 @@
 #include "GFXcanvasSerialDemo.h"
 #include "GFXcanvasSerialDemo.h"
 #include <Arduino.h>
 #include <Arduino.h>
 
 
-GFXcanvasSerialDemo::GFXcanvasSerialDemo(uint16_t w, uint16_t h)
+GFXcanvas1SerialDemo::GFXcanvas1SerialDemo(uint16_t w, uint16_t h)
+    : GFXcanvas1(w, h) {}
+
+void GFXcanvas1SerialDemo::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++) {
+      bool pixel;
+      if (rotated) {
+        pixel = this->getPixel(x, y);
+      } else {
+        pixel = this->getRawPixel(x, y);
+      }
+      sprintf(pixel_buffer, " %d", pixel);
+      Serial.print(pixel_buffer);
+    }
+    Serial.print("\n");
+  }
+}
+
+GFXcanvas8SerialDemo::GFXcanvas8SerialDemo(uint16_t w, uint16_t h)
     : GFXcanvas8(w, h) {}
     : GFXcanvas8(w, h) {}
 
 
-void GFXcanvasSerialDemo::print(bool rotated) {
+void GFXcanvas8SerialDemo::print(bool rotated) {
   char pixel_buffer[8];
   char pixel_buffer[8];
   uint16_t width, height;
   uint16_t width, height;
 
 
@@ -30,3 +60,33 @@ void GFXcanvasSerialDemo::print(bool rotated) {
     Serial.print("\n");
     Serial.print("\n");
   }
   }
 }
 }
+
+GFXcanvas16SerialDemo::GFXcanvas16SerialDemo(uint16_t w, uint16_t h)
+    : GFXcanvas16(w, h) {}
+
+void GFXcanvas16SerialDemo::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++) {
+      uint16_t pixel;
+      if (rotated) {
+        pixel = this->getPixel(x, y);
+      } else {
+        pixel = this->getRawPixel(x, y);
+      }
+      sprintf(pixel_buffer, " %04x", pixel);
+      Serial.print(pixel_buffer);
+    }
+    Serial.print("\n");
+  }
+}

+ 42 - 2
examples/GFXcanvas/GFXcanvasSerialDemo.h

@@ -8,9 +8,49 @@
   for a device driver.
   for a device driver.
 */
 */
 /**********************************************************************/
 /**********************************************************************/
-class GFXcanvasSerialDemo : public GFXcanvas8 {
+class GFXcanvas1SerialDemo : public GFXcanvas1 {
 public:
 public:
-  GFXcanvasSerialDemo(uint16_t w, uint16_t h);
+  GFXcanvas1SerialDemo(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);
+};
+
+/**********************************************************************/
+/*!
+  @brief	Demonstrates using the GFXconvas classes as the backing store
+  for a device driver.
+*/
+/**********************************************************************/
+class GFXcanvas8SerialDemo : public GFXcanvas8 {
+public:
+  GFXcanvas8SerialDemo(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);
+};
+
+/**********************************************************************/
+/*!
+  @brief	Demonstrates using the GFXconvas classes as the backing store
+  for a device driver.
+*/
+/**********************************************************************/
+class GFXcanvas16SerialDemo : public GFXcanvas16 {
+public:
+  GFXcanvas16SerialDemo(uint16_t w, uint16_t h);
 
 
   /**********************************************************************/
   /**********************************************************************/
   /*!
   /*!