|
<!DOCTYPE html> |
|
<style type="text/css"> |
|
* { background: #333; color: #FFF; font-size: 1.5em; text-align: center; } |
|
h1 { cursor: pointer; min-height: 200px; } |
|
h1, h1 * { background: #FFF; max-height: 200px; vertical-align: top; } |
|
</style> |
|
<h1 title="Click to open SVG image" onclick="location.href='data:image/svg+xml,'+escape(this.innerHTML)">140byt es</h1> |
|
<input onkeyup="refreshLogo(this.value)" value="140byt es"> |
|
<script type="text/javascript"> |
|
var svg = function(w, x, y, z) |
|
{ |
|
z = { //character map, each path must start and end on the baseline |
|
' ': 'm1 0', //move 1 forward on the baseline without drawing a line |
|
'!': 'm1 -3v1.99m0 1v.01', |
|
'"': 'm1 -3v1m1 -1v1m0 2', |
|
'#': 'm1 -2h3m-3 1h3m-2 -2v3m1 -3v3m1 0', |
|
"'": 'm1 -3v1m0 2', |
|
'+': 'm1 -1h2h-1v1v-2m1 2', |
|
',': 'm1 1v-1', //move 1 forward and 1 down, then draw a vertical line 1 up |
|
'-': 'm1 -1h1m0 1', //move 1 forward and 1 up, draw horizontal line, move 1 down to the baseline |
|
'.': 'm1 -.01v.01', |
|
'/': 'm1 0l1 -2m0 2', |
|
'0': 'm3 0h-2v-2h2z', //move 3 forward, draw 2 backward, 2 up, 2 forward and close the subpath |
|
'1': 'm1 -2h1v2', |
|
'2': 'm1 -2h2v1m-2 0v1h2', |
|
'3': 'm1 -2h2v1h-1h1v1h-2h2', |
|
'4': 'm1 -2v1h2v-1v2', |
|
'5': 'm3 -2h-2v1m2 0v1h-2h2', |
|
'6': 'm1 -1h2v1h-2v-2h2m0 2', |
|
'7': 'm1 -2h2v2', |
|
'8': 'm3 0h-2v-2h2v1h-2h2z', |
|
'9': 'm3 -1h-2v-1h2v2', |
|
':': 'm1 -2v.01m0 2v-.01', |
|
';': 'm1 -1.01v.01m0 2v-1', |
|
'<': 'm2 -2l-1 1l1 1', //move forward and up, draw two diagonal lines |
|
'>': 'm1 -2l1 1l-1 1m1 0', |
|
'@': 'm2 -2v1h2v-2h-3v3h3', |
|
'\\': 'm1 -2l1 2', |
|
'_': 'm1 0h1', |
|
'a': 'm1 -1v1h2v-2h-2m2 2', |
|
'b': 'm3 0h-2v-3v1h2z', |
|
'c': 'm3 -2h-2v2h2', |
|
'd': 'm3 0h-2v-2h2v-1z', |
|
'e': 'm3 -1v-1h-2v2h2', |
|
'f': 'm2 -3h-1v3v-2h1m0 2', |
|
'g': 'm3 -2h-2v2h2v-1v1', |
|
'h': 'm1 0v-3v1h2v2', |
|
'i': 'm1 -2v2', |
|
'j': 'm1 1h1v-3v2', |
|
'k': 'm1 -3v3l2 -2l-1 1l1 1', |
|
'l': 'm1 -3v3h1', |
|
'm': 'm1 0v-2h1.5v2v-2h1.5v2', |
|
'n': 'm1 0v-2h2v2', |
|
'o': 'm3 0h-2v-2h2z', |
|
'p': 'm3 0h-2v1v-3h2z', |
|
'q': 'm3 1v-3h-2v2h2', |
|
'r': 'm1 0v-2h1m0 2', |
|
's': 'm3 -2h-2v1m2 0v1h-2h2', |
|
't': 'm2 -2h-1v-1v3h1', |
|
'u': 'm1 -2v2h2v-2v2', |
|
'v': 'm1 -2l1 2l1 -2m0 2', |
|
'w': 'm1 -2v2h1.5v-2v2h1.5v-2v2', |
|
'x': 'm1 0l2 -2m-2 0l2 2', |
|
'y': 'm1 -2v2h1v1v-1h1v-2v2', |
|
'z': 'm1 -2h2l-2 2h2', |
|
'|': 'm1 -3v3' |
|
} |
|
y = [0, -4, 1, 6] //viewBox with x, y, width, height |
|
x = '><path d="'; //XML fragment |
|
w = [ //array of default styles with fixed positions |
|
'fill:none', //w[0] |
|
'stroke:#000', //w[1] |
|
'stroke-linecap:round', //w[2] |
|
'stroke-linejoin:round', //w[3] |
|
'stroke-width:.9' //w[4] |
|
] |
|
this.color = function(a) { return this.setStyle(1, a) } |
|
this.linecap = function(a) { return this.setStyle(2, a) } |
|
this.linejoin = function(a) { return this.setStyle(3, a) } |
|
this.width = function(a) { return this.setStyle(4, a) } |
|
this.setStyle = function(a, b) |
|
{ |
|
w[a] = w[a].replace(/:.*/, ':' + b); |
|
return this //make all method calls chainable |
|
} |
|
this.padding = function(a) //can not be called multiple times |
|
{ |
|
a = --a || -1; //default padding is 1 |
|
y = [y[0] - a, y[1] - a, y[2] + a * 2, y[3] + a * 2]; |
|
return this |
|
} |
|
// 127 bytes |
|
this.text = function(a, b, c, d) //can be called multiple times |
|
{ |
|
d = ''; //compile path for the current string |
|
for (b = 0; c = a.charAt(b++); ) //for each character in the string |
|
d += z[c] || //append path from the character map or |
|
z._; //use the underscore for undefined characters |
|
b = /[hlm]([--9]+)/g; //match first number from all horizontal/line/move commands |
|
for (; c = b.exec(d); ) //for each match in the compiled path |
|
y[2] += +c[1]; //expand viewBox by the matched width, converted to a number |
|
x += d; //append the compiled path to the XML fragment |
|
return this //make the method call chainable |
|
} |
|
this.background = function(a) //can not be called multiple times |
|
{ |
|
// This way of setting a background color (instead of adding a colored rect) |
|
// works in Firefox and Opera but is ignored when loading the SVG in Inkscape. |
|
x = ' style="background:' + (a || '#FFF') + '"' + x; |
|
return this |
|
} |
|
this.toString = function() |
|
{ |
|
return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="' + y.join(' ') + '"' + |
|
x + '" style="' + w.join(';') + '"/></svg>' |
|
} |
|
} |
|
var container = document.getElementsByTagName('H1')[0]; |
|
var refreshLogo = function(a, b) |
|
{ |
|
container.innerHTML = new svg().color('#333').text(a.toLowerCase()); |
|
// A more complex example: |
|
//container.innerHTML = new svg().background('green').color('white').padding(3).width(.5).text(a); |
|
|
|
// Instead of embedding the SVG in HTML we can create an image object with a data URI. |
|
// This is a little more compatible but flickers when replacing the image. |
|
//b = new Image(); |
|
//b.src = 'data:image/svg+xml,' + escape(new svg().text(a)); |
|
//container.replaceChild(b, container.firstChild); |
|
} |
|
refreshLogo(container.firstChild.data); |
|
// Create optional favicon, because we can. ;-) |
|
var l = document.createElement('LINK'); |
|
l.rel = 'shortcut icon'; |
|
// Opera is able to render the background color but does not when using the SVG as favicon. |
|
// Firefox does not display the SVG favicon when reloading the page. |
|
l.href = 'data:image/svg+xml,' + escape(new svg().background('#FD2').padding(.7).width(.6).text('js')); |
|
document.getElementsByTagName('HEAD')[0].appendChild(l); |
|
</script> |
No, to compress the input even further. Gzip is a mix between LZW and huffman. Incidentially, I do have a huffman compressor in JS (http://tinyjs.sourceforge.net/tiny-huffman.js), but it's nowhere near 140bytes.