Skip to content
2 changes: 2 additions & 0 deletions src/arr/trove/starter2024.arr
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ provide from I:
underlay-align-list,
underlay-list,
underlay-xy,
vertical-symmetry,
horizontal-symmetry,
wedge,
x-center,
x-left,
Expand Down
49 changes: 49 additions & 0 deletions src/js/trove/image-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -1759,6 +1759,52 @@

LineImage.prototype = heir(BaseImage.prototype);

var verticalSymmetry = function(img) {
var width = img.getWidth();
var height = img.getHeight();
var halfW = Math.floor(width / 2);
if (halfW === 0 || height === 0) { return 1; }
var canvas = makeCanvas(width, height);
img.render(canvas.getContext("2d"));
var data = canvas.getContext("2d").getImageData(0, 0, width, height).data;
var sumSq = 0, count = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < halfW; x++) {
var i1 = (y * width + x) * 4;
var i2 = (y * width + (width - 1 - x)) * 4;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate magic formulas like these :( Though I do understand it, I kinda wish we had

const getPixel(data, x, y, channel) => data[((y * width) + x) * 4 + channel];

And then you'd have var d = getPixel(data, x, y, ch) - getPixel(data, width - 1 - x, y, ch), which to me reads a lot more cleanly. OTOH, you're writing this in raw JS because of performance, so you could do

const basePixelIndex(x, y) => ((y * width) + x) * 4;

and then have

var i1 = basePixelIndex(x, y);
var i2 = basePixelIndex(width - 1 - x, y);

which saves two whole multiplications per loop ;-)

for (var ch = 0; ch < 4; ch++) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the actual similarity formula being used in these two functions? I think, if I'm understanding correctly, that it's the root mean-squared error over every pixel and every color channel? Probably worth a clarifying comment somewhere...

var d = data[i1 + ch] - data[i2 + ch];
sumSq += d * d;
}
count += 4;
}
}
return 1 - Math.sqrt(sumSq / count) / 255;
};

var horizontalSymmetry = function(img) {
var width = img.getWidth();
var height = img.getHeight();
var halfH = Math.floor(height / 2);
if (width === 0 || halfH === 0) { return 1; }
var canvas = makeCanvas(width, height);
img.render(canvas.getContext("2d"));
var data = canvas.getContext("2d").getImageData(0, 0, width, height).data;
var sumSq = 0, count = 0;
for (var y = 0; y < halfH; y++) {
for (var x = 0; x < width; x++) {
var i1 = (y * width + x) * 4;
var i2 = ((height - 1 - y) * width + x) * 4;
for (var ch = 0; ch < 4; ch++) {
var d = data[i1 + ch] - data[i2 + ch];
sumSq += d * d;
}
count += 4;
}
}
return 1 - Math.sqrt(sumSq / count) / 255;
};

var colorAtPosition = function(img, x, y) {
var width = img.getWidth(),
height = img.getHeight(),
Expand Down Expand Up @@ -2038,6 +2084,9 @@
colorBlue: colorBlue,
colorAlpha: colorAlpha,
colorString: colorString,

verticalSymmetry: verticalSymmetry,
horizontalSymmetry: horizontalSymmetry,
}
);
return RUNTIME.makeJSModuleReturn();
Expand Down
2 changes: 2 additions & 0 deletions src/js/trove/internal-image-typed.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@
"image-baseline": ["arrow", ["Image"], "Number"],
"image-pinhole-x": ["arrow", ["Image"], "Number"],
"image-pinhole-y": ["arrow", ["Image"], "Number"],
"vertical-symmetry": ["arrow", ["Image"], "Number"],
"horizontal-symmetry": ["arrow", ["Image"], "Number"],
"name-to-color": ["arrow", ["String"], "OptColor"],
"color-named": ["arrow", ["String"], "Color"],
"empty-image": "Image"
Expand Down
2 changes: 2 additions & 0 deletions src/js/trove/internal-image-untyped.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@
"image-baseline": ["arrow", ["Image"], "Number"],
"image-pinhole-x": ["arrow", ["Image"], "Number"],
"image-pinhole-y": ["arrow", ["Image"], "Number"],
"vertical-symmetry": ["arrow", ["Image"], "Number"],
"horizontal-symmetry": ["arrow", ["Image"], "Number"],
"name-to-color": ["arrow", ["String"], "OptColor"],
"color-named": ["arrow", ["String"], "Color"],
"empty-image": "Image"
Expand Down
14 changes: 14 additions & 0 deletions src/js/trove/make-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,20 @@
return runtime.wrap(img.getHeight());
});

f("vertical-symmetry", function(maybeImg) {
checkArity(1, arguments, "vertical-symmetry", false);
c1("vertical-symmetry", maybeImg, annImage);
var img = unwrapImage(maybeImg);
return runtime.wrap(image.verticalSymmetry(img));
});

f("horizontal-symmetry", function(maybeImg) {
checkArity(1, arguments, "horizontal-symmetry", false);
c1("horizontal-symmetry", maybeImg, annImage);
var img = unwrapImage(maybeImg);
return runtime.wrap(image.horizontalSymmetry(img));
});

f("image-baseline", function(maybeImg) {
checkArity(1, arguments, "image-baseline", false);
c1("image-baseline", maybeImg, annImage);
Expand Down
Loading