Skip to content

Instantly share code, notes, and snippets.

@notmasteryet
Created September 13, 2011 01:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save notmasteryet/1212949 to your computer and use it in GitHub Desktop.
Save notmasteryet/1212949 to your computer and use it in GitHub Desktop.
Building JPEGs
<!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