Astro Component - Ixmage

Component - Out of this world imaging.
published 2022-02-15

I discovered Astro recently and fell in love with it. Sorry Nuxt.js.

I re-did this marketing website and went away from Nuxt.js, which was giving me SPA behavior and required ”enhancing” it with multiple add-ons to make it behave like a normal website.

Because the site was mainly Vue, and is not very big, it took me like 2 days to convert over to Astro.

Pre-requisites

Usage

Original image

I grabbed this image from unsplash.com homepage, it is 1.5 MB in size, with dimensions of 3000x1685. I have placed it here with a width="300"



Using the original image, and telling the browser to display it at 300px width. This will download the 1.5MB image. The original image is of type image/jpeg.

Optimized Image

Using the same src, but with the Ixmage component



Requesting the same image, but leveraging the ixmage service. Because I am using Microsoft Edge browser, the image came back as image/webp. The image size is 4.6 kB.



Above, explicitly requesting the image to be image/jpg comes back in a size of 9.3 kB.

Ixmage Component

Version 1.0 is done in vue.
It does not require client-side interactivity so no vue javascript is bundled.

The ixmage service brings into play a CDN, and the image optimization processing. Ixmage will also choose to deliver a webp image when the browser hints its capabilities, but this can be overriden by explicitly asking for a format.

<template>
  <img :src="theurl" :width="width" :height="height" :alt="alt" :title="title||alt||''" />
</template>

<script>
export default {
  props: {
    token: { type: String, required: true },
    src: { type: String, required: true },
    alt: { type: String, required: false },
    width: { type: String, required: false },
    height: { type: String, required: false },
    title: { type: String, required: false },
    bgc: { type: String, default: 'transparent' },
    format: { type: String, default: '' },
    flip: { type: Boolean, default: false },
    flop: { type: Boolean, default: false },
    quality: { type: Number, default: 0 },
    behavior: { type: String, default: '' },
    allowenl: { type: Boolean, default: false },
    sharpen: { type: Boolean, default: false },
    dpr: { type: Number, required: false },
    pixelate: { type: Number, default: 0 },
    blur: { type: Number, default: 0 },
    brightness: { type: Number, default: 0 },
    hue: { type: Number, default: 0 },
    saturation: { type: Number, default: 0 },
    sepia: { type: Number, default: 0 },
    grayscale: { type: Boolean, default: false },
  },
  data () {
    return {
      baseUri: 'https://cdn.ixmage.com/v2/'
    };
  },
  computed: {
    theurl () {
      let xfs = '?v=1';
      if (this.width) xfs += `&w=${this.width}`;
      if (this.height) xfs += `&h=${this.height}`;
      if (this.format) xfs += `&f=${this.format}`;
      if (this.format.toLowerCase() === 'jpg') xfs += '&fmt=jpg';
      if (this.format.toLowerCase() === 'png') xfs += '&fmt=png';
      if (this.format.toLowerCase() === 'gif') xfs += '&fmt=gif';
      if (this.format.toLowerCase() === 'webp') xfs += '&fmt=webp';
      if (this.allowenl) xfs += `&allowenl=1`;
      if (this.sharpen) xfs += `&sharp=1`;
      if (this.flip) xfs += `&flip=1`;
      if (this.flop) xfs += `&flop=1`;
      if (this.quality) xfs += `&q=${this.quality}`;
      if (this.behavior.toLowerCase() === 'extend') xfs += `&extend=1`;
      if (this.behavior.toLowerCase() === 'cover') xfs += `&cover=1`;
      if (this.dpr) xfs += `&dpr=${this.dpr}`;
      if (this.pixelate && this.pixelate !== '0') xfs += `&pixelate=${this.pixelate}`;
      if (this.blur && this.blur !== '0') xfs += `&blur=${this.blur}`;
      if (this.brightness) xfs += `&mod=${this.brightness}`;
      if (this.hue) xfs += `&hue=${this.hue}`;
      if (this.saturation) xfs += `&sat=${this.saturation}`;
      if (this.sepia) xfs += `&sepia=${this.sepia}`;
      if (this.grayscale) xfs += `&grey=1`;
      xfs += `&bgc=${this.bgc}`;
      return this.baseUri + this.token + '/' + this.src + xfs;
    }
  }
}
</script>

Template

The template portion is just an img tag and its main attributes.

A later version will make it a bit more complex to allow setting a source set to specify a list of sizes so the browser can pick the best one for the situation.

Script

The script portion defines the exposed properties to work on the image. Then, it has the logic to build the image src url that will be used.

Basic properties

prop info
token required Your ixmage account token.
src required url to your image.
width Image width, for both the image and the browser.
height Image height, for both the image and the browser.
alt Alt Text.

Less important properties

prop info
title Caption for the img tag title; used as alt text when alt text not supplied.
bgc Background color for the image in case padding is needed. Defaults to transparent
format In case you need your image in this format, else the format will be set automatically depending on the requesting browser capabilites.
quality Set the quality percentage for JPG or WEBP.
behavior Allowed values are extend and cover
allowenl Allow the image to grow more than its original size.
dpr

Effect properties

prop info
flip Vertical mirror reflection of the image.
flop Horizontal mirror reflection of the image.
sharpen Sharpen the resulting image; may enhance the image when the resizing is very drastic.
pixelate Pixelation effect
blur Blur effect
brightness Adjust image brightness
hue Adjust image hue
saturation Adjust image saturation
sepia Sepia effect
grayscale Grayscale effect
ok!