Added image loading routines and a triangular lattice sampler
This commit is contained in:
@@ -31,8 +31,18 @@ function setup() {
|
|||||||
setup();
|
setup();
|
||||||
|
|
||||||
|
|
||||||
|
const { load_image_from_src, Image_Data_Sampler, Bitfield_Image_Sampler } = await import('../lib/image-functions.js');
|
||||||
|
|
||||||
const { load_image_from_src, Image_Data_Sampler } = await import('../lib/image-functions.js');
|
/*
|
||||||
|
//Convert
|
||||||
const sampler = new Image_Data_Sampler(await load_image_from_src("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAFVJREFUOE9jZGBg+A/EZAMmsnVCNQ4DA1hAXvn/HxGOjIyMJAULC0gzsiZ0PiHTwC5AB8guQpdD52M1gJA3YK4E0SwgxZSEASjERlMieryQyKc4MwEA45UXJyonWOMAAAAASUVORK5CYII="));
|
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());
|
console.log(sampler.encode_as_bitfield());
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Load
|
||||||
|
const sampler = Bitfield_Image_Sampler.from_string('16,16,AAAAAAAAAAAAAA4AEQDx/xGgDqAAAAAAAAAAAAAAAAA=');
|
||||||
|
sampler.pixel_map((x, y, value) => {
|
||||||
|
C.beginPath();
|
||||||
|
C.arc(x * 0.1 - sampler.width * .05, sampler.height * .05 - y * 0.1, value ? 0.05 : 0.02, 0, Math.PI * 2);
|
||||||
|
C.fill();
|
||||||
|
});
|
||||||
|
|||||||
90
canvas/triangular-lattice-sampler.js
Normal file
90
canvas/triangular-lattice-sampler.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
//Create useful variables
|
||||||
|
const aspect = W / H;
|
||||||
|
const scale = aspect >= 1 ? H / 2 : W / 2;
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
const [W, H] = [400, 400];
|
||||||
|
canvas.width = W;
|
||||||
|
canvas.height = H;
|
||||||
|
|
||||||
|
// 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 { Bitfield_Image_Sampler } = await import('../lib/image-functions.js');
|
||||||
|
//Load
|
||||||
|
const sampler = Bitfield_Image_Sampler.from_string('16,16,AAAAAAAAAAAAAA4AEQDx/xGgDqAAAAAAAAAAAAAAAAA=');
|
||||||
|
console.log(sampler);
|
||||||
|
|
||||||
|
const s = 0.2;
|
||||||
|
for (let y = -10; y < 10; y++) {
|
||||||
|
const xo = y & 1 ? s * .5 : 0;
|
||||||
|
const sxo = 0;
|
||||||
|
//const sxo = y & 1 ? 1 : 0;
|
||||||
|
for (let x = -10; x < 10; x++) {
|
||||||
|
const p0 = [xo + (x + .5) * s, y * s];
|
||||||
|
const p1 = [xo + (x + 1.5) * s, y * s];
|
||||||
|
const p2 = [xo + (x + 1) * s, (y + 1) * s];
|
||||||
|
const p3 = [xo + (x + 0) * s, (y + 1) * s];
|
||||||
|
|
||||||
|
// Filled parallelogram
|
||||||
|
C.beginPath();
|
||||||
|
C.moveTo(...p0);
|
||||||
|
C.lineTo(...p1);
|
||||||
|
C.lineTo(...p2);
|
||||||
|
C.lineTo(...p3);
|
||||||
|
C.closePath();
|
||||||
|
|
||||||
|
if (sampler.sample(sxo + x + 8, 8 - y)) {
|
||||||
|
C.fillStyle = `#cf8`;
|
||||||
|
} else {
|
||||||
|
C.fillStyle = `#f88`;
|
||||||
|
}
|
||||||
|
|
||||||
|
C.fill();
|
||||||
|
|
||||||
|
// Triangle lines
|
||||||
|
C.strokeStyle = '#000';
|
||||||
|
C.lineWidth = 1 / scale;
|
||||||
|
|
||||||
|
// Outline parallelogram
|
||||||
|
C.beginPath();
|
||||||
|
C.moveTo(...p0);
|
||||||
|
C.lineTo(...p1);
|
||||||
|
C.lineTo(...p2);
|
||||||
|
C.lineTo(...p3);
|
||||||
|
C.closePath();
|
||||||
|
C.stroke();
|
||||||
|
|
||||||
|
// Diagonal from p0 to p2
|
||||||
|
C.beginPath();
|
||||||
|
C.moveTo(...p0);
|
||||||
|
C.lineTo(...p2);
|
||||||
|
C.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
<li><a href="canvas/test1.html">Default configuration</a></li>
|
<li><a href="canvas/test1.html">Default configuration</a></li>
|
||||||
<li><a href="canvas/test1.html?src=triangular-lattice.js">Triangular lattice</a></li>
|
<li><a href="canvas/test1.html?src=triangular-lattice.js">Triangular lattice</a></li>
|
||||||
<li><a href="canvas/test1.html?src=triangular-lattice-offset-corrected.js">Triangular lattice - corrected offset</a></li>
|
<li><a href="canvas/test1.html?src=triangular-lattice-offset-corrected.js">Triangular lattice - corrected offset</a></li>
|
||||||
|
<li><a href="canvas/test1.html?src=triangular-lattice-sampler.js">Triangular lattice - sampling raster</a></li>
|
||||||
|
<li><a href="canvas/test1.html?src=image-loading.js">Image loading</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,77 @@ export function load_image_from_src(src) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Bitfield_Image_Sampler {
|
||||||
|
constructor(width, height, data) {
|
||||||
|
Object.assign(this, { width, height, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
static from_string(encoded) {
|
||||||
|
const [width_str, height_str, b64] = encoded.split(',');
|
||||||
|
const width = parseInt(width_str, 10);
|
||||||
|
const height = parseInt(height_str, 10);
|
||||||
|
const decoded = atob(b64);
|
||||||
|
const data = new Uint8Array(decoded.length);
|
||||||
|
for (let i = 0; i < decoded.length; i++) {
|
||||||
|
data[i] = decoded.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return new this(width, height, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
*iter_row(row) {
|
||||||
|
const { width, data } = this;
|
||||||
|
const row_offset = row * Math.ceil(width / 8);
|
||||||
|
let byte_index = row_offset;
|
||||||
|
let bit_mask = 1;
|
||||||
|
let byte = data[byte_index++] ?? 0;
|
||||||
|
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
yield (byte & bit_mask) !== 0;
|
||||||
|
bit_mask <<= 1;
|
||||||
|
if (bit_mask === 256) {
|
||||||
|
bit_mask = 1;
|
||||||
|
byte = data[byte_index++] ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*[Symbol.iterator]() {
|
||||||
|
for (let y = 0; y < this.height; y++) {
|
||||||
|
yield new Image_Row_Reference(this, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sample(rawx, rawy) {
|
||||||
|
const { width, height, data } = this;
|
||||||
|
|
||||||
|
const x = Math.floor(rawx);
|
||||||
|
const y = Math.floor(rawy);
|
||||||
|
|
||||||
|
if (x < 0 || y < 0 || x >= width || y >= height ) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const row_offset = y * Math.ceil(width / 8);
|
||||||
|
let byte_index = row_offset + Math.floor(x / 8);
|
||||||
|
|
||||||
|
return data[byte_index] & (1 << x % 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pixel_map(cb) {
|
||||||
|
let y = 0;
|
||||||
|
for (const row of this) {
|
||||||
|
let x = 0;
|
||||||
|
for (const pixel of row) {
|
||||||
|
cb(x, y, pixel);
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class Image_Row_Reference {
|
export class Image_Row_Reference {
|
||||||
constructor(sampler, row) {
|
constructor(sampler, row) {
|
||||||
Object.assign(this, { sampler, row });
|
Object.assign(this, { sampler, row });
|
||||||
|
|||||||
Reference in New Issue
Block a user