Skip to content

Instantly share code, notes, and snippets.

@brettz9
Created October 26, 2013 00:07
Show Gist options
  • Save brettz9/7163724 to your computer and use it in GitHub Desktop.
Save brettz9/7163724 to your computer and use it in GitHub Desktop.
ICO attempt
<!DOCTYPE html>
<html xmlns="http:/www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<style>
</style>
</head>
<body>
<canvas id="canvas" width="16" height="16"></canvas>
<script>
// Based on http://mrcoles.com/favicon-creator/favicon.js
(function(undefined) {
function _asLittleEndianHex(value, bytes) {
// Convert value into little endian hex bytes
// value - the number as a decimal integer (representing bytes)
// bytes - the number of bytes that this value takes up in a string
// Example:
// _asLittleEndianHex(2835, 4)
// > '\x13\x0b\x00\x00'
var result = [];
for (; bytes>0; bytes--) {
result.push(String.fromCharCode(value & 255));
value >>= 8;
}
return result.join('');
}
window.generateIcoDataURL = function(bmp, dimension) {
// Expects rows starting in bottom left
// formatted like this: [[[255, 0, 0], [255, 255, 0], ...], ...]
// which represents: [[red, yellow, ...], ...]
// optional 4th value in each color is the alpha! -- ignored for now!!
if (!window.btoa) {
alert('Oh no, your browser does not support base64 encoding - window.btoa()!!');
return false;
}
var height = dimension, // the number of rows
width = dimension, // the number of columns per row
row_padding = (width * 3) % 4, // pad each row to a multiple of 4 bytes (should be 0)
num_data_bytes = (width * 4 + row_padding) * height, // size in bytes of BMP data
num_bmp_bytes = 40 + num_data_bytes + 64, // full header size (offset) + size of data
pixmap_height,
pixmap_width,
raw_1bit_bitmap = (new Array(width * height * 2 / 8 + 1)).join('\x00'),
file;
pixmap_height = _asLittleEndianHex(height * 2, 4); // NOTE: my example .ico had 2x the Pixma height
pixmap_width = _asLittleEndianHex(width, 4);
height = _asLittleEndianHex(height, 1);
width = _asLittleEndianHex(width, 1);
num_data_bytes = _asLittleEndianHex(num_data_bytes, 4);
num_bmp_bytes = _asLittleEndianHex(num_bmp_bytes, 4);
// ==HEADER==
file = ('\x00\x00' + // Reserved. Should always be 0.
'\x01\x00' + // Specifies image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid.
'\x01\x00' + // Specifies number of images in the file.
// ==IMAGE==
width + // **Specifies image width in pixels. Can be any number between 0 to 255. Special case: 0 means 256 pixels**
height + // **Specifies image height in pixels. Can be any number between 0 to 255. Special case: 0 means 256 pixels**
'\x00' + // Specifies number of colors in the color palette. Should be 0 if the image is truecolor.
'\x00' + // Reserved. Should be 0.
'\x01\x00' + // In .ICO format: Specifies color planes. Should be 0 or 1.
'\x20\x00' + // In .ICO format: Specifies bits per pixel (32 = 24 color + 8 alpha)
num_bmp_bytes + // **Specifies the size of the bitmap data in bytes**
'\x16\x00\x00\x00' + // Specifies the offset of bitmap data address in the file (22 bytes!)
// ==ICO Data Header ==
'\x28\x00\x00\x00' + // Header size (40 bytes!)
pixmap_width + // **Pixmap width**
pixmap_height + // **Pixmap height (why 32 for the 16x16 example?)**
'\x01\x00' + // Color Planes
'\x20\x00' + // The number of bits per pixel
'\x00\x00\x00\x00' + // The compression method being used (0 is uncompressed)
num_data_bytes + // **The image size. This is the size of the raw bitmap data . should not be confused with the file size**
'\x00\x00\x00\x00' + // The horizontal resolution of the image. (pixel per meter, signed integer, usually 2835)
'\x00\x00\x00\x00' + // The vertical resolution of the image. (pixel per meter, signed integer, usually 2835)
'\x00\x00\x00\x00' + // The number of colors in the color palette, or 0 to default to 24 or 32 bits
'\x00\x00\x00\x00' + // The number of important colors used, or 0 when every color is important; generally ignored.
// ==Raw Data 4 bytes each (B, G, R, A) ==
bmpB64 +
// ==After this RAW data, a 1-bit bitmap is also RAW saved. If you save it as a back of bytes with the value 0, it will get the Alpha channel instead.==
raw_1bit_bitmap
);
return 'data:image/vnd.microsoft.icon;base64,' + btoa(file);
};
})();
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillRect(2,2,15,15);
ctx.clearRect(6,6,10,10);
ctx.strokeRect(8,8,8,8);
document.body.appendChild(canvas);
var bmpB64 = canvas.toDataURL('image/bmp').slice(22);
var img = new Image();
img.src = generateIcoDataURL(atob(bmpB64), canvas.width);
document.body.appendChild(img);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment