1

This is from a simplified testing scope. I have some WP site with Foogallery Pro being used on it. The client added a plethora of huge jpegs for a full screen presentation. Like 900 images, net worth 1 GiB of network load for a single page. Can't be talked out of it either.

For modern Browsers I figured I'd experiment with trying to fool the thing into using AVIF (88 MiB total rather than 1GiB) images I generated for the test. Only computed some 24 hours on a 16 core Xeon WS but alas.

Now for my test I siply figure I'd trigger the replacement by presence of a CSS class .useAVIF on the sub page I'm testing this on.

I then want to know if the browser can display AVIF images in the first place and find out by JS:

var canUseAVIF=false;
var avif = new Image();
avif.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
avif.onload = function () {canUseAVIF=true;};

So far so good, later on when we have a DOM, I figured I'd just replace all the DOM elements that Foogallery uses with the AVIFs rather than the JPEGs. They simply all reside in the same folder, they all exist, too.

jQuery(document).ready(function( $ ){
    canUseAVIF=($(".useAVIF").size()>0)&&canUseAVIF;
    if (canUseAVIF)
    {
      $(".foogallery-container .fg-item-inner img").each(function(){
        var avif=$(this).attr('data-src-fg');
        avif=avif.replace(".jpg", ".avif");
        $(this).attr('data-src-fg',avif);
        avif=$(this).attr('src');
        avif=avif.replace(".jpg", ".avif");
        $(this).attr('src',avif);
      });
      $(".foogallery-container .fg-item-inner a").each(function(){
        var avif=$(this).attr('href');
        avif=avif.replace(".jpg", ".avif");
        $(this).attr('href',avif);
      });
    }
...

Could be more elegant but it is a quick test, rember.

Now that does tweak the DOM like I thought but it does not work. Because the Foogalery specific scripts must have already parsed the content or there must be some other mechanism at play. When the images get loaded the src becomes JPEG again.

Does anyone have insight or inspiration where those JPEG references may live in the JS datastructures, so that I could loop over them and replace them?

C.O.
  • 2,281
  • 6
  • 28
  • 51

1 Answers1

2

** See edit for alternate code snippet **

The following should get you headed in the right direction. The approach I took was to rather hook into FooGallery's item create and parse methods and alter the URL's as needed. I've commented the script but if you have any questions let me know:

new Promise( ( resolve, reject ) => {
    const img = new Image();
    img.onload = function() { resolve(); };
    img.onerror = function() { reject(); };
    img.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
} ).then( () => {
    document.addEventListener( 'foogallery-ready', ( event ) => {
        const jpg2avif = (url) => url.replace(".jpg", ".avif");
        const FG = event.detail;

        // handle items being supplied via HTML by overriding the item parser method
        FG.Item.override( 'doParseItem', function( $elem ) {
            // first call the original method to parse the supplied $elem
            if ( this._super( $elem ) ) {
                // and if successful update the parsed properties
                this.href = jpg2avif( this.href );
                this.src = jpg2avif( this.src );
                this.srcset = jpg2avif( this.srcset );

                // and then update the actual DOM elements
                this.$anchor.attr('href', this.href);
                this.$image.attr({
                    'data-src-fg': this.src,
                    'data-srcset-fg': this.srcset
                });
                // return true as parsing is complete
                return true;
            }
            // something failed in the original parse so return false
            return false;
        } );

        // handle items being supplied via JSON by overriding the item create method
        FG.Item.override( 'doCreateItem', function() {
            // first update the required values
            this.href = jpg2avif( this.href );
            this.src = jpg2avif( this.src );
            this.srcset = jpg2avif( this.srcset );
            // then call the original method to create the DOM elements
            return this._super();
        } );
    });
} );

For future reference with a FooGallery Pro subscription you can get direct support from the authors via their website, which should be quicker than asking here.

Thanks

EDIT: The following snippet will produce the same results without relying on the promise or the window events. This could be inserted directly within the FooGallery > Settings > Custom JS & CSS > Custom Javascript option.

(function(_){

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

    const jpg2avif = (url) => url.replace(".jpg", ".avif");

    // handle items being supplied via HTML by overriding the item parser method
    _.Item.override( 'doParseItem', function( $elem ) {
        // first call the original method to parse the supplied $elem
        if ( this._super( $elem ) ) {
            if ( avifSupported ) {
                // and if successful update the parsed properties
                this.href = jpg2avif( this.href );
                this.src = jpg2avif( this.src );
                this.srcset = jpg2avif( this.srcset );

                // and then update the actual DOM elements
                this.$anchor.attr('href', this.href);
                this.$image.attr({
                    'data-src-fg': this.src,
                    'data-srcset-fg': this.srcset
                });
            }
            // return true as parsing is complete
            return true;
        }
        // something failed in the original parse so return false
        return false;
    } );

    // handle items being supplied via JSON by overriding the item create method
    _.Item.override( 'doCreateItem', function() {
        if ( avifSupported ) {
            // first update the required values
            this.href = jpg2avif( this.href );
            this.src = jpg2avif( this.src );
            this.srcset = jpg2avif( this.srcset );
        }
        // then call the original method to create the DOM elements
        return this._super();
    } );

})(FooGallery);
  • I must be doing something stupid, all listeners added to document for either foogallery-ready or foogallery-loaded do not ever fire, I find no reference to the events being dispatched, where does that happen? – C.O. Dec 16 '22 at 02:06
  • Hi @C.O., I just saw this notification now. The global window events were only added into FooGallery JS in Oct 2022. I'll supply another answer applying the same logic but without the need for the global events or waiting on the result of the promise. – Steve Usher Jan 16 '23 at 08:27
  • Thank you so much. I have yet to try it but I shall do so soon; until proven otherwise answer is accepted again :-) – C.O. Jan 23 '23 at 20:57