Created
September 13, 2011 01:39
-
-
Save notmasteryet/1212949 to your computer and use it in GitHub Desktop.
Building JPEGs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<script> | |
function buildJpeg(data, components, transform, embed) { | |
var chunks = []; | |
// SOI | |
chunks.push([0xFF, 0xD8]); | |
// APP12 | |
if (embed) | |
chunks.push([0xFF, 0xEC, 0, 8, 0x45, 0x4D, 0x42, 0x45, 0x44, 0]); | |
// APP14 | |
chunks.push([0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, transform]); | |
// DQT | |
chunks.push([0xFF, 0xDB, 0x00, 0x43, 0x00, | |
0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | |
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | |
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | |
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]); | |
// SOF0 | |
chunks.push([0xFF, 0xC0, 0x00, 0x14, 0x08, 0x00, 0x08, 0x00, 0x40, 0x04, | |
components[0], 0x11, 0x00, components[1], 0x11, 0x00, components[2], 0x11, 0x00, components[3], 0x11, 0x00]); | |
// DHT | |
var dcTable = [0x00, | |
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]; | |
var acTable = [0x10, | |
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00]; | |
var dhtLength = 2 + dcTable.length + acTable.length; | |
chunks.push([0xFF, 0xC4, (dhtLength >>> 8), (dhtLength & 0xFF)]); | |
chunks.push(dcTable); | |
chunks.push(acTable); | |
// SOS | |
chunks.push([0xFF, 0xDA, 0x00, 0x0E, 0x04, | |
components[0], 0x00, components[1], 0x00, components[2], 0x00, components[3], 0x00, 0x00, 0x3F, 0x00]); | |
function encodeData(v) { | |
var t = ""; | |
var ssss; | |
if (v == 0) | |
ssss = 0; | |
else if (v >= -1 && v <= 1) | |
ssss = 1; | |
else if (v >= -3 && v <= 3) | |
ssss = 2; | |
else if (v >= -7 && v <= 7) | |
ssss = 3; | |
else if (v >= -15 && v <= 15) | |
ssss = 4; | |
else if (v >= -31 && v <= 31) | |
ssss = 5; | |
else if (v >= -63 && v <= 63) | |
ssss = 6; | |
else if (v >= -127 && v <= 127) | |
ssss = 7; | |
else if (v >= -255 && v <= 255) | |
ssss = 8; | |
else if (v >= -511 && v <= 511) | |
ssss = 9; | |
else if (v >= -1023 && v <= 1023) | |
ssss = 10; | |
else if (v >= -2047 && v <= 2047) | |
ssss = 11; | |
t += "0" + ((ssss & 8) ? "1" : "0") + ((ssss & 4) ? "1" : "0") + | |
((ssss & 2) ? "1" : "0") + ((ssss & 1) ? "1" : "0"); | |
if (v < 0) | |
v--; | |
for (var i = ssss - 1; i >= 0; --i) { | |
t += (v & (1 << i)) ? "1" : "0"; | |
} | |
t += "0"; | |
return t; | |
} | |
var last = [0,0,0,0], bits = ""; | |
for (var i = 0; i < data.length; i++) { | |
for (var j = 0; j < 4; ++j) { | |
var d = (data[i][j] - 128); | |
var q = (d - last[j]); | |
bits += encodeData(q); | |
last[j] = d; | |
} | |
} | |
while ((bits.length % 8) != 0) bits += "0"; | |
var dataChunk = []; | |
for (var i = 0; i < bits.length; i += 8) { | |
var q = | |
(bits[i] == "1" ? 0x80 : 0) | | |
(bits[i + 1] == "1" ? 0x40 : 0) | | |
(bits[i + 2] == "1" ? 0x20 : 0) | | |
(bits[i + 3] == "1" ? 0x10 : 0) | | |
(bits[i + 4] == "1" ? 0x08 : 0) | | |
(bits[i + 5] == "1" ? 0x04 : 0) | | |
(bits[i + 6] == "1" ? 0x02 : 0) | | |
(bits[i + 7] == "1" ? 0x01 : 0); | |
dataChunk.push(q); | |
if (q == 255) dataChunk.push(0); | |
} | |
chunks.push(dataChunk); | |
// EOI | |
chunks.push([0xFF, 0xD9]); | |
var s = "", bytes = []; | |
for (var i = 0; i < chunks.length; i++) { | |
for (var j = 0; j < chunks[i].length; j++) { | |
s += String.fromCharCode(chunks[i][j]); | |
bytes.push(chunks[i][j]); | |
} | |
} | |
window.bytes = bytes; | |
return 'data:image/jpeg;base64,' + window.btoa(s); | |
} | |
function run() { | |
// colors to display: W, R, Y, G, C, B, M, K | |
// build CMYK | |
var data1 = [ | |
[255, 255, 255, 255], | |
[255, 0, 0, 255], | |
[255, 255, 0, 255], | |
[0, 255, 0, 255], | |
[0, 255, 255, 255], | |
[0, 0, 255, 255], | |
[255, 0, 255, 255], | |
[255, 255, 255, 0] | |
]; | |
var url1 = buildJpeg(data1, [0x43,0x4D,0x59,0x4B], 0, false); | |
console.log(url1); | |
document.getElementById("img1").src = url1; | |
// build YCCK | |
var data2 = [ | |
[0, 128, 128, 255], | |
[179, 171, 0, 255], | |
[29, 256, 107, 255], | |
[105, 212, 255, 255], | |
[76, 85, 256, 255], | |
[226, 1, 149, 255], | |
[150, 44, 21, 255], | |
[0, 128, 128, 0] | |
]; | |
var url2 = buildJpeg(data2, [1,2,3,4], 2, false); | |
console.log(url2); | |
document.getElementById("img2").src = url2; | |
// build YCCK (embed) | |
var data3 = [ | |
[255, 128, 128, 0], | |
[76, 85, 255, 0], | |
[226, 1, 149, 0], | |
[150, 44, 0, 0], | |
[179, 171, 0, 0], | |
[29, 255, 107, 0], | |
[105, 212, 235, 0], | |
[255, 128, 149, 255] | |
]; | |
var url3 = buildJpeg(data3, [1,2,3,4], 2, true); | |
console.log(url3); | |
document.getElementById("img3").src = url3; | |
} | |
</script> | |
<body onload="run()"> | |
<img id="img1"><br> | |
<img id="img2"><br> | |
<img id="img3"><br> | |
</body></html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment