UNPKG

imagescript

Version:

zero-dependency javascript image manipulation

303 lines (253 loc) 8.63 kB
export function cubic(framebuffer) { const width = framebuffer.width; const height = framebuffer.height; framebuffer.resize('cubic', Math.max(1, .008 * width), Math.max(1, .008 * height)); framebuffer.resize('cubic', width, height); } export function box(radius, framebuffer) { if (!radius) return; const u8 = framebuffer.u8; const width = framebuffer.width; const height = framebuffer.height; const old = framebuffer.u8.slice(); bb(u8, old, width, height, radius); } export function gaussian(radius, framebuffer) { if (0 >= radius) return; const a = Math.exp(.726 ** 2) / radius; const g1 = Math.exp(-a); const g2 = Math.exp(a * -2); const old = framebuffer.u8.slice(); const k = ((1 - g1) ** 2) / (1 - g2 + 2 * a * g1); const b2 = -g2; const b1 = 2 * g1; const a3 = -k * g2; const a1 = k * g1 * (a - 1); const a2 = k * g1 * (a + 1); const lc = (k + a1) / (1 - b1 - b2); const width = framebuffer.width | 0; const rc = (a2 + a3) / (1 - b1 - b2); const height = framebuffer.height | 0; const tmp = new Float32Array(4 * Math.max(width, height)); gc(old, framebuffer.u8, tmp, width, height, k, a1, a2, a3, b1, b2, lc, rc); gc(framebuffer.u8, old, tmp, height, width, k, a1, a2, a3, b1, b2, lc, rc); } function bb(u8, old, width, height, radius) { const divisor = 1 / (1 + radius + radius); bbt(u8, old, width, height, radius, divisor); bbh(u8, old, width, height, radius, divisor); } function bbh(u8, old, width, height, radius, divisor) { for (var y = 0; y < height; y++) { let y_offset = y * width; let li = y_offset; let ri = radius + y_offset; const fv_offset = 4 * y_offset; const lv_offset = 4 * (width - 1 + y_offset); const rfv = old[fv_offset]; const gfv = old[1 + fv_offset]; const bfv = old[2 + fv_offset]; const afv = old[3 + fv_offset]; const rlv = old[lv_offset]; const glv = old[1 + lv_offset]; const blv = old[2 + lv_offset]; const alv = old[3 + lv_offset]; let r = rfv * (1 + radius); let g = gfv * (1 + radius); let b = bfv * (1 + radius); let a = afv * (1 + radius); for (let x = 0; x < radius; x++) { const offset = 4 * (x + y_offset); r += old[offset]; g += old[1 + offset]; b += old[2 + offset]; a += old[3 + offset]; } for (let x = 0; x <= radius; x++) { let offset = 4 * ri++; r += old[offset] - rfv; g += old[1 + offset] - gfv; b += old[2 + offset] - bfv; a += old[3 + offset] - afv; offset = 4 * y_offset++; u8[offset] = Math.round(r * divisor); u8[1 + offset] = Math.round(g * divisor); u8[2 + offset] = Math.round(b * divisor); u8[3 + offset] = Math.round(a * divisor); } for (let x = 1 + radius; x < (width - radius); x++) { let offset = 4 * ri++; const roffset = 4 * li++; r += old[offset] - old[roffset]; g += old[1 + offset] - old[1 + roffset]; b += old[2 + offset] - old[2 + roffset]; a += old[3 + offset] - old[3 + roffset]; // todo: how far is roffset offset = 4 * y_offset++; u8[offset] = Math.round(r * divisor); u8[1 + offset] = Math.round(g * divisor); u8[2 + offset] = Math.round(b * divisor); u8[3 + offset] = Math.round(a * divisor); } for (let x = width - radius; x < width; x++) { let offset = 4 * li++; r += rlv - old[offset]; g += glv - old[1 + offset]; b += blv - old[2 + offset]; a += alv - old[3 + offset]; offset = 4 * y_offset++; u8[offset] = Math.round(r * divisor); u8[1 + offset] = Math.round(g * divisor); u8[2 + offset] = Math.round(b * divisor); u8[3 + offset] = Math.round(a * divisor); } } } function bbt(u8, old, width, height, radius, divisor) { for (var x = 0; x < width; x++) { let ti = x; let li = ti; const fv_offset = 4 * ti; let ri = ti + width * radius; const lv_offset = 4 * (ti + width * (height - 1)); const rfv = old[fv_offset]; const gfv = old[1 + fv_offset]; const bfv = old[2 + fv_offset]; const afv = old[3 + fv_offset]; const rlv = old[lv_offset]; const glv = old[1 + lv_offset]; const blv = old[2 + lv_offset]; const alv = old[3 + lv_offset]; let r = rfv * (1 + radius); let g = gfv * (1 + radius); let b = bfv * (1 + radius); let a = afv * (1 + radius); for (let y = 0; y < radius; y++) { const offset = 4 * (ti + y * width); r += old[offset]; g += old[1 + offset]; b += old[2 + offset]; a += old[3 + offset]; } for (let y = 0; y <= radius; y++) { let offset = 4 * ri; r += old[offset] - rfv; g += old[1 + offset] - gfv; b += old[2 + offset] - bfv; a += old[3 + offset] - afv; offset = 4 * ti; u8[offset] = Math.round(r * divisor); u8[1 + offset] = Math.round(g * divisor); u8[2 + offset] = Math.round(b * divisor); u8[3 + offset] = Math.round(a * divisor); ri += width; ti += width; } for (let y = 1 + radius; y < (height - radius); y++) { let offset = 4 * ri; const xoffset = 4 * li; r += old[offset] - old[xoffset]; g += old[1 + offset] - old[1 + xoffset]; b += old[2 + offset] - old[2 + xoffset]; a += old[3 + offset] - old[3 + xoffset]; // todo: how far is xoffset offset = 4 * ti; u8[offset] = Math.round(r * divisor); u8[1 + offset] = Math.round(g * divisor); u8[2 + offset] = Math.round(b * divisor); u8[3 + offset] = Math.round(a * divisor); li += width; ri += width; ti += width; } for (let y = height - radius; y < height; y++) { let offset = 4 * li; r += rlv - old[offset]; g += glv - old[1 + offset]; b += blv - old[2 + offset]; a += alv - old[3 + offset]; offset = 4 * ti; u8[offset] = Math.round(r * divisor); u8[1 + offset] = Math.round(g * divisor); u8[2 + offset] = Math.round(b * divisor); u8[3 + offset] = Math.round(a * divisor); li += width; ti += width; } } } function gc(u8, old, tmp, width, height, k, a1, a2, a3, b1, b2, lc, rc) { const width4 = width * 4; const height4 = height * 4; const hw1 = height * (width - 1); for (let y = 0; y < height; y++) { let toffset = 0 | 0; let ooffset = (y * width4) | 0; let offset = (4 * (y + hw1)) | 0; let por = old[ooffset]; let pog = old[1 + ooffset]; let pob = old[2 + ooffset]; let poa = old[3 + ooffset]; let pur = lc * por; let pug = lc * pog; let pub = lc * pob; let pua = lc * poa; let ppur = pur; let ppug = pug; let ppub = pub; let ppua = pua; for (let x = 0; x < width; x++) { const cor = old[ooffset++]; const cog = old[ooffset++]; const cob = old[ooffset++]; const coa = old[ooffset++]; const cur = k * cor + a1 * por + b1 * pur + b2 * ppur; const cug = k * cog + a1 * pog + b1 * pug + b2 * ppug; const cub = k * cob + a1 * pob + b1 * pub + b2 * ppub; const cua = k * coa + a1 * poa + b1 * pua + b2 * ppua; ppur = pur; pur = cur; por = cor; ppug = pug; pug = cug; pog = cog; ppub = pub; pub = cub; pob = cob; ppua = pua; pua = cua; poa = coa; tmp[toffset++] = pur; tmp[toffset++] = pug; tmp[toffset++] = pub; tmp[toffset++] = pua; } ooffset -= 4; toffset -= 4; ppur = rc * (por = old[ooffset]); ppug = rc * (pog = old[1 + ooffset]); ppub = rc * (pob = old[2 + ooffset]); ppua = rc * (poa = old[3 + ooffset]); pur = ppur; pug = ppug; pub = ppub; pua = ppua; let cor = por; let cog = pog; let cob = pob; let coa = poa; for (let x = width - 1; 0 <= x; x--) { const cur = a2 * cor + a3 * por + b1 * pur + b2 * ppur; const cug = a2 * cog + a3 * pog + b1 * pug + b2 * ppug; const cub = a2 * cob + a3 * pob + b1 * pub + b2 * ppub; const cua = a2 * coa + a3 * poa + b1 * pua + b2 * ppua; ppur = pur; pur = cur; por = cor; ppug = pug; pug = cug; pog = cog; ppub = pub; pub = cub; pob = cob; ppua = pua; pua = cua; poa = coa; cor = old[ooffset]; cog = old[1 + ooffset]; cob = old[2 + ooffset]; coa = old[3 + ooffset]; u8[offset] = pur + tmp[toffset]; u8[1 + offset] = pug + tmp[1 + toffset]; u8[2 + offset] = pub + tmp[2 + toffset]; u8[3 + offset] = pua + tmp[3 + toffset]; ooffset -= 4; toffset -= 4; offset -= height4; } } }