carved = {
const image = await FileAttachment("The_Scream_by_Edvard_Munch,_1893_-_Nasjonalgalleriet small@1.jpg").image();
const w = Math.min(width, image.naturalWidth);
const h = Math.round(w / image.naturalWidth * image.naturalHeight);
const context = DOM.context2d(w, h, 1);
context.canvas.style = "max-width: 100%;";
context.drawImage(image, 0, 0, w, h);
context.lineCap = "round";
context.lineJoin = "round";
context.lineWidth = 2;
const originalImageData = context.getImageData(0, 0, w, h);
const input = context.getImageData(0, 0, w, h);
const inputData = input.data;
const inputData32 = new Uint32Array(inputData.buffer);
const originalColumns = new Uint16Array(w * h);
const newColumns = new Uint16Array(w * h);
const removedSeamLoc = new Uint16Array(h);
const insertedSeamLoc = new Uint16Array(h);
function initBuffers() {
inputData.set(originalImageData.data);
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
originalColumns[x + y * w] = x;
}
}
newColumns.fill(0);
removedSeamLoc.fill(0);
insertedSeamLoc.fill(0);
}
const { sqrt, min, max, SQRT1_2 } = Math;
const pixelOrder = (function checkEndian() {
const arrayBuffer = new ArrayBuffer(2);
const uint8Array = new Uint8Array(arrayBuffer);
const uint16array = new Uint16Array(arrayBuffer);
uint8Array[0] = 0xAA;
uint8Array[1] = 0xBB;
if (uint16array[0] === 0xBBAA) return "ABGR";
if (uint16array[0] === 0xAABB) return "RGBA";
else throw new Error("Something crazy just happened");
})();
const dPixel =
pixelOrder == "RGBA"
? function dPixel(p0, p1) {
const rgba0 = inputData32[p0];
const rgba1 = inputData32[p1];
const r0 = rgba0 >>> 24;
const g0 = (rgba0 >> 16) & 0xFF;
const b0 = (rgba0 >> 8) & 0xFF;
const r1 = rgba1 >>> 24;
const g1 = (rgba1 >> 16) & 0xFF;
const b1 = (rgba1 >> 8) & 0xFF;
const r = r0 - r1;
const g = g0 - g1;
const b = b0 - b1;
const y =
r * 0.2124681075446384 +
g * 0.4169973963260294 +
b * 0.08137907133969426;
const i =
r * 0.3258860837850668 -
g * 0.14992193838645426 -
b * 0.17596414539861255;
const q =
r * 0.0935501584120867 -
g * 0.23119531908149002 +
b * 0.13764516066940333;
return sqrt(y * y + i * i + q * q);
}
: function dPixel(p0, p1) {
const abgr0 = inputData32[p0];
const abgr1 = inputData32[p1];
const r0 = abgr0 & 0xFF;
const g0 = (abgr0 >> 8) & 0xFF;
const b0 = (abgr0 >> 16) & 0xFF;
const r1 = abgr1 & 0xFF;
const g1 = (abgr1 >> 8) & 0xFF;
const b1 = (abgr1 >> 16) & 0xFF;
const r = r0 - r1;
const g = g0 - g1;
const b = b0 - b1;
const y =
r * 0.2124681075446384 +
g * 0.4169973963260294 +
b * 0.08137907133969426;
const i =
r * 0.3258860837850668 -
g * 0.14992193838645426 -
b * 0.17596414539861255;
const q =
r * 0.0935501584120867 -
g * 0.23119531908149002 +
b * 0.13764516066940333;
return sqrt(y * y + i * i + q * q);
};
const costMap = new Float64Array(w * h);
function initCostMap() {
costMap[0] = dPixel(0, 1);
for (let x = 1; x < w - 1; x++) {
costMap[x] = dPixel(x - 1, x + 1);
}
costMap[w - 1] = dPixel(w - 2, w - 1);
for (let y = 1; y < h; y++) {
const line = y * w;
const linem1 = line - w;
{
const Cu = dPixel(line, line + 1) * 2;
const Cr = dPixel(linem1, line + 1);
const Mu = costMap[linem1] + Cu;
const Mr = costMap[linem1 + 1] + Cu + Cr;
costMap[line] = Mu < Mr ? Mu : Mr;
}
for (let x = 1; x < w - 1; x++) {
const Cl = dPixel(x + linem1, x - 1 + line);
const Cu = dPixel(x - 1 + line, x + 1 + line);
const Cr = dPixel(x + linem1, x + 1 + line);
const Clr = SQRT1_2 * dPixel(x - 1 + line, x + 1 + linem1);
const Crl = SQRT1_2 * dPixel(x + 1 + line, x - 1 + linem1);
const Ml = costMap[x - 1 + linem1] + Cu + Cl + Crl;
const Mu = costMap[x + linem1] + Cu + Clr + Crl;
const Mr = costMap[x + 1 + linem1] + Cu + Cr + Clr;
const M = Mr < Mu ? Mr : Mu;
costMap[x + line] = M < Ml ? M : Ml;
}
{
const x = w - 1;
const Cl = dPixel(x + linem1, x - 1 + line);
const Cu = dPixel(x - 1 + line, x + line);
const Ml = costMap[x - 1 + linem1] + Cu + Cl;
const Mu = costMap[x + linem1] + Cu * 2;
costMap[x + line] = Ml < Mu ? Ml : Mu;
}
}
}
while (true) {
initBuffers();
initCostMap();
let inputEnd = w - 1;
while (inputEnd > 0) {
let y = h - 1;
let line = y * w;
let xMin = 0,
costMin = costMap[line];
for (let x = 1; x < inputEnd; x++) {
const xCost = costMap[x + line];
if (xCost < costMin) {
costMin = xCost;
xMin = x;
}
}
while (y >= 0) {
const rgbMin = inputData32[xMin + line];
const loc = originalColumns[xMin + line];
removedSeamLoc[y] = xMin;
let i = xMin;
let idx = i + line;
while (i < inputEnd) {
inputData32[idx] = inputData32[idx + 1];
originalColumns[idx] = originalColumns[idx + 1];
idx++;
i++;
}
while (i < w - 1 && loc > newColumns[idx + 1]) {
inputData32[idx] = inputData32[idx + 1];
newColumns[idx] = newColumns[idx + 1];
idx++;
i++;
}
inputData32[idx] = rgbMin;
newColumns[idx] = loc;
insertedSeamLoc[y] = i;
y--;
line = y * w;
costMin = costMap[xMin + line];
if (costMap[max(0, xMin - 1) + line] < costMin) {
xMin = max(0, xMin - 1);
costMin = costMap[xMin + line];
}
if (costMap[Math.min(inputEnd, xMin + 1) + line] < costMin) {
xMin = Math.min(inputEnd, xMin + 1);
costMin = costMap[xMin + line];
}
}
inputEnd--;
context.putImageData(input, 0, 0);
yield {
context,
input,
inputData32,
inputEnd,
originalColumns,
newColumns
};
if (xMin === 0) {
costMap[0] = dPixel(0, 1);
costMap[1] = dPixel(0, 2);
} else if (xMin >= inputEnd) {
costMap[inputEnd - 1] = dPixel(inputEnd - 2, inputEnd);
costMap[inputEnd] = dPixel(inputEnd - 1, inputEnd);
} else {
costMap[xMin - 1] = dPixel(max(0, xMin - 2), xMin);
costMap[xMin] = dPixel(xMin - 1, xMin + 1);
costMap[xMin + 1] = dPixel(xMin, min(inputEnd, xMin + 2));
}
let xStart = max(0, xMin - 1),
xEnd = min(xMin + 1, inputEnd);
for (let y = 1; y < h; y++) {
const line = y * w;
const linem1 = line - w;
let x = xStart;
if (x === 0) {
const Cu = dPixel(line, line + 1) * 2;
const Cr = dPixel(linem1, line + 1);
const Mu = costMap[linem1] + Cu;
const Mr = costMap[linem1 + 1] + Cu + Cr;
costMap[line] = Mu < Mr ? Mu : Mr;
} else {
const Cl = dPixel(x + linem1, x - 1 + line);
const Cu = dPixel(x - 1 + line, x + 1 + line);
const Cr = dPixel(x + linem1, x + 1 + line);
const Clr = SQRT1_2 * dPixel(x - 1 + line, x + 1 + linem1);
const Crl = SQRT1_2 * dPixel(x + 1 + line, x - 1 + linem1);
const Ml = costMap[x - 1 + linem1] + Cu + Cl + Crl;
const Mu = costMap[x + linem1] + Cu + Clr + Crl;
const Mr = costMap[x + 1 + linem1] + Cu + Cr + Clr;
const M = Mr < Mu ? Mr : Mu;
costMap[x + line] = M < Ml ? M : Ml;
}
while (++x < xEnd) {
const Cl = dPixel(x + linem1, x - 1 + line);
const Cu = dPixel(x - 1 + line, x + 1 + line);
const Cr = dPixel(x + linem1, x + 1 + line);
const Ml = costMap[x - 1 + linem1] + Cu + Cl;
const Mu = costMap[x + linem1] + Cu;
const Mr = costMap[x + 1 + linem1] + Cu + Cr;
const M = Mr < Mu ? Mr : Mu;
costMap[x + line] = M < Ml ? M : Ml;
}
if (x === inputEnd) {
const Cl = dPixel(x + linem1, x - 1 + line);
const Cu = dPixel(x - 1 + line, x + line);
const Ml = costMap[x - 1 + linem1] + Cu + Cl;
const Mu = costMap[x + linem1] + Cu * 2;
costMap[x + line] = Ml < Mu ? Ml : Mu;
} else {
const Cl = dPixel(x + linem1, x - 1 + line);
const Cu = dPixel(x - 1 + line, x + 1 + line);
const Cr = dPixel(x + linem1, x + 1 + line);
const Ml = costMap[x - 1 + linem1] + Cu + Cl;
const Mu = costMap[x + linem1] + Cu;
const Mr = costMap[x + 1 + linem1] + Cu + Cr;
const M = Mr < Mu ? Mr : Mu;
costMap[x + line] = M < Ml ? M : Ml;
}
xStart = max(0, xStart - 1);
xEnd = min(inputEnd, xEnd + 1);
}
}
context.putImageData(input, 0, 0);
yield {
context,
input,
inputData32,
inputEnd,
originalColumns,
newColumns
};
}
}