2 votes

Filtre SVG : résultat différent selon le navigateur

J'essaie d'ajouter un effet de lumière ponctuelle à un SVG rectangle. Le problème est que j'obtiens des résultats différents selon le navigateur que j'utilise. Par exemple, dans Chrome et Safari, j'ai obtenu les résultats suivants :

enter image description hereenter image description here

Comment puis-je obtenir un résultat cohérent en utilisant des filtres svg sur différents navigateurs ?

*, *:before, *:after {
  box-sizing: border-box;
}

<link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" rel="stylesheet"/>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <filter id="customPointLight">
      <feSpecularLighting result="lightBuffer" specularConstant="1.5"
          specularExponent="80" lighting-color="#fff">
        <fePointLight x="100" y="100" z="80"/>
      </feSpecularLighting>
      <feComposite in="SourceGraphic" in2="lightBuffer" operator="out"
          k1="0" k2="1" k3="1" k4="0"/>
    </filter>
  </defs>

  <rect x="50" y="50" width="100" height="100" fill="blue" filter="url(#customPointLight)"></rect>

</svg>

2voto

Michael Mullany Points 9020

Safari choisit automatiquement une résolution de filtre incorrecte, probablement parce que personne n'a pris la peine de mettre à jour le code pour les écrans rétina. Vous pouvez inciter Safari à faire "presque" ce qu'il faut en ajoutant filterRes="200" à l'élément de filtre, car il n'a pas encore abandonné la prise en charge de filterRes.

Cela dit, aujourd'hui, la bonne chose à faire pour tous les navigateurs est de renoncer complètement aux sources de lumière et d'utiliser simplement un rectangle rempli d'un dégradé radial noir/blanc importé en tant que data:URI avec feImage (pour la compatibilité avec Firefox et Edge). Un screen blend ajoutera la haute lumière blanche à l'original, comme je pense que vous le souhaitiez. Comme ceci :

svg {
background: red;
}

<svg width="400px" height="200px" xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
     <radialGradient id="lightHack">
      <stop offset="35%" stop-color="white"/>
      <stop offset="80%" stop-color="black"/>
    </radialGradient>

    <filter id="customPointLight">
      <feSpecularLighting result="lightBuffer" specularConstant="1.5"
          specularExponent="80" lighting-color="#fff">
        <fePointLight x="100" y="100" z="80"/>
      </feSpecularLighting>
      <feComposite in="SourceGraphic" in2="lightBuffer" operator="out"
          k1="0" k2="1" k3="1" k4="0"/>
    </filter>

    <filter id="pointLightHack" x="0%" y="0%" width="100%" height="100%">
       <feImage width="100" height="100" xlink:href="data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KDQogIDxkZWZzPg0KICAgIDxyYWRpYWxHcmFkaWVudCBpZD0iZXhhbXBsZUdyYWRpZW50Ij4NCiAgICAgIDxzdG9wIG9mZnNldD0iNDAlIiBzdG9wLWNvbG9yPSJ3aGl0ZSIvPg0KICAgICAgPHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9ImJsYWNrIi8+DQogICAgPC9yYWRpYWxHcmFkaWVudD4NCiAgPC9kZWZzPg0KICA8Y2lyY2xlIGZpbGw9InVybCgjZXhhbXBsZUdyYWRpZW50KSIgY3g9IjUwIiBjeT0iNTAiIHI9IjUwIi8+DQo8L3N2Zz4="/>
      <feBlend mode="screen" in="SourceGraphic"/>
    </filter>
  </defs>

  <rect x="50" y="50" width="100" height="100" fill="blue" filter="url(#customPointLight)"/>
  <rect x="250" y="50" height="100" width="100" fill="blue" filter="url(#pointLightHack)"/>
</svg>

  <!-- SVG source of the base64 encoded feImage -->

  <svg width="100" height="100" viewBox="0 0 100 100"
   xmlns="http://www.w3.org/2000/svg">

  <defs>
    <radialGradient id="exampleGradient">
      <stop offset="40%" stop-color="white"/>
      <stop offset="75%" stop-color="black"/>
    </radialGradient>
  </defs>
  <circle fill="url(#exampleGradient)" cx="50" cy="50" r="50"/>
</svg>

Par ailleurs, vous n'utilisez pas l'effet d'éclairage correctement, l'éclairage spéculaire est censé ajouter des reflets "brillants", donc l'utilisation correcte est de composer le résultat au-dessus de la source. L'éclairage diffus est censé ajouter une lumière "normale" et doit être multiplié par le graphique d'origine. Dans les deux cas, vous ne devez pas utiliser une opération composite "out", qui consiste à percer un trou transparent dans votre rectangle, comme vous pouvez le voir lorsque vous ajoutez le fond rouge ci-dessus.

1voto

ccprog Points 10020

Pour tous les filtres qui utilisent les pixels voisins dans leur calcul, comme par exemple feSpecularLighting , feGaussianBlur o feConvolveMatrix le résultat est influencé par l'attribut filterRes qui définit la résolution pour le calcul de l'effet de filtre. Contrairement aux autres attributs, l'attribut spécification ne définit aucun défaut :

S'il n'est pas fourni, l'agent utilisateur utilisera des valeurs raisonnables pour produire un résultat de haute qualité sur le périphérique de sortie.

Cela laisse de la place pour de nombreuses différences entre les UA.

feSpecularLighting a lui-même un attribut kernelUnitLength qui fait explicitement référence à la résolution du filtre :

Pour un certain niveau de cohérence (sic !) pour tous les supports d'affichage et agents utilisateurs, il est nécessaire qu'une valeur soit fournie pour au moins l'un des éléments suivants filtreRes y kernelUnitLength .

0voto

revy Points 534

Résolu pour l'instant en ajoutant un cercle avec une primitive de flou qui donne un effet similaire et semble être rendu correctement à travers les navigateurs.

*, *:before, *:after {
  box-sizing: border-box;
}

<link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" rel="stylesheet"/>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <filter id="blur">
      <feGaussianBlur in="SourceGraphic" stdDeviation="4"></feGaussianBlur>
    </filter>
  </defs>

  <rect x="50" y="50" width="100" height="100" fill="blue""></rect>
  <circle cx="100" cy="100" r="20" fill="#fff" filter="url(#blur)"></circle>    

</svg>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X