Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nodejs implementation #43

Closed
fvisticot opened this issue Feb 24, 2020 · 9 comments
Closed

nodejs implementation #43

fvisticot opened this issue Feb 24, 2020 · 9 comments
Labels
documentation Improvements or additions to documentation question Further information is requested

Comments

@fvisticot
Copy link

I would try this algorithm but how to convert/use Uint8ClampedArray type in nodejs service.
Is it possible to have a more generic algorithm using only "basic" types ?

It seems that Uint8ClampedArray is an array of 8-bit unsigned integers clamped to 0-255

@rbozan
Copy link

rbozan commented Feb 28, 2020

I just used this library, I am not sure what I am doing is correct, but this seems to work:

import * as blurhash from 'blurhash'
import { createCanvas, loadImage, Image } from 'canvas'

const getImageData = (image: Image) => {
  const canvas = createCanvas(image.width, image.height)
  const context = canvas.getContext('2d')
  context.drawImage(image, 0, 0)
  return context.getImageData(0, 0, image.width, image.height)
}

const image = await loadImage('https://fakeimg.pl/300/')
console.log(' image = ', image.width, image.height)
const imageData = getImageData(image)
return blurhash.encode(
  imageData.data,
  imageData.width,
  imageData.height,
  4,
  4
)

@fvisticot
Copy link
Author

Tx for your help.
I agree that it could work but we need to add another dependency to the node server side (canvas)
I was hoping that we could use this library without any other external lib.

@rbozan
Copy link

rbozan commented Feb 28, 2020

It would be nice, but for now this seems to work OK.

@rhnorskov
Copy link

rhnorskov commented Mar 11, 2020

An alternative implementation is to use Sharp.
Sharp also allows you to resize the image before hashing, which will greatly reduce processing time, while still giving a nice result.

const sharp = require("sharp");
const { encode } = require("blurhash");

const encodeImageToBlurhash = path =>
  new Promise((resolve, reject) => {
    sharp(path)
      .raw()
      .ensureAlpha()
      .resize(32, 32, { fit: "inside" })
      .toBuffer((err, buffer, { width, height }) => {
        if (err) return reject(err);
        resolve(encode(new Uint8ClampedArray(buffer), width, height, 4, 4));
      });
  });

encodeImageToBlurhash("./img.jpg").then(hash => {
  console.log(hash);
});

@jinxmcg
Copy link

jinxmcg commented Jun 13, 2020

If you only work with png files use upng-js for other formats there are similar libraries with no extra processing libraries.

Both of the previous techniques require a some heavy libraries Sharp uses 'libvips' and 'canvas' uses cairo OpenGL and it's overkill

The lightest solution I found which only relies on javascript and works oob in nodejs/browsers:
upng-js plain javascript library (png only)

for example I needed to SSR so I can add the src to the image directly.

    import decode as decodeBlurhash from 'blurhash';
    import UPNG from 'upng-js';
    import encode as encode64 from 'base64-arraybuffer';

    let width = 512;
    let height = 512;
    let colorsNumber = 256; //0 should use all colors but it does not work

    let blurHashString='here is your blurhash string';
    let pixels = decodeBlurhash(blurHashString, width, height);
    let png = UPNG.encode([pixels], width, height, colorsNumber) ;
    
    //I needed it as bas64string png you can just do something else with png data
    imageSrc = 'data:image/png;base64,' + encode64(png); 

   // and so on....

for making the blurhash string directly from png files in pure javascript (i have not tested the 2nd code) but should work. Use it as guideline please.

    import * as fs from 'fs'
    import encode as encodeBlurhash from 'blurhash';
    import UPNG from 'upng-js';

    fs.readFile(`demopic.png`, (err, data)=>{
        var img  = UPNG.decode(data);
        let blurHashString = encodeBlurhash(img.data,img.width,img.height,4,4);   
    })

@ItsWendell
Copy link

For people looking for node js implementation to create an image from your blurhash, here's a solution using Sharp.

import { decode } from "blurhash";
import sharp from "sharp";

export const generateBlurhashURI = async (
  hash: string,
  width: number,
  height: number,
  options = {
    size: 16,
    quality: 40,
  }
) => {
  const hashWidth = options?.size;
  const hashHeight = Math.round(hashWidth * (height / width));

  const pixels = decode(hash, hashWidth, hashHeight);

  const resizedImageBuf = await sharp(Buffer.from(pixels), {
    raw: {
      channels: 4,
      width: hashWidth,
      height: hashHeight,
    },
  })
    .jpeg({
      overshootDeringing: true,
      quality: 40,
    })
    .toBuffer(); // Here also possible to do whatever with your image, e.g. save it or something else.

  return `data:image/jpeg;base64,${resizedImageBuf.toString("base64")}`;
};

@tewnut
Copy link

tewnut commented Sep 3, 2021

If you only work with png files use upng-js for other formats there are similar libraries with no extra processing libraries.

Both of the previous techniques require a some heavy libraries Sharp uses 'libvips' and 'canvas' uses cairo OpenGL and it's overkill

The lightest solution I found which only relies on javascript and works oob in nodejs/browsers:
upng-js plain javascript library (png only)

for example I needed to SSR so I can add the src to the image directly.

    import decode as decodeBlurhash from 'blurhash';
    import UPNG from 'upng-js';
    import encode as encode64 from 'base64-arraybuffer';

    let width = 512;
    let height = 512;
    let colorsNumber = 256; //0 should use all colors but it does not work

    let blurHashString='here is your blurhash string';
    let pixels = decodeBlurhash(blurHashString, width, height);
    let png = UPNG.encode([pixels], width, height, colorsNumber) ;
    
    //I needed it as bas64string png you can just do something else with png data
    imageSrc = 'data:image/png;base64,' + encode64(png); 

   // and so on....

for making the blurhash string directly from png files in pure javascript (i have not tested the 2nd code) but should work. Use it as guideline please.

    import * as fs from 'fs'
    import encode as encodeBlurhash from 'blurhash';
    import UPNG from 'upng-js';

    fs.readFile(`demopic.png`, (err, data)=>{
        var img  = UPNG.decode(data);
        let blurHashString = encodeBlurhash(img.data,img.width,img.height,4,4);   
    })

I like this approach, but found error:

Error [ValidationError]: Width and height must match the pixels array
at new ValidationError (C:\Code\backend\file-management\node_modules\blurhash\dist\error.js:19:28)
at Object.encode (C:\Code\backend\file-management\node_modules\blurhash\dist\encode.js:43:15)

@jerry-git jerry-git added question Further information is requested documentation Improvements or additions to documentation labels Jun 10, 2022
@fvisticot
Copy link
Author

I just used this library, I am not sure what I am doing is correct, but this seems to work:

import * as blurhash from 'blurhash'
import { createCanvas, loadImage, Image } from 'canvas'

const getImageData = (image: Image) => {
  const canvas = createCanvas(image.width, image.height)
  const context = canvas.getContext('2d')
  context.drawImage(image, 0, 0)
  return context.getImageData(0, 0, image.width, image.height)
}

const image = await loadImage('https://fakeimg.pl/300/')
console.log(' image = ', image.width, image.height)
const imageData = getImageData(image)
return blurhash.encode(
  imageData.data,
  imageData.width,
  imageData.height,
  4,
  4
)

canvas does not work for me with my new Mac M1 :( any workaround for M1 ?

@Thisen
Copy link
Collaborator

Thisen commented Jul 14, 2022

Thanks to everyone coming with great solutions!

I believe both canvas and sharp are great options.

Anyone, feel free to create a package and open a PR here with a link 🙏🏼

However, I think this goes beyond the scope of this repo, so closing this.

@Thisen Thisen closed this as completed Jul 14, 2022
This was referenced Jul 14, 2022
@woltapp woltapp locked and limited conversation to collaborators Jul 15, 2022
@Thisen Thisen converted this issue into discussion #189 Jul 15, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
documentation Improvements or additions to documentation question Further information is requested
Projects
None yet
Development

No branches or pull requests

8 participants