IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Changer la couleur d'un png uniquement en JS "pur"


Sujet :

JavaScript

  1. #1
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut Changer la couleur d'un png uniquement en JS "pur"
    Je ne connais rien à ce type de problème, mais en voici les données:

    j'ai un png, genre une étoile (ou un carré si vous voulez*) utilisant un fond invisible, il sera de couleur unie, et je veux pouvoir le "placer" juste une fois sur page html, mais en en changeant sa couleur suivant un contexte simple genre une valeur en 1 et 5 => rouge; (6,10) => orange, (10,15) => bleu; etc...

    J'ai vu qu'il y avait la possibilité d'appliquer un filtre en JS, mais je ne comprends rien aux tenants et aux aboutissants, je n'ai aucune culture graphique qui puisse m'aider à lire et à comprendre sur le sujet.

    1 : quelle couleur doit avoir l'image de base pour que le "filtrage" puisse s'appliquer directement, en noir ou en blanc?, ou autre chose ?
    2 : j'imagine et j’espère que le "filtrage" ne s'applique pas sur la partie transparente ?
    3 : comment procéder le plus simplement possible - [ est-ce qu'un bout de code d'une dizaine de lignes max peut résoudre ce problème ] ?


    * en réalité c'est une forme de tache (ne me demandez pas pourquoi)
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  2. #2
    Rédacteur

    Avatar de danielhagnoul
    Homme Profil pro
    Étudiant perpétuel
    Inscrit en
    Février 2009
    Messages
    6 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant perpétuel
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2009
    Messages : 6 389
    Points : 22 933
    Points
    22 933
    Billets dans le blog
    125
    Par défaut


    Je sais que la libpng existe, mais je ne l'ai jamais utilisée : https://libpng.sourceforge.io/index.html

    Blog

    Sans l'analyse et la conception, la programmation est l'art d'ajouter des bogues à un fichier texte vide.
    (Louis Srygley : Without requirements or design, programming is the art of adding bugs to an empty text file.)

  3. #3
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    ah, merci je vais regarder, mais je crois "connaître" cette librairie, de mémoire c'est une librairie en C, servant à "faire" du png, si on réalise un logiciel de dessin...?
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  4. #4
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Bonjour,
    Citation Envoyé par psychadelic Voir le message
    1 : quelle couleur doit avoir l'image de base pour que le "filtrage" puisse s'appliquer directement, en noir ou en blanc?, ou autre chose ?
    En noir ou blanc, ça risque de rester en niveaux de gris, à moins de pouvoir réaliser une vraie transformation de la couleur, ce ne serait plus un simple filtre (Edit : en fait, je veux dire que pour passer du noir/blanc à une vraie couleur, il faudrait soit faire un remplacement de couleur soit ajouter comme un calque coloré translucide, concrètement ou par le biais d'une opération qui s'y apparente).
    Je partirais plutôt sur une couleur pleinement saturée.

    Citation Envoyé par psychadelic Voir le message
    2 : j'imagine et j’espère que le "filtrage" ne s'applique pas sur la partie transparente ?
    Ce qui est transparent devrait le rester.

    Citation Envoyé par psychadelic Voir le message
    3 : comment procéder le plus simplement possible - [ est-ce qu'un bout de code d'une dizaine de lignes max peut résoudre ce problème ] ?
    "uniquement en JS "pur" " : sous-entendu "pas de PHP" ou "pas de CSS" également ?
    Parce qu'en CSS, hue-rotate(...deg) semble bien convenir.
    Après essai avec une image rouge, je vois qu'il faudrait ajuster également la saturation et/ou la luminosité, car je constate beaucoup de perte en saturation/luminosité (j'ai fait une petite recherche et apparemment, il y aurait effectivement un souci à ce niveau).
    Une solution serait donc de préparer des classes CSS pour les différentes couleurs en tâtonnant pour ajuster la saturation/luminosité, et d'appliquer la classe souhaitée à l'utilisation.
    Idéalement, il faudrait trouver un code qui permet de trouver les réglages exacts à faire depuis une couleur de base vers une couleur d'arrivée...

    Sinon de rouge vers jaune par exemple, la rotation est de 60°.
    Il faut considérer un nuancier classique : de gauche à droite on va de rouge à rouge en passant par orange, jaune, vert, bleu, violet, rose...

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Citation Envoyé par Loralina Voir le message
    ...en CSS, hue-rotate(...deg) semble bien convenir...
    CSS - hue-rotate()

  6. #6
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    bon, j'ai pas trop regardé du coté CSS, mais j'ai fini par trouver un script js "pur" qui devrait le faire..

    je l'ai un peu adapté pour mon idée ( j'ai laissé les commentaires en anglais)

    je me suis fait rapidos une image png de Largeur=300px, Hauteur=200px en noir sur du transparent. ( j'ai pas testé pour l'opacité)

    Le truc c'est que ça produit une nouvelle image sur canvas, donc on double, ou triple, ou quadruple, x fois la mémoire (pour l'image), si on veut plusieurs images de couleurs différentes.

    et mon image de base fait dans les 100k et surtout 16000x380 ( je sais j'ai pas dit au départ, et c'est une image qui sert de fond défilant [encore une autre histoire] )

    et comme vous allez le voir ce code exécute une boucle sur chaque pixel pour en changer la couleur, donc pas glop.
    Code HTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    <!DOCTYPE html>
    <html lang="fr">
     
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Changer les couleurs d'un PNG (Noir + transparent) </title>
      <style>
        * {
          margin  : 0;
          padding : 0;
          border  : 0;
          box-sizing: border-box;
        }
        body {
          background-color : #c5ba23;  /* mo edi à un color picker, et je l'utilise        */
          color            : #a80c14;  /* pour choisir une couleur moche de remplacement   */
        }
        #origImg {
          display : block;
          width   : 300px;
          height  : 200px;
          margin  : 20px;
        }
        #myCanvas {
          margin : 20px;
          width  : 600px;  /* pour tester un effet de déformation */
          height : 200px;
        }
      </style>
    </head>
    <body>
     
      <!--
         <img id="origImg" src="test_1.png">  image en L=300px, H=200px
      -->
     
      <canvas id="myCanvas" ></canvas> 
     
      <script>
     
        var imageObj = new Image();
     
        imageObj.onload = function()
        {
          alterImage(this, '#a80c14', 300, 200)
        }
     
     
        imageObj.src = "test_1.png";  // url relative
        // imageObj.src = document.getElementById( "origImg" ).src;
     
     
        function alterImage(imageObj, newColor, wImg, hImg)
        {
          let
            RGB    = hex2rgb(newColor),
            canvas = document.getElementById("myCanvas"),
            ctx    = canvas.getContext("2d");
     
          //  console.log("a", canvas.width, canvas.height )
          //  console.log("b", canvas.scrollWidth, canvas.scrollHeight )
     
          canvas.setAttribute('width', wImg);
          canvas.setAttribute('height', hImg);
     
          ctx.drawImage(imageObj, 0, 0);
     
          //let id = ctx.getImageData(0, 0, canvas.width, canvas.height);
          let id = ctx.getImageData(0, 0, wImg, hImg);
     
          // Iterate over data.  Data is RGBA matrix so go by +=4 to get to next pixel data.
          for (let i=0, iMax=id.data.length ; i < iMax; i +=4)
          {
              // Check if RGB == 0 (black)
            if ( id.data[i] + id.data[i+1] + id.data[i+2] == 0 )
            {
              id.data[i]   = RGB.r;      
              id.data[i+1] = RGB.g;
              id.data[i+2] = RGB.b;
              // id.data[i+3]  reste inchangé, correspond au canal aplha ( opacité ) ?? ( à vérifier)
            }
          }
     
          // redraw your altered data on the canvas.
          ctx.putImageData(id, 0, 0);
        }
     
        function hex2rgb(hexStr)
        {
          // note: hexStr should be #rrggbb
          let
            hex = parseInt(hexStr.substring(1), 16),
            r   = (hex & 0xff0000) >> 16,
            g   = (hex & 0x00ff00) >> 8,
            b   =  hex & 0x0000ff;
          return {r, g, b};
        }
     
      </script>
    </body>
    </html>

    bref je sais pas trop si c'est le plus mieux génial, j'ai un gros doute
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  7. #7
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    je viens d'essayer le hue-rotate, avec mon image en Noir, puis en blanc
    Code css : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        #origImg {
          display : block;
          width   : 300px;
          height  : 200px;
          margin  : 20px;
     
          filter: hue-rotate(60deg);
        }

    mais ça fait rien du tout.
    faut partir d'une couleur unie pour ce truc puisse fonctionner, c'est un peu compliqué, et effectivement va valoir tâtonner, (j'aime pas du tout du tout tâtonner, ça me rends malade quand les trucs ne sont pas rationnels)
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  8. #8
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Pour canvas, juste ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ctx.fillStyle=newColor;
    ctx.fillRect(0,0,canvas.width,canvas.height);
    ctx.globalCompositeOperation="destination-in";
    ctx.drawImage(imageObj,0,0);
    Après on peut envoyer ça sur une balise image avec toDataURL et supprimer le canvas.

    Pour hue-rotate, oui c'est ce que je dis, il faut partir d'une couleur, rouge étant à 0°, mais il faut gérer ensuite le problème de saturation/luminosité.

  9. #9
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Bonjour,
    Au niveau des filtres CSS, j'ai regardé un peu le principe de filter:url.
    Il y a peut-être une piste intéressante avec SVG<filter>.
    J'ai fait ce test qui donne le même résultat qu'avec canvas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <svg style="height:0;width:0;"><filter id="filtre"><feColorMatrix type="matrix" color-interpolation-filters="sRGB"></filter></svg>
    <img src="image.png" style="filter:url(#filtre);">
    <script>
    function rapportsRGB(nb_) {return {r:((nb_>>16)&0xFF)/255,g:((nb_>>8)&0xFF)/255,b:(nb_&0xFF)/255};}
    var ob_=rapportsRGB(0xCC99FF);
    document.getElementsByTagName("feColorMatrix")[0].setAttribute("values",
    	"0 0 0 0 "+ob_.r+
    	" 0 0 0 0 "+ob_.g+
    	" 0 0 0 0 "+ob_.b+
    	" 0 0 0 1 0");
    </script>
    Au niveau de la matrice :
    - Je mets les coefficients de multiplication RGB à 0, l'image devient noire.
    - Je définis les coefficients d'addition RGB sur les valeurs souhaitées.

    La petite chose dérangeante, c'est cette balise <svg>.

  10. #10
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    A c'est pas mal comme idée, je vais tester

    Ça me donne aussi l'idée d'utiliser une image SVG, ce sera plus simple pour changer la couleur, voir les couleurs... (mais faut encore la dessiner et je suis pas doué pour ça)

    Pour la petite histoire, ce que j'essaie de faire c'est de refaire à peu prés le même truc que ça : http://codyhouse.co/gem/animated-transition-effects/
    mais sans jQuery, et surtout en allégeant le css délirant qu'ils utilisent, (je passe par requestAnimationFrame)

    je pense aussi pouvoir l'adapter pour des séquences faites en stop motion
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  11. #11
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Bonjour,
    J'ai à priori réussi à faire quelque chose avec les filtres CSS, sans SVG.

    J'ai d'abord cherché une fonction convertissant du RGB en du HSV standard, comme on en a classiquement sur les nuanciers.
    La difficulté est que les fonctions HSV des filtres CSS donnent des résultats très différents.
    J'ai de ce fait cherché également les algorithmes de ces filtres CSS (voir ici).

    A partir de là, je voyais deux possibilités :

    - Soit résoudre les équations permettant d'obtenir directement les bonnes valeurs HSV façon filtres CSS, mais c'est à la limite du faisable tellement les équations sont longues.

    - Soit imaginer une méthode qui permet d'affiner progressivement les valeurs.
    J'ai fini par tenter une idée sans savoir ce qu'elle allait donner et j'ai eu de la chance car cela semble fonctionner.

    J'ai vérifié mon script en testant toutes les couleurs possibles de 0 à 0xFFFFFF (j'ai utilisé while et setInterval).
    Au maximum, il faudrait 54 tours de boucle pour arriver à la solution, ce qui est insignifiant.

    Voilà mon script qui, à partir du rouge pur (l'image doit donc être rouge, peu importe les valeurs alpha) et d'une couleur d'arrivée, donne le CSS pour hue-rotate, saturate et brightness :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    <img src="image.png">
    <script>
    /*
    https://stackoverflow.com/questions/2348597/why-doesnt-this-javascript-rgb-to-hsl-code-work
    Adaptations :
    - Remplacement paramètres "r", "g" et "b" par "color".
    - Ajout du cas où r=g=b.
    - Suppression des "Math.floor".
    - Retour d'un Object à la place du Array.
    */
    function rgbToHsv(color)
    	{
    	var
    		r = color.r,
    		g = color.g,
    		b = color.b;
    	if(r===g && g===b)
    		{
    		return {h : 0,s : 0,v : 100 * r / 255};
    		}
    	var
    		min = Math.min(r, g, b),
    		max = Math.max(r, g, b),
    		delta = max - min,
    		h, s, v = max;
    		v = max / 255 * 100;
    		s = delta / max * 100;
    	if( r == max )
    		{
    		h = ( g - b ) / delta;
    		}
    	else if( g == max )
    		{
    		h = 2 + ( b - r ) / delta;
    		}
    	else
    		{
    		h = 4 + ( r - g ) / delta;
    		}
    	h = h * 60;
    	if( h < 0 )
    		{
    		h += 360;
    		}
    	return {h : h,s : s,v : v};
    	}
     
    /*
    https://github.com/WebKit/webkit/blob/fb3c15607f80e19d7d3773e0cbcabe5bb2d6125e/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp
    Adaptations :
    - Réécriture en js.
    - Suppression alpha.
    */
    function applyHueRotateFilter(color, u_filterAmount)
    	{
    	var c = Math.cos(u_filterAmount * Math.PI / 180.0);
    	var s = Math.sin(u_filterAmount * Math.PI / 180.0);
    	return {
    		r : color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928),
    		g : color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283),
    		b : color.r * (0.213 - c * 0.213 - s * 0.787) +  color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072)
    		};
    	}
    function applySaturateFilter(color, u_filterAmount)
    	{
    	return {
    		r : (0.213 + 0.787 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b,
    		g : (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 + 0.285 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b,
    		b : (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 + 0.928 * u_filterAmount) * color.b
    		};
    	}
    function applyBrightnessFilter(color, u_filterAmount)
    	{
    	return {
    		r : color.r * u_filterAmount,
    		g : color.g * u_filterAmount,
    		b : color.b * u_filterAmount
    		};
    	}
     
    /*
    Fonction que j'avais récupérée (mais où ?) et adaptée.
    */
    function RGB(color)
    	{
    	return {
    		r:(color>>16)&0xFF,
    		g:(color>>8)&0xFF,
    		b:color&0xFF
    		};
    	}
     
    /*
    Ma solution par rapprochement.
    */
    function hsvFilter(color)
    	{
    	var color_rgb;
    	var color_hsl;
     
    	var colorInit_rgb=RGB(0xFF0000);
    	var colorInit_hsl=rgbToHsv(colorInit_rgb);
     
    	var colorFina_rgb=RGB(color);
    	var colorFina_hsl=rgbToHsv(colorFina_rgb);
     
    	var h=colorFina_hsl.h-colorInit_hsl.h;
    	var s=colorFina_hsl.s/colorInit_hsl.s;
    	var v=colorFina_hsl.v/colorInit_hsl.v;
     
    	if(colorFina_rgb.r===colorFina_rgb.g && colorFina_rgb.g===colorFina_rgb.b)
    		{
    		s=0;
    		if(colorFina_rgb.r===0)
    			{
    			return {h:0,s:0,v:0};
    			}
    		}
     
    	var i=-1; //utilisation d'un compteur par sécurité (à priori inutile)
    	do
    		{
    		color_rgb=applyHueRotateFilter(colorInit_rgb,h);
    		color_rgb=applySaturateFilter(color_rgb,s);
    		color_rgb=applyBrightnessFilter(color_rgb,v);
    		color_hsl=rgbToHsv(color_rgb);
    		h+=colorFina_hsl.h-color_hsl.h;
    		if(s!==0)
    			{
    			s*=colorFina_hsl.s/color_hsl.s;
    			}
    		v*=colorFina_hsl.v/color_hsl.v;
    		}
    	while(++i<1000 && (Math.abs(colorFina_hsl.h-color_hsl.h)>0.1 || Math.abs(colorFina_hsl.s-color_hsl.s)>0.1 || Math.abs(colorFina_hsl.v-color_hsl.v)>0.1));
     
    	console.log(i,Math.abs(colorFina_hsl.h-color_hsl.h),Math.abs(colorFina_hsl.s-color_hsl.s),Math.abs(colorFina_hsl.v-color_hsl.v)); //i maximal observé : 54
    	console.log("colorFina_rgb",colorFina_rgb);
    	console.log("colorFina_hsl",colorFina_hsl);
    	console.log("color_rgb",color_rgb);
    	console.log("color_hsl",color_hsl);
     
    	return {h:h,s:s,v:v};
    	}
     
    var ob_=hsvFilter(0x6581A8);
    document.getElementsByTagName("img")[0].style.filter="hue-rotate("+ob_.h+"deg) saturate("+ob_.s+") brightness("+ob_.v+")";
    </script>

  12. #12
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    oula, ya du lourd!

    bon y va me falloir un peu de temps pour digérer tout ça.. (je vais pas pouvoir te répondre rapidement)

    en tout cas merci vraiment de de pencher sur cette question.
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  13. #13
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    Et bien, j'ai testé, et c'est pas mal du tout...

    Je ne pensais pas à une solution utilisant les filtres css, et finalement c'est la bonne piste.
    Donc mon problème est juste d'avoir 5 ou 6 filtres différents pour obtenir une nouvelle image de couleur sur laquelle je peux facilement via du JS "pur" le filtre css choisi.
    Du coup le probleme est juste de déterminer ces valeurs de filtres, et l'utilisation de js ou jQuery n'est pas importante ( mais merci à Loralina pour cet effort)

    J'ai aussi fini par trouver ça : https://codepen.io/sosuke/pen/Pjoqqp

    il y a un lien vers stackoverflow, j'ai été voir, la solution codepen est la plus rapide, mais l'auteur parle aussi d'une solution plus lente, mais plus précise.
    Bref je vais faire mes tests pour me faire un outil de fabrication de filtres css.

    Il y a aussi un peu de Math dans l'histoire, je ne suis pas certain d'avoir envie de me plonger la dedans, et si les approximations sont suffisamment proches, "je prend"

    en tout cas, merci à tous, et surtout à Loralina
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  14. #14
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Merci pour ce retour, psychadelic.

    Je viens de voir une nouvelle problématique !

    Sur Firefox, je vois que le code de codepen donne parfois des erreurs alors qu'il indique "Loss: 0.0. This is a perfect result.".

    Pour mieux comparer les résultats, j'ai copié dans un fichier html les filtres obtenus à partir :
    - de deux exécutions du code de codepen (vu qu'il donne des résultats variables d'une fois à l'autre).
    - d'une exécution de mon code (qui donne toujours le même résultat car il n'y a pas d'aléatoire dans la recherche).

    Voici le code :
    Code HTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    https://codepen.io/sosuke/pen/Pjoqqp :
    <div style="background-color:#00a4d6;">&nbsp;</div>
    <div style="background-color:#000000;filter: invert(53%) sepia(88%) saturate(4187%) hue-rotate(165deg) brightness(100%) contrast(101%);">&nbsp;</div>
    <div style="background-color:#000000;filter: invert(49%) sepia(50%) saturate(2729%) hue-rotate(160deg) brightness(93%) contrast(101%);">&nbsp;</div>
    <br>
    Loralina :
    <div style="background-color:#00a4d6;">&nbsp;</div>
    <div style="background-color:#FF0000;filter: hue-rotate(196.36deg) saturate(0.306457) brightness(2.44244);">&nbsp;</div>

    Sur Firefox :
    - Mon code donne le bon résultat.
    - Le premier résultat du code de codepen est erroné, le second est correct.

    Sur Edge :
    - Mon code donne le bon résultat.
    - Les deux résultats du code de codepen sont erronés.

    Sur Chrome :
    - Mon code donne un résultat erroné.
    - Les deux résultats du code de codepen sont corrects.


    J'allais poster cette réponse, mais j'ai tenté une idée pour voir :
    Inverser l'ordre d'application des filtres H et S dans mon code et maintenant ça semble fonctionner sur les trois navigateurs.

    Je reposte donc mon code avec également au passage la correction d'une mini maladresse (il y en a d'autres, mais tant pis, disons que mon code est encore au stade du brouillon) :
    Code HTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    <img src="image.png">
    <script>
    /*
    https://stackoverflow.com/questions/2348597/why-doesnt-this-javascript-rgb-to-hsl-code-work
    Adaptations :
    - Remplacement paramètres "r", "g" et "b" par "color".
    - Ajout du cas où r=g=b.
    - Suppression des "Math.floor".
    - Retour d'un Object à la place du Array.
    */
    function rgbToHsv(color)
            {
            var
                    r = color.r,
                    g = color.g,
                    b = color.b;
            if(r===g && g===b)
                    {
                    return {h : 0,s : 0,v : 100 * r / 255};
                    }
            var
                    min = Math.min(r, g, b),
                    max = Math.max(r, g, b),
                    delta = max - min,
                    h, s, v = max;
                    v = max / 255 * 100;
                    s = delta / max * 100;
            if( r == max )
                    {
                    h = ( g - b ) / delta;
                    }
            else if( g == max )
                    {
                    h = 2 + ( b - r ) / delta;
                    }
            else
                    {
                    h = 4 + ( r - g ) / delta;
                    }
            h = h * 60;
            if( h < 0 )
                    {
                    h += 360;
                    }
            return {h : h,s : s,v : v};
            }
     
    /*
    https://github.com/WebKit/webkit/blob/fb3c15607f80e19d7d3773e0cbcabe5bb2d6125e/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp
    Adaptations :
    - Réécriture en js.
    - Suppression alpha.
    */
    function applyHueRotateFilter(color, u_filterAmount)
            {
            var c = Math.cos(u_filterAmount * Math.PI / 180.0);
            var s = Math.sin(u_filterAmount * Math.PI / 180.0);
            return {
                    r : color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928),
                    g : color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283),
                    b : color.r * (0.213 - c * 0.213 - s * 0.787) +  color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072)
                    };
            }
    function applySaturateFilter(color, u_filterAmount)
            {
            return {
                    r : (0.213 + 0.787 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b,
                    g : (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 + 0.285 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b,
                    b : (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 + 0.928 * u_filterAmount) * color.b
                    };
            }
    function applyBrightnessFilter(color, u_filterAmount)
            {
            return {
                    r : color.r * u_filterAmount,
                    g : color.g * u_filterAmount,
                    b : color.b * u_filterAmount
                    };
            }
     
    /*
    Fonction que j'avais récupérée (mais où ?) et adaptée.
    */
    function RGB(color)
            {
            return {
                    r:(color>>16)&0xFF,
                    g:(color>>8)&0xFF,
                    b:color&0xFF
                    };
            }
     
    /*
    Ma solution par rapprochement.
    */
    function hsvFilter(color)
            {
            var color_rgb;
            var color_hsl;
     
            var colorInit_rgb=RGB(0xFF0000);
            var colorInit_hsl=rgbToHsv(colorInit_rgb);
     
            var colorFina_rgb=RGB(color);
            var colorFina_hsl=rgbToHsv(colorFina_rgb);
     
            var h=colorFina_hsl.h-colorInit_hsl.h;
            var s=colorFina_hsl.s/colorInit_hsl.s;
            var v=colorFina_hsl.v/colorInit_hsl.v;
     
            if(colorFina_rgb.r===colorFina_rgb.g && colorFina_rgb.g===colorFina_rgb.b)
                    {
                    if(colorFina_rgb.r===0)
                            {
                            return {h:0,s:0,v:0};
                            }
                    s=0;
                    }
     
            var i=-1; //utilisation d'un compteur par sécurité (à priori inutile)
            do
                    {
                    color_rgb=applyHueRotateFilter(colorInit_rgb,h);
                    color_rgb=applySaturateFilter(color_rgb,s);
                    color_rgb=applyBrightnessFilter(color_rgb,v);
                    color_hsl=rgbToHsv(color_rgb);
                    h+=colorFina_hsl.h-color_hsl.h;
                    if(s!==0)
                            {
                            s*=colorFina_hsl.s/color_hsl.s;
                            }
                    v*=colorFina_hsl.v/color_hsl.v;
                    }
            while(++i<1000 && (Math.abs(colorFina_hsl.h-color_hsl.h)>0.1 || Math.abs(colorFina_hsl.s-color_hsl.s)>0.1 || Math.abs(colorFina_hsl.v-color_hsl.v)>0.1));
     
            console.log(i,Math.abs(colorFina_hsl.h-color_hsl.h),Math.abs(colorFina_hsl.s-color_hsl.s),Math.abs(colorFina_hsl.v-color_hsl.v)); //i maximal observé : 54
            console.log("colorFina_rgb",colorFina_rgb);
            console.log("colorFina_hsl",colorFina_hsl);
            console.log("color_rgb",color_rgb);
            console.log("color_hsl",color_hsl);
     
            return {h:h,s:s,v:v};
            }
     
    var ob_=hsvFilter(0x6581A8);
    document.getElementsByTagName("img")[0].style.filter="saturate("+ob_.s+") hue-rotate("+ob_.h+"deg) brightness("+ob_.v+")";
    </script>
    J'ai simplement testé 4 ou 5 couleurs et non toutes les couleurs comme la dernière fois.
    Idéalement, il faudrait recalculer les RGB obtenus pour voir s'il y a des écarts par rapport aux valeurs souhaitées. Il est sans doute possible qu'en arrondissant, il y ait une unité de décalage.

  15. #15
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    J’ai mis ce sujet comme «*résolu*» parce que j’y ai la une solution, mais en réalité, je continue de travailler sur le sujet, et tout nouvelle info est bonne à prendre.

    Donc encore grand merci de continuer un peu avec moi.

    Je teste principalement avec FireFox, et quand le résultat est bon je vérifie sur Chromium.

    J’utilise une image png pour tester elle est noire ou rouge suivant l’algo (avec une partie avec un canal alpha en dégressif) et j’utilise un color picker systeme pour vérifier la couleur (Gpicker [Gnome]).

    La je suis juste en train de coder un ensemble de «*testeurs*» en fait une simple page html mettant en œuvre l’algo ciblé.

    Je décortique le contenu du post sur stackoverflow.com ( celui qui à donné l’exemple sur codePen) et mis à part que le resultat codePen soit "satisfaisant" je reste encore dans l’expectative.

    Je compte implémenter suivant mon protocole les algo de «*Dave*» , de « MultiplyByZer0*» et bien sur le tien*

    PS: j’utilise un «*input type="color" (https://developer.mozilla.org/en-US/...nt/input/color très joli sous FireFox mais débile sous Chromium)

    Bref je suis en phase de test sur ce sujet, et je vais mon rythme (suivant mon temps libre).

    Sinon, j’ai commencé par l’implémentation du filtre SVG, qui donne un résultat parfait, mais qui à ce gros désavantage d’imposer la présence d’un élément svg sur la page, même si ça taille est à zéro.
    J’ai essayé mais sans succès de passer le SVG en mémoire via des document.createElementNS… mais ça coince au niveau de l’imputation du flitre (document.querySelector('#Img-test').setAttribute('style','"filter:url(#filterSVG)"'); qui semble mal passer, car si j’attribue bien le bon ID, ce filtre reste dans la partie Mémoire du DOM et n’est pas présent sur l’interface, ou alors j’ai loupé un truc. → je posterai le code tantôt, il est resté dans un état «*brut*», et si qq1 peut résoudre cette énigme, ce serait un grand bon pour moi et ma connaissance, et aussi pour l’humanité si on est d’un optimisme inqualifiable.
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  16. #16
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Bonjour,
    Citation Envoyé par psychadelic Voir le message
    Sinon, j’ai commencé par l’implémentation du filtre SVG, qui donne un résultat parfait, mais qui à ce gros désavantage d’imposer la présence d’un élément svg sur la page, même si ça taille est à zéro.
    J'ai repensé à l'exemple de la documentation : filter: url("../../media/examples/shadow.svg#element-id");.

    Je me suis dit qu'on pourrait tenter quelque chose de dynamique avec URL.createObjectURL.
    Ainsi pas besoin de balise svg, ni de fichier externe.

    Ca fonctionne bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <img src="image.png">
    <script>
    function rapportsRGB(nb_) {return {r:((nb_>>16)&0xFF)/255,g:((nb_>>8)&0xFF)/255,b:(nb_&0xFF)/255};}
     
    var ob_;
    var ob_feColorMatrix;
    var ob_filter;
    var ob_svg;
    var st_ns;
     
    ob_=rapportsRGB(0xCC99FF);
    ob_svg=document.createElementNS(st_ns="http://www.w3.org/2000/svg","svg");
    ob_svg.appendChild(ob_filter=document.createElementNS(st_ns,"filter"));
    ob_filter.setAttribute("id","filtre");
    ob_filter.appendChild(ob_feColorMatrix=document.createElementNS(st_ns,"feColorMatrix"));
    ob_feColorMatrix.setAttribute("type","matrix");
    ob_feColorMatrix.setAttribute("color-interpolation-filters","sRGB");
    ob_feColorMatrix.setAttribute("values",
    	"0 0 0 0 "+ob_.r+
    	" 0 0 0 0 "+ob_.g+
    	" 0 0 0 0 "+ob_.b+
    	" 0 0 0 1 0");
    document.getElementsByTagName("img")[0].style.filter="url("+URL.createObjectURL(new Blob([new XMLSerializer().serializeToString(ob_svg)],{type:"image/svg+xml"}))+"#filtre)";
    </script>
    Cependant, cela ne devrait passer que sur Chrome et Firefox : dans la page dont j'ai mis le lien, on ne voit que ces deux navigateurs de supportés (voir le tableau à la fin : "On SVG elements").

  17. #17
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    Wahou!

    Je ne connaissais pas cette possibilité en JS !

    Le truc, c'est que je n'arrive pas à le faire fonctionner avec mon "protocole".

    Voici ma page de test avec un SVG présent sur la page ( et qui fonctionne bien ) :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    <!DOCTYPE html>
    <html lang="fr">
     
    <head>
      <meta charset="UTF-8">
      <title>SVG Filter 'simple'</title>
      <style>
        #RGBval    { text-transform: uppercase }
        #PickColor { height: 50px; margin: 0 20px }
        th         { background-color: lightblue; padding: 5px 20px }
        pre        { margin: 0 15px }
        #ImgTest   { filter: url(#FilterSVG) }
      </style>
    </head>
     
    <body>
      <svg height="0px" width="0px">
        <defs>
          <filter id="FilterSVG" color-interpolation-filters="sRGB">
            <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0"/>
          </filter>
        </defs>
      </svg>
     
      <table>
        <caption>SVG method</caption>
        <tr> <th>Image</th> <th>Color</th> </tr>
        <tr>
          <td><img src="https://www.nouveauelevator.com/image/black-icon/android.png" id="ImgTest" /></td> 
          <td><input type="color" value="#000000"  id="PickColor" ></td>
        </tr>
        <tr> <td>.</td> <td>.</td> </tr>
        <tr> <th>Filter value </th> <th>#RBG target</th> </tr>
        <tr>
          <td><pre id="FilterVal">
        0 0 0 0 0
        0 0 0 0 0
        0 0 0 0 0
        0 0 0 1 0</pre></td>
            <td id="RGBval">#000000</td>
        </tr>
      </table>
     
      <script>
        PickColor.onchange=()=>{
            RGBval.textContent = PickColor.value;
     
            let 
            HexT = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(PickColor.value),
            r = parseInt(HexT[1], 16),
            g = parseInt(HexT[2], 16),
            b = parseInt(HexT[3], 16);
     
            FilterVal.textContent =  SetFilter( r, g, b);
        }
        function SetFilter( r, g, b )
        {
            const Matrix  = document.querySelector('#FilterSVG feColorMatrix');
            r = r/255;
            g = g/255;
            b = b/255;
     
            Matrix.setAttribute("values",  "0 0 0 0 "+r+" 0 0 0 0 "+g+ " 0 0 0 0 "+b+" 0 0 0 1 0");
     
            return "\n 0 0 0 0 "+r+"\n 0 0 0 0 "+g+ "\n 0 0 0 0 "+b+"\n 0 0 0 1 0"
        }
      </script>
    </body>
     
    </html>


    et voici son équivalent en SVG "caché" :
    qui utilise ta méthode URL.createObjectURL mais qui ne donne rien... j'ai raté quelque chose ?

    [edit] code effacé : comme ce code est erroné et qu'il y a la solution par la suite..
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  18. #18
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Oui, en fait, il faut déplacer ce morceau :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        var
          MyBlobSVG = new Blob([new XMLSerializer().serializeToString(mySVG)],{type:"image/svg+xml"}),
          xURL      = URL.createObjectURL(MyBlobSVG);
     
     
        // document.querySelector('#ImgTest').setAttribute('style', "url(" + URL.createObjectURL(MyBlobSVG) + "#FilterSVG)" ); 
     
     
        document.querySelector('#ImgTest').style.filter="url("+ xURL +"#FilterSVG)";
    Et le mettre dans la fonction SetFilter, avant le return.

    Il faut en effet régénérer, parce que la conversion en string new XMLSerializer().serializeToString(mySVG) fait perdre toute référence.

  19. #19
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    re wahou!
    ça marche super bien
    et vraiment super merci,
    c'en est au point ou je me demande si je vais pas laisser tomber les filtres css, ( mais j'ai qd même envie d'en avoir le coeur net de ce coté)

    Le seul truc qui me chiffonne c'est la gestion mémoire, car ça revient à créer un nouveau blob et un nouveau XMLSerializer à chaque utilisation.
    J'imagine que le garbage colector se débrouille avec, mais est-ce qu'il ne serait pas préférable de lui filler un petit coup de main en déclarant ces trois variables en globales

    peut-être même caser un null dessus ou ce nouvel opérateur delete ? => https://developer.mozilla.org/fr/doc...9rateur_delete

    mais je vois pas trop ou.

    en tete de script :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
          var
            xXMLs = null,
            xBlob = null,
            xURL  = null;
    puis dans la function SetFilter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          xXMLs = new XMLSerializer().serializeToString(mySVG);
          xBlob = new Blob([xXMLs],{type:"image/svg+xml"});
          xURL  = URL.createObjectURL(xBlob);
     
          ImgTest.style.filter = "url(" + xURL + "#FilterSVG)";
    ce qui donne au final (j'ai tout mis dans un objet JS pour que ce soit plus simple à porter ailleurs) :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    <!DOCTYPE html>
    <html lang="fr">
     
    <head>
      <meta charset="UTF-8">
      <title>SVG Filter</title>
      <style>
        #RGBval    { text-transform: uppercase }
        #PickColor { height: 50px; margin: 0 20px }
        th         { background-color: lightblue; padding: 5px 20px }
        pre        { margin: 0 15px }
      </style>
    </head>
     
    <body>
      <table>
        <caption>SVG method</caption>
        <tr> <th>Image</th> <th>Color</th> </tr>
        <tr>
          <td><img src="https://www.nouveauelevator.com/image/black-icon/android.png" id="ImgTest" /></td> 
          <td><input type="color" value="#000000"  id="PickColor" ></td>
        </tr>
        <tr> <td>.</td> <td>.</td> </tr>
        <tr> <th>Filter value </th> <th>#RBG target</th> </tr>
        <tr>
          <td><pre id="FilterVal">
        0 0 0 0 0
        0 0 0 0 0
        0 0 0 0 0
        0 0 0 1 0</pre></td>
            <td id="RGBval">#000000</td>
        </tr>
      </table>
     
      <script>
        const
          SVG_Filter = {
            init(ImgID) 
            {
              this.Img = document.getElementById(ImgID);
              let
                NS = 'http://www.w3.org/2000/svg';
     
              this.SVG    = document.createElementNS(NS,'svg'),
              this.filter = document.createElementNS(NS,'filter'),
              this.matrix = document.createElementNS(NS,'feColorMatrix');
     
              this.filter.setAttribute( 'id', 'FilterSVG');
              this.filter.setAttribute( 'color-interpolation-filters', 'sRGB');
     
              this.matrix.setAttribute( 'type', 'matrix');
              this.matrix.setAttribute("values", "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0");
     
              this.filter.appendChild(this.matrix);
              this.SVG.appendChild(this.filter);
     
              this.xXMLs = null,
              this.xBlob = null,
              this.xURL  = null;
            },
            SetColor( r, g, b )
            {
              r = r/255;
              g = g/255;
              b = b/255;
     
              this.matrix.setAttribute("values",  "0 0 0 0 "+r+" 0 0 0 0 "+g+ " 0 0 0 0 "+b+" 0 0 0 1 0");
     
              this.xXMLs = new XMLSerializer().serializeToString(this.SVG);
              this.xBlob = new Blob([this.xXMLs],{type:"image/svg+xml"});
              this.xURL  = URL.createObjectURL(this.xBlob);
     
              this.Img.style.filter = "url(" + this.xURL + "#FilterSVG)";
     
              return "\n 0 0 0 0 "+r+"\n 0 0 0 0 "+g+ "\n 0 0 0 0 "+b+"\n 0 0 0 1 0";
            }
          }
     
        SVG_Filter.init('ImgTest');
     
        PickColor.onchange=()=>{
          RGBval.textContent = PickColor.value;
     
          let 
            HexT = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(PickColor.value),
            r = parseInt(HexT[1], 16),
            g = parseInt(HexT[2], 16),
            b = parseInt(HexT[3], 16);
     
          FilterVal.textContent = SVG_Filter.SetColor( r, g, b );
        }
      </script>
    </body>
     
    </html>
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  20. #20
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Bonjour,
    Citation Envoyé par psychadelic Voir le message
    Le seul truc qui me chiffonne c'est la gestion mémoire, car ça revient à créer un nouveau blob et un nouveau XMLSerializer à chaque utilisation.
    J'imagine que le garbage colector se débrouille avec, mais est-ce qu'il ne serait pas préférable de lui filler un petit coup de main en déclarant ces trois variables en globales
    A mon avis, dans le cas présent c'est au voisinage de 0 niveau mémoire.
    Je pense que le blob ne contiendra qu'un peu de texte.

    Après le ramasse-miettes, il se débrouillera au mieux j'imagine : si une variable n'est plus référencée, elle ne sera peut-être pas supprimée tout de suite de la mémoire, mais quand ce sera utile.
    Il ne devrait pas y avoir besoin de forcer quoi que ce soit.
    Je ne m'inquiète pas non plus de sa capacité à supprimer quelques variables à répétition, il n'y a pas besoin de les rendre persistantes en vue de moins le solliciter.

    Ce qu'on doit pouvoir rajouter par contre, c'est URL.revokeObjectURL.

    En cas de doute, dans F12, on peut analyser la mémoire.
    Il faudra quand même probablement faire une boucle générant beaucoup d'objets pour mieux évaluer ça.

    Concernant les variables globales, moins il y en a, mieux c'est, d'un point de vue conceptuel, mais pas que !
    C'est toujours mieux de dépendre le moins possible du contexte extérieur et de passer par des paramètres ou de créer les éléments à la volée (bon je dis ça, mais il faut aussi considérer les propriétés de classes qu'on ne va bien sûr pas forcément passer en paramètres à l'utilisation des méthodes).
    Et puis, les accès aux variables locales devraient être plus rapides.

    D'un autre côté, en performance, recréer un objet peut être un peu plus coûteux.
    Dans certains cas, on peut garder un objet persistant dans un autre contexte et le passer en paramètre.

    Il est vrai aussi que propreté du code et performance (mémoire ou vitesse) ne vont pas toujours de pair.

    Citation Envoyé par psychadelic Voir le message
    ou ce nouvel opérateur delete
    Il est plus vieux que moi.

    delete ou null peuvent en effet être utilisés (rappelons que delete s'applique sur une propriété), l'objectif peut être la mémoire, mais aussi l'algorithmique tout simplement.
    Maintenant je doute qu'il soit utile en fin de fonction de mettre à null une variable locale : je ne pense pas que ça force le ramasse-miettes a réagir plus vite.

    Dans le code actuel, si les propriétés "xXMLs", "xBlob", "xURL" ne sont pas utilisées en dehors de la fonction SetColor, pour moi il est mieux de passer par des variables locales et de privilégier la libération de la mémoire.
    Toutefois, il est valable de créer this.xXMLs = new XMLSerializer() à l'initialisation et de faire simplement this.xBlob = new Blob([this.xXMLs.serializeToString(this.SVG)],{type:"image/svg+xml"}); dans la fonction SetColor.
    C'est à décider en fonction de si on privilégie la vitesse ou la mémoire.

    Mais je redis que pour moi, il s'agit là d'optimisations imperceptibles.

    Sinon, pour une compatibilité plus large, je tiens à rajouter ce petit exemple avec canvas qui pourra intéresser certains et utilisant ce que j'avais précédemment indiqué :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <image src="image.png">
    <script>
    document.getElementsByTagName("img")[0].addEventListener("load",function tutu()
    	{
    	var canvas;
    	var ctx;
     
    	this.removeEventListener("load",tutu); //essentiel car src modifié ensuite
    	(canvas=document.createElement("canvas")).setAttribute('width',this.width);
    	canvas.setAttribute('height',this.height);
    	(ctx=canvas.getContext("2d")).fillStyle="#CC99FF";
    	ctx.fillRect(0,0,canvas.width,canvas.height);
    	ctx.globalCompositeOperation="destination-in";
    	ctx.drawImage(this,0,0);
    	this.src=canvas.toDataURL(); //variantes possibles
    	});
    </script>
    Ca marche même sur Internet Explorer.
    En revanche, il est assez lourd de générer une grande image.
    Sur Chrome, ça ne fonctionnera pas si on passe par le système de fichiers.

    Je précise enfin que dans tout le code que j'ai pu donner ici, je n'utilise que peu voire jamais un certain nombre de choses et qu'il peut y avoir des maladresses et des oublis.
    Il est préférable d'aller approfondir par ailleurs.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Changer la couleur de certains caractères uniquement
    Par guillaume_31400 dans le forum Excel
    Réponses: 5
    Dernier message: 14/11/2017, 18h35
  2. [GD] Changer la couleur d'un fichier PNG
    Par The Transporter dans le forum Bibliothèques et frameworks
    Réponses: 3
    Dernier message: 09/01/2009, 14h43
  3. Réponses: 0
    Dernier message: 11/10/2008, 14h31
  4. Changer la couleur d'un PNG
    Par utwor dans le forum Windows Forms
    Réponses: 6
    Dernier message: 08/02/2008, 17h01
  5. Changer les couleurs de la palette avec du RGB
    Par le mage tophinus dans le forum x86 16-bits
    Réponses: 11
    Dernier message: 13/01/2003, 08h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo