Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Happy-Ferret/d6ae1535548d102e993b6f6887e49402 to your computer and use it in GitHub Desktop.
Save Happy-Ferret/d6ae1535548d102e993b6f6887e49402 to your computer and use it in GitHub Desktop.
_ff-addon-snippet-gtkScreenshot - Takes screenshot of all monitors on on GTK systems. [jsctypes] [gtk] [gdk]
Cu.import('resource://gre/modules/ctypes.jsm');
var gdk2 = ctypes.open('libgdk-x11-2.0.so.0');
var _void = ctypes.void_t;
var gint = ctypes.int;
var GdkPixbuf = ctypes.StructType('GdkPixbuf');
var GdkDrawable = ctypes.StructType('GdkDrawable');
var GdkColormap = ctypes.StructType('GdkColormap');
var GdkWindow = ctypes.StructType('GdkWindow');
var guchar = ctypes.unsigned_char;
var guint = ctypes.unsigned_int;
var int = ctypes.int;
var gint = ctypes.int;
var gboolean = gint;
// https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#gdk-get-default-root-window
var gdk_get_default_root_window = gdk2.declare('gdk_get_default_root_window', ctypes.default_abi, GdkWindow.ptr);
// https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#gdk-window-get-origin
var gdk_drawable_get_size = gdk2.declare('gdk_drawable_get_size', ctypes.default_abi,
gint, // return
GdkWindow.ptr, // *window
gint.ptr, // *x
gint.ptr // *y
);
// https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#gdk-window-get-origin
var gdk_window_get_origin = gdk2.declare('gdk_window_get_origin', ctypes.default_abi,
gint, // return
GdkWindow.ptr, // *window
gint.ptr, // *x
gint.ptr // *y
);
// https://developer.gnome.org/gdk2/stable/gdk2-Pixbufs.html#gdk-pixbuf-get-from-drawable
var gdk_pixbuf_get_from_drawable = gdk2.declare('gdk_pixbuf_get_from_drawable', ctypes.default_abi,
GdkPixbuf.ptr, // return
GdkPixbuf.ptr, // *dest
GdkDrawable.ptr, // *src
GdkColormap.ptr, // *cmap
int, // src_x
int, // src_y
int, // dest_x
int, // dest_y
int, // width
int // height
);
// https://developer.gnome.org/gdk-pixbuf/unstable/gdk-pixbuf-The-GdkPixbuf-Structure.html#gdk-pixbuf-get-pixels
var gdk_pixbuf_get_pixels = gdk2.declare('gdk_pixbuf_get_pixels', ctypes.default_abi,
guchar.ptr, // return
GdkPixbuf.ptr // *pixbuf
);
// https://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-Utilities.html#gdk-pixbuf-add-alpha
var gdk_pixbuf_add_alpha = gdk2.declare('gdk_pixbuf_add_alpha', ctypes.default_abi,
GdkPixbuf.ptr, // return
GdkPixbuf.ptr, // *pixbuf
gboolean, // substitute_color
guchar, // r
guchar, // g
guchar // b
);
//
var libc = ctypes.open('libc.so.6');
var memcpy = libc.declare('memcpy', OS.Constants.Sys.Name.toLowerCase().indexOf('win') == 0 ? ctypes.winapi_abi : ctypes.default_abi,
ctypes.void_t, // return
ctypes.void_t.ptr, // *dest
ctypes.void_t.ptr, // *src
ctypes.size_t // count
);
var rootGdkWin = gdk_get_default_root_window();
console.info('rootGdkWin:', rootGdkWin.toString());
var x_orig = gint();
var y_orig = gint();
var width = gint();
var height = gint();
var rez_gdkDrawGetSiz = gdk_drawable_get_size(rootGdkWin, width.address(), height.address());
console.info('width:', width.value, 'height:', height.value);
var rez_gdkWinGetOrg = gdk_window_get_origin(rootGdkWin, x_orig.address(), y_orig.address());
console.info('x:', x_orig.value, 'y:', y_orig.value);
var rootGdkDrawable = ctypes.cast(rootGdkWin, GdkDrawable.ptr);
console.time('gdk_pixbuf');
var screenshot = gdk_pixbuf_get_from_drawable(null, rootGdkDrawable, null, x_orig.value, y_orig.value, 0, 0, width.value, height.value);
console.timeEnd('gdk_pixbuf');
console.info('screenshot:', screenshot.toString());
/* METHOD 2 - use c to add alpha
console.time('gdk_rgba');
var screenshot_with_a = gdk_pixbuf_add_alpha(screenshot, false, 0, 0, 0);
console.timeEnd('gdk_rgba');
console.time('gdk_pixels');
var rgba = gdk_pixbuf_get_pixels(screenshot_with_a);
console.timeEnd('gdk_pixels');
var n_channels = 4;
var pixbuf_len = width.value * height.value * n_channels;
// console.time('cast pixels');
// var casted_rgba = ctypes.cast(rgba, guchar.array(pixbuf_len).ptr).contents;
// console.timeEnd('cast pixels');
// console.info('casted_rgba:', casted_rgba, casted_rgba[0], casted_rgba[1], casted_rgba[2], casted_rgba[3]);
console.time('init imagedata');
var imagedata = new ImageData(width.value, height.value);
console.timeEnd('init imagedata');
console.time('memcpy');
memcpy(imagedata.data, rgba, pixbuf_len);
console.timeEnd('memcpy');
//*/
///* METHOD 1 - use js to add alpha
console.time('gdk_pixels');
var rgb = gdk_pixbuf_get_pixels(screenshot);
console.timeEnd('gdk_pixels');
var n_channels = 3;
var pixbuf_len = width.value * height.value * n_channels;
// console.time('cast pixels');
// var casted_rgb = ctypes.cast(rgba, guchar.array(pixbuf_len).ptr).contents;
// console.timeEnd('cast pixels');
// console.info('casted_rgb:', casted_rgb, casted_rgb[0], casted_rgb[1], casted_rgb[2], casted_rgb[3]);
console.time('init imagedata');
var imagedata = new ImageData(width.value, height.value);
console.timeEnd('init imagedata');
console.time('memcpy');
memcpy(imagedata.data, rgb, pixbuf_len);
console.timeEnd('memcpy');
var pixbuf_pos = pixbuf_len - 1;
var dataRef = imagedata.data;
var dataRef_pos = parseInt(imagedata.data.length)- 1;
console.time('js_rgba');
while (dataRef_pos > -1) {
dataRef[dataRef_pos-3] = dataRef[pixbuf_pos-2];
dataRef[dataRef_pos-2] = dataRef[pixbuf_pos-1];
dataRef[dataRef_pos-1] = dataRef[pixbuf_pos];
dataRef[dataRef_pos] = 255;
pixbuf_pos -= 3;
dataRef_pos -= 4;
}
console.timeEnd('js_rgba');
console.info('ok rgba done, pixbuf_pos:', pixbuf_pos, 'dataRef_pos:', dataRef_pos);
//*/
var idat = imagedata;
var NS_HTML = 'http://www.w3.org/1999/xhtml';
var can = document.createElementNS(NS_HTML, 'canvas');
can.width = width.value;
can.height = height.value;
var ctx = can.getContext('2d');
ctx.putImageData(idat, 0, 0);
gBrowser.contentDocument.documentElement.appendChild(can);
gdk2.close();
libc.close();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment