0

I am trying to optimize the image by formatting that to avif. But some of the browser's are not supporting avif.

So I created a utility function like this

  function isAvifSupported() {
    let returnValue;
    const avif = new Image();
    avif.src =
      "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
    avif.onload = function () {
        returnValue = true
    };
    return returnValue;
  }

but when I try to call this function it always returns undefined. But when I use the function that has been provided in avif site. it works fine. Below is the code for it

function AddClass(class) { document.documentElement.classList.add(class) };
var avif = new Image();
avif.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
avif.onload = function () { AddClass("avif") };
avif.onerror = function () {
  var webp = new Image();
  webp.src = "data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
  webp.onload = function () { AddClass("webp") }
}

But the above-defined function adds the css at the top level of dom. Instead of adding the class, It has to return true or false. So that i am able to handle that easily like this.


let updatedImageUrl = isAvifSupported() ? `${imageUrl}?fm=avif` ? imageUrl

But I don't know, how to fix this. Please recommend a solution.

SDK
  • 1,356
  • 3
  • 19
  • 44

2 Answers2

0

The main problem with your snippet is that you're not taking the asynchronous call into consideration.

onload will be called after the function returns. To work around this, you have to either provide a callback and implement promises as the example below shows.

function isAvifSupported() {
  return new Promise(resolve => {
      var image = new Image();
  
      image.onload = image.onerror = function() {
        resolve(image.width === 2);
      };
  
      image.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
    });
}

isAvifSupported().then(console.log);

As inspiration, I adjusted the standard modernizr snippet to fit your use case and used your dummy image.

Keep in mind that because you have to use an async call the feature detect has to be async, too.

isAvifSupported().then(
  isSupported => {
    const updatedImageUrl = isSupported ?
      `${imageUrl}?fm=avif` :
      imageUrl;
  }
);

Depending on your project you might need to refactor some things to implement the promise (or callback) solution, but unfortunately, there's no way to check avif support synchronously.

stefan judis
  • 3,416
  • 14
  • 22
0

The below functionality will work fine. It is an extended answer version of @Stefan Judis. I modified this depending upon my project

import React, { useEffect, useState } from "react";
import "./styles.css";

const url =
  "https://images.ctfassets.net/{space_id}/1WJFyl9C8q18KI6OQG7mPu/{unique_name}/name.jpg";

const ImageFormat = () => {
  const [imageFormat, setImageFormat] = useState("");

  function addImageProcess(src) {
    return new Promise((resolve, reject) => {
      let img = new Image();
      img.onload = () => resolve("avif");
      img.onerror = () => {
        const webp = new Image();
        webp.src =
          "data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
        webp.onload = async () => {
          resolve("webp");
        };

        webp.onerror = () => {
          reject("");
        };
      };
      img.src = src;
    });
  }

  useEffect(() => {
    async function logImageFormat(imageUrl) {
      let imageFormatValue = await addImageProcess(imageUrl);
      setImageFormat(`${url}?fm=${imageFormatValue}&w=3500`);
    }

    logImageFormat(
      "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A="
    );
  }, []);

  return (
    <>
      <div className="App">{imageFormat}</div>
    </>
  );
};

export default ImageFormat;

SDK
  • 1,356
  • 3
  • 19
  • 44