/* // // ImageSaver // JSActions helper script // capture specified rect and returns input stream. // // Original auther: KUMAGAI Kentaro // // Released under the Creative Commons Attribution-ShareAlike licence. // http://creativecommons.org/licenses/by-sa/3.0/ // */ var ImageSaver = { VERSION: "0.0.1", GUI: { style: null, // to change cursor to crosshair. status: null, from: null, to: null, rect: null, onkeypress: null, onmousedown: null, onmousemove: null, on_rect_selected: null, saving_text: 'Saving...', dim: { x: {prop: 'width', origin: 'left'}, y: {prop: 'height', origin: 'top'} }, show_text: function (text) { var doc = window._content.document; var d = doc.createElement('div'); d.innerHTML = text; d.style.position = 'fixed'; d.style.top = '2px'; d.style.right = '2px'; d.style.color = 'white'; d.style.backgroundColor = '#E72D89'; d.style.padding = '5px'; d.style.zIndex = 2100000000; doc.body.appendChild(d); this.status = d; }, close_text_delayed: function (html, duration) { duration = duration || 20 * 1000; this.status.innerHTML = html; this.status.style.backgroundColor = '#0063DC'; window.setTimeout( function () { this.status.parentNode.removeChild( this.status ); }.bind(this), duration ); }, update_rect: function (e) { var to = {x: e.clientX, y: e.clientY}; var x, y; for ( var n in this.dim ) { var v = this.dim[n]; var t; if ( ( t = to[n] - this.from[n] ) < 0 ) { this.rect.style[v.origin] = (this.from[n] + t) + 'px'; } this.rect.style[v.prop] = Math.abs(t) + 'px'; } this.rect.style.height = (to.y - this.from.y ) + 'px'; }, start_select_rect: function ( on_rect_selected ) { this.on_rect_selected = on_rect_selected; this.onkeypress = this.key_pressed.bind(this); this.onmousemove = this.update_rect.bind(this); this.onmousedown = this.select_rect.bind(this); var d = window._content.document; d.addEventListener( 'click', this.onclick, true ); d.addEventListener( 'keypress', this.onkeypress, true ); d.addEventListener( 'mousedown', this.onmousedown, true ); var s = d.createElement('style'); s.innerHTML = '* {cursor: crosshair !important;}'; d.body.appendChild(s); this.style = s; }, cancel_capture: function (e) { this.stop_event_listening(); this.show_text(''); this.close_text_delayed('Canceled', 3 * 1000); }, cleanup: function ( html ) { this.close_text_delayed(html); }, stop_event_listening: function () { var d = window._content.document; d.removeEventListener( 'click', this.onclick, true ); d.removeEventListener( 'keypress', this.onkeypress, true ); d.removeEventListener( 'mousedown', this.onmousedown, true ); if ( this.onmousemove ) { d.removeEventListener( 'mousemove', this.onmousemove, true ); } this.style.parentNode.removeChild( this.style ); if ( this.rect ) { this.rect.parentNode.removeChild(this.rect); } }, select_rect: function (e) { if ( this.from == null ) { this.from = {x: e.clientX, y: e.clientY}; var d = window._content.document; this.rect = d.createElement('div'); this.rect.style.outlineWidth = '2px'; this.rect.style.outlineStyle = 'dotted'; this.rect.style.outlineColor = '#0063DC'; this.rect.style.backgroundColor = '#0063DC'; this.rect.style.opacity = '0.5'; this.rect.style.position = 'fixed'; this.rect.style.width = '0px'; this.rect.style.height = '0px'; this.rect.style.zIndex = 2100000000; this.rect.style.top = this.from.y + 'px', this.rect.style.left = this.from.x + 'px', d.body.appendChild(this.rect); d.addEventListener( 'mousemove', this.onmousemove, true ); } else if ( this.to == null ) { this.to = {x: e.clientX, y: e.clientY}; var rect = {}; ["top", "left", "width", "height"].forEach( function(n) { rect[n] = parseInt( this.rect.style[n] ); }.bind(this) ); this.stop_event_listening(); this.on_rect_selected( rect ); } return false; }, onclick: function (e) { e.preventDefault(); return false; }, key_pressed: function(e) { if ( e.keyCode == e.DOM_VK_ESCAPE ) { this.cancel_capture(); return false; } return true; }, }, capture_rect: function ( canvas_stream_reader ) { this.GUI.start_select_rect( function (rect) { var canvas_stream = this.capture(rect); this.GUI.show_text( this.GUI.saving_text ); var title = (window._content.document.title); canvas_stream_reader.apply(this, [ canvas_stream, title ] ); this.destroy_canvas(this.canvas); }.bind(this) ); }, copy: function ( rect ) { }, /** need to call destroy_canvas() to delete canvas. @return nsIInputStream of canvas **/ capture: function (rect) { rect = rect || { left: 0, top: 0, width: window._content.document.width, height: window._content.document.height }; this.create_canvas(rect); var ctx = this.canvas.getContext("2d"); ctx.clearRect(0, 0, rect.width, rect.height); ctx.save(); ctx.scale(1.0, 1.0); var x1 = rect.left + window.pageXOffset; var x2 = rect.left + rect.width + window.pageXOffset; var y1 = rect.top + window.pageYOffset; var y2 = rect.top + rect.height + window.pageYOffset; ctx.drawWindow(window._content, x1, y1, x2, y2, "rgb(255,255,255)"); ctx.restore(); try { var url = this.canvas.toDataURL("image/png"); } catch(ex) { return alert("This feature requires Firefox 2.0.\n" + ex); } const IO_SERVICE = Components.classes['@mozilla.org/network/io-service;1'] .getService(Components.interfaces.nsIIOService); url = IO_SERVICE.newURI(url, null, null); var channel = IO_SERVICE.newChannelFromURI( url ); var input = channel.open(); return input; }, create_canvas: function (rect) { var d = window._content.document; var canvas = d.createElement('canvas'); canvas.setAttribute("id", "svcanvas"); canvas.style.display = "inline"; canvas.width = rect.width; canvas.height = rect.height; var statusbar = ( top.document.getElementById('status-bar') ); var body = ( d.getElementsByTagName('body') ); var p = body[0]; p.appendChild(canvas); this.canvas = canvas; }, destroy_canvas: function (canvas) { canvas.parentNode.removeChild(canvas); //canvas.style.display = "none"; //canvas.width = 1; //canvas.height = 1; } };