| 123456789101112131415161718192021222324 |
- // Bounded image processing; never adds pixels beyond source-derived sampling density.
- import assert from 'node:assert/strict'
- export function roofRasterSize(span, {maxDimension=256, metresPerPixel=null}={}) {
- assert.ok(span.length===2&&span.every(x=>Number.isFinite(x)&&x>0))
- assert.ok(Number.isInteger(maxDimension)&&maxDimension>=16&&maxDimension<=512)
- assert.ok(metresPerPixel===null||(Number.isFinite(metresPerPixel)&&metresPerPixel>0))
- const longest=Math.max(...span)
- const dimension=metresPerPixel===null?maxDimension:Math.max(16,Math.min(maxDimension,Math.ceil(longest/metresPerPixel)))
- return span.map(x=>Math.max(16,Math.min(dimension,Math.ceil(x/longest*dimension))))
- }
- export function sharpenRoofRgba(input,width,height,amount=0.25) {
- assert.equal(input.length,width*height*4)
- assert.ok(Number.isFinite(amount)&&amount>=0&&amount<=0.5)
- const result=Buffer.from(input)
- if(amount===0)return result
- // Restrained cross-kernel unsharp mask, per-channel delta bounded to avoid bright halos.
- for(let y=1;y<height-1;y++)for(let x=1;x<width-1;x++)for(let c=0;c<3;c++){
- const i=(y*width+x)*4+c
- const mean=(input[i-4]+input[i+4]+input[i-width*4]+input[i+width*4])/4
- const delta=Math.max(-8,Math.min(8,(input[i]-mean)*amount))
- result[i]=Math.max(0,Math.min(255,Math.round(input[i]+delta)))
- }
- return result
- }
|