From d52d77cf11860103dc0a098000cb1ff899df26fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20L=C3=B6vqvist?= Date: Mon, 21 Jul 2025 22:51:03 +0200 Subject: [PATCH] Worked on image functions --- canvas/image-loading.js | 38 +++++++++++++ image/test1.html | 5 +- lib/image-functions.js | 115 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 canvas/image-loading.js create mode 100644 lib/image-functions.js diff --git a/canvas/image-loading.js b/canvas/image-loading.js new file mode 100644 index 0000000..11def24 --- /dev/null +++ b/canvas/image-loading.js @@ -0,0 +1,38 @@ +//Create useful variables +const aspect = W / H; +const scale = aspect >= 1 ? H / 2 : W / 2; + +function setup() { + // Reset transform + C.setTransform(1, 0, 0, 1, 0, 0); + + // Clear canvas + C.clearRect(0, 0, W, H); + + // Reset common properties + C.globalCompositeOperation = 'source-over'; + C.fillStyle = 'rgba(255,200,100,1)'; + C.strokeStyle = 'rgba(0,0,0,1)'; + + + // Set up transform to map -1,-1..1,1 to canvas with aspect fit + const offsetX = W / 2; + const offsetY = H / 2; + + //Apply transform + C.translate(offsetX, offsetY); + C.scale(scale, -scale); + + // Set 1 pixel wide lines + C.lineWidth = 1 / scale; +} + + +setup(); + + + +const { load_image_from_src, Image_Data_Sampler } = await import('../lib/image-functions.js'); +const sampler = new Image_Data_Sampler(await load_image_from_src("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAFVJREFUOE9jZGBg+A/EZAMmsnVCNQ4DA1hAXvn/HxGOjIyMJAULC0gzsiZ0PiHTwC5AB8guQpdD52M1gJA3YK4E0SwgxZSEASjERlMieryQyKc4MwEA45UXJyonWOMAAAAASUVORK5CYII=")); + +console.log(sampler.encode_as_bitfield()); diff --git a/image/test1.html b/image/test1.html index 6587f9b..d33d5af 100644 --- a/image/test1.html +++ b/image/test1.html @@ -141,7 +141,8 @@ padding: '0.5em 1em', borderRadius: '5px', opacity: '0.9', - zIndex: 1000 + zIndex: 1000, + pointerEvents: 'none', }); document.body.appendChild(toast); setTimeout(() => toast.remove(), 1500); @@ -155,7 +156,7 @@ (AltD) (AltS) -
Paste an image here (Ctrl+V)
+
Paste an image here (CtrlV)

Data URL

EcmaScript

diff --git a/lib/image-functions.js b/lib/image-functions.js new file mode 100644 index 0000000..b19e1ec --- /dev/null +++ b/lib/image-functions.js @@ -0,0 +1,115 @@ +export function load_image_from_src(src) { + return new Promise((resolve, reject) => { + const image = new Image(); + image.src = src; + + image.addEventListener('load', ({ target }) => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + canvas.width = target.width; + canvas.height = target.height; + + ctx.drawImage(target, 0, 0); + + resolve(ctx.getImageData(0, 0, target.width, target.height)); + }); + }); +} + +export class Image_Row_Reference { + constructor(sampler, row) { + Object.assign(this, { sampler, row }); + } + + *[Symbol.iterator]() { + yield* this.sampler.iter_row(this.row); + } +} + +export class RGBA_unorm8 { + constructor(R=0, G=0, B=0, A=255) { + Object.assign(this, { R, G, B, A }); + } + + *[Symbol.iterator]() { + const {R, G, B, A} = this; + yield* [R, G, B, A]; + } + + get non_zero() { + const {R, G, B, A} = this; + return (A > 0) && ((R > 0) || (G > 0) || (B > 0)); + } + +} + +export class Image_Data_Sampler { + constructor(image_data) { + Object.assign(this, { image_data }); + } + + encode_as_bitfield() { + //TODO - add alignment option + const { width, height } = this.image_data; + let result = ''; + const bytes_per_row = Math.ceil(width / 8); + + for (const row of this) { + let pending_value = 0; + let bit_value = 1; + for (const pixel of row) { + + if (pixel.non_zero) { + pending_value |= bit_value; + } + + bit_value <<= 1; + if (bit_value === 256) { + result += String.fromCharCode(pending_value); + pending_value = 0; + bit_value = 1; + } + } + if (bit_value > 1) { //If we have a tail we flush it here. + result += String.fromCharCode(pending_value); + pending_value = 0; + bit_value = 1; + } + } + return `${width},${height},${btoa(result)}`; + } + + *iter_row(row) { + const { pixelFormat, data, width, height } = this.image_data; + switch(pixelFormat) { + case 'rgba-unorm8': { + const pixel_offset_y = row * width; + for (let x=0; x