sku-pg
Version:
Skulpt is a Javascript implementation of Python 2.x. Python that runs in your browser!
445 lines (388 loc) • 17.5 kB
JavaScript
var ImageMod; // the single identifier needed in the global scope
var $builtinmodule;
if (!ImageMod) {
ImageMod = {};
ImageMod.canvasLib = [];
}
$builtinmodule = function (name) {
var screen;
var pixel;
var eImage;
var mod = {};
var updateCanvasAndSuspend;
var initializeImage;
var checkPixelRange;
var remapImageIdToURL;
var image = function ($gbl, $loc) {
initializeImage = function (self) {
self.width = self.image.width;
self.height = self.image.height;
self.delay = 0;
self.updateCount = 0;
self.updateInterval = 1;
self.lastx = 0;
self.lasty = 0;
self.canvas = document.createElement("canvas");
self.canvas.height = self.height;
self.canvas.width = self.width;
self.ctx = self.canvas.getContext("2d");
self.ctx.drawImage(self.image, 0, 0);
self.imagedata = self.ctx.getImageData(0, 0, self.width, self.height);
};
$loc.__init__ = new Sk.builtin.func(function (self, imageId) {
var susp;
Sk.builtin.pyCheckArgs("__init__", arguments, 2, 2);
try {
self.image = document.getElementById(Sk.ffi.remapToJs(imageId));
initializeImage(self);
} catch (e) {
self.image = null;
}
if (self.image == null) {
susp = new Sk.misceval.Suspension();
susp.resume = function () {
// Should the post image get stuff go here??
if (susp.data["error"]) {
throw new Sk.builtin.IOError(susp.data["error"].message);
}
};
susp.data = {
type: "Sk.promise",
promise: new Promise(function (resolve, reject) {
var newImg = new Image();
newImg.crossOrigin = "";
newImg.onerror = function () {
reject(Error("Failed to load URL: " + newImg.src));
};
newImg.onload = function () {
self.image = this;
initializeImage(self);
resolve();
};
// look for mapping from imagename to url and possible an image proxy server
newImg.src = remapImageIdToURL(imageId);
}
)
};
return susp;
}
});
remapImageIdToURL = function (imageId) {
// if imageId starts with http -- OK
// if imageId is in Sk.imageMap -- look it up
// if imageId is the name of an image file prepend http://host/app/book/_static/
// if image proxy server is configured construct url for proxy
// return the final URL
var url;
var ret;
ret = Sk.ffi.remapToJs(imageId);
url = document.createElement("a");
url.href = ret;
if (window.location.host !== url.host) {
ret = Sk.imageProxy + "/" + ret;
}
return ret;
};
checkPixelRange = function (self, x, y) {
if (x < 0 || y < 0 || x >= self.width || y >= self.height) {
throw new Sk.builtin.ValueError("Pixel index out of range.");
}
};
$loc.setDelay = new Sk.builtin.func(function (self, delay, interval) {
var i;
Sk.builtin.pyCheckArgs("setDelay", arguments, 2, 3);
self.delay = Sk.ffi.remapToJs(delay);
i = Sk.builtin.asnum$(interval);
if (!i) {
self.updateInterval = 1;
} else {
self.updateInterval = i;
}
});
//get a one-dimensional array of pixel objects - Zhu
$loc.getPixels = new Sk.builtin.func(function (self) {
var arr = [];//initial array
var i;
Sk.builtin.pyCheckArgs("getPixels", arguments, 1, 1);
for (i = 0; i < self.image.height * self.image.width; i++) {
arr[i] = Sk.misceval.callsim(self.getPixel, self,
i % self.image.width, Math.floor(i / self.image.width));
}
return new Sk.builtin.tuple(arr);
});
$loc.getPixel = new Sk.builtin.func(function (self, x, y) {
var red;
var blue;
var green;
var index;
Sk.builtin.pyCheckArgs("getPixel", arguments, 3, 3);
x = Sk.builtin.asnum$(x);
y = Sk.builtin.asnum$(y);
checkPixelRange(self, x, y);
index = (y * 4) * self.width + (x * 4);
red = self.imagedata.data[index];
green = self.imagedata.data[index + 1];
blue = self.imagedata.data[index + 2];
return Sk.misceval.callsim(mod.Pixel, red, green, blue, x, y);
});
updateCanvasAndSuspend = function (self, x, y) {
var susp = new Sk.misceval.Suspension();
susp.resume = function () {
return Sk.builtin.none.none$;
};
susp.data = {
type: "Sk.promise",
promise: new Promise(function (resolve, reject) {
self.updateCount++;
if ((self.updateCount % self.updateInterval) === 0) {
if (self.lastx + self.updateInterval >= self.width) {
self.lastCtx.putImageData(self.imagedata, self.lastUlx, self.lastUly,
0, self.lasty, self.width, 2);
} else if (self.lasty + self.updateInterval >= self.height) {
self.lastCtx.putImageData(self.imagedata, self.lastUlx, self.lastUly,
self.lastx, 0, 2, self.height);
} else {
self.lastCtx.putImageData(self.imagedata, self.lastUlx, self.lastUly,
Math.min(x, self.lastx),
Math.min(y, self.lasty),
Math.max(Math.abs(x - self.lastx), 1),
Math.max(Math.abs(y - self.lasty), 1));
}
self.lastx = x;
self.lasty = y;
if (self.delay > 0) {
window.setTimeout(resolve, self.delay);
} else {
resolve();
}
} else {
resolve();
}
})
};
return susp;
};
$loc.setPixel = new Sk.builtin.func(function (self, x, y, pix) {
var index;
Sk.builtin.pyCheckArgs("setPixel", arguments, 4, 4);
x = Sk.builtin.asnum$(x);
y = Sk.builtin.asnum$(y);
checkPixelRange(self, x, y);
index = (y * 4) * self.width + (x * 4);
self.imagedata.data[index] = Sk.builtin.asnum$(Sk.misceval.callsim(pix.getRed, pix));
self.imagedata.data[index + 1] = Sk.builtin.asnum$(Sk.misceval.callsim(pix.getGreen, pix));
self.imagedata.data[index + 2] = Sk.builtin.asnum$(Sk.misceval.callsim(pix.getBlue, pix));
self.imagedata.data[index + 3] = 255;
return updateCanvasAndSuspend(self, x, y);
});
// update the image with the pixel at the given count - Zhu
$loc.setPixelAt = new Sk.builtin.func(function (self, count, pixel) {
var x;
var y;
var index;
Sk.builtin.pyCheckArgs("setPixelAt", arguments, 3, 3);
count = Sk.builtin.asnum$(count);
x = count % self.image.width;
y = Math.floor(count / self.image.width);
checkPixelRange(self, x, y);
index = (y * 4) * self.width + (x * 4);
self.imagedata.data[index] = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getRed, pixel));
self.imagedata.data[index + 1] = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getGreen, pixel));
self.imagedata.data[index + 2] = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getBlue, pixel));
self.imagedata.data[index + 3] = 255;
return updateCanvasAndSuspend(self, x, y);
});
// new updatePixel that uses the saved x and y location in the pixel - Barb Ericson
$loc.updatePixel = new Sk.builtin.func(function (self, pixel) {
var x;
var y;
var index;
Sk.builtin.pyCheckArgs("updatePixel", arguments, 2, 2);
x = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getX, pixel));
y = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getY, pixel));
checkPixelRange(self, x, y);
index = (y * 4) * self.width + (x * 4);
self.imagedata.data[index] = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getRed, pixel));
self.imagedata.data[index + 1] = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getGreen, pixel));
self.imagedata.data[index + 2] = Sk.builtin.asnum$(Sk.misceval.callsim(pixel.getBlue, pixel));
self.imagedata.data[index + 3] = 255;
return updateCanvasAndSuspend(self, x, y);
});
$loc.getHeight = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("getHeight", arguments, 1, 1);
return new Sk.builtin.int_(self.image.height);
});
$loc.getWidth = new Sk.builtin.func(function (self, titlestring) {
Sk.builtin.pyCheckArgs("getWidth", arguments, 1, 1);
return new Sk.builtin.int_(self.image.width);
});
$loc.draw = new Sk.builtin.func(function (self, win, ulx, uly) {
var susp;
Sk.builtin.pyCheckArgs("draw", arguments, 2, 4);
susp = new Sk.misceval.Suspension();
susp.resume = function () {
return Sk.builtin.none.none$;
};
susp.data = {
type: "Sk.promise",
promise: new Promise(function (resolve, reject) {
var can;
var ctx;
win = Sk.builtin.asnum$(win);
ulx = Sk.builtin.asnum$(ulx);
uly = Sk.builtin.asnum$(uly);
can = Sk.misceval.callsim(win.getWin, win);
ctx = can.getContext("2d");
if (!ulx) {
ulx = 0;
uly = 0;
}
self.lastUlx = ulx;
self.lastUly = uly;
self.lastCtx = ctx; // save a reference to the context of the window the image was last drawn in
//ctx.putImageData(self.imagedata,0,0,0,0,self.imagedata.width,self.imagedata.height);
ctx.putImageData(self.imagedata, ulx, uly);
if (self.delay > 0) {
window.setTimeout(resolve, self.delay);
} else {
window.setTimeout(resolve, 200);
}
})
};
return susp;
});
// toList
};
mod.Image = Sk.misceval.buildClass(mod, image, "Image", []);
eImage = function ($gbl, $loc) {
$loc.__init__ = new Sk.builtin.func(function (self, width, height) {
Sk.builtin.pyCheckArgs("__init__", arguments, 3, 3);
self.width = Sk.builtin.asnum$(width);
self.height = Sk.builtin.asnum$(height);
self.canvas = document.createElement("canvas");
self.ctx = self.canvas.getContext("2d");
self.canvas.height = self.height;
self.canvas.width = self.width;
self.imagedata = self.ctx.getImageData(0, 0, self.width, self.height);
});
};
mod.EmptyImage = Sk.misceval.buildClass(mod, eImage, "EmptyImage", [mod.Image]);
// create a ListImage object
pixel = function ($gbl, $loc) {
$loc.__init__ = new Sk.builtin.func(function (self, r, g, b, x, y) {
Sk.builtin.pyCheckArgs("__init__", arguments, 4, 6);
self.red = Sk.builtin.asnum$(r);
self.green = Sk.builtin.asnum$(g);
self.blue = Sk.builtin.asnum$(b);
self.x = Sk.builtin.asnum$(x);
self.y = Sk.builtin.asnum$(y);
});
$loc.getRed = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("getRed", arguments, 1, 1);
return Sk.builtin.assk$(self.red);
});
$loc.getGreen = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("getGreen", arguments, 1, 1);
return Sk.builtin.assk$(self.green);
});
$loc.getBlue = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("getBlue", arguments, 1, 1);
return Sk.builtin.assk$(self.blue);
});
$loc.getX = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("getX", arguments, 1, 1);
return Sk.builtin.assk$(self.x);
});
$loc.getY = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("getY", arguments, 1, 1);
return Sk.builtin.assk$(self.y);
});
$loc.setRed = new Sk.builtin.func(function (self, r) {
Sk.builtin.pyCheckArgs("setRed", arguments, 2, 2);
self.red = Sk.builtin.asnum$(r);
});
$loc.setGreen = new Sk.builtin.func(function (self, g) {
Sk.builtin.pyCheckArgs("setGreen", arguments, 2, 2);
self.green = Sk.builtin.asnum$(g);
});
$loc.setBlue = new Sk.builtin.func(function (self, b) {
Sk.builtin.pyCheckArgs("setBlue", arguments, 2, 2);
self.blue = Sk.builtin.asnum$(b);
});
$loc.setX = new Sk.builtin.func(function (self, x) {
Sk.builtin.pyCheckArgs("setX", arguments, 2, 2);
self.x = Sk.builtin.asnum$(x);
});
$loc.setY = new Sk.builtin.func(function (self, y) {
Sk.builtin.pyCheckArgs("setY", arguments, 2, 2);
self.y = Sk.builtin.asnum$(y);
});
$loc.__getitem__ = new Sk.builtin.func(function (self, k) {
k = Sk.builtin.asnum$(k);
if (k === 0) {
return self.red;
} else if (k == 1) {
return self.green;
} else if (k == 2) {
return self.blue;
}
});
$loc.__str__ = new Sk.builtin.func(function (self) {
return "[" + self.red + "," + self.green + "," + self.blue + "]";
});
//getColorTuple
$loc.getColorTuple = new Sk.builtin.func(function (self, x, y) {
});
//setRange -- change from 0..255 to 0.0 .. 1.0
$loc.setRange = new Sk.builtin.func(function (self, mx) {
self.max = Sk.builtin.asnum$(mx);
});
};
mod.Pixel = Sk.misceval.buildClass(mod, pixel, "Pixel", []);
screen = function ($gbl, $loc) {
$loc.__init__ = new Sk.builtin.func(function (self, width, height) {
var currentCanvas;
var tmpCan, tmpDiv;
Sk.builtin.pyCheckArgs("__init__", arguments, 1, 3);
currentCanvas = ImageMod.canvasLib[Sk.canvas];
if (currentCanvas === undefined) {
tmpCan = document.createElement("canvas");
tmpDiv = document.getElementById(Sk.canvas);
self.theScreen = tmpCan;
tmpDiv.appendChild(tmpCan);
ImageMod.canvasLib[Sk.canvas] = tmpCan;
ImageMod.canvasLib[Sk.canvas] = self.theScreen;
} else {
self.theScreen = currentCanvas;
self.theScreen.height = self.theScreen.height;
}
if (width !== undefined) {
self.theScreen.height = height.v;
self.theScreen.width = width.v;
} else {
if (Sk.availableHeight) {
self.theScreen.height = Sk.availableHeight;
}
if (Sk.availableWidth) {
self.theScreen.width = Sk.availableWidth;
}
}
self.theScreen.style.display = "block";
});
$loc.getWin = new Sk.builtin.func(function (self) {
return self.theScreen;
});
// exitonclick
$loc.exitonclick = new Sk.builtin.func(function (self) {
var canvas_id = self.theScreen.id;
self.theScreen.onclick = function () {
document.getElementById(canvas_id).style.display = "none";
document.getElementById(canvas_id).onclick = null;
delete ImageMod.canvasLib[canvas_id];
};
});
//getMouse
};
mod.ImageWin = Sk.misceval.buildClass(mod, screen, "ImageWin", []);
return mod;
};