Last active
August 7, 2023 14:20
-
-
Save schickling/db0aa873565a4132b1b02c6059a79c1f to your computer and use it in GitHub Desktop.
Random Node Effect image utils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
inputs = { | |
nixpkgs.url = "github:NixOS/nixpkgs/master"; | |
flake-utils.url = "github:numtide/flake-utils"; | |
}; | |
outputs = { self, nixpkgs, flake-utils }: | |
flake-utils.lib.eachDefaultSystem (system: | |
let | |
pkgs = nixpkgs.legacyPackages.${system}; | |
in | |
{ | |
devShell = with pkgs; pkgs.mkShell { | |
buildInputs = [ | |
nodejs_20 | |
(yarn.override { nodejs = nodejs_20; }) | |
# needed for `canvas` NPM package | |
pkg-config | |
pixman | |
cairo | |
pango | |
libjpeg | |
] ++ lib.optionals stdenv.isDarwin [ | |
# needed for `canvas` NPM package | |
pkgs.darwin.apple_sdk.frameworks.CoreText | |
]; | |
}; | |
NIX_LDFLAGS = "-F${pkgs.darwin.apple_sdk.frameworks.CoreText}/Library/Frameworks -framework CoreText $NIX_LDFLAGS"; | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as blurhash from 'blurhash' | |
import { Effect, pipe } from '../effect/index.js' | |
import sharp from 'sharp' | |
import * as Canvas from 'canvas' | |
export * as blurhash from 'blurhash' | |
export type ImageDataUrlFromHash = { | |
hash: string | |
width: number | |
height: number | |
options?: { | |
size: number | |
quality: number | |
} | |
} | |
export const imageDataUrlFromHash = ({ | |
hash, | |
width, | |
height, | |
options = { size: 16, quality: 40 }, | |
}: ImageDataUrlFromHash) => | |
Effect.gen(function* ($) { | |
const hashWidth = options?.size | |
const hashHeight = Math.round(hashWidth * (height / width)) | |
const pixels = blurhash.decode(hash, hashWidth, hashHeight) | |
const resizedImageBuf = yield* $( | |
Effect.tryPromiseOrDie( | |
() => | |
sharp(Buffer.from(pixels), { | |
raw: { channels: 4, width: hashWidth, height: hashHeight }, | |
}) | |
.jpeg({ overshootDeringing: true, quality: options.quality }) | |
.toBuffer(), // Here also possible to do whatever with your image, e.g. save it or something else.) | |
), | |
) | |
const b64 = resizedImageBuf.toString('base64') | |
return `data:image/jpeg;base64,${b64}` | |
}) | |
export const decodeAndHashFromImage = (encodedImage: Buffer) => | |
Effect.gen(function* ($) { | |
const { data, height, width } = yield* $(decodeImageViaCanvas(encodedImage)) | |
const hash = blurhash.encode(data, width, height, 4, 4) | |
return { hash, width, height } | |
}) | |
export const blurhashEncode = (imageData: ArrayBuffer, width: number, height: number) => | |
pipe( | |
Effect.try(() => blurhash.encode(new Uint8ClampedArray(imageData), width, height, 4, 4)), | |
Effect.orDie, | |
Effect.withSpan('blurhashEncode', { attributes: { width, height } }), | |
) | |
export const decodeAndImageDataUrlFromImage = (encodedImage: Buffer, options: Omit<ImageDataUrlFromHash, 'hash'>) => | |
pipe( | |
decodeAndHashFromImage(encodedImage), | |
Effect.flatMap(({ hash, height, width }) => | |
Effect.all({ | |
dataUrl: imageDataUrlFromHash({ hash, ...options }), | |
width: Effect.succeed(width), | |
height: Effect.succeed(height), | |
}), | |
), | |
) | |
export const decodeImageViaCanvas = (imageBuffer: Buffer) => | |
Effect.gen(function* ($) { | |
const img = yield* $(Effect.tryPromiseOrDie(() => Canvas.loadImage(imageBuffer))) | |
const canvas = Canvas.createCanvas(img.width, img.height) | |
const ctx = canvas.getContext('2d') | |
ctx.drawImage(img, 0, 0) | |
const imageData = ctx.getImageData(0, 0, img.width, img.height) | |
return { | |
width: img.width, | |
height: img.height, | |
data: imageData.data, | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment