QCC 2020 épisode 9 : Ecrans et profondeurs
Posted: 23 Aug 2020, 19:10
Quelle Calculatrice programmable Choisir 2020
(index des épisodes)
Episode 9 - Ecrans et profondeurs
(index des épisodes)
Episode 9 - Ecrans et profondeurs
L'écran est décidément un élément incontournable de ta calculatrice graphique. Après avoir couvert dans des épisodes précédents ses dimensions, définition et zone graphique, nous allons aujourd'hui traiter de sa profondeur, c'est-à-dire du nombre de couleurs différentes qu'il peut afficher.
Commençons par enfoncer les portes ouvertes, avec les modèles dont le contrôleur écran ne gère que 1 bit de profondeur, ne permettant donc que 21= 2 couleurs différentes.
D'une part, voici les modèles à cristaux liquides bleus, affichant donc en bleu et blanc :
D'une part, voici les modèles à cristaux liquides bleus, affichant donc en bleu et blanc :
- Esquisse GCEXFR
- Lexibook GC3000FR
- Casio Graph 25+E
Et voici les modèles à cristaux liquides noirs, affichant en noir et blanc :
- Casio Graph 25+E II
- Casio Graph 35+E
- Casio Graph 35+E II
- Casio Graph 75+E
- TI-82 Advanced
- TI-84 Plus T
- Casio fx-92+ Spéciale Collège
Passons maintenant aux choses sérieuses ; nous allons te présenter notre protocole de test.
Notre idée est donc d'afficher une mire avec des dégradés des composantes primaires rouge-vert-bleu, afin de déterminer le nombre de bits utilisés par chacune.
Histoire d'avoir un script de test aussi universel que possible, commençons par ressortir nos fonctions Python magiques que nous t'avons déjà présentées :
Voici de quoi récupérer tout ça :
Maintenant que nous connaissons les positions et tailles des zones graphiques contrôlables par les scripts Python, faisons une fonction permettant de les récupérer rapidement cette fois-ci sans avoir à tester l'écran :
Il y a 2 façons de coder les couleurs dans le contexte des pixels en Python :
Prévoyons une fonction pour tester le codage utilisé, par simple vérification du type de retour d'une lecture de pixel.
Dans le cas d'un retour de type entier, tentons de plus en passant de détecter le nombre de bits gérés par le contrôleur écran, en écrivant des valeurs de pixels de plus en plus grandes et vérifiant à chaque fois si le pixel concerné a bien pris la valeur en question.
Un appel
Pour notre script universel il faudra bien choisir un codage plutôt qu'un autre, alors prévoyons une fonction de conversion :
Voici de quoi tracer des lignes verticales et horizontales :
Et voici enfin notre code de tracé de la mire :
Tu vas vite comprendre tout ça avec notre premier exemple.
Notre idée est donc d'afficher une mire avec des dégradés des composantes primaires rouge-vert-bleu, afin de déterminer le nombre de bits utilisés par chacune.
Histoire d'avoir un script de test aussi universel que possible, commençons par ressortir nos fonctions Python magiques que nous t'avons déjà présentées :
- get_pf() pour récupérer un code identifiant la plateforme détectée
- get_pixel_functions(pf) pour récupérer les fonctions de lecture/écriture des pixels correspondant à la plateforme en question
- Code: Select all
# detects calculator Python platform
def get_pf():
c256 = True
try:
if chr(256)==chr(0):
# Xcas/KhiCAS Python compatibility
if "HP" in version():
return 13 # HP Prime
else:
if not white:
return 12 # Graph 35+E II
elif "Numworks" in version():
return 10 # NumWorks
elif "Nspire" in version():
return 8 # Nspire
else: # Graph 90+E
return 11
except:
c256 = False
try:
import sys
try:
if sys.platform == "nspire":
try: # Nspire Ndless
import graphic
return 7 # KhiCAS Micropython
except: # MicroPython
return 6
elif sys.platform == "TI-Nspire":
return 3 # Nspire CX II
elif sys.platform == "numworks":
return 9 # NumWorks KhiCAS Micropython
elif sys.platform.startswith('TI-Python'):
return 2 # 83P/84+ CE
except: # Graph 35+E/USB / 75/85/95
return 5
except:
pass
if not c256:
return 1 # Graph 90/35+E II
try:
import kandinsky
return 0 # NumWorks
except:
try: # HP Prime
import hpprime
return 4
except:
pass
return -1
#return get_pixel and set_pixel functions for the platform
gp_prime = lambda x, y: GETPIX_P(x, y)
sp_prime = lambda x, y, c: PIXON_P(x, y, c)
def get_pixel_functions(pf):
gp, sp = lambda: None, lambda: None
if pf == 0: # NumWorks
import kandinsky
gp, sp = kandinsky.get_pixel, kandinsky.set_pixel
elif pf == 1: # Graph 90/35+E II
import casioplot
gp, sp = casioplot.get_pixel, casioplot.set_pixel
elif pf == 2: # 83P/84+ CE
import ti_graphics
gp, sp = ti_graphics.getPixel, ti_graphics.setPixel
elif pf == 3: # Nspire CX II
pass
elif pf == 4: # HP Prime
import hpprime
sp = hpprime.pixon
elif pf == 6: # Nspire: Ndless MicroPython
from nsp import Texture
canvas = Texture(320, 240, 0)
gp, sp = canvas.getPx, canvas.setPx
elif pf == 7 or pf == 9: # Nspire/NumWorks: KhiCAS-MicroPython
import graphic
gp, sp = graphic.get_pixel, graphic.set_pixel
elif pf == 13: # HP Prime
gp, sp = gp_prime, sp_prime
return gp, sp
Voici de quoi récupérer tout ça :
- Code: Select all
gp, sp = get_pixel_functions(pf)
sw, sh, sy0 = scr_infos(pf)
Maintenant que nous connaissons les positions et tailles des zones graphiques contrôlables par les scripts Python, faisons une fonction permettant de les récupérer rapidement cette fois-ci sans avoir à tester l'écran :
- Code: Select all
#returns platform screen infos : width, height, color_mode/bits
def scr_infos(pf):
# uPy uPy
# G352 CPy uPy KhiCAS---------------------> CAS
# NW G90 CE CX2 HP GXX NS NS NS NW NW G90 G352 HP
l_vlines = (222, 192, 210, 212, 240, 064, 240, 222, 222, 222, 222, 192, 064, 240)
l_vcols = (320, 384, 320, 318, 320, 128, 320, 320, 320, 320, 320, 384, 128, 320)
l_y0 = (000, 000, 030, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000)
l_modes = (000, 000, 000, 016, 032, 000, 016, 000, 016, 000, 016, 016, 001, 032)
return l_vcols[pf], l_vlines[pf], l_y0[pf], l_modes[pf]
Il y a 2 façons de coder les couleurs dans le contexte des pixels en Python :
- soit avec un tuple (r,g,b) décrivant les valeurs de chaque composante primaire rouge-vert-bleu par un entier de 0 à 255
- soit par un nombre entier qui sera directement la valeur fournie au contrôleur écran
Prévoyons une fonction pour tester le codage utilisé, par simple vérification du type de retour d'une lecture de pixel.
Dans le cas d'un retour de type entier, tentons de plus en passant de détecter le nombre de bits gérés par le contrôleur écran, en écrivant des valeurs de pixels de plus en plus grandes et vérifiant à chaque fois si le pixel concerné a bien pris la valeur en question.
- Code: Select all
#0: (R,G,B) >0: RGB-bits
def get_color_mode():
c = gp(0, 0)
try:
c[2]
return 0
except:
b, v = 0, 1
x, y = 0, sy0
sp(x, y, v)
while gp(x, y) == v:
b += 1
v *= 2
sp(x, y, v)
return b
Un appel
color_mode = get_color_mode()
pourra donc renvoyer par exemple :- 0 : pour un codage des couleurs par des tuples (r,g,b)
- 15 : pour un codage des couleurs sur des entiers de 15 bits
- 16 : pour un codage des couleurs sur des entiers de 16 bits
- 24 : pour un codage des couleurs sur des entiers de 24 bits
- ...
Pour notre script universel il faudra bien choisir un codage plutôt qu'un autre, alors prévoyons une fonction de conversion :
- Code: Select all
def fixcolor(c, bits=16):
try:
if not color_mode:
return c
r, g, b = c[0], c[1], c[2]
except:
if color_mode == bits:
return c
if bits == 16:
br, bg, bb = 5, 6, 5
else:
br, bg, bb = 8, 8, 8
r, g, b = c & (2**br - 1) * 2**(8 - br), c & ((2**bg - 1) * 2**br) // 2**br * 2**(8 - bg), c & ((2**bb - 1) * 2**(br + bg)) // 2**(br + bg) * 2**(8 - bb)
if not color_mode:
return (r, g, b)
else:
if color_mode == 16:
br, bg, bb = 5, 6, 5
else:
br, bg, bb = 8, 8, 8
r, g, b = r // 2**(8 - br), g // 2**(8 - bg) * 2**br, b // 2 **(8 - bb) * 2**(br + bg)
c = r + g - (r & g)
return c + b - (c & b)
Voici de quoi tracer des lignes verticales et horizontales :
- Code: Select all
def draw_vline(x, y1, y2, c):
for j in range(y2 - y1 + 1):
sp(x, y1 + j, c)
def draw_hline(y, x1, x2, c):
for j in range(x2 - x1 + 1):
sp(x1 + j, y, c)
Et voici enfin notre code de tracé de la mire :
- Code: Select all
#o: 0=horizontal, 1=vertical
#s: 0=no_shadow, 1=shadow left/up, -1=shadow right/down
def mire(s=1, o=0, w=sw, h=sh, y0=sy0):
if o:
l1, l2, f, i1, i2 = h, w, draw_hline, y0, 0
else:
l1, l2, f, i1, i2 = w, h, draw_vline, 0, y0
n = 8
for m in range(l1):
v = 255
if s != 0:
v = v * (s*m % l1) // (l1 - 1)
for j in range(n):
f(m + i1, j * l2 // n + i2, (j + 1) * l2 // n - 1 + i2, fixcolor(color8(j, v)))
def color8(j, v):
c = [0, 0, 0]
for b in range(3):
if j & 2**b:
c[b] = v
return c
Tu vas vite comprendre tout ça avec notre premier exemple.
Commençons donc par les TI-83 Premium CE Edition Python et TI-84 Plus CE-T Python Edition que nous allons tester en Python.
Nous considérerons que c'est pareil sur les anciennes TI-83 Premium CE et TI-84 Plus CE.
Cela ne t'apprendra sans doute rien mais histoire de vérifier que ça marche, d'après get_color_mode() sur TI-83 Premium CE Edition Python et TI-84 Plus CE Python Edition les couleurs de pixels sont codées en Python par des tuples (r,g,b).
On peut noter ci-contre que le vert ainsi que les couleurs composées de vert (cyan, jaune et blanc) ont un dégradé beaucoup moins saccadé, beaucoup plus fluide. En effet si tu regardes bien elles utilisent 2 fois plus de teintes intermédiaires, très exactement 64 teintes contre 32 pour les autres :
Nous considérerons que c'est pareil sur les anciennes TI-83 Premium CE et TI-84 Plus CE.
Cela ne t'apprendra sans doute rien mais histoire de vérifier que ça marche, d'après get_color_mode() sur TI-83 Premium CE Edition Python et TI-84 Plus CE Python Edition les couleurs de pixels sont codées en Python par des tuples (r,g,b).
On peut noter ci-contre que le vert ainsi que les couleurs composées de vert (cyan, jaune et blanc) ont un dégradé beaucoup moins saccadé, beaucoup plus fluide. En effet si tu regardes bien elles utilisent 2 fois plus de teintes intermédiaires, très exactement 64 teintes contre 32 pour les autres :
- canal rouge sur 5 bits pour 25= 32 teintes
- canal vert sur 6 bits pour 26= 64 teintes
- canal bleu sur 5 bits pour 25= 32 teintes
Voici maintenant la Casio Graph 90+E et son superbe écran.
Ici encore les paramètres de couleur sont passés sous forme de tuples (r,g,b).
Même constat ici, nous notons 2 fois plus de teintes intermédiaires pour les dégradés de vert et de couleurs incluant du vert :
Ici encore les paramètres de couleur sont passés sous forme de tuples (r,g,b).
Même constat ici, nous notons 2 fois plus de teintes intermédiaires pour les dégradés de vert et de couleurs incluant du vert :
- canal rouge sur 5 bits pour 25= 32 teintes
- canal vert sur 6 bits pour 26= 64 teintes
- canal bleu sur 5 bits pour 25= 32 teintes
Arrive maintenant la NumWorks.
Avec l'application Python officielle, les paramètres de couleur prennent toujours la forme de tuples (r,g,b).
Encore pareil, 2 fois plus de teintes intermédiaires dans le vert :
Tu peux installer le firmware tiers Omega et ensuite, si tu disposes du dernier modèle NumWorks N0110, l'application KhiCAS, une adaptation pour ta calculatrice du logiciel intégré de Mathématiques Xcas par Bernard Parisse, enseignant-chercheur à l'université de Grenoble, et programmable grâce à son interpréteur MicroPython intégré.
Pas de raison que la mire soit différente, mais précisons tout de même au passage que cette édition de KhiCAS fonctionne elle aussi avec des tuples (r,g,b).
Avec l'application Python officielle, les paramètres de couleur prennent toujours la forme de tuples (r,g,b).
Encore pareil, 2 fois plus de teintes intermédiaires dans le vert :
- canal rouge sur 5 bits pour 25= 32 teintes
- canal vert sur 6 bits pour 26= 64 teintes
- canal bleu sur 5 bits pour 25= 32 teintes
Tu peux installer le firmware tiers Omega et ensuite, si tu disposes du dernier modèle NumWorks N0110, l'application KhiCAS, une adaptation pour ta calculatrice du logiciel intégré de Mathématiques Xcas par Bernard Parisse, enseignant-chercheur à l'université de Grenoble, et programmable grâce à son interpréteur MicroPython intégré.
Pas de raison que la mire soit différente, mais précisons tout de même au passage que cette édition de KhiCAS fonctionne elle aussi avec des tuples (r,g,b).
Passons donc aux TI-Nspire. Nous disposons d'une préversion de la prochaine mise à jour 5.2 rajoutant Python aux TI-Nspire CX II, mais hélas nous n'avons pas à ce jour l'autorisation de te faire de nouvelles révélations à son sujet.
Donc tant pis, adaptons notre script de mire dans le langage orienté fonction historique de la machine.
Et nous considérerons que c'est pareil sur les anciennes TI-Nspire CX.
Toujours 2 fois plus de teintes intermédiaires tirant sur le vert :
Sur les anciennes TI-Nspire CX et TI-Nspire monochromes soit donc avant la version 5.0, le langage interprété ne dispose hélas pas des fonctions de tracé.
Adaptons donc notre mire dans le langage de script Lua :
Sur les TI-Nspire monochromes nous avons donc 4 bits pour 24= 16 niveaux de gris.
Cela ne changera rien au résultat, mais précisons que sur les anciennes TI-Nspire monochromes et TI-Nspire CX si munie d'une version 4.5.0 ou inférieure, tu peux installer Ndless puis MicroPython. Dans ce cas les paramètres de couleur ne sont pas des tuples, mais des entiers sur 16 bits. Heureusement que nous avions prévu notre fonction de conversion automatique.
Sur les anciennes TI-Nspire CX, il est de plus possible dans ce cas d'installer la version de KhiCAS en cours de développement, avec son propre interpréteur MicroPython intégré.
Ici on retrouve la spécification des couleurs sous forme de tuples (r,g,b).
Donc tant pis, adaptons notre script de mire dans le langage orienté fonction historique de la machine.
Et nous considérerons que c'est pareil sur les anciennes TI-Nspire CX.
- Code: Select all
Define mire(s,o,w,h)=
Prgm
Local l1,l2,f,c,j,m,n,v
If o≠0 Then
l1:=h
l2:=w
Define f(y,x1,x2,c)=Prgm
SetColor c[1],c[2],c[3]
DrawLine x1,y,x2,y
EndPrgm
Else
l1:=w
l2:=h
Define f(x,y1,y2,c)=Prgm
SetColor c[1],c[2],c[3]
DrawLine x,y1,x,y2
EndPrgm
EndIf
n:=8
For m,0,l1-1
v:=int(255*when(s=0,1,((mod(s*m,l1))/(l1-1))))
For j,0,n-1
f(m,((j*l2)/(n)),(((j+1)*l2)/(n))-1,color8(j,v))
EndFor
EndFor
EndPrgm
Define color8(j,v)=
Func
Local l,k
l:=newList(3)
For k,1,dim(l)
If mod(int(((j)/(2^(k-1)))),2)≠0 Then
l[k]:=v
EndIf
EndFor
Return l
EndFunc
Toujours 2 fois plus de teintes intermédiaires tirant sur le vert :
- canal rouge sur 5 bits pour 25= 32 teintes
- canal vert sur 6 bits pour 26= 64 teintes
- canal bleu sur 5 bits pour 25= 32 teintes
Sur les anciennes TI-Nspire CX et TI-Nspire monochromes soit donc avant la version 5.0, le langage interprété ne dispose hélas pas des fonctions de tracé.
Adaptons donc notre mire dans le langage de script Lua :
- Code: Select all
o = false
s = 1
function on.charIn(c)
print(c)
olds, oldo = s, o
if c == "−" or c == "-" then
s = -1
elseif c == "+" then
s = 1
elseif c == "0" then
s = 0
elseif c == "*" or c == "/" then
o = not o
end
if s ~= olds or o ~= oldo then
platform.window.invalidate()
end
end
function on.resize(w, h)
platform.window.invalidate()
end
function color8(j, v)
l={0, 0, 0}
for k = 1, #l do
if math.floor(j / 2^(k - 1)) % 2 ~= 0 then
l[k] = v
end
end
return l
end
function on.paint(gc)
pw = platform.window
w, h = pw.width(), pw.height()
if o then
l1, l2 = h, w
function f(gc, y, x1, x2, c)
gc:setColorRGB(c[1], c[2], c[3])
gc:drawRect(x1, y, x2, y)
end
else
l1, l2 = w, h
function f(gc, x, y1, y2, c)
gc:setColorRGB(c[1], c[2], c[3])
gc:drawRect(x, y1, x, y2)
end
end
n = 8
for m = 0, l1 - 1 do
v = 255
if s ~=0 then
v = v * (s * m % l1) / (l1 - 1)
end
for j = 0, n - 1 do
f(gc, m, j * l2 / n, (j + 1)*l2/n - 1, color8(j, v))
end
end
end
Sur les TI-Nspire monochromes nous avons donc 4 bits pour 24= 16 niveaux de gris.
Cela ne changera rien au résultat, mais précisons que sur les anciennes TI-Nspire monochromes et TI-Nspire CX si munie d'une version 4.5.0 ou inférieure, tu peux installer Ndless puis MicroPython. Dans ce cas les paramètres de couleur ne sont pas des tuples, mais des entiers sur 16 bits. Heureusement que nous avions prévu notre fonction de conversion automatique.
Sur les anciennes TI-Nspire CX, il est de plus possible dans ce cas d'installer la version de KhiCAS en cours de développement, avec son propre interpréteur MicroPython intégré.
Ici on retrouve la spécification des couleurs sous forme de tuples (r,g,b).
Sur Casio fx-CP400+E nous ne pouvons hélas pas te programmer de mire.
En effet dans le langage interprété historique de la machine et seul langage qui nous est accessible, le paramètre de couleur des fonctions graphiques ne peut prendre que 7 valeurs différentes.
Alors plan B, générons et enregistrons notre mire sous forme d'image, et convertissons-la en image .c2p pour la calculatrice à l'aide de notre convertisseur en ligne.
Toujours le même résultat avec 2 fois plus de teintes intermédiaires dans les tons de vert :
On peut remarquer un petit bug d'affichage dans le dégradé de bleu, comme si la teinte la plus claire avait été marquée en tant que couleur transparente.
Mais ce n'est pas un bug lié à notre convertisseur, nous obtenons exactement le même défaut en utilisant le logiciel de conversion officiel de Casio. Le problème se situe donc ou dans le format, ou dans la calculatrice...
En effet dans le langage interprété historique de la machine et seul langage qui nous est accessible, le paramètre de couleur des fonctions graphiques ne peut prendre que 7 valeurs différentes.
Alors plan B, générons et enregistrons notre mire sous forme d'image, et convertissons-la en image .c2p pour la calculatrice à l'aide de notre convertisseur en ligne.
Toujours le même résultat avec 2 fois plus de teintes intermédiaires dans les tons de vert :
- canal rouge sur 5 bits pour 25= 32 teintes
- canal vert sur 6 bits pour 26= 64 teintes
- canal bleu sur 5 bits pour 25= 32 teintes
On peut remarquer un petit bug d'affichage dans le dégradé de bleu, comme si la teinte la plus claire avait été marquée en tant que couleur transparente.
Mais ce n'est pas un bug lié à notre convertisseur, nous obtenons exactement le même défaut en utilisant le logiciel de conversion officiel de Casio. Le problème se situe donc ou dans le format, ou dans la calculatrice...
Et enfin nous arrive la HP Prime. Une version alpha très préliminaire incluant une application Python a été diffusée en octobre 2019.
Toutefois hélas, son module graphique n'offre de fonction que pour écrire les pixels, pas pour les lire. Impossible donc ici d'y détecter automatiquement le format de couleur.
Revenons donc sur une version plus stable, et passons la calculatrice en mode CAS afin d'y exploiter la compatibilité syntaxique Python.
Grosse surprise, les paramètres de couleur sont ici détectés comme étant des entiers codés sur 24 bits !
Ici c'est ainsi fantastique, des dégradés extrêmement fluides et ce peu importe la teinte !
Toutefois hélas, son module graphique n'offre de fonction que pour écrire les pixels, pas pour les lire. Impossible donc ici d'y détecter automatiquement le format de couleur.
Revenons donc sur une version plus stable, et passons la calculatrice en mode CAS afin d'y exploiter la compatibilité syntaxique Python.
Grosse surprise, les paramètres de couleur sont ici détectés comme étant des entiers codés sur 24 bits !
Ici c'est ainsi fantastique, des dégradés extrêmement fluides et ce peu importe la teinte !
- canal rouge sur 8 bits pour 28= 256 teintes
- canal vert sur 8 bits pour 28= 256 teintes
- canal bleu sur 8 bits pour 28= 256 teintes