I am trying to do some dynamic programming based on the number of characters in a sentence. Which letter of the English alphabet takes up the most pixels on the screen?
I am trying to do some dynamic programming based on the number of characters in a sentence. Which letter of the English alphabet takes up the most pixels on the screen?
I know the accepted answer here is W, W is for WIN.
However, in this case, W is also for Width. The case study used employed a simple width test to examine pixels, but it was only the width, not the total pixel count. As an easy counter example, the accepted answer assumes that O and Q take up the same amount of pixels, yet they only take up the same amount of space.
Thus, W takes up the most space. But, is it all the pixels it's cracked up to be?
Let's get some empirical data. I created imgur images from the following B, M and W. I then analyzed their pixel count (see below), here are the results:
B : 114 pixels
M : 150 pixels
W : 157 pixels
Here is how I fed them into canvas and analyzed the raw pixel data from the images.
var imgs = {
B : "//i.imgur.com/YOuEPOn.png",
M : "//i.imgur.com/Aev3ZKQ.png",
W : "//i.imgur.com/xSUwE7w.png"
};
window.onload = function(){
for(var key in imgs){(function(img,key){
var Out = document.querySelector("#"+key+"Out");
img.crossOrigin = "Anonymous";
img.src=imgs[key];
img.onload = function() {
var canvas = document.querySelector('#'+key);
(canvas.width = img.width,canvas.height = img.height);
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
var data = context.getImageData(0, 0, img.width, img.height).data;
Out.innerHTML = "Total Pixels: " + data.length/4 + "<br>";
var pixelObject = {};
for(var i = 0; i < data.length; i += 4){
var rgba = "rgba("+data[i]+","+data[i+1]+","+data[i+2]+","+data[i+3]+")";
pixelObject[rgba] = pixelObject[rgba] ? pixelObject[rgba]+1 : 1;
}
Out.innerHTML += "Total Whitespace: " + pixelObject["rgba(255,255,255,255)"] + "<br>";
Out.innerHTML += "Total Pixels In "+ key +": " + ((data.length/4)-pixelObject["rgba(255,255,255,255)"]) + "<br>";
};
})(new Image(),key)}
};
<table>
<tr>
<td>
<canvas id="B" width="100%" height="100%"></canvas>
</td>
<td id="BOut">
</td>
</tr>
<tr>
<td>
<canvas id="M" width="100%" height="100%"></canvas>
</td>
<td id="MOut">
</td>
</tr>
<tr>
<td>
<canvas id="W" width="100%" height="100%"></canvas>
</td>
<td id="WOut">
</td>
</tr>
</table>
Want to know the real longest glyph, not just guessing?
And I'm not just talking about the letters, digits and common symbols (!, @ and so on). I mean the longest glyph in all the 32,834 characters of UTF-16.
So I started with answer by @NK that had a programmatic solution to it, and made a modification:
var capsIndex = 65;
var smallIndex = 97;
var div = document.createElement('div');
div.style.float = 'left';
document.body.appendChild(div);
var highestWidth = 0;
var elem;
for(var i = capsIndex; i < 32834; i++) {
div.innerText = String.fromCharCode(i);
var computedWidth = window.getComputedStyle(div, null).getPropertyValue("width");
if(highestWidth < parseFloat(computedWidth)) {
highestWidth = parseFloat(computedWidth);
elem = String.fromCharCode(i);
}
}
div.innerHTML = '<b>' + elem + '</b>' + ' won';
After running this and waiting (and waiting), it gives the output ௌ won.
And there you have it, the longest character in UTF-32!
Note that on most fonts the longest glyph is ﷽, but some fonts (especially monospace ones) overlap the characters, as with the font that the program was run with.
This code will get widths for all characters as array:
const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var widths = [];
var div = document.createElement('div');
div.style.float = 'left';
document.body.appendChild(div);
var highestObservedWidth = 0;
// widest characters (not just one)
var answer = '';
for (var i = 0; i < alphabet.length; i++) {
div.innerText = alphabet[i];
var computedWidthString = window.getComputedStyle(div, null).getPropertyValue("width");
var computedWidth = parseFloat(computedWidthString.slice(0, -2));
// console.log(typeof(computedWidth));
widths[i] = computedWidth;
if(highestObservedWidth == computedWidth) {
answer = answer + ', ' + div.innerText;
}
if(highestObservedWidth < computedWidth) {
highestObservedWidth = computedWidth;
answer = div.innerText;
}
}
if (answer.length == 1) {
div.innerHTML = ' Winner: ';
} else {
div.innerHTML = ' Winners: ';
}
div.innerHTML = div.innerHTML + answer + '.';
console.log(widths.sort((a, b) => a - b));
Or if you want to have a map of widths, containing more than just alpha(numeric) characters like described above (like I needed in a non-browser environment)
const chars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "\"", "#", "$", "%", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "=", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", " ", "&", ">", "<"]
const test = document.createElement('div')
test.id = "Test"
document.body.appendChild(test)
test.style.fontSize = 12
const result = {}
chars.forEach(char => {
let newStr = ""
for (let i = 0; i < 10; i++) {
if (char === " ") {
newStr += " "
} else {
newStr += char
}
}
test.innerHTML = newStr
const width = (test.clientWidth)
result[char] = width / 10
})
console.log('RESULT:', result)
#Test
{
position: absolute;
/* visibility: hidden; */
height: auto;
width: auto;
white-space: nowrap; /* Thanks to Herb Caudill comment */
}