ImageSource.js

import { blobToBase64, base64ToDataURL, checkResponse } from './Common.js'

/**
 * ImageSource
 * @classdesc Class to handle loading various image formats
 *
 * @see {@link Probe}
 */
export class ImageSource {
  source
  url
  imageData
  type
  /**
   * Instantiate an ImageSource
   * @constructor
   * @param {string} source - The source of the image data.
   * @param {string} [type] - The type of data in the image source, valid values
   * are 'url', 'base64', and 'dataurl'. If not provided 'base64' is the default.
   *
   * @example
   * const personPhoto = new ImageSource('/person/123.jpg', 'url')
   */
  constructor (source, type = 'base64') {
    // TODO:
    // If the source is typeof object and/or type=object we should do some duck
    // typing and accept any of...
    // - The result of an ICAO check that contains a cropped image
    // - An Image tag (fetch the source)
    // - A Blob
    // - An Array Buffer
    // - An object that has a fullCapture method (call function in .data())
    this.type = type
    switch (this.type) {
      case 'url':
        this.url = source
        break
      case 'base64':
        this.imageData = source
        break
      case 'dataurl':
        this.imageData = source.split(',')[1]
        break
      case undefined:
      case null:
      default:
        throw new Error('Invalid image source type provided')
    }
  }

  /**
   * Fetch the image data and base64 encode it
   * @async
   * @example
   * const personPhoto = new ImageSource("/img/photo.jpg")
   * await personPhoto.data()
   * console.log(personPhoto.imageData)
   */
  async data () {
    if (!this.imageData && this.url) {
      const response = await fetch(this.url)
      await checkResponse(response)
      const blob = await response.blob()
      this.imageData = await blobToBase64(blob)
    }
    return this.imageData
  }

  /**
   * Create an <img> element, wait for it to load and return it
   * @async
   * @example
   * // Load the image and draw it on a Canvas
   * const img = await imgSrc.toImage()
   * const canvas = document.createElement('canvas')
   * const ctx = canvas.getContext('2d')
   * canvas.width = img.width
   * canvas.height = img.height
   * ctx.drawImage(img, canvas.width, canvas.height, img.width, img.height)
   */
  async toImage () {
    const img = new window.Image()
    const promise = new Promise((resolve, reject) => {
      img.onload = (data) => resolve(img)
      img.onerror = (err) => reject(err)
    })
    switch (this.type) {
      case 'url':
        img.src = this.url
        break
      case 'base64':
      case 'dataurl':
        img.src = base64ToDataURL(this.imageData)
        break
      case undefined:
      case null:
      default:
        throw new Error('Invalid image source type provided')
    }
    return promise
  }

  toJSON () {
    return this.imageData
  }
}

export default ImageSource