Skip to content

Instantly share code, notes, and snippets.

@kig
Created February 10, 2011 01:14
Show Gist options
  • Save kig/819732 to your computer and use it in GitHub Desktop.
Save kig/819732 to your computer and use it in GitHub Desktop.
DrawHistorySerializer = Klass({
magic: 'SRBL',
majorVersion: 0,
minorVersion: 0,
getVersionTag : function() {
return [this.magic, this.majorVersion, this.minorVersion, ''].join(",")
},
serialize : function(history) {
return [this.getVersionTag(), this.serializeBody(history)].join("");
},
deserialize : function(string) {
var t = this.getVersionTag();
if (string.substring(0, t.length) != t)
throw (new Error("Unknown version tag"))
return this.deserializeBody(string.substring(t.length));
},
serializeBody : function(history) {
return JSON.stringify(history);
},
deserializeBody : function(history) {
return JSON.parse(history);
}
});
// sketch of a binary serializer. lacking parser and binary encoder funcs.
// dunno if i should throw some crazy entropy encoder there as well
// (arithmetic-encode brushstroke coord deltas)
CompressedDrawHistorySerializer = Klass(DrawHistorySerializer, {
commands : [
'drawPoint',
'drawLine',
'clear',
'setColor',
'setBackground',
'setLineCap',
'setLineWidth',
'setOpacity'
],
collapsible : {
'clear' : true,
'setColor' : true,
'setBackground' : true,
'setLineCap' : true,
'setLineWidth' : true,
'setOpacity' : true
},
majorVersion: 1,
minorVersion: 0,
initialize : function() {
this.commandCodes = {};
for (var i=0; i<this.commands.length; i++) {
this.commandCodes[this.commands[i]] = i;
}
},
serializeBody : function(history) {
var output = [];
for (var i=0; i<history.length; i++) {
var e = history[i];
if (this.collapsible[e.methodName] && history[i+1]
&& history[i+1].methodName == e.methodName) {
// only the last element matters in a string of collapsible actions
// (a = 1; a = 2; a = 3; a = 4) <=> (a = 4)
continue;
}
var cmd = this.commandCodes[e.methodName];
if (e.methodName == 'drawLine') {
// delta-encode a string of drawLine actions
var coords = [e.args[0], e.args[1]];
e = history[i+1];
while (e && e.methodName == 'drawLine') {
if (this.canDeltaEncode(coords, e.args))
coords.push(e.args[1]);
else
break;
i++;
e = history[i+1];
}
var deltaString = this.deltaEncode(coords);
output.push(cmd + this.encodeInt16(deltaString.length) + deltaString);
continue;
} else {
var args = this.encodeArgs(e.args);
output.push(cmd + args);
}
}
return output.join("");
},
deserializeBody : function(string) {
var output = [];
var obj = {};
for (var i=0; i<string.length;) {
i += this.readCommand(string, obj);
if (obj.methodName == 'drawLine') {
var coords = this.decodeDeltas(obj.args);
for (var j=0; j<coords.length; j++)
output.push({methodName: 'drawLine', args: coords[j]});
} else {
var o = {methodName: obj.methodName, args: obj.args};
if (this.breakpointMethod[obj.methodName])
o.breakpoint = true;
output.push(o);
}
}
return output;
},
canDeltaEncode : function(coords, args) {
var l = coords.last();
return (
coords.length < 30000 &&
(l.x == args[0].x && l.y == args[0].y) &&
(Math.abs(l.x-args[1].x) < 127 && Math.abs(l.y-args[1].y) < 127)
);
},
deltaEncode : function(coords) {
var base = coords[0];
var deltas = [this.encodeInt16(base.x),this.encodeInt16(base.y)];
for (var i=1; i<coords.length-1; i++) {
var prev = coords[i-1];
var cur = coords[i];
deltas.push(this.encodeInt8(cur.x-prev.x), this.encodeInt8(cur.y-prev.y));
}
return deltas.join("");
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment