adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.09k stars 1.21k forks source link

Inconsistent rendering of border pixels with vectorio #8742

Open bablokb opened 10 months ago

bablokb commented 10 months ago

CircuitPython version

Adafruit CircuitPython 8.2.9 on 2023-12-06; Raspberry Pi Pico with rp2040

Code/REPL

import time
import board
import displayio
import busio
import adafruit_ssd1675

from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label as label
from vectorio import Rectangle
from terminalio import FONT as font

LOREM_IPSUM = (("Lorem ipsum "*3)+"\n")*11

def show_text(display):
  view = displayio.Group()
  shader = displayio.Palette(2)
  shader[0] = 0xFFFFFF
  shader[1] = 0x000000
  view.append(Rectangle(pixel_shader=shader,x=0,y=0,
                   width=display.width,
                   height=display.height,
                   color_index=1))
  view.append(Rectangle(pixel_shader=shader,x=1,y=1,
                   width=display.width-2,
                   height=display.height-2,
                   color_index=0))
  mytext = label.Label(font=font,color=shader[1],
                       tab_replacement=(2," "),
                       line_spacing=1,
                       text=LOREM_IPSUM,
                       anchor_point=(0.5,0.5))
  mytext.anchored_position = (display.width/2,
                              display.height/2)
  view.append(mytext)
  display.root_group = view
  display.refresh()

# --- main program   --------------------------------

displayio.release_displays()
epd_cs    = board.GP22
epd_dc    = board.GP21
epd_reset = board.GP20
epd_busy  = board.GP17
epd_sck   = board.GP18
epd_mosi  = board.GP19
spi = busio.SPI(epd_sck,MOSI=epd_mosi)
display_bus = displayio.FourWire(
    spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000
)
display = adafruit_ssd1675.SSD1675(
    display_bus, width=250, height=122, rotation=270, busy_pin=epd_busy
)

show_text(display)
print("refreshed")

while True:
  time.sleep(1)

Behavior

The code should create a one-pixel border around the screen. I am testing this with an Adafruit 2.13 monochrome e-ink.

The code only creates the border on the top, right and bottom (pin) side (i.e. missing on the left). Setting the rotation parameter to 90 instead of 270, the missing border is now on the pin-side (which is now the "top"-side after rotation). Not logical, my expectation here was that rotating by 180° would move the missing border to the other side.

I also tried with a PyPortal (with slightly changed colors), but also here the borders don't render as expected.

This seems to be some sort of "off-by-1" problem. In the rotation=270 case, I get the expected result by assuming that the x-axis starts at pixel 1 (i.e. x=1,y=0 for the first rectangle and x=2,y=1 for the second rectangle). In the rotation=90 case, the y-axis has to start at pixel 1.

Description

No response

Additional information

No response

bablokb commented 10 months ago

BTW: works correct when replacing vectorio.Rectangle with adafruit_display_shapes.rect.Rect. But this is not a valid option, since the latter uses much more memory.

carson-coder commented 10 months ago

Could you upload a picture

bablokb commented 10 months ago

Below are five images with varying parameters. The first, third and fifth are the expected result. But for the third and fifth I have to tweak the values so the result is correct.

If you take a closer look at the second image, you can see that the border on left is missing and the border on the right is two pixels wide. In the fourth image, the bottom border is missing and the top border is two pixels wide.

carson-coder commented 10 months ago

why do you have the rotation on the rects

bablokb commented 10 months ago

If you want to use the display in landscape mode, you either need rotation=270 or rotation=90.

See the example code from Adafruit here: https://learn.adafruit.com/adafruit-2-13-eink-display-breakouts-and-featherwings/circuitpython-usage

FoamyGuy commented 9 months ago

I confirmed this issue exists on TFT screens as well with a Feather ESP32-S2 TFT.

Here is some reproducer code that can run on any device with a built-in display:

import board
import displayio
import vectorio

main_group = displayio.Group()

palette = displayio.Palette(2)
palette[0] = 0x00ff00
palette[1] = 0x000000

display = board.DISPLAY

display.rotation = 180

print(f"width: {display.width} height: {display.height}")

border_rectangle = vectorio.Rectangle(pixel_shader=palette,
                                      width=display.width,
                                      height=display.height,
                                      x=0, y=0)
main_group.append(border_rectangle)

inside_rectangle = vectorio.Rectangle(pixel_shader=palette,
                                      width=display.width - 2,
                                      height=display.height - 2,
                                      x=1, y=1,
                                      color_index=1)
main_group.append(inside_rectangle)

display.root_group = main_group

while True:
    pass