jpeg_camera 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 64570f77a25c5034e335b4e59440007d56ceb361
4
+ data.tar.gz: 793cce21b60946b0f6b9e7d56d180ef900de62f1
5
+ SHA512:
6
+ metadata.gz: 6b0d9f6c6d15429d8c0dae0faf16d9850912f658cd26ffe6dfd54a4f927afc8821aaf0f33e6f628fee0851c7f93ef0f3e7da4ec33413efc7f371d5637bda69ff
7
+ data.tar.gz: 955210d1bd55c3697eb8801e2e2b131ba068e8acb7b732e380117c312ddc31006a8013ac0bad7cba1a3feaabd912d3d0be0e2a6c6bbe5d0bbbc7588f63db73a5
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Adam Wróbel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,146 @@
1
+ ## About
2
+
3
+ JpegCamera is a JavaScript library that allows you display a camera stream on
4
+ a web page and then capture, show and upload JPEG snapshots to the server. It
5
+ uses HTML5 in Chrome, Firefox and Opera and falls back to Flash in less capable
6
+ browsers. The video stream is placed without any UI in a container of your
7
+ choice and you control it through JavaScript API and your own UI elements.
8
+
9
+ The idea is based on a similar
10
+ [JpegCam](https://github.com/mattclements/jpegcam) library which was Flash only.
11
+ Beside working without Flash and offering a cleaner, more modern API, JpegCamera
12
+ has some nice, new features.
13
+
14
+ ## Features
15
+
16
+ - Works natively in Chrome, Firefox, Opera and with a Flash plugin in all other
17
+ browsers.
18
+ - Manage and upload multiple snapshots at once. You don't have to wait for the
19
+ first upload to finish before capturing the next image. This means you can
20
+ take a few shots in a short interval.
21
+ - Allows you to retry failed uploads.
22
+ - Easily read server response text and code after upload.
23
+ - Send CSRF tokens to secure your user's session from [Cross-site request
24
+ forgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery#Prevention)
25
+
26
+ ## Dependencies
27
+
28
+ - [Canvas-to-Blob](https://github.com/blueimp/JavaScript-Canvas-to-Blob)
29
+ polyfill for the standard JavaScript `canvas.toBlob` method.
30
+ - [SWFObject](http://code.google.com/p/swfobject/) for embedding the
31
+ Flash-based fallback.
32
+
33
+ For convenience these scripts are packaged with JpegCamera.
34
+
35
+ ## Installation
36
+
37
+ You can load JpegCamera directly on any web page, but if you're writing Rails
38
+ 3.1 application consider using a gem. In either case you have an option
39
+ of loading full library that includes HTML5 implementation with Flash fallback
40
+ or HTML5 version only.
41
+
42
+ ### Standalone app
43
+
44
+ Copy all the files from `dist` into `jpeg_camera` directory under your server's
45
+ root.
46
+
47
+ Load JpegCamera and it's dependencies in the `HEAD` section of your page.
48
+
49
+ <script src="/jpeg_camera/swfobject.min.js" type="text/javascript"></script>
50
+ <script src="/jpeg_camera/canvas-to-blob.min.js" type="text/javascript"></script>
51
+ <script src="/jpeg_camera/jpeg_camera.min.js" type="text/javascript"></script>
52
+
53
+ SWFObject and Canvas-to-Blob are stored in separate files so that you don't have
54
+ to load them again if you already use them in your project. If you want to cut
55
+ down on HTTP requests then there is a concatenated version you can use.
56
+
57
+ <script src="/jpeg_camera/jpeg_camera_with_dependencies.min.js" type="text/javascript"></script>
58
+
59
+ If you want to use HTML5-only version you can load jpeg_camera_no_flash.min.js.
60
+ There is no "with dependencies" version of this file, so you have to remember
61
+ to also load Canvas-to-Blob. You don't need SWFObject for HTML5.
62
+
63
+ ### Ruby on Rails 3.1 applications
64
+
65
+ Require the gem in your Gemfile.
66
+
67
+ gem "jpeg_camera", "~> 1.0.0"
68
+
69
+ Add appropriate requires to your application.js. SWFObject and Canvas-to-Blob
70
+ are stored in separate files so that you don't have to load them again if you
71
+ already use them in your project. The assets pipeline will take care of
72
+ minifying and concatenating everything into one script.
73
+
74
+ //= require jpeg_camera/swfobject
75
+ //= require jpeg_camera/canvas-to-blob
76
+ //= require jpeg_camera/jpeg_camera
77
+
78
+ If you want to use HTML5-only version then use this instead:
79
+
80
+ //= require jpeg_camera/canvas-to-blob
81
+ //= require jpeg_camera/jpeg_camera_no_flash
82
+
83
+ Minified versions of all the scripts are also included in the gem if you don't
84
+ want to include JpegCamera in your application.js file and would rather use
85
+ `javascript_include_tag` on select pages of your application.
86
+
87
+ ## Usage
88
+
89
+ var camera = new JpegCamera("#camera");
90
+
91
+ var snapshot = camera.capture();
92
+
93
+ snapshot.show(); // Display the snapshot
94
+
95
+ snapshot.upload({api_url: "/upload_image"}).done(function(response) {
96
+ response_container.innerHTML = response;
97
+ this.discard(); // discard snapshot and show video stream again
98
+ }).fail(function() {
99
+ alert("Upload failed.");
100
+ });
101
+
102
+ A detailed documentation using in-code comments is maintained for
103
+ [JpegCamera](http://amw.github.io/jpeg_camera/doc/classes/JpegCamera.html) and
104
+ [Snapshot](http://amw.github.io/jpeg_camera/doc/classes/Snapshot.html)
105
+ classes.
106
+
107
+ ## Caveats
108
+
109
+ To use Flash fallback your camera container must be at least 215 pixels wide and
110
+ 138 pixels tall. This is the minimum to display privacy settings dialog.
111
+
112
+ With Flash in some browsers it's impossible to read response body for requests
113
+ that finish with status codes from outside the 2XX range (like 404 Not Found or
114
+ 422 Unprocessable Entity). If you're using version of JpegCamera with Flash
115
+ fallback your application should not rely on reading body of these responses.
116
+ The status code number is always available.
117
+
118
+ ## Contributing
119
+
120
+ The source code is available on [Github](https://github.com/amw/jpeg_camera).
121
+ Please send pull requests on topic branches.
122
+
123
+ To build dist files from source you need `npm` — Node Package Manager.
124
+
125
+ npm install # install required dependencies
126
+ npm install -g grunt-cli # install grunt command
127
+ grunt dist # build js & swf files
128
+ grunt js # only builds js files
129
+ grunt swf # only builds swf file
130
+ grunt doc # update documentation
131
+ grunt # build dist files and update documentation
132
+
133
+ To build swf file you need to have `mxmlc` available in your `$PATH`. It comes
134
+ in the [Flex SDK](http://www.adobe.com/devnet/flex/flex-sdk-download.html).
135
+
136
+ ## Acknowledgements
137
+
138
+ Thanks to Joseph Huckaby for creating and Matt Clements for maintaining
139
+ Flash-based [JpegCam library](http://code.google.com/p/jpegcam/) which I have
140
+ been using until HTML5 became a viable solution. If you're interested here's
141
+ [Matt's repo](https://github.com/mattclements/jpegcam) and here's
142
+ [mine](https://github.com/amw/jpegcam). Thanks to everyone else contributing to
143
+ that project.
144
+
145
+
146
+ Copyright [Adam Wróbel](http://adamwrobel.com), released under the MIT License.
@@ -0,0 +1,6 @@
1
+ require 'jpeg_camera/version'
2
+
3
+ module JpegCamera
4
+ class Engine < ::Rails::Engine
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ require "json"
2
+
3
+ module JpegCamera
4
+ package_file = File.expand_path '../../../package.json', __FILE__
5
+ package_info = JSON.parse File.read(package_file)
6
+ VERSION = package_info["version"]
7
+ HOMEPAGE = package_info["homepage"]
8
+ end
@@ -0,0 +1,95 @@
1
+ /*
2
+ * JavaScript Canvas to Blob 2.0.5
3
+ * https://github.com/blueimp/JavaScript-Canvas-to-Blob
4
+ *
5
+ * Copyright 2012, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ *
11
+ * Based on stackoverflow user Stoive's code snippet:
12
+ * http://stackoverflow.com/q/4998908
13
+ */
14
+
15
+ /*jslint nomen: true, regexp: true */
16
+ /*global window, atob, Blob, ArrayBuffer, Uint8Array, define */
17
+
18
+ (function (window) {
19
+ 'use strict';
20
+ var CanvasPrototype = window.HTMLCanvasElement &&
21
+ window.HTMLCanvasElement.prototype,
22
+ hasBlobConstructor = window.Blob && (function () {
23
+ try {
24
+ return Boolean(new Blob());
25
+ } catch (e) {
26
+ return false;
27
+ }
28
+ }()),
29
+ hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array &&
30
+ (function () {
31
+ try {
32
+ return new Blob([new Uint8Array(100)]).size === 100;
33
+ } catch (e) {
34
+ return false;
35
+ }
36
+ }()),
37
+ BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder ||
38
+ window.MozBlobBuilder || window.MSBlobBuilder,
39
+ dataURLtoBlob = (hasBlobConstructor || BlobBuilder) && window.atob &&
40
+ window.ArrayBuffer && window.Uint8Array && function (dataURI) {
41
+ var byteString,
42
+ arrayBuffer,
43
+ intArray,
44
+ i,
45
+ mimeString,
46
+ bb;
47
+ if (dataURI.split(',')[0].indexOf('base64') >= 0) {
48
+ // Convert base64 to raw binary data held in a string:
49
+ byteString = atob(dataURI.split(',')[1]);
50
+ } else {
51
+ // Convert base64/URLEncoded data component to raw binary data:
52
+ byteString = decodeURIComponent(dataURI.split(',')[1]);
53
+ }
54
+ // Write the bytes of the string to an ArrayBuffer:
55
+ arrayBuffer = new ArrayBuffer(byteString.length);
56
+ intArray = new Uint8Array(arrayBuffer);
57
+ for (i = 0; i < byteString.length; i += 1) {
58
+ intArray[i] = byteString.charCodeAt(i);
59
+ }
60
+ // Separate out the mime component:
61
+ mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
62
+ // Write the ArrayBuffer (or ArrayBufferView) to a blob:
63
+ if (hasBlobConstructor) {
64
+ return new Blob(
65
+ [hasArrayBufferViewSupport ? intArray : arrayBuffer],
66
+ {type: mimeString}
67
+ );
68
+ }
69
+ bb = new BlobBuilder();
70
+ bb.append(arrayBuffer);
71
+ return bb.getBlob(mimeString);
72
+ };
73
+ if (window.HTMLCanvasElement && !CanvasPrototype.toBlob) {
74
+ if (CanvasPrototype.mozGetAsFile) {
75
+ CanvasPrototype.toBlob = function (callback, type, quality) {
76
+ if (quality && CanvasPrototype.toDataURL && dataURLtoBlob) {
77
+ callback(dataURLtoBlob(this.toDataURL(type, quality)));
78
+ } else {
79
+ callback(this.mozGetAsFile('blob', type));
80
+ }
81
+ };
82
+ } else if (CanvasPrototype.toDataURL && dataURLtoBlob) {
83
+ CanvasPrototype.toBlob = function (callback, type, quality) {
84
+ callback(dataURLtoBlob(this.toDataURL(type, quality)));
85
+ };
86
+ }
87
+ }
88
+ if (typeof define === 'function' && define.amd) {
89
+ define(function () {
90
+ return dataURLtoBlob;
91
+ });
92
+ } else {
93
+ window.dataURLtoBlob = dataURLtoBlob;
94
+ }
95
+ }(this));
@@ -0,0 +1 @@
1
+ !function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,n=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),o=n&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,i=(n||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,a,l,u,B;for(e=t.split(",")[0].indexOf("base64")>=0?atob(t.split(",")[1]):decodeURIComponent(t.split(",")[1]),i=new ArrayBuffer(e.length),a=new Uint8Array(i),l=0;l<e.length;l+=1)a[l]=e.charCodeAt(l);return u=t.split(",")[0].split(":")[1].split(";")[0],n?new Blob([o?a:i],{type:u}):(B=new r,B.append(i),B.getBlob(u))};t.HTMLCanvasElement&&!e.toBlob&&(e.mozGetAsFile?e.toBlob=function(t,n,o){o&&e.toDataURL&&i?t(i(this.toDataURL(n,o))):t(this.mozGetAsFile("blob",n))}:e.toDataURL&&i&&(e.toBlob=function(t,e,n){t(i(this.toDataURL(e,n)))})),"function"==typeof define&&define.amd?define(function(){return i}):t.dataURLtoBlob=i}(this);
@@ -0,0 +1,736 @@
1
+ /*! JpegCamera 1.0.0 | 2013-07-29
2
+ (c) 2013 Adam Wrobel
3
+ http://amw.github.io/jpeg_camera */
4
+ (function() {
5
+ var JpegCamera, JpegCameraFlash, JpegCameraHtml5, Snapshot, supported_flash_version, _ref, _ref1,
6
+ __hasProp = {}.hasOwnProperty,
7
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
8
+
9
+ JpegCamera = (function() {
10
+ JpegCamera.DefaultOptions = {
11
+ shutter_url: "/jpeg_camera/shutter.mp3",
12
+ swf_url: "/jpeg_camera/jpeg_camera.swf",
13
+ on_debug: function(message) {
14
+ if (console && console.log) {
15
+ return console.log("JpegCamera: " + message);
16
+ }
17
+ },
18
+ quality: 0.9,
19
+ shutter: true,
20
+ mirror: false,
21
+ timeout: 0
22
+ };
23
+
24
+ function JpegCamera(container, options) {
25
+ if ("string" === typeof container) {
26
+ this.container = document.querySelector(container);
27
+ } else {
28
+ this.container = container;
29
+ }
30
+ if (!(this.container && this.container.offsetWidth)) {
31
+ throw "JpegCamera: invalid container";
32
+ }
33
+ this.container.innerHTML = "";
34
+ this.options = this._extend({}, this.constructor.DefaultOptions, options);
35
+ this._engine_init();
36
+ }
37
+
38
+ JpegCamera.prototype.ready = function(callback) {
39
+ this.options.on_ready = callback;
40
+ if (this.options.on_ready && this._is_ready) {
41
+ this.options.on_ready.call(this);
42
+ }
43
+ return this;
44
+ };
45
+
46
+ JpegCamera.prototype._is_ready = false;
47
+
48
+ JpegCamera.prototype.error = function(callback) {
49
+ this.options.on_error = callback;
50
+ if (this.options.on_error && this._error_occured) {
51
+ this.options.on_error.call(this, this._error_occured);
52
+ }
53
+ return this;
54
+ };
55
+
56
+ JpegCamera.prototype._error_occured = false;
57
+
58
+ JpegCamera.prototype.capture = function(options) {
59
+ var snapshot, _options;
60
+ if (options == null) {
61
+ options = {};
62
+ }
63
+ snapshot = new Snapshot(this, options);
64
+ this._snapshots[snapshot.id] = snapshot;
65
+ _options = snapshot._options();
66
+ if (_options.shutter) {
67
+ this._engine_play_shutter_sound();
68
+ }
69
+ this._engine_capture(snapshot, _options.mirror, _options.quality);
70
+ return snapshot;
71
+ };
72
+
73
+ JpegCamera.prototype._snapshots = {};
74
+
75
+ JpegCamera.prototype.show_stream = function() {
76
+ this._engine_show_stream();
77
+ this._displayed_snapshot = null;
78
+ return this;
79
+ };
80
+
81
+ JpegCamera.prototype.discard_all = function() {
82
+ var id, snapshot, _ref;
83
+ if (this._displayed_snapshot) {
84
+ this.show_stream();
85
+ }
86
+ _ref = this._snapshots;
87
+ for (id in _ref) {
88
+ snapshot = _ref[id];
89
+ this._engine_discard(snapshot);
90
+ snapshot._discarded = true;
91
+ }
92
+ this._snapshots = {};
93
+ return this;
94
+ };
95
+
96
+ JpegCamera.prototype._extend = function(object) {
97
+ var key, source, sources, value, _i, _len;
98
+ sources = Array.prototype.slice.call(arguments, 1);
99
+ for (_i = 0, _len = sources.length; _i < _len; _i++) {
100
+ source = sources[_i];
101
+ if (source) {
102
+ for (key in source) {
103
+ value = source[key];
104
+ object[key] = value;
105
+ }
106
+ }
107
+ }
108
+ return object;
109
+ };
110
+
111
+ JpegCamera.prototype._debug = function(message) {
112
+ if (this.options.on_debug) {
113
+ return this.options.on_debug.call(this, message);
114
+ }
115
+ };
116
+
117
+ JpegCamera.prototype._view_width = function() {
118
+ return parseInt(this.container.offsetWidth, 10);
119
+ };
120
+
121
+ JpegCamera.prototype._view_height = function() {
122
+ return parseInt(this.container.offsetHeight, 10);
123
+ };
124
+
125
+ JpegCamera.prototype._display = function(snapshot) {
126
+ this._engine_display(snapshot);
127
+ return this._displayed_snapshot = snapshot;
128
+ };
129
+
130
+ JpegCamera.prototype._displayed_snapshot = null;
131
+
132
+ JpegCamera.prototype._upload = function(snapshot, api_url, csrf_token, timeout) {
133
+ return this._engine_upload(snapshot, api_url, csrf_token, timeout);
134
+ };
135
+
136
+ JpegCamera.prototype._discard = function(snapshot) {
137
+ if (this._displayed_snapshot === snapshot) {
138
+ this.show_stream();
139
+ }
140
+ this._engine_discard(snapshot);
141
+ snapshot._discarded = true;
142
+ return delete this._snapshots[snapshot.id];
143
+ };
144
+
145
+ JpegCamera.prototype._prepared = function() {
146
+ this._is_ready = true;
147
+ if (this.options.on_ready) {
148
+ return this.options.on_ready.call(this);
149
+ }
150
+ };
151
+
152
+ JpegCamera.prototype._got_error = function(error) {
153
+ this._debug("Error - " + error);
154
+ this._error_occured = error;
155
+ if (this.options.on_error) {
156
+ return this.options.on_error.call(this, this._error_occured);
157
+ }
158
+ };
159
+
160
+ return JpegCamera;
161
+
162
+ })();
163
+
164
+ navigator.getUserMedia || (navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
165
+
166
+ if (navigator.getUserMedia) {
167
+ JpegCameraHtml5 = (function(_super) {
168
+ __extends(JpegCameraHtml5, _super);
169
+
170
+ function JpegCameraHtml5() {
171
+ _ref = JpegCameraHtml5.__super__.constructor.apply(this, arguments);
172
+ return _ref;
173
+ }
174
+
175
+ JpegCameraHtml5.prototype._engine_init = function() {
176
+ var get_user_media_options, horizontal_padding, that, vertical_padding;
177
+ this._debug("Using HTML5 engine");
178
+ this.internal_container = document.createElement("div");
179
+ this.internal_container.style.width = "100%";
180
+ this.internal_container.style.height = "100%";
181
+ this.internal_container.style.position = "relative";
182
+ this.container.appendChild(this.internal_container);
183
+ vertical_padding = Math.floor(this._view_height() * 0.2);
184
+ horizontal_padding = Math.floor(this._view_width() * 0.2);
185
+ this.message = document.createElement("div");
186
+ this.message["class"] = "message";
187
+ this.message.style.width = "100%";
188
+ this.message.style.height = "100%";
189
+ this._add_prefixed_style(this.message, "boxSizing", "border-box");
190
+ this.message.style.overflow = "hidden";
191
+ this.message.style.textAlign = "center";
192
+ this.message.style.paddingTop = "" + vertical_padding + "px";
193
+ this.message.style.paddingBottom = "" + vertical_padding + "px";
194
+ this.message.style.paddingLeft = "" + horizontal_padding + "px";
195
+ this.message.style.paddingRight = "" + horizontal_padding + "px";
196
+ this.message.style.position = "absolute";
197
+ this.message.style.zIndex = 3;
198
+ this.message.innerHTML = "Please allow camera access when prompted by the browser.";
199
+ this.internal_container.appendChild(this.message);
200
+ this.video_container = document.createElement("div");
201
+ this.video_container.style.width = "" + (this._view_width()) + "px";
202
+ this.video_container.style.height = "" + (this._view_height()) + "px";
203
+ this.video_container.style.overflow = "hidden";
204
+ this.video_container.style.position = "absolute";
205
+ this.video_container.style.zIndex = 1;
206
+ this.internal_container.appendChild(this.video_container);
207
+ this.video = document.createElement('video');
208
+ this.video.autoplay = true;
209
+ this._add_prefixed_style(this.video, "transform", "scalex(-1.0)");
210
+ window.AudioContext || (window.AudioContext = window.webkitAudioContext);
211
+ if (window.AudioContext) {
212
+ this._load_shutter_sound();
213
+ }
214
+ get_user_media_options = {
215
+ video: {
216
+ optional: [
217
+ {
218
+ minWidth: 1280
219
+ }, {
220
+ minWidth: 640
221
+ }, {
222
+ minWidth: 480
223
+ }, {
224
+ minWidth: 360
225
+ }
226
+ ]
227
+ }
228
+ };
229
+ that = this;
230
+ return navigator.getUserMedia(get_user_media_options, function(stream) {
231
+ that._remove_message();
232
+ if (window.URL) {
233
+ that.video.src = URL.createObjectURL(stream);
234
+ } else {
235
+ that.video.src = stream;
236
+ }
237
+ return that._wait_for_video_ready();
238
+ }, function(error) {
239
+ var code, key, value;
240
+ code = error.code;
241
+ for (key in error) {
242
+ value = error[key];
243
+ if (key === "code") {
244
+ continue;
245
+ }
246
+ that._got_error(key);
247
+ return;
248
+ }
249
+ return that._got_error("UNKNOWN ERROR");
250
+ });
251
+ };
252
+
253
+ JpegCameraHtml5.prototype._engine_play_shutter_sound = function() {
254
+ var source;
255
+ if (!this.shutter_buffer) {
256
+ return;
257
+ }
258
+ source = this.audio_context.createBufferSource();
259
+ source.buffer = this.shutter_buffer;
260
+ source.connect(this.audio_context.destination);
261
+ return source.start(0);
262
+ };
263
+
264
+ JpegCameraHtml5.prototype._engine_capture = function(snapshot, mirror, quality) {
265
+ var canvas, context, crop;
266
+ crop = this._get_capture_crop();
267
+ canvas = document.createElement("canvas");
268
+ canvas.width = crop.width;
269
+ canvas.height = crop.height;
270
+ context = canvas.getContext("2d");
271
+ context.drawImage(this.video, crop.x_offset, crop.y_offset, crop.width, crop.height, 0, 0, crop.width, crop.height);
272
+ snapshot._canvas = canvas;
273
+ snapshot._mirror = mirror;
274
+ return snapshot._quality = quality;
275
+ };
276
+
277
+ JpegCameraHtml5.prototype._engine_display = function(snapshot) {
278
+ if (this.displayed_canvas) {
279
+ this.internal_container.removeChild(this.displayed_canvas);
280
+ }
281
+ this.displayed_canvas = snapshot._canvas;
282
+ this.displayed_canvas.style.width = "" + (this._view_width()) + "px";
283
+ this.displayed_canvas.style.height = "" + (this._view_height()) + "px";
284
+ this.displayed_canvas.style.top = 0;
285
+ this.displayed_canvas.style.left = 0;
286
+ this.displayed_canvas.style.position = "absolute";
287
+ this.displayed_canvas.style.zIndex = 2;
288
+ this._add_prefixed_style(this.displayed_canvas, "transform", "scalex(-1.0)");
289
+ return this.internal_container.appendChild(this.displayed_canvas);
290
+ };
291
+
292
+ JpegCameraHtml5.prototype._engine_discard = function(snapshot) {
293
+ if (snapshot._xhr) {
294
+ snapshot._xhr.abort();
295
+ }
296
+ delete snapshot._xhr;
297
+ delete snapshot._canvas;
298
+ return delete snapshot._jpeg_blob;
299
+ };
300
+
301
+ JpegCameraHtml5.prototype._engine_show_stream = function() {
302
+ if (this.displayed_canvas) {
303
+ this.internal_container.removeChild(this.displayed_canvas);
304
+ this.displayed_canvas = null;
305
+ }
306
+ return this.video_container.style.display = "block";
307
+ };
308
+
309
+ JpegCameraHtml5.prototype._engine_upload = function(snapshot, api_url, csrf_token, timeout) {
310
+ var canvas, context, handler, that, xhr;
311
+ that = this;
312
+ if (snapshot._jpeg_blob) {
313
+ this._debug("Uploading the file");
314
+ handler = function(event) {
315
+ delete snapshot._xhr;
316
+ snapshot._status = event.target.status;
317
+ snapshot._response = event.target.responseText;
318
+ if (snapshot._status >= 200 && snapshot._status < 300) {
319
+ return snapshot._upload_done();
320
+ } else {
321
+ snapshot._error_message = event.target.statusText || "Unknown error";
322
+ return snapshot._upload_fail();
323
+ }
324
+ };
325
+ xhr = new XMLHttpRequest();
326
+ xhr.open('POST', api_url);
327
+ xhr.timeout = timeout;
328
+ if (csrf_token) {
329
+ xhr.setRequestHeader("X-CSRF-Token", csrf_token);
330
+ }
331
+ xhr.onload = handler;
332
+ xhr.onerror = handler;
333
+ xhr.onabort = handler;
334
+ xhr.send(snapshot._jpeg_blob);
335
+ return snapshot._xhr = xhr;
336
+ } else {
337
+ this._debug("Generating JPEG file");
338
+ if (snapshot._mirror) {
339
+ canvas = document.createElement("canvas");
340
+ canvas.width = snapshot._canvas.width;
341
+ canvas.height = snapshot._canvas.height;
342
+ context = canvas.getContext("2d");
343
+ context.setTransform(1, 0, 0, 1, 0, 0);
344
+ context.translate(canvas.width, 0);
345
+ context.scale(-1, 1);
346
+ context.drawImage(snapshot._canvas, 0, 0);
347
+ } else {
348
+ canvas = snapshot._canvas;
349
+ }
350
+ return canvas.toBlob(function(blob) {
351
+ snapshot._jpeg_blob = blob;
352
+ return that._engine_upload(snapshot, api_url, csrf_token, timeout);
353
+ }, "image/jpeg", this.quality);
354
+ }
355
+ };
356
+
357
+ JpegCameraHtml5.prototype._remove_message = function() {
358
+ return this.message.style.display = "none";
359
+ };
360
+
361
+ JpegCameraHtml5.prototype._load_shutter_sound = function() {
362
+ var request, that;
363
+ if (this.audio_context) {
364
+ return;
365
+ }
366
+ this.audio_context = new AudioContext();
367
+ request = new XMLHttpRequest();
368
+ request.open('GET', this.options.shutter_url, true);
369
+ request.responseType = 'arraybuffer';
370
+ that = this;
371
+ request.onload = function() {
372
+ return that.audio_context.decodeAudioData(request.response, function(buffer) {
373
+ return that.shutter_buffer = buffer;
374
+ });
375
+ };
376
+ return request.send();
377
+ };
378
+
379
+ JpegCameraHtml5.prototype._wait_for_video_ready = function() {
380
+ var crop, that, video_height, video_width;
381
+ video_width = parseInt(this.video.videoWidth);
382
+ video_height = parseInt(this.video.videoHeight);
383
+ if (video_width > 0 && video_height > 0) {
384
+ this.video_container.appendChild(this.video);
385
+ this.video_width = video_width;
386
+ this.video_height = video_height;
387
+ this._debug("Camera resolution " + this.video_width + "x" + this.video_height + "px");
388
+ crop = this._get_video_crop();
389
+ this.video.style.position = "relative";
390
+ this.video.style.width = "" + crop.width + "px";
391
+ this.video.style.height = "" + crop.height + "px";
392
+ this.video.style.left = "" + crop.x_offset + "px";
393
+ this.video.style.top = "" + crop.y_offset + "px";
394
+ return this._prepared();
395
+ } else if (this._status_checks_count > 100) {
396
+ return this._got_error("Camera failed to initialize in 10 seconds");
397
+ } else {
398
+ this._status_checks_count++;
399
+ that = this;
400
+ return setTimeout((function() {
401
+ return that._wait_for_video_ready();
402
+ }), 100);
403
+ }
404
+ };
405
+
406
+ JpegCameraHtml5.prototype._status_checks_count = 0;
407
+
408
+ JpegCameraHtml5.prototype._add_prefixed_style = function(element, style, value) {
409
+ var uppercase_style;
410
+ uppercase_style = style.charAt(0).toUpperCase() + style.slice(1);
411
+ element.style[style] = value;
412
+ element.style["Webkit" + uppercase_style] = value;
413
+ element.style["Moz" + uppercase_style] = value;
414
+ element.style["ms" + uppercase_style] = value;
415
+ return element.style["O" + uppercase_style] = value;
416
+ };
417
+
418
+ JpegCameraHtml5.prototype._get_video_crop = function() {
419
+ var scaled_video_height, scaled_video_width, video_ratio, video_scale, view_height, view_ratio, view_width;
420
+ view_width = this._view_width();
421
+ view_height = this._view_height();
422
+ video_ratio = this.video_width / this.video_height;
423
+ view_ratio = view_width / view_height;
424
+ if (video_ratio >= view_ratio) {
425
+ this._debug("Filling height");
426
+ video_scale = view_height / this.video_height;
427
+ scaled_video_width = Math.round(this.video_width * video_scale);
428
+ return {
429
+ width: scaled_video_width,
430
+ height: view_height,
431
+ x_offset: -Math.floor((scaled_video_width - view_width) / 2.0),
432
+ y_offset: 0
433
+ };
434
+ } else {
435
+ this._debug("Filling width");
436
+ video_scale = view_width / this.video_width;
437
+ scaled_video_height = Math.round(this.video_height * video_scale);
438
+ return {
439
+ width: view_width,
440
+ height: scaled_video_height,
441
+ x_offset: 0,
442
+ y_offset: -Math.floor((scaled_video_height - view_height) / 2.0)
443
+ };
444
+ }
445
+ };
446
+
447
+ JpegCameraHtml5.prototype._get_capture_crop = function() {
448
+ var snapshot_height, snapshot_width, video_ratio, view_height, view_ratio, view_width;
449
+ view_width = this._view_width();
450
+ view_height = this._view_height();
451
+ video_ratio = this.video_width / this.video_height;
452
+ view_ratio = view_width / view_height;
453
+ if (video_ratio >= view_ratio) {
454
+ snapshot_width = Math.round(this.video_height * view_ratio);
455
+ return {
456
+ width: snapshot_width,
457
+ height: this.video_height,
458
+ x_offset: Math.floor((this.video_width - snapshot_width) / 2.0),
459
+ y_offset: 0
460
+ };
461
+ } else {
462
+ snapshot_height = Math.round(this.video_width / view_ratio);
463
+ return {
464
+ width: this.video_width,
465
+ height: snapshot_height,
466
+ x_offset: 0,
467
+ y_offset: Math.floor((this.video_height - snapshot_height) / 2.0)
468
+ };
469
+ }
470
+ };
471
+
472
+ return JpegCameraHtml5;
473
+
474
+ })(JpegCamera);
475
+ ({
476
+ video_width: null,
477
+ video_height: null
478
+ });
479
+ window.JpegCamera = JpegCameraHtml5;
480
+ }
481
+
482
+ supported_flash_version = '9';
483
+
484
+ if (!window.JpegCamera && window.swfobject && swfobject.hasFlashPlayerVersion(supported_flash_version)) {
485
+ JpegCameraFlash = (function(_super) {
486
+ __extends(JpegCameraFlash, _super);
487
+
488
+ function JpegCameraFlash() {
489
+ _ref1 = JpegCameraFlash.__super__.constructor.apply(this, arguments);
490
+ return _ref1;
491
+ }
492
+
493
+ JpegCameraFlash._send_message = function(id, method) {
494
+ var args, instance;
495
+ instance = this._instances[parseInt(id)];
496
+ if (!instance) {
497
+ return;
498
+ }
499
+ args = Array.prototype.slice.call(arguments, 2);
500
+ return this.prototype[method].apply(instance, args);
501
+ };
502
+
503
+ JpegCameraFlash._instances = {};
504
+
505
+ JpegCameraFlash._next_id = 1;
506
+
507
+ JpegCameraFlash.prototype._engine_init = function() {
508
+ var attributes, callback, flash_object_id, flashvars, height, params, that, width;
509
+ this._debug("Using Flash engine");
510
+ this._id = this.constructor._next_id++;
511
+ this.constructor._instances[this._id] = this;
512
+ width = this._view_width();
513
+ height = this._view_height();
514
+ if (width < 215 || height < 138) {
515
+ this._got_error("camera is too small to display privacy dialog");
516
+ return;
517
+ }
518
+ flash_object_id = "flash_object_" + this._id;
519
+ params = {
520
+ loop: "false",
521
+ allowScriptAccess: "always",
522
+ allowFullScreen: "false",
523
+ quality: "best",
524
+ wmode: "opaque",
525
+ menu: "false"
526
+ };
527
+ attributes = {
528
+ id: flash_object_id,
529
+ align: "middle"
530
+ };
531
+ flashvars = {
532
+ id: this._id,
533
+ width: width,
534
+ height: height,
535
+ shutter_url: this.options.shutter_url
536
+ };
537
+ that = this;
538
+ callback = function(event) {
539
+ if (!event.success) {
540
+ return that._got_error("Flash loading failed.");
541
+ } else {
542
+ that._debug("Flash loaded");
543
+ return that._flash = document.getElementById(flash_object_id);
544
+ }
545
+ };
546
+ this.internal_container = document.createElement("div");
547
+ this.internal_container.id = "jpeg_camera_flash_" + this._id;
548
+ this.internal_container.style.width = "100%";
549
+ this.internal_container.style.height = "100%";
550
+ this.container.appendChild(this.internal_container);
551
+ return swfobject.embedSWF(this.options.swf_url, this.internal_container.id, width, height, '9', null, flashvars, params, attributes, callback);
552
+ };
553
+
554
+ JpegCameraFlash.prototype._engine_play_shutter_sound = function() {
555
+ return this._flash._play_shutter();
556
+ };
557
+
558
+ JpegCameraFlash.prototype._engine_capture = function(snapshot, mirror, quality) {
559
+ return this._flash._capture(snapshot.id, mirror, quality);
560
+ };
561
+
562
+ JpegCameraFlash.prototype._engine_display = function(snapshot) {
563
+ return this._flash._display(snapshot.id);
564
+ };
565
+
566
+ JpegCameraFlash.prototype._engine_discard = function(snapshot) {
567
+ return this._flash._discard(snapshot.id);
568
+ };
569
+
570
+ JpegCameraFlash.prototype._engine_show_stream = function() {
571
+ return this._flash._show_stream();
572
+ };
573
+
574
+ JpegCameraFlash.prototype._engine_upload = function(snapshot, api_url, csrf_token, timeout) {
575
+ return this._flash._upload(snapshot.id, api_url, csrf_token, timeout);
576
+ };
577
+
578
+ JpegCameraFlash.prototype._flash_prepared = function() {
579
+ return this._prepared();
580
+ };
581
+
582
+ JpegCameraFlash.prototype._flash_upload_complete = function(snapshot_id, status_code, error, response) {
583
+ var snapshot;
584
+ snapshot_id = parseInt(snapshot_id);
585
+ snapshot = this._snapshots[snapshot_id];
586
+ snapshot._status = parseInt(status_code);
587
+ snapshot._response = response;
588
+ if (snapshot._status >= 200 && snapshot._status < 300) {
589
+ return snapshot._upload_done();
590
+ } else {
591
+ snapshot._error_message = error;
592
+ return snapshot._upload_fail();
593
+ }
594
+ };
595
+
596
+ return JpegCameraFlash;
597
+
598
+ })(JpegCamera);
599
+ window.JpegCamera = JpegCameraFlash;
600
+ }
601
+
602
+ Snapshot = (function() {
603
+ Snapshot._next_snapshot_id = 1;
604
+
605
+ function Snapshot(camera, options) {
606
+ this.camera = camera;
607
+ this.options = options;
608
+ this.id = this.constructor._next_snapshot_id++;
609
+ }
610
+
611
+ Snapshot.prototype._discarded = false;
612
+
613
+ Snapshot.prototype.show = function() {
614
+ if (this._discarded) {
615
+ raise("discarded snapshot cannot be used");
616
+ }
617
+ this.camera._display(this);
618
+ return this;
619
+ };
620
+
621
+ Snapshot.prototype.hide = function() {
622
+ if (this.camera.displayed_snapshot() === this) {
623
+ this.camera.show_stream();
624
+ }
625
+ return this;
626
+ };
627
+
628
+ Snapshot.prototype.upload = function(options) {
629
+ var cache, csrf_token;
630
+ if (options == null) {
631
+ options = {};
632
+ }
633
+ if (this._discarded) {
634
+ raise("discarded snapshot cannot be used");
635
+ }
636
+ if (this._uploading) {
637
+ this._debug("Upload already in progress");
638
+ return;
639
+ }
640
+ this._uploading = true;
641
+ this._upload_options = options;
642
+ cache = this._options();
643
+ if (!cache.api_url) {
644
+ this.camera._debug("Snapshot#upload called without valid api_url");
645
+ throw "Snapshot#upload called without valid api_url";
646
+ }
647
+ if ("string" === typeof cache.csrf_token && cache.csrf_token.length > 0) {
648
+ csrf_token = cache.csrf_token;
649
+ } else {
650
+ csrf_token = null;
651
+ }
652
+ this._done = false;
653
+ this._response = null;
654
+ this._fail = false;
655
+ this._status = null;
656
+ this._error_message = null;
657
+ this.camera._upload(this, cache.api_url, csrf_token, cache.timeout);
658
+ return this;
659
+ };
660
+
661
+ Snapshot.prototype._upload_options = {};
662
+
663
+ Snapshot.prototype._uploading = false;
664
+
665
+ Snapshot.prototype.done = function(callback) {
666
+ var cache;
667
+ if (this._discarded) {
668
+ raise("discarded snapshot cannot be used");
669
+ }
670
+ this._upload_options.on_upload_done = callback;
671
+ cache = this._options();
672
+ if (cache.on_upload_done && this._done) {
673
+ cache.on_upload_done.call(this, this._response);
674
+ }
675
+ return this;
676
+ };
677
+
678
+ Snapshot.prototype._done = false;
679
+
680
+ Snapshot.prototype._response = null;
681
+
682
+ Snapshot.prototype.fail = function(callback) {
683
+ var cache;
684
+ if (this._discarded) {
685
+ raise("discarded snapshot cannot be used");
686
+ }
687
+ this._upload_options.on_upload_fail = callback;
688
+ cache = this._options();
689
+ if (cache.on_upload_fail && this._fail) {
690
+ cache.on_upload_fail.call(this, this._status, this._error_message, this._response);
691
+ }
692
+ return this;
693
+ };
694
+
695
+ Snapshot.prototype._fail = false;
696
+
697
+ Snapshot.prototype._status = null;
698
+
699
+ Snapshot.prototype._error_message = null;
700
+
701
+ Snapshot.prototype.discard = function() {
702
+ this.camera._discard(this);
703
+ return void 0;
704
+ };
705
+
706
+ Snapshot.prototype._options = function() {
707
+ return this.camera._extend({}, this.camera.options, this.options, this._upload_options);
708
+ };
709
+
710
+ Snapshot.prototype._upload_done = function() {
711
+ var cache;
712
+ this.camera._debug("Upload completed");
713
+ this._uploading = false;
714
+ this._done = true;
715
+ cache = this._options();
716
+ if (cache.on_upload_done) {
717
+ return cache.on_upload_done.call(this, this._response);
718
+ }
719
+ };
720
+
721
+ Snapshot.prototype._upload_fail = function() {
722
+ var cache;
723
+ this.camera._debug("Upload failed with status " + this._status);
724
+ this._uploading = false;
725
+ this._fail = true;
726
+ cache = this._options();
727
+ if (cache.on_upload_fail) {
728
+ return cache.on_upload_fail.call(this, this._status, this._error_message, this._response);
729
+ }
730
+ };
731
+
732
+ return Snapshot;
733
+
734
+ })();
735
+
736
+ }).call(this);