typescriptsupabasedeno

How to get width / height of a base64 image in deno?


This is a repeat of this question: Get image width and height from the Base64 code in JavaScript but I am asking with regards to deno. Deno does not have the new Image() that is used in all the solutions I have read. I intend on doing this in an edge function so reduced dependencies is important. A few things I have considered:

Is there a way to do this without a package or to do it simply using some built-in package?


Solution

  • In order to get image width & height without external libraries, you need to parse the image header. If you're only dealing with few image type you could easly avoid using third-party libs.

    For example for parsing a png image width & height from a base64 encoded image you could do it like this:

    import { decode } from "https://deno.land/std/encoding/base64.ts"
    
    const pngImageb64 = /* some png image in base64 */
    
    const pngImage = decode(pngImageb64);
    const dataView = new DataView(pngImage.buffer);
    // The width and height are 4-byte integers starting 
    // at byte offset 16 and 20, respectively.
    const width = dataView.getUint32(16);
    const height = dataView.getUint32(20);
    

    Ref: http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html

    Width and height give the image dimensions in pixels. They are 4-byte integers. Zero is an invalid value. The maximum for each is 2^31


    For jpeg it's a bit harder since the dimensions are stored in the Start of Frame (SOF) markers. The following should work for most cases (only tested it in a few jpegs)

    const jpegImageb64 = /* some jpeg image in base64 */
    
    const jpegImage = decode(jpegImageb64);
    const dataView = new DataView(jpegImage.buffer);
    
    let width, height;
    for (let i = 0; i < dataView.byteLength - 9; i++) {  // - 9 prevent out-of-bounds access
        if (dataView.getUint16(i) === 0xFFC0 || dataView.getUint16(i) === 0xFFC2) {
          height = dataView.getUint16(i + 5);
          width = dataView.getUint16(i + 7);
          break;
      }
    }
    

    Other possible solutions:


    To detect the image type so you know which parser to use, you have to read the first bytes of the image, you could use file-type lib for it (after decoding base64)

    See https://github.com/sindresorhus/file-type/blob/5c42f8057f056fe41cbe4bffb53f56987d02e909/core.js#L238-L249 for detecting jpeg yourself.


    Depending on the image type you're dealing with, it could be more complicated, if you support a wide variety of image formats I would recommend using a library such as sharp for parsing that data.