partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 12de4ceb6109196827bf6058b838e39c4a9db5f5
parent e5ce4d688650ccb41b83c5a7001d63586fd6bfbc
Author: Felicitus <felicitus@felicitus.org>
Date:   Sun, 10 Jul 2011 03:50:40 +0200

Added file upload support via webcam

Diffstat:
Mfrontend/index.php | 3++-
Mfrontend/js/Components/Widgets/AttachmentGrid.js | 22++++++++++++++++++++++
Afrontend/js/Components/Widgets/WebcamPanel.js | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afrontend/js/webcam.js | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afrontend/resources/webcam.swf | 0
Msrc/de/RaumZeitLabor/PartKeepr/TempFile/TempFileService.php | 17+++++++++++++++++
6 files changed, 299 insertions(+), 1 deletion(-)

diff --git a/frontend/index.php b/frontend/index.php @@ -34,7 +34,8 @@ include("config.php"); <?php } ?> - <script type="text/javascript" src="js/org.phpjs.lib/php.default.min.js" defer="defer"></script> + <script type="text/javascript" src="js/org.phpjs.lib/php.default.min.js"></script> + <script type="text/javascript" src="js/webcam.js"></script> </head> <body> diff --git a/frontend/js/Components/Widgets/AttachmentGrid.js b/frontend/js/Components/Widgets/AttachmentGrid.js @@ -42,6 +42,13 @@ Ext.define('PartKeepr.AttachmentGrid', { disabled: true }); + this.webcamButton = Ext.create("Ext.button.Button", { + text: i18n("Take image"), + handler: this.onWebcamClick, + scope: this, + icon: 'resources/fugue-icons/icons/webcam.png' + }); + this.dockedItems = [{ xtype: 'toolbar', items: [{ @@ -50,6 +57,7 @@ Ext.define('PartKeepr.AttachmentGrid', { icon: 'resources/silkicons/attach.png', handler: this.onAddClick }, + this.webcamButton, this.viewButton, this.deleteButton ] @@ -90,6 +98,20 @@ Ext.define('PartKeepr.AttachmentGrid', { this.getSelectionModel().on('selectionchange', this.onSelectChange, this); this.on("itemdblclick", this.onDoubleClick, this); }, + onWebcamClick: function () { + var wp = Ext.create("PartKeepr.WebcamPanel"); + wp.on("uploadComplete", this.onFileUploaded, this); + + var j = Ext.create("Ext.window.Window", { + items: [ + wp + ] + }); + + wp.on("uploadComplete", function () { j.close(); }); + + j.show(); + }, onDoubleClick: function (view, record) { if (record) { this.viewAttachment(record); diff --git a/frontend/js/Components/Widgets/WebcamPanel.js b/frontend/js/Components/Widgets/WebcamPanel.js @@ -0,0 +1,60 @@ +/** + * Creates a panel with a webcam widget. The webcam widget is + * a flash (jpegcam). + */ +Ext.define('PartKeepr.WebcamPanel', { + extend: 'Ext.panel.Panel', + alias: 'widget.WebcamPanel', + initComponent: function () { + // Create a toolbar with the "take photo" button + this.bbar = Ext.create("Ext.toolbar.Toolbar", { + enableOverflow: true, + items: [ + { + xtype: 'button', + text: i18n("Take picture and upload"), + icon: 'resources/fugue-icons/icons/webcam.png', + handler: this.takePhoto + } + ] + }); + + // Render the SWF + this.on("afterrender", this.renderWebcam, this); + + // Fires when the image upload is complete + this.addEvents("uploadComplete"); + this.callParent(); + }, + /** + * Renders the webcam swf. + * @param e The element for this component + */ + renderWebcam: function (e) { + webcam.set_swf_url("resources/webcam.swf"); + webcam.set_quality(90); + webcam.set_api_url(PartKeepr.getBasePath()+"?service=TempFile&call=uploadCam&session="+PartKeepr.getApplication().getSession()); + webcam.set_shutter_sound(false); + webcam.set_hook('onComplete', Ext.bind(this.onUploadComplete, this)); + + e.body.insertHtml('beforeEnd', webcam.get_html(640,480, 640, 480)); + }, + /** + * Takes a photo using the webcam. + */ + takePhoto: function () { + webcam.snap(); + }, + /** + * Called when the upload is complete. Resumes webcam operation + * and fires the event. 'uploadComplete' + * @param message The server side message + */ + onUploadComplete: function (message) { + var response = Ext.decode(message); + + webcam.reset(); + this.fireEvent("uploadComplete", response.response); + + } +});+ \ No newline at end of file diff --git a/frontend/js/webcam.js b/frontend/js/webcam.js @@ -0,0 +1,197 @@ +/* JPEGCam v1.0.9 */ +/* Webcam library for capturing JPEG images and submitting to a server */ +/* Copyright (c) 2008 - 2009 Joseph Huckaby <jhuckaby@goldcartridge.com> */ +/* Licensed under the GNU Lesser Public License */ +/* http://www.gnu.org/licenses/lgpl.html */ + +/* Usage: + <script language="JavaScript"> + document.write( webcam.get_html(320, 240) ); + webcam.set_api_url( 'test.php' ); + webcam.set_hook( 'onComplete', 'my_callback_function' ); + function my_callback_function(response) { + alert("Success! PHP returned: " + response); + } + </script> + <a href="javascript:void(webcam.snap())">Take Snapshot</a> +*/ + +// Everything is under a 'webcam' Namespace +window.webcam = { + version: '1.0.9', + + // globals + ie: !!navigator.userAgent.match(/MSIE/), + protocol: location.protocol.match(/https/i) ? 'https' : 'http', + callback: null, // user callback for completed uploads + swf_url: 'webcam.swf', // URI to webcam.swf movie (defaults to cwd) + shutter_url: 'shutter.mp3', // URI to shutter.mp3 sound + api_url: '', // URL to upload script + loaded: false, // true when webcam movie finishes loading + quality: 90, // JPEG quality (1 - 100) + shutter_sound: true, // shutter sound effect on/off + stealth: false, // stealth mode (do not freeze image upon capture) + hooks: { + onLoad: null, + onComplete: null, + onError: null + }, // callback hook functions + + set_hook: function(name, callback) { + // set callback hook + // supported hooks: onLoad, onComplete, onError + if (typeof(this.hooks[name]) == 'undefined') + return alert("Hook type not supported: " + name); + + this.hooks[name] = callback; + }, + + fire_hook: function(name, value) { + // fire hook callback, passing optional value to it + if (this.hooks[name]) { + if (typeof(this.hooks[name]) == 'function') { + // callback is function reference, call directly + this.hooks[name](value); + } + else if (typeof(this.hooks[name]) == 'array') { + // callback is PHP-style object instance method + this.hooks[name][0][this.hooks[name][1]](value); + } + else if (window[this.hooks[name]]) { + // callback is global function name + window[ this.hooks[name] ](value); + } + return true; + } + return false; // no hook defined + }, + + set_api_url: function(url) { + // set location of upload API script + this.api_url = url; + }, + + set_swf_url: function(url) { + // set location of SWF movie (defaults to webcam.swf in cwd) + this.swf_url = url; + }, + + get_html: function(width, height, server_width, server_height) { + // Return HTML for embedding webcam capture movie + // Specify pixel width and height (640x480, 320x240, etc.) + // Server width and height are optional, and default to movie width/height + if (!server_width) server_width = width; + if (!server_height) server_height = height; + + var html = ''; + var flashvars = 'shutter_enabled=' + (this.shutter_sound ? 1 : 0) + + '&shutter_url=' + escape(this.shutter_url) + + '&width=' + width + + '&height=' + height + + '&server_width=' + server_width + + '&server_height=' + server_height; + + if (this.ie) { + html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+this.protocol+'://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="webcam_movie" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+this.swf_url+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/></object>'; + } + else { + html += '<embed id="webcam_movie" src="'+this.swf_url+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="webcam_movie" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" />'; + } + + this.loaded = false; + return html; + }, + + get_movie: function() { + // get reference to movie object/embed in DOM + if (!this.loaded) return alert("ERROR: Movie is not loaded yet"); + var movie = document.getElementById('webcam_movie'); + if (!movie) alert("ERROR: Cannot locate movie 'webcam_movie' in DOM"); + return movie; + }, + + set_stealth: function(stealth) { + // set or disable stealth mode + this.stealth = stealth; + }, + + snap: function(url, callback, stealth) { + // take snapshot and send to server + // specify fully-qualified URL to server API script + // and callback function (string or function object) + if (callback) this.set_hook('onComplete', callback); + if (url) this.set_api_url(url); + if (typeof(stealth) != 'undefined') this.set_stealth( stealth ); + + this.get_movie()._snap( this.api_url, this.quality, this.shutter_sound ? 1 : 0, this.stealth ? 1 : 0 ); + }, + + freeze: function() { + // freeze webcam image (capture but do not upload) + this.get_movie()._snap('', this.quality, this.shutter_sound ? 1 : 0, 0 ); + }, + + upload: function(url, callback) { + // upload image to server after taking snapshot + // specify fully-qualified URL to server API script + // and callback function (string or function object) + if (callback) this.set_hook('onComplete', callback); + if (url) this.set_api_url(url); + + this.get_movie()._upload( this.api_url ); + }, + + reset: function() { + // reset movie after taking snapshot + this.get_movie()._reset(); + }, + + configure: function(panel) { + // open flash configuration panel -- specify tab name: + // "camera", "privacy", "default", "localStorage", "microphone", "settingsManager" + if (!panel) panel = "camera"; + this.get_movie()._configure(panel); + }, + + set_quality: function(new_quality) { + // set the JPEG quality (1 - 100) + // default is 90 + this.quality = new_quality; + }, + + set_shutter_sound: function(enabled, url) { + // enable or disable the shutter sound effect + // defaults to enabled + this.shutter_sound = enabled; + this.shutter_url = url ? url : 'shutter.mp3'; + }, + + flash_notify: function(type, msg) { + // receive notification from flash about event + switch (type) { + case 'flashLoadComplete': + // movie loaded successfully + this.loaded = true; + this.fire_hook('onLoad'); + break; + + case 'error': + // HTTP POST error most likely + if (!this.fire_hook('onError', msg)) { + alert("JPEGCam Flash Error: " + msg); + } + break; + + case 'success': + // upload complete, execute user callback function + // and pass raw API script results to function + this.fire_hook('onComplete', msg.toString()); + break; + + default: + // catch-all, just in case + alert("jpegcam flash_notify: " + type + ": " + msg); + break; + } + } +}; diff --git a/frontend/resources/webcam.swf b/frontend/resources/webcam.swf Binary files differ. diff --git a/src/de/RaumZeitLabor/PartKeepr/TempFile/TempFileService.php b/src/de/RaumZeitLabor/PartKeepr/TempFile/TempFileService.php @@ -27,5 +27,22 @@ class TempFileService extends Service { return array("id" => $tmpFile->getId(), "extension" => $tmpFile->getExtension(), "size" => $tmpFile->getSize(), "originalFilename" => $tmpFile->getOriginalFilename()); } + + /** + * Processes data via HTTP POST. Reads php://input and creates a temporary image out of it. + */ + public function uploadCam () { + $tempFile = tempnam("/tmp", "PWC") . ".jpg"; + $result = file_put_contents( $tempFile, file_get_contents('php://input') ); + + $image = new TempUploadedFile(); + $image->replace($tempFile); + $image->setOriginalFilename(sprintf(PartKeepr::i18n("Cam photo of %s"), date("Y-m-d H:i:s")).".jpg"); + + PartKeepr::getEM()->persist($image); + PartKeepr::getEM()->flush(); + + return array("id" => $image->getId(), "extension" => $image->getExtension(), "size" => $image->getSize(), "originalFilename" => $image->getOriginalFilename()); + } } \ No newline at end of file