Add grayscale support for B/W displays
Is your feature request related to a problem? Please describe. I have a 2.7 inch Waveshare HAT with a resolution of 264x176. On such a small screen, fonts are mostly hard to read without antialiasing.
Example with PaperPi: https://i0.wp.com/dronebotworkshop.com/wp-content/uploads/2022/02/paperpi-weather.png
Describe the solution you'd like The display supports 4 shades of gray, as can be seen in https://github.com/waveshareteam/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in7.py#L436.
This also seems to apply to other models.
To use it, one must create a 4 color image with palette #000000, #808080, #c0c0c0, #ffffff, and call init_4Gray, getBuffer_4Gray and display_4Gray instead of the methods without the _4Gray suffix.
Describe alternatives you've considered More dithering in black & white doesn't help.
Additional context
For comparison, I converted the same input image to B/W and 4 colors, and the difference is significant:
This is something I've wanted to do for a while, but will take some overhaul of the underlying epdlib that manages all of the display interface. Once that's done, it would be relatively easy to add into PaperPi. Right now there are three classes of devices that are supported by epdlib: HD, 1 Bit and 7 Color. The HD screens all support grayscale, but the oddballs like the 2in7 aren't supported (yet).
The basic problems is that the 2in7 and others have oddball methods that require a lot of extra code to manage for writing in grayscale and also for managing the other color layers. The Screen.writeEPD() method would need to be adjusted to handle additional write functions loaded from the waveshare drivers.
Unfortunately I'm pretty swamped with other commitments right now and don't have access to my 2in7 display for testing. If you're interested in tackling the epdlib side of things, I can offer some support and guidance, but I can't do much right now.
PRs are always welcome!
I'll see what I can do. My python skills are very basic so I can't promise anything.
@txoof Can you please confirm the following?
- There is nothing to do for HD displays
- HD displays are exactly the ones without any Waveshare drivers (as per this code)?
You're on the right track. The HD displays are managed with another, non-waveshare driver altogether.
The _load_non_hd method is where all the various types of waveshare drivers are setup. Upon further investigation on lines 514..520, I see that I was starting to implement this. The display mode for your type of screen is inferred to support grayscale because the display_args_spec has > 2 parameters. This typically implies that it's a grayscale screen.
To test if this works, create an epdlib.Screen instance and set it up with the appropriate 2in7 driver and then push a grayscale image to it and see what happens. If that works, then the problem is in PaperPi not recognizing that the display is grayscale and falling back to 1 bit images.
If you need some hints on setting up a screen object and pushing images to it, look at the main() function at the bottom. It has a fairly complete implementation of all the steps.
Looking at the blame, it looks like it's been at least 4 years since I thought about this, so I'm just going by comments and the logic there and that might be...wrong.
Let me know what you get to and I'll try to give some more pointers.
Looking at the Waveshare catalog, these are the device classes:
- black/white only
- black/white with 4 gray levels
- black/white with 16 gray levels (HD only)
- black/white/red
- black/white/yellow
- black/white/red/yellow
- 7 color
- full color (HD only)
The display mode for your type of screen is inferred to support grayscale because the display_args_spec has > 2 parameters. This typically implies that it's a grayscale screen.
Not quite. This indicates a screen from class 4/5/6.
The class 2 models have 2 parameters in the display method, and come with an additional display_4Gray method, also with 2 parameters.
Should be pretty straight-forward to implement for that case. Let me look into it.
edit
What I get from the driver code:
| Class | Waveshare driver methods |
|---|---|
| 1. black/white only | display(bw_image) |
| 2. black/white with 4 gray levels | display(bw_image), or, at your choice, display_4Gray(gray4_image) (Colors need to be reduced explicitly) |
| 3. black/white with 16 gray levels | - |
| 4. black/white/red | display(bw_image, red_image) |
| 5. black/white/yellow | display(bw_image, yellow_image) |
| 6. black/white/red/yellow | display(bwry_image) (Colors will be reduced in getbuffer) |
| 7. 7-color | display(color7_image) (Colors will be reduced in getbuffer) |
| 8. full Color | - |
There are some adustments needed in PaperPi
https://github.com/txoof/PaperPi/blob/224a7cbfd952e47d6f76d5b351b8ac800a95e19b/paperpi/paperpi.py#L682-L691