Page 1 of 1

QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 23 Aug 2020, 19:10
by critor
5409
Quelle Calculatrice programmable Choisir 2020
(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 :
  • Esquisse GCEXFR
  • Lexibook GC3000FR
  • Casio Graph 25+E
1149712780

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
12588716611396

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 :
  • 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).

12795On 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
Total donc 16 bits pour 216= 65536 couleurs affichables, et un contrôleur écran fonctionnant donc au format RGB 565.


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).

12826Mê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
Total donc 16 bits pour 216= 65536 couleurs affichables, et un contrôleur écran fonctionnant donc au format RGB 565.


Arrive maintenant la NumWorks.

Avec l'application Python officielle, les paramètres de couleur prennent toujours la forme de tuples (r,g,b).

12836Encore 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
Total donc 16 bits pour 216= 65536 couleurs affichables, et un contrôleur écran fonctionnant donc au format RGB 565.

1285512856Tu 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.
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

12857Toujours 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
Total donc 16 bits pour 216= 65536 couleurs affichables, et un contrôleur écran fonctionnant donc au format RGB 565.

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

12869
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. :mj:

12871Alors 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
Total donc 16 bits pour 216= 65536 couleurs affichables, et un contrôleur écran fonctionnant donc au format RGB 565.

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 ! :bj:

12882Ici c'est ainsi fantastique, des dégradés extrêmement fluides et ce peu importe la teinte ! :D
  • 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
Total donc 24 bits pour 224= 16777216 couleurs affichables, et un contrôleur écran fonctionnant donc au format RGB 888 ! :#tritop#:


Résumé donc des données collectées jusqu'à présent sur les écrans, avec :
  • en bas les capacités officielles de la machine en mode examen
  • en haut les possibilités hors mode examen

Re: QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 23 Aug 2020, 19:55
by cent20
Op op op quelques ajouts et remarques subjectives...

Les photos sont très intéressantes, car on observe une zone noire énorme sur la plupart des modèles dans la partie la plus foncée de la mire. Il est évident que le rendu photo dégrade le rendu réel, certes, mais il permet quand même de juger de la luminosité de l’écran et / ou de son constate, qui peut plante le traitement photo du smartphone.

Mes tests réalisés cet après midi avec une luminosité maximale.

Sur une TI 83 PCE, La barre supérieure vire très vite du noir au gris et réciproquement. Ceci prouve que l’écran n’est pas un écran IPS mais une simple dalle TN de moindre qualité. La première version de la numworks, la N0100 souffrait de ce défaut.

TN < VA < IPS < AMOLED < OLED

Sur la graph 90, même combat, l’écran s’assombrit d’un coup d’un seul donc ce n’est pas de l’IPS...
Autre possibilité, la distance entre la dalle et la protection de dalle trop importante, ce qui génère les défauts précédemment évoqués mais je n’y crois pas trop.

En tout cas, un test fait à l’arrache cet après-midi m’indique que l’écran de la Casio graph 90 est 3x moins lumineux que celui de la NumWoks, ce qui peut rend les blancs un peu gris. Ayant eut une HP en main j’ai en trouvé son écran très bon, peut être meilleur que celui de la Numworks même si bon, comme chez Casio, l’équipe qui dessine les icônes devrait être renouvelée.

Re: QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 23 Aug 2020, 19:59
by critor
Merci pour ton retour fort instructif.
Je vais voir si il est encore possible de monter un protocole en ce sens cette année. :)

Re: QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 23 Aug 2020, 20:18
by Zocipal
Ah merci pour cet article ;-) Sympa pour la préversion de la Nspire ! Tu sais quand est-ce que tu pourras en parler ?

Re: QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 23 Aug 2020, 20:20
by critor
Merci pour ton retour.

Je ne sais pas encore, mais nous avons couvert toutes les infos déjà officielles par ici :
viewtopic.php?t=23827&p=252949

Re: QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 24 Aug 2020, 15:25
by compsystems
this is a translation done by an artificial "intelligence"

Hello Critor
I see a lot of code with graphics manipulation in your posts
There is a programming language for those who are new to the world of algorithmic and computational logic developed by microsoft.
This application is called SmallBasic (SB) and unlike other languages focused on teaching and learning, it includes two windows, a text input and output window and another graphic window, including the turtle.

I think it is much easier to learn to code in SB than Python. It may be a good idea to explore this language and post with this platform. or contrast code between Python and SB.

http://www.smallbasic.com

Code: Select all
' Lesson 3: getting set up
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.PenColor = "White"
paddle = Shapes.AddRectangle(120, 12)
Shapes.Move(paddle, 0, GraphicsWindow.Height - 12)

GraphicsWindow.BrushColor = GraphicsWindow.GetRandomColor()
ball = Shapes.AddEllipse(16, 16)
GraphicsWindow.BackgroundColor = GraphicsWindow.GetRandomColor()

' Lesson 4: let's get moving
GraphicsWindow.MouseMove = WhenMouseMoves
Sub WhenMouseMoves
  mouseX= GraphicsWindow.MouseX
  Shapes.Move(paddle, mouseX-60, GraphicsWindow.Height-12)
EndSub

' Lesson 5&6: making the ball move
moveX = 1
moveY = 1
stillPlaying = "True"
While stillPlaying = "True"
  x= x + moveX
  y= y + moveY
  Shapes.Move(ball, x, y)
  Program.Delay(5) 'Make this number bigger to make the ball move slower

  If(y > GraphicsWindow.Height) Then
    GraphicsWindow.ShowMessage("You Lose", "Paddle")
    stillPlaying= "False"
  EndIf

  ' Lesson 6: make it bounce
  paddleX= Shapes.GetLeft(paddle)
  If(y >= GraphicsWindow.Height - 26 and x >= paddleX and x <= paddleX + 120) Then
    moveY= -moveY
  EndIf

  If(y < 0) Then
    moveY= -moveY
  EndIf

  If(x >= GraphicsWindow.Width - 16 or x < 0) Then
    moveX= -moveX
  EndIf
EndWhile


Image

Re: QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 24 Aug 2020, 17:50
by DoOmnimaga
Est-ce que l'écran de la HP Prime G1 est capable d'afficher la totalité des 24 bits de couleurs disponibles en programmation? J'ai cru lire à maintes reprises dans les années suivantes la sortie de la HP Prime que l'écran ne pouvait afficher que 32768 couleurs et que les couleurs additionnelles étaient arrondies aux plus proches.

Re: QCC 2020 épisode 9 : Ecrans et profondeurs

Unread postPosted: 24 Aug 2020, 17:52
by critor
C'était le logiciel qui était bridé en RGB-555.
Il suffit de mettre à jour les HP Prime G1 pour passer l'affichage en RGB-888. :)