Skip to content

Commit c9bc079

Browse files
committed
fix ASCII art dimensions calculation
1 parent bcf69db commit c9bc079

File tree

2 files changed

+24
-18
lines changed

2 files changed

+24
-18
lines changed

src/commands/context/ascii-image.mjs

-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ export const execute = async (interaction) => {
4343
attachment.height,
4444
// 2000 is the maximus size allowd by discord
4545
// -6 is to make space for the ``` before and after the message
46-
// FIXME: does not take into account \n characters
4746
2000 - 6
4847
);
4948
const content = '```' + result + '```';

src/util/imageToAscii.mjs

+24-17
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,32 @@ const chars = '%&#MHGw*+-. ';
88
// const chars = 'BS#&@$%*!:. ';
99

1010
/**
11-
* Calculate the maximum rectangle that has an area less that maxChars and the same aspect ratio (width/height) as the image
11+
* Calculate the maximum rectangle that has a surface area <= `maxSurface` and the same aspect ratio
1212
*
1313
* @param {number} width the image width
1414
* @param {number} height the image heigth
15-
* @param {number} maxChars maximum number of chars allowed in Discord message
16-
* @param {number} heightMultiplier allows to scale the images height so it doesn't look stretched when after being converted to ASCII characters.
15+
* @param {number} maxSurface maximum surface area of the output rectangle
1716
* @returns
1817
*/
19-
const calculateSize = (
20-
width,
21-
height,
22-
maxChars = 2000,
23-
heightMultiplier = 0.4 // TODO: calculate an accurate value, this value was just eyeballed
24-
) => {
25-
const w = width;
26-
const h = height * heightMultiplier;
18+
const calculateSize = (width, height, maxSurface = 2000) => {
19+
const imageArea = width * height;
20+
21+
/*
22+
We want to keep the aspect ratio of the image, this means that we must scale width and height by the same factor:
23+
(1) newW = scaleFactor * width
24+
(2) newH = scaleFactor * height
2725
28-
const imageArea = w * h;
29-
const scaleFactor = Math.sqrt(maxChars / imageArea);
26+
We also want the are of the new image to be <= than maxSurface (we add 1 to width to account for the \n characters at the end of the lines)
27+
(3) (newW + 1) * newH <= maxSurface
3028
31-
const newW = Math.floor(scaleFactor * w);
32-
const newH = Math.floor(scaleFactor * h);
29+
We substitute (1) and (2) into (3) and solve for `scaleFactor` to find the formula below.
30+
*/
31+
const scaleFactor =
32+
(-height + Math.sqrt(height * height + 4 * imageArea * maxSurface)) /
33+
(2 * imageArea);
34+
35+
const newW = Math.floor(scaleFactor * width);
36+
const newH = Math.floor(scaleFactor * height);
3337
return [newW, newH];
3438
};
3539

@@ -75,12 +79,15 @@ function groupLines(lineLength) {
7579
export const urlToAscii = async (
7680
url,
7781
originalWidth,
78-
origianalHeight,
82+
originalHeight,
7983
maxChars
8084
) => {
8185
const [width, height] = calculateSize(
8286
originalWidth,
83-
origianalHeight,
87+
88+
// Since pixels are square but character are not, we must squish the image so that it doesn't look stretched after being converted to ASCII
89+
// TODO: calculate an accurate value, this value was just eyeballed
90+
originalHeight * 0.4,
8491
maxChars
8592
);
8693

0 commit comments

Comments
 (0)