Anzeige von PNG-Bitmaps aus Grafana auf einem e-Paper Display

A post was merged into an existing topic: Anzeige der Daten auf einem Kiosk-Display mit RaspberryPi und Grafana

Hi Clemens,

Das stimmt – das wäre ne Menge Holz.

Praktisch wäre es auf jeden Fall. Ich finde es auf jeden Fall sinnvoll. Es ist nur leider mit einigen zusätzlichen Unwägbarkeiten verbunden im Vergleich dazu, was wir nun bei Anzeige der Daten auf einem e-Paper Display - #50 by MKO auf Basis des GitHub - G6EJD/ESP32-e-Paper-Weather-Display: An ESP32 and 2.9", 4.2" or 7.5" ePaper Display reads Weather Underground data via their API and then displays the weather haben.

Vielleicht bestellst Du Dir im Herbst auch mal ein solches Waveshare Modul und wir verfolgen die Idee auf Basis des Schnipsels bei Unfinished spike to load PNG via HTTP and display on e-Paper display with ESP32 · GitHub weiter?

Vielleicht können wir auch @Stefan und @Oliver dafür begeistern, dabei mitzuhelfen.

Viele Grüße,
Andreas.

Es liegen schon eine Zeit welche hier, ich hatte damals – mangels besseren Wissens – leider nur die raw panels bestellt und der controller fehlt jetzt noch! ;-)

Ick versteh Euch nicht ganz. Wo ist das Problem, wenn Ihr schon bereit seid die Daten von Außen zu laden und nicht noch lokal vorzuhalten? Die Queries sind ja schon da. Ok, in der Tat, der Auswertungsteil (Icons/Farben in Abhängigkeit von Grenzwerten) muss wiedererfunden werden.

Der Einzelteil-Weg hat zumindest den Vorteil, dass auf dem Display auch zumindest lokale Ist-Werte stehen können ohne dass es Interdings hat.

Bzgl

Frag ich mich noch: Ist hier die Farb-PNG → s/w-BMP-conversion gemeint? Falls ja: Fänd ich spannend wie lang das auf nem FiPy braucht. Der hat ja schon etwas Unz. Als ich allerdings jüngst mal mit nem epaper display (auch 400x300) spielte war ich schon sehr irritiert wie lang der braucht um nen einfaches Rechteck zu malen. Ich glaub da hats nen µ Potential …

Verwendet hatte ich diese waveshare-epd libraries für µpython (Link korrigiert):

Das ist auf jeden Fall cool für low-memory. Preprocessing ist aber auf jeden Fall sinnvoll, gerade weil wir damit serverseitig flexibel skalieren und farb- und kontrastwandeln können etc. pepe.

Diese beiden hier wären also die Wunschkandidaten, ja?

Gewicht & tägliche Gewichtsdifferenz (Graph)

Übersicht: Letzte Werte (Boom Table)

Mit dem WiPy hatte ich es aber auch schon in Betrieb aber da war alles Schleppender.
Aktuell verwenden ich C auf dem ESP32. Da scheint es wesentlich potenter. Kann aber auch von der Libary her kommen.

Hier Mal ein kleines Video davon Reset wird ungefähr in sec 3-4 gedrückt. (Kurz bevor ich wieder auf Display schwenke)
In der Zeit wird erledigt:

  • Hochfahren
  • WiFi verbindung
  • 4 http requests (2x Open Weather Map, 1x swarm.hiveeyes, 1x Apicast)
  • Datenaufbereitung und Zeichnen des Bildschirms (incl resizing Icons usw.)
  • Aktualisierung Bildschrm
3 Likes

Ja, und wenn wir dann doch was ändern, an Grenzwerten, icons, Bezeichnungen und man das synchron haben möchte, müsste man das in Grafana und auf dem Anzeigegerät ändern. In Grafana ist das deutlich einfacher und schneller mit einer grafischen UI.

Ja, das wäre ein Argument! Und dass es ggf. besser ausschaut wenn ich die rendering-Ergebnisse oben anschaue.

Die displays sind recht wählerisch was die PNGs angeht, man kann nicht einfach irgendein PNG reinstecken, wenn ichs richtig verstanden habe.

  • PNG to s/w oder 3 Farben (für die s/w rot oder s/w gelb Displays), keine Ahnung, ob die mit Graustufen genügsamer sind und mehr fressen
  • dann was für die alten Arduino-C-libs noch nötig war konvertierung in inline byte-array wie in post 9 oben beschrieben.

In den Forks von GitHub - mcauser/micropython-waveshare-epaper: MicroPython drivers for Waveshare e-paper modules hatte ich kürzlich jene Commits entdeckt:

Leider erkennt man im Diff des ersten Commits kaum etwas, weil viel Whitespace-/Newline-Noise dabei ist ;[.

Analyse Graph

300x200 geht gerade noch

image image

https://swarm.hiveeyes.org/grafana/render/d-solo/start/welcome?orgId=2&panelId=9&from=1555547678893&to=1557998019523&var-beekeeper=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&var-sensors=default_1_sensors&theme=light&width=300&height=200&tz=Europe%2FBerlin

130x100 geht in die Hose

image image

https://swarm.hiveeyes.org/grafana/render/d-solo/start/welcome?orgId=2&panelId=9&from=1555547678893&to=1557998019523&var-beekeeper=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&var-sensors=default_1_sensors&theme=light&width=130&height=100&tz=Europe%2FBerlin

Gedanken

Ein Drittel der Displaybreite – also ein Panel im aktuellen Layout – hat mit dem 4.2’’ e-Paper eine Breite von ~130 Pixeln.

image

Fazit

Im Vollbild könnte man den Graphen also gut anzeigen. Klein komprimiert wird nicht klappen – das müssten wir wohl manuell rendern.

Analyse Boom Table

200x350

image image

https://swarm.hiveeyes.org/grafana/render/d-solo/OvnLNPqiz/statista-stockubersicht-and-bienenwetter-testvolk-zk-u?panelId=23&orgId=2&from=1546297200000&to=1577833199999&var-beekeeper=hiveeyes_open_hive_test_statista&var-sensors=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&theme=light&width=200&height=350&tz=Europe%2FBerlin

Dieses Ausgabeformat nennt sich auch X BitMap (XBM) aka. “XBM – X Windows system bitmap, black and white only”, siehe X BitMap - Wikipedia.

Hier im Artikel wird beschrieben, dass auch GIMP dieses Format erzeugen kann.

Im obigen Artikel wird auch der Image Converter genannt – ebenfalls ein Online-Werkzeug.

Habe gestern Nacht Mal angefangen zu experimentieren und Div. BMP per Http und Https in einen Buffer zu laden und aus dem Buffer wieder anzuzeigen.
Habe dafür das WiFi Beispiel von GxEPD2 genommen.


Ein skalieren der Bilder sowie Umgang mit Farbe sowie Graustufen Bildern scheint auch zu klappen.
Die Ausgabe auf dem Display war allerdings nur SW und nicht Graustufen dafür aber wie gewohnt recht flüssig.
Als nächster Schritt steht jetzt das Laden eines PNG an. Da in dem Beispiel auch der Header des Bildes gelesen und Analysiert wird wird denke ich, das da die ersten Probleme auftauchen könnten.

Dann fehlt nur noch die Decodierung vor der eigentlichen Anzeige, das wenn die Treiber keine Probleme machen klappen sollte.

Die BMP lade und Anzeige Funktion lasse ich aber drin, man weiß ja nie ob jemand das nicht doch mal brauchen könnte. Zusätzliche Libarys werden dafür eh nicht gebraucht.

2 Likes

Durch das Antialiasing des Bildes ist es evtl. Sogar ratsam das Bild etwas größer zu laden, in SW umzuwandeln und dann erst zu verkleinern so wirken die Kanten evtl. schärfer.

Müssten wir auf alle Fälle dann ausprobieren wenn es funktioniert. Also erstmal bitte nichts an den Pannels ändern, könnte sein, das das kontraproduktiv ist.

1 Like

Ich fass nix an, nur der Hinweis: Man kann in dem Boom-table-plugin auch sehr fein mit der Schriftgröße rumspielen. (In den Einstellung einjeden “Patterns” janz unten.)

1 Like

Folgendes kleines Werkzeug kann uns u.U. weiterhelfen, welches auf der Python Imaging Library Pillow basiert:

XBM output

imagecast \
  --uri="https://unsplash.com/photos/WvdKljW55rM/download?force=true" \
  --monochrome=80 --crop=850,1925,-950,-900 --width=320 --format=xbm

Studie: Graph

# Define URI to image
export IMAGE='https://swarm.hiveeyes.org/grafana/render/d-solo/start/welcome?orgId=2&panelId=9&from=1555547678893&to=1557998019523&var-beekeeper=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&var-sensors=default_1_sensors&theme=light&width=400&height=300&tz=Europe%2FBerlin'
# Convert image to monochrome, also slightly crop and resize
imagecast --uri="$IMAGE" --monochrome=200 --crop=40,50,-50,-40 --width=200 --display

image

# Try grayscale
imagecast --uri="$IMAGE" --grayscale --crop=40,50,-50,-40 --width=200 --display

image

Studie: Boom table

# Define URI to image
export IMAGE='https://swarm.hiveeyes.org/grafana/render/d-solo/OvnLNPqiz/statista-stockubersicht-and-bienenwetter-testvolk-zk-u?panelId=23&orgId=2&from=1546297200000&to=1577833199999&var-beekeeper=hiveeyes_open_hive_test_statista&var-sensors=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&theme=light&width=200&height=350&tz=Europe%2FBerlin'

# Same procedure.
imagecast --uri="$IMAGE" --monochrome=200 --crop=20,40,-20,-40 --display

image

1 Like

Studie: Graph mit 130er Breite

image

imagecast --uri="$IMAGE" \
  --monochrome=200 --crop=40,50,-50,-40 --width=130 \
  --format=bytes > graph.raw

Als bi-level bitmap aka. MONO:raw hat dieser Eumel dann nur noch eine Größe von 1496 Bytes und könnte ohne Dekodierung direkt in den Framebuffer geladen werden.

imagecast --uri="$IMAGE" \
  --monochrome=200 --crop=40,50,-50,-40 --width=130 \
  --save=graph.png

Das entsprechende PNG ist sogar nur 429 Bytes klein.

Die Achsenbeschriftungen habe ich bewusst weggeschnitten, weil der Text die extreme Skalierung bestimmt nur wenig ansehnlich überlebt hätte. Bei der entsprechenden e-Paper Bibliothek sind optimierte Fonts für eine deutlich bessere Textausgabe dabei, so dass man damit vielleicht wieder eine Legende anbauen könnte, die zumindest über den dargestellten Zeitraum informiert.

[edit] Mit einer Breite von 400 px ist die Achsenbeschriftung noch lesbar:

imagecast.hiveeyes.org

1 Like

Wer Karten nicht legendiert oder Achsen nicht beschriftet,
wer nicht legendierte Karten oder unbeschriftete Achsen in Umlauf bringt, wird
mit Einzelwertetabellen
nicht unter zwei Seiten bestraft.

scnr

1 Like

Damit wollte ich Dich noch zitieren, aber mir ist der Spruch nicht mehr eingefallen. Danke! ;]

Leider läuft bei mir imagecast auf der WSL nicht wie gewünscht.
Hatte mich zwar sehr gewundert, wenn es ein Bild hätte anzeigen können.
Aber ein versuch macht klug

user@Werkstatt:/usr$ export IMAGE='https://swarm.hiveeyes.org/grafana/render/d-solo/OvnLNPqiz/statista-stockubersicht-and-bienenwetter-testvolk-zk-u?panelId=23&orgId=2&from=1546297200000&to=1577833199999&var-beekeeper=hiveeyes_open_hive_test_statista&var-sensors=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&theme=light&width=200&height=350&tz=Europe%2FBerlin'
user@Werkstatt:/usr$ imagecast --uri="$IMAGE" --monochrome=200 --crop=20,40,-20,-40 --display
user@Werkstatt:/usr$ display-im6.q16hdri: unable to open X server `' @ error/display.c/DisplayImageCommand/432.

Aber bei dem Service hatte ich mir schon ein paar mehr Chancen ausgerechnet.

user@Werkstatt:/usr$ imagecast service
2020-06-07 00:14:23,996 [imagecast.cli         ] INFO   : Starting imagecast 0.1.1
2020-06-07 00:14:23,996 [imagecast.cli         ] INFO   : Starting web service on localhost:9999
INFO:     Uvicorn running on http://localhost:9999 (Press CTRL+C to quit)
INFO:     Started reloader process [8289] using statreload
ERROR:    Error loading ASGI app. Attribute "app" not found in module "imagecast.api".

In der Windows PowerShell gibt es bereits beim Installieren Probleme. PIP findet Pillow 7.1.2 nicht.
wenn ich Pillow Manuell mit Pip ohne Versionierung Installiere Läd er bei mir nur 6.2.2

PS C:\Users\Büro1> pip install imagecast
Collecting imagecast
  Using cached https://files.pythonhosted.org/packages/cc/33/a53753e1fd6c58ea53358aa00c14c3d25b0ca9de68be10ceaff3601e8011/imagecast-0.1.1.tar.gz
Collecting docopt==0.6.2 (from imagecast)
  Using cached https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz
Collecting munch==2.3.2 (from imagecast)
  Using cached https://files.pythonhosted.org/packages/68/f4/260ec98ea840757a0da09e0ed8135333d59b8dfebe9752a365b04857660a/munch-2.3.2.tar.gz
Collecting Pillow==7.1.2 (from imagecast)
  Could not find a version that satisfies the requirement Pillow==7.1.2 (from imagecast) (from versions: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7.0, 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 2.0.0, 2.1.0, 2.2.0, 2.2.1, 2.2.2, 2.3.0, 2.3.1, 2.3.2, 2.4.0, 2.5.0, 2.5.1, 2.5.2, 2.5.3, 2.6.0, 2.6.1, 2.6.2, 2.7.0, 2.8.0, 2.8.1, 2.8.2, 2.9.0, 3.0.0, 3.1.0rc1, 3.1.0, 3.1.1, 3.1.2, 3.2.0, 3.3.0, 3.3.1, 3.3.2, 3.3.3, 3.4.0, 3.4.1, 3.4.2, 4.0.0, 4.1.0, 4.1.1, 4.2.0, 4.2.1, 4.3.0, 5.0.0, 5.1.0, 5.2.0, 5.3.0, 5.4.0, 5.4.1, 6.0.0, 6.1.0, 6.2.0, 6.2.1, 6.2.2)
No matching distribution found for Pillow==7.1.2 (from imagecast)

Mit dem Direkten Laden und Decodieren auf dem ESP32 über upng, bin ich auch nicht wirklich weiter gekommen.
Aktuell lande ich beim übergeben des Buffers in einem fiesen Core dump

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:9720
ho 0 tail 12 room 4
load:0x40080400,len:6364
entry 0x400806b8
␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀
WiFi.getAutoConnect()=0
WiFi.SSID()=
Connecting to FRITZ!Box 7490
.3
WiFi connected
192.168.178.175

downloading file "statista-stockubersicht-and-bienenwetter-testvolk-zk-u.PNG"
connecting to swarm.hiveeyes.org
requesting URL: https://swarm.hiveeyes.org/grafana/render/d-solo/OvnLNPqiz/statista-stockubersicht-and-bienenwetter-testvolk-zk-u?panelId=23&orgId=2&from=1546297200000&to=1577833199999&var-beekeeper=hiveeyes_open_hive_test_statista&var-sensors=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&theme=light&width=100&height=100&tz=Europe%2FBerlinstatista-stockubersicht-and-bienenwetter-testvolk-zk-u.PNG
request sent



HTTP/1.1 200 OK
headers received
loaded in 4457 ms

 decodeGuru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d3cf2  PS      : 0x00060c30  A0      : 0x800d3ede  A1      : 0x3ffb1da0  
A2      : 0x00000000  A3      : 0x5e5d859c  A4      : 0x5e5d859c  A5      : 0x3ffc5048  
A6      : 0x3ffb1d5c  A7      : 0x3ffb1d5c  A8      : 0x00000089  A9      : 0x0003d032  
A10     : 0x3ffba794  A11     : 0x3ffb1d5c  A12     : 0x00000008  A13     : 0x3ffb1da0  
A14     : 0x3ffb1d20  A15     : 0x00000008  SAR     : 0x0000000a  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x0003d032  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  

Backtrace: 0x400d3cf2:0x3ffb1da0 0x400d3edb:0x3ffb1dc0 0x400d1edf:0x3ffb1e20 0x400d20a0:0x3ffb1ee0 0x400d20e8:0x3ffb1f20 0x400d231f:0x3ffb1f50 0x400d7907:0x3ffb1fb0 0x40088b9d:0x3ffb1fd0

Rebooting...

wenn ich das ganze nicht als char sondern als String lade kann ich es zwar nicht an uPNG übergeben aber per Serial ausgeben.
Die erste Zeile kommt mir verdächtig vor, habe ich da was vom http header übersehen?

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:9720
ho 0 tail 12 room 4
load:0x40080400,len:6364
entry 0x400806b8
␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀
WiFi.getAutoConnect()=0
WiFi.SSID()=
Connecting to FRITZ!Box 7490
.3
WiFi connected
192.168.178.175

downloading file "statista-stockubersicht-and-bienenwetter-testvolk-zk-u.PNG"
connecting to swarm.hiveeyes.org
requesting URL: https://swarm.hiveeyes.org/grafana/render/d-solo/OvnLNPqiz/statista-stockubersicht-and-bienenwetter-testvolk-zk-u?panelId=23&orgId=2&from=1546297200000&to=1577833199999&var-beekeeper=hiveeyes_open_hive_test_statista&var-sensors=All&var-COMMON_CDC_NAME=Berlin-Tegel&var-COMMON_MOSMIX_NAME=BERLIN-TEGEL&var-STATION=Berlin-Tegel&theme=light&width=100&height=100&tz=Europe%2FBerlinstatista-stockubersicht-and-bienenwetter-testvolk-zk-u.PNG
request sent





HTTP/1.1 200 OK
headers received

client disconnected.
Data from server captured in readString:

�PNG
␚
IHDR␀␀␀d␀␀␀␆␀␀␀p�T␀␀␀␁sRGB␀��␜�␀␀␇�IDATx���␡P��␁��o�␐   (BTT@��$"�U춮��UtWO�j�,Ȝ?␐������v�����uW�2�@␑␄�[�F���ۦ��u���V   � �N␂␚␂ �w␡�␙␘�і��|>␡yo��y������W���jww/�␞␏���*
:�␖��ݣ�␘b�*
�␖>@SS␓]].̦␄?␟���{�Ws�PWgc��Utuvq�H9Z�Bz�Zv��.�ť4]�®�/␐␝␝�a��m�[�����R\.7�}6��8��íџ�␐Fxx8�j�␀\�XC@@␀_z�␋TW��!��}g��xcͯA.��q�B5␙␙ϰ4�q␀�␛␛����␖�1��� ␔E�l6␁␐␜␜���p␀�z�(␎G␇iϬ!22␒�g�pk��hJ�le␕␞���j␋&��␅␋>��N�KG�␓��␎EQ�����␙�_����␃P\\Fqqـל�N���␆ݷ��2���c6�X�,u��0␙��w�␟4^n�b�!u�c$%�␅�b���j%&&␚�>p�␟t␔�5��[�7׬f�\��␂␃'��pKoo/����j�l����7׏����wc?u�4v{␛���L�2����p��E��␛x�+_␞����_�DEE␁��j�h�I��ݸ\.�Z-␀␚��␗���Zm�_�άY�␆�v�����ߜ9␎␎���2yr0qq�␀̛�ĉ␓'q�����␁~␎b4&���ğ�r␜�$␝s�"9~�$AAA|␡�␋␀�␙Bq:;y�c␜��dm�ġ���V��쭙�z���-k���␜,=ĉ␓'���!)�Lƺ��l���R���%␎␟)'>.␎��Foo/v{␛�w��[�t       �֭�␙?#|ưk��dJ��␏>$9y�w��lB��␒c�4␃��-��������t��U������r����3��
@���␞�_G�A�S��O␄2�`d␐�� ��A␄#F␆␑�␌"␘␙D02�`d␐�� ��A␄#F␆␑�␌"␘␙D02�`d␐�� ��A␄#F␆␑�␌"␘a�l����␙�D� #UXx���\��␟k␓>��␛����hp�\��␜�LE%z��G␞y�����-Y�␇<sX������b��<�9~�Ý␀B���x���␖<␞␏7nܠ���UO.gf�L��n��n<��+�;�␏7�X␓���͙�lڸ�␇␟L��蠸����␡��0␡�}|+#��Щ����shoo�7��������/�o�7�bŊ'|�O�␚2�����e�OW��xD*�␂��x?a�Ld����x�:���)1�:e73�3F��𗬉�␡␌␀����*�s������AF���: �m6��␝��F␔E^�F���ʎ��ެ␝tL�X^␡�l��A␆␑��d      F␆␑�␌"␘␙D02�`d␐�� ��A␄#F␆␑�␌"␘␙D02�`d␐�� ��A␄#F␆␑�␌"␘␙D02�`d␐�� ��A␄#F␆␑�␌"␘␙D02�`d␐�� ��A␄#F␆␑�␌"␘␙D02�`d␐�(ȇ�š��Q4����2�EUUPA�h�/�('␌���␑␀␀␀␀IEND�B`�

End of readString
==================

loaded in 6285 ms
bitmap format not handled.
_PowerOn : 34999
_Update_Full : 1518001
_PowerOff : 19001
GxEPD2_WiFi_Example done

Die WSL kann leider überhaupt nichts anzeigen, da fehlt der X-Server. Da brauchst Du entweder einen anderen Rechner mit X-Server oder Du wartest - das Feature ist für die WSL angekündigt.

pillow install läuft bei mir - ganz normal in CMD:

Microsoft Windows [Version 10.0.18363.836]
(c) 2019 Microsoft Corporation. Alle Rechte vorbehalten.

C:\Users\Markus>pip install pillow
Collecting pillow
  Downloading Pillow-7.1.2-cp38-cp38-win32.whl (1.8 MB)
     |████████████████████████████████| 1.8 MB 242 kB/s
Installing collected packages: pillow
Successfully installed pillow-7.1.2