diff --git a/guacamole-common-js/src/main/webapp/modules/Client.js b/guacamole-common-js/src/main/webapp/modules/Client.js index 75e1684b4..31b3b398b 100644 --- a/guacamole-common-js/src/main/webapp/modules/Client.js +++ b/guacamole-common-js/src/main/webapp/modules/Client.js @@ -886,6 +886,27 @@ Guacamole.Client = function(tunnel) { }, + "img": function(parameters) { + + var stream_index = parseInt(parameters[0]); + var channelMask = parseInt(parameters[1]); + var layer = getLayer(parseInt(parameters[2])); + var mimetype = parameters[3]; + var x = parseInt(parameters[4]); + var y = parseInt(parameters[5]); + + // Create stream + var stream = streams[stream_index] = new Guacamole.InputStream(guac_client, stream_index); + var reader = new Guacamole.DataURIReader(stream, mimetype); + + // Draw image when stream is complete + reader.onend = function drawImageBlob() { + display.setChannelMask(layer, channelMask); + display.draw(layer, x, y, reader.getURI()); + }; + + }, + "jpeg": function(parameters) { var channelMask = parseInt(parameters[0]); diff --git a/guacamole-common-js/src/main/webapp/modules/DataURIReader.js b/guacamole-common-js/src/main/webapp/modules/DataURIReader.js new file mode 100644 index 000000000..65e9c4d07 --- /dev/null +++ b/guacamole-common-js/src/main/webapp/modules/DataURIReader.js @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +var Guacamole = Guacamole || {}; + +/** + * A reader which automatically handles the given input stream, returning + * received blobs as a single data URI built over the course of the stream. + * Note that this object will overwrite any installed event handlers on the + * given Guacamole.InputStream. + * + * @constructor + * @param {Guacamole.InputStream} stream + * The stream that data will be read from. + */ +Guacamole.DataURIReader = function(stream, mimetype) { + + /** + * Reference to this Guacamole.DataURIReader. + * @private + */ + var guac_reader = this; + + /** + * Current data URI. + * + * @type String + */ + var uri = 'data:' + mimetype + ';base64,'; + + // Receive blobs as array buffers + stream.onblob = function dataURIReaderBlob(data) { + + // Currently assuming data will ALWAYS be safe to simply append. This + // will not be true if the received base64 data encodes a number of + // bytes that isn't a multiple of three (as base64 expands in a ratio + // of exactly 3:4). + uri += data; + + }; + + // Simply call onend when end received + stream.onend = function dataURIReaderEnd() { + if (guac_reader.onend) + guac_reader.onend(); + }; + + /** + * Returns the data URI of all data received through the underlying stream + * thus far. + * + * @returns {String} + * The data URI of all data received through the underlying stream thus + * far. + */ + this.getURI = function getURI() { + return uri; + }; + + /** + * Fired once this stream is finished and no further data will be written. + * + * @event + */ + this.onend = null; + +}; \ No newline at end of file diff --git a/guacamole-common-js/src/main/webapp/modules/Display.js b/guacamole-common-js/src/main/webapp/modules/Display.js index e5fb74610..ab286792f 100644 --- a/guacamole-common-js/src/main/webapp/modules/Display.js +++ b/guacamole-common-js/src/main/webapp/modules/Display.js @@ -527,6 +527,41 @@ Guacamole.Display = function() { }); }; + /** + * Draws the image contained within the specified Blob at the given + * coordinates. The Blob specified must already be populated with image + * data. + * + * @param {Guacamole.Layer} layer + * The layer to draw upon. + * + * @param {Number} x + * The destination X coordinate. + * + * @param {Number} y + * The destination Y coordinate. + * + * @param {Blob} blob + * The Blob containing the image data to draw. + */ + this.drawBlob = function(layer, x, y, blob) { + + // Create URL for blob + var url = URL.createObjectURL(blob); + + // Draw and free blob URL when ready + var task = scheduleTask(function __display_drawBlob() { + layer.drawImage(x, y, image); + URL.revokeObjectURL(url); + }, true); + + // Load image from URL + var image = new Image(); + image.onload = task.unblock; + image.src = url; + + }; + /** * Draws the image at the specified URL at the given coordinates. The image * will be loaded automatically, and this and any future operations will