Gestion des images avec eFORTH pour le web

publication: 21 mars 2023 / mis à jour 19 avril 2023

Read this page in english

 


Chargement et affichage des images

La gestion des images est réalisée à partir du mot drawImage. ce mot n'étant pas défini dans eFORTH, voici comment le créer dans le vocabulaire web:

web definitions
JSWORD: drawImage { a n x y }
    let img = new Image();
    img.addEventListener('load', function() {
        context.ctx.drawImage(img, x, y);
    }, false);
    img.src = GetString(a, n);
~
forth definitions

Voici une image, au format GIF, qui va nous servir pour ces premiers tests. Vous pouvez récupérer cette image par clic-droit et Enregistrer l'image sous....

Et voici comment utiliser drawImage pour l'intégrer à canvas:

600 constant ctxWidth 
300 constant ctxHeight 
 
web 
gr 
ctxWidth ctxHeight window 
 
s" greenPencil.gif"   20 10 drawImage 

Pour centrer cette image, il faut récupérer ses dimensions. Pour ce faire, définissons ce mot:

web definitions
JSWORD: imageSize { a n -- w h }
    let img = new Image();
    img.src = GetString(a, n);
    if(img.complete){
        return [img.naturalWidth, img.naturalHeight];
    }  
~
forth definitions

Voici un code non optimisé montrant comment calculer la position de l'image pour qu'elle soit positionnée au centre de notre espace délimité par canvas.

forth definitions 
 
600 constant ctxWidth 
300 constant ctxHeight 
 
web 
gr 
ctxWidth ctxHeight window 
 
0 value imageWidth  
0 value imageHeight 
 
s" greenPencil.gif" imageSize 
    to imageHeight 
    to imageWidth 
        
s" greenPencil.gif"  
    ctxWidth  imageWidth  - 2/  
    ctxHeight imageHeight - 2/ drawImage 

Affichage et découpage d'une image au format jpg

Le mot drawImage sait afficher divers format d'images: gif, png, jpg, svg. Voyons comment afficher et découper une image au format jpg. Mais avant de voir en détail ce découpage d'image, définissons ces mots:

web definitions 
JSWORD: getImageData { addr len x y w h } 
    var myString = GetString(addr, len); 
    const imageData = context.ctx.getImageData(x, y, w, h); 
    Object.assign(context.ctx, {[myString]:imageData}); 
~ 
\ usage: 
\   s" motorhome" 20 30 100 200 getImageData 
\   create copie from canvas content, named "motorhome" 
 
JSWORD: putImageData { addr len x y } 
    var myString = "context.ctx." + GetString(addr, len); 
    const imageData = eval(myString); 
    console.info(imageData); 
    context.ctx.putImageData(imageData, x, y); 
~ 
\ usage: 
\   s" motorhome" 300 30 putImageData 
 
\ create  in dictionnay and save part of image 
\ execuction of  x y   display saved part of image 
: getImage: ( comp: x y w h --  | exec: x y  ) 
    create 
        >r >r >r >r 
        latestxt dup ,  
        >name  r> r> r> r>  getImageData 
    does> 
        -rot >r >r 
        @ >name r> r>  putImageData 
  ; 
forth definitions 

Fonctionnement de ces trois nouvelles définitions:

Voici l'utilisation du mot getImage::

: imgCCar ( -- addr len ) 
    s" ccar.jpg"  
  ; 
 
web gr 
ctxWidth ctxHeight window 
 
imgCCar 5 5 drawImage 
500 ms 
 
30 5 80 232 getImage: motorhome 
 
380 5 motorhome 
465 5 motorhome 

Notre image a comme nom ccar.jpg. Le mot imgCCar est donc une sorte de constante de chaine alphanumérique.

La séquence de code 30 5 80 232 getImage: motorhome va copier une partie de l'image affichée dans canvas, à partir de x et y (30 5) et de 80 pixels de large et 232 pixels de haut. Le mot getImage: crée le mot motorhome.

L'exécution de motorhome précédé des coordonnées x y d'affichage affiche la partie d'image copiée au moment de créer motorhome.

Tester la couleur d'un pixel image

Pour tester la couleur d'un pixel, on définit une variante du mot getImageData, mais qui teste seulement un pixel dans l'espace graphique canvas:

web definitions 
\ get pixel color at x y 
JSWORD: getPixelColor { x y -- c } 
    var pixel = context.ctx.getImageData(x, y, 1, 1); 
    console.info(pixel); 
    return pixel.data[0]*256*256 + pixel.data[1]*256 + pixel.data[2]; 
~ 
forth definitions 

Voici un cas d'école. Tracer trois boites rectangulaires. L'astuce, ici, c'est de tracer ces trois boites en bleu, mais avec une couleur bleur adaptée à chaque boite:

$0000ff constant colorBox1 
$0001ff constant colorBox2 
$0100ff constant colorBox3 
 
web gr 
ctxWidth ctxHeight window 
colorBox1 color! 
10 10 100 50 fillRect 
colorBox2 color! 
120 10 300 120 fillRect 
colorBox3 color! 
400 140 180 120 fillRect 

Voici une définition testBoxes qui va tester le pixel pointé par la souris. La couleur testée permet de savoir quelle boite est pointée:

: waitButtonDown ( -- ) 
    begin 
        button 0= 
    until 
  ; 
 
: testBoxes  
    begin 
        button if 
            getMousePosition getPixelColor  
            case 
                page 
                colorBox2 of    ." BOX 2 selected" cr    endof 
                colorBox3 of    ." BOX 3 selected" cr    endof 
                colorBox1 of    ." BOX 1 selected" cr    endof 
            endcase 
            200 ms 
        then  
    key? until  
  ;    
 
." click on any blue box / space to STOP" cr 
testBoxes 

Voici la définition de getMousePosition qui n'est pas défini dans le vocabulaire web d'origine:

web definitions 
\ The word mouse delivers the position of the mouse pointer from the origin x y (0, 0)  
\ of the HTML page and not from the origin of the canvas. 
\ The word getMousePosition retrieves and recalculates the relative position of the  
\ mouse pointer from the origin of the canvas. 
JSWORD: getMousePosition { -- mousex mousey } 
    var offset = {x: 0, y: 0}; 
    var node = context.ctx.canvas; 
    while (node) { 
        offset.x += node.offsetLeft; 
        offset.y += node.offsetTop; 
        node = node.offsetParent; 
    } 
    return [context.mouse_x-offset.x, context.mouse_y-offset.y]; 
~ 
forth definitions 

Cette définition est à utiliser en remplacement de mouse.


Legal: site web personnel sans commerce / personal site without seling