jpeg_camera 1.0.2 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b34d1a1ff1a8ef2e17e01a2cded7304a1fc58c6f
4
- data.tar.gz: 937b143f723694535e65d9467f413e1c58f2f1a9
3
+ metadata.gz: 3a7c6193f58611135096435b910e2e8993c3b9e2
4
+ data.tar.gz: c7b3cefe427aad352edb709cbb69c7ad68e6af8b
5
5
  SHA512:
6
- metadata.gz: 8cb35009a29f678f51a3bdd2325acd44ca446fa379683629acdf5e9de40089bc191e7998ed78b58c5e02734eaeb84007f66226e870a87357aee6b95b2426a74e
7
- data.tar.gz: dc32b6a1034e5e07726fb57f3aa1a1414a53ad6f09dcb3a206149b2435574058f62b9ab211ca9d60edaf416223d4503b2bd4f3ee1aea1ed9b1cd767dbb5cab2d
6
+ metadata.gz: 4c5bf844429a15859fdee5e5cbce30109d675887a22a00271e2fbe69b60a854897cf8458b023bc4ace060efe8776ac969081ca895c2020f532608d67c6f53298
7
+ data.tar.gz: 344a2fc9f83f7447379e52a65f0c9b595983a1e9cc675b6ec7f70433ac53c9842dfc108766fb81780439053eaeeda89bd05083218d7a730fdb8c4820b0adda1f
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## About
2
2
 
3
- JpegCamera is a JavaScript library that allows you display a camera stream on
3
+ JpegCamera is a JavaScript library that allows you to display a camera stream on
4
4
  a web page and then capture, show and upload JPEG snapshots to the server. It
5
5
  uses HTML5 in Chrome, Firefox and Opera and falls back to Flash in less capable
6
6
  browsers. The video stream is placed without any UI in a container of your
@@ -18,10 +18,20 @@ has some nice, new features.
18
18
  - Manage and upload multiple snapshots at once. You don't have to wait for the
19
19
  first upload to finish before capturing the next image. This means you can
20
20
  take a few shots in a short interval.
21
+ - You can get snapshots for display outside the camera container in browsers
22
+ that support `canvas` element - even when using Flash fallback.
21
23
  - Allows you to retry failed uploads.
22
24
  - Easily read server response text and code after upload.
23
25
  - Send CSRF tokens to secure your user's session from [Cross-site request
24
26
  forgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery#Prevention)
27
+ - Prevents users from messing with HTML5 VIDEO or Flash object elements
28
+ by overlaying transparent DIV over them after initialization.
29
+ - Makes sure the camera is really ready by checking stream's color standard
30
+ deviation. Safeguard from weird all-black or all-white snapshots.
31
+
32
+ ## Demo
33
+
34
+ Check out the [demo page](http://amw.github.io/jpeg_camera/demo/).
25
35
 
26
36
  ## Dependencies
27
37
 
@@ -64,7 +74,7 @@ to also load Canvas-to-Blob. You don't need SWFObject for HTML5.
64
74
 
65
75
  Require the gem in your Gemfile.
66
76
 
67
- gem "jpeg_camera", "~> 1.0.2"
77
+ gem "jpeg_camera", "~> 1.1.1"
68
78
 
69
79
  Add appropriate requires to your application.js. SWFObject and Canvas-to-Blob
70
80
  are stored in separate files so that you don't have to load them again if you
@@ -115,6 +125,10 @@ that finish with status codes from outside the 2XX range (like 404 Not Found or
115
125
  fallback your application should not rely on reading body of these responses.
116
126
  The status code number is always available.
117
127
 
128
+ Current stable versions of Firefox and Opera support getUserMedia, but do not
129
+ support Web Audio API. I have decided against loading a Flash object in
130
+ these browsers so JpegCamera will be silent.
131
+
118
132
  ## Contributing
119
133
 
120
134
  The source code is available on [Github](https://github.com/amw/jpeg_camera).
@@ -1,8 +1,8 @@
1
- /*! JpegCamera 1.0.2 | 2013-07-30
1
+ /*! JpegCamera 1.1.1 | 2013-08-05
2
2
  (c) 2013 Adam Wrobel
3
3
  http://amw.github.io/jpeg_camera */
4
4
  (function() {
5
- var JpegCamera, JpegCameraFlash, JpegCameraHtml5, Snapshot, supported_flash_version, _ref, _ref1,
5
+ var JpegCamera, JpegCameraFlash, JpegCameraHtml5, Snapshot, check_canvas_to_blob, supported_flash_version, _ref, _ref1,
6
6
  __hasProp = {}.hasOwnProperty,
7
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
8
 
@@ -22,16 +22,25 @@
22
22
  retry_success: false
23
23
  };
24
24
 
25
+ JpegCamera._canvas_supported = !!document.createElement('canvas').getContext;
26
+
27
+ JpegCamera.canvas_supported = function() {
28
+ return this._canvas_supported;
29
+ };
30
+
25
31
  function JpegCamera(container, options) {
26
32
  if ("string" === typeof container) {
27
- this.container = document.querySelector(container);
28
- } else {
29
- this.container = container;
33
+ container = document.getElementById(container.replace("#", ""));
30
34
  }
31
- if (!(this.container && this.container.offsetWidth)) {
35
+ if (!(container && container.offsetWidth)) {
32
36
  throw "JpegCamera: invalid container";
33
37
  }
34
- this.container.innerHTML = "";
38
+ container.innerHTML = "";
39
+ this.container = document.createElement("div");
40
+ this.container.style.width = "100%";
41
+ this.container.style.height = "100%";
42
+ this.container.style.position = "relative";
43
+ container.appendChild(this.container);
35
44
  this.options = this._extend({}, this.constructor.DefaultOptions, options);
36
45
  this._engine_init();
37
46
  }
@@ -56,6 +65,18 @@
56
65
 
57
66
  JpegCamera.prototype._error_occured = false;
58
67
 
68
+ JpegCamera.StatsCaptureScale = 0.2;
69
+
70
+ JpegCamera.prototype.get_stats = function(callback) {
71
+ var snapshot, that;
72
+ snapshot = new Snapshot(this, {});
73
+ this._engine_capture(snapshot, false, 0.1, JpegCamera.StatsCaptureScale);
74
+ that = this;
75
+ return snapshot.get_stats(function(stats) {
76
+ return callback.call(that, stats);
77
+ });
78
+ };
79
+
59
80
  JpegCamera.prototype.capture = function(options) {
60
81
  var snapshot, _options;
61
82
  if (options == null) {
@@ -67,7 +88,7 @@
67
88
  if (_options.shutter) {
68
89
  this._engine_play_shutter_sound();
69
90
  }
70
- this._engine_capture(snapshot, _options.mirror, _options.quality);
91
+ this._engine_capture(snapshot, _options.mirror, _options.quality, 1.0);
71
92
  return snapshot;
72
93
  };
73
94
 
@@ -130,10 +151,6 @@
130
151
 
131
152
  JpegCamera.prototype._displayed_snapshot = null;
132
153
 
133
- JpegCamera.prototype._upload = function(snapshot, api_url, csrf_token, timeout) {
134
- return this._engine_upload(snapshot, api_url, csrf_token, timeout);
135
- };
136
-
137
154
  JpegCamera.prototype._discard = function(snapshot) {
138
155
  if (this._displayed_snapshot === snapshot) {
139
156
  this.show_stream();
@@ -144,10 +161,33 @@
144
161
  };
145
162
 
146
163
  JpegCamera.prototype._prepared = function() {
147
- this._is_ready = true;
148
- if (this.options.on_ready) {
149
- return this.options.on_ready.call(this);
150
- }
164
+ var that;
165
+ that = this;
166
+ return setTimeout((function() {
167
+ return that._wait_until_stream_looks_ok(true);
168
+ }), 1);
169
+ };
170
+
171
+ JpegCamera.prototype._wait_until_stream_looks_ok = function(show_debug) {
172
+ return this.get_stats(function(stats) {
173
+ var that;
174
+ if (stats.std > 2) {
175
+ this._debug("Stream mean gray value = " + stats.mean + " standard deviation = " + stats.std);
176
+ this._debug("Camera is ready");
177
+ this._is_ready = true;
178
+ if (this.options.on_ready) {
179
+ return this.options.on_ready.call(this);
180
+ }
181
+ } else {
182
+ if (show_debug) {
183
+ this._debug("Stream mean gray value = " + stats.mean + " standard deviation = " + stats.std);
184
+ }
185
+ that = this;
186
+ return setTimeout((function() {
187
+ return that._wait_until_stream_looks_ok(false);
188
+ }), 100);
189
+ }
190
+ });
151
191
  };
152
192
 
153
193
  JpegCamera.prototype._got_error = function(error) {
@@ -158,13 +198,45 @@
158
198
  }
159
199
  };
160
200
 
201
+ JpegCamera.prototype._block_element_access = function() {
202
+ this._overlay = document.createElement("div");
203
+ this._overlay.style.width = "100%";
204
+ this._overlay.style.height = "100%";
205
+ this._overlay.style.position = "absolute";
206
+ this._overlay.style.top = 0;
207
+ this._overlay.style.left = 0;
208
+ this._overlay.style.zIndex = 2;
209
+ return this.container.appendChild(this._overlay);
210
+ };
211
+
212
+ JpegCamera.prototype._overlay = null;
213
+
214
+ JpegCamera._add_prefixed_style = function(element, style, value) {
215
+ var uppercase_style;
216
+ uppercase_style = style.charAt(0).toUpperCase() + style.slice(1);
217
+ element.style[style] = value;
218
+ element.style["Webkit" + uppercase_style] = value;
219
+ element.style["Moz" + uppercase_style] = value;
220
+ element.style["ms" + uppercase_style] = value;
221
+ return element.style["O" + uppercase_style] = value;
222
+ };
223
+
161
224
  return JpegCamera;
162
225
 
163
226
  })();
164
227
 
165
228
  navigator.getUserMedia || (navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
166
229
 
230
+ check_canvas_to_blob = function() {
231
+ var canvas;
232
+ canvas = document.createElement("canvas");
233
+ if (canvas.getContext && !canvas.toBlob) {
234
+ throw "JpegCamera: Canvas-to-Blob is not loaded";
235
+ }
236
+ };
237
+
167
238
  if (navigator.getUserMedia) {
239
+ check_canvas_to_blob();
168
240
  JpegCameraHtml5 = (function(_super) {
169
241
  __extends(JpegCameraHtml5, _super);
170
242
 
@@ -174,20 +246,15 @@
174
246
  }
175
247
 
176
248
  JpegCameraHtml5.prototype._engine_init = function() {
177
- var get_user_media_options, horizontal_padding, that, vertical_padding;
249
+ var error, failure, get_user_media_options, horizontal_padding, success, that, vertical_padding;
178
250
  this._debug("Using HTML5 engine");
179
- this.internal_container = document.createElement("div");
180
- this.internal_container.style.width = "100%";
181
- this.internal_container.style.height = "100%";
182
- this.internal_container.style.position = "relative";
183
- this.container.appendChild(this.internal_container);
184
251
  vertical_padding = Math.floor(this._view_height() * 0.2);
185
252
  horizontal_padding = Math.floor(this._view_width() * 0.2);
186
253
  this.message = document.createElement("div");
187
254
  this.message["class"] = "message";
188
255
  this.message.style.width = "100%";
189
256
  this.message.style.height = "100%";
190
- this._add_prefixed_style(this.message, "boxSizing", "border-box");
257
+ JpegCamera._add_prefixed_style(this.message, "boxSizing", "border-box");
191
258
  this.message.style.overflow = "hidden";
192
259
  this.message.style.textAlign = "center";
193
260
  this.message.style.paddingTop = "" + vertical_padding + "px";
@@ -196,18 +263,18 @@
196
263
  this.message.style.paddingRight = "" + horizontal_padding + "px";
197
264
  this.message.style.position = "absolute";
198
265
  this.message.style.zIndex = 3;
199
- this.message.innerHTML = "Please allow camera access when prompted by the browser.";
200
- this.internal_container.appendChild(this.message);
266
+ this.message.innerHTML = "Please allow camera access when prompted by the browser.<br><br>" + "Look for camera icon around your address bar.";
267
+ this.container.appendChild(this.message);
201
268
  this.video_container = document.createElement("div");
202
269
  this.video_container.style.width = "" + (this._view_width()) + "px";
203
270
  this.video_container.style.height = "" + (this._view_height()) + "px";
204
271
  this.video_container.style.overflow = "hidden";
205
272
  this.video_container.style.position = "absolute";
206
273
  this.video_container.style.zIndex = 1;
207
- this.internal_container.appendChild(this.video_container);
274
+ this.container.appendChild(this.video_container);
208
275
  this.video = document.createElement('video');
209
276
  this.video.autoplay = true;
210
- this._add_prefixed_style(this.video, "transform", "scalex(-1.0)");
277
+ JpegCamera._add_prefixed_style(this.video, "transform", "scalex(-1.0)");
211
278
  window.AudioContext || (window.AudioContext = window.webkitAudioContext);
212
279
  if (window.AudioContext) {
213
280
  this._load_shutter_sound();
@@ -228,16 +295,19 @@
228
295
  }
229
296
  };
230
297
  that = this;
231
- return navigator.getUserMedia(get_user_media_options, function(stream) {
298
+ success = function(stream) {
232
299
  that._remove_message();
233
300
  if (window.URL) {
234
301
  that.video.src = URL.createObjectURL(stream);
235
302
  } else {
236
303
  that.video.src = stream;
237
304
  }
305
+ that._block_element_access();
238
306
  return that._wait_for_video_ready();
239
- }, function(error) {
307
+ };
308
+ failure = function(error) {
240
309
  var code, key, value;
310
+ that.message.innerHTML = "<span style=\"color: red;\">" + "You have denied camera access." + "</span><br><br>" + "Look for camera icon around your address bar to change your " + "decision.";
241
311
  code = error.code;
242
312
  for (key in error) {
243
313
  value = error[key];
@@ -248,7 +318,13 @@
248
318
  return;
249
319
  }
250
320
  return that._got_error("UNKNOWN ERROR");
251
- });
321
+ };
322
+ try {
323
+ return navigator.getUserMedia(get_user_media_options, success, failure);
324
+ } catch (_error) {
325
+ error = _error;
326
+ return navigator.getUserMedia("video", success, failure);
327
+ }
252
328
  };
253
329
 
254
330
  JpegCameraHtml5.prototype._engine_play_shutter_sound = function() {
@@ -262,14 +338,14 @@
262
338
  return source.start(0);
263
339
  };
264
340
 
265
- JpegCameraHtml5.prototype._engine_capture = function(snapshot, mirror, quality) {
341
+ JpegCameraHtml5.prototype._engine_capture = function(snapshot, mirror, quality, scale) {
266
342
  var canvas, context, crop;
267
343
  crop = this._get_capture_crop();
268
344
  canvas = document.createElement("canvas");
269
- canvas.width = crop.width;
270
- canvas.height = crop.height;
345
+ canvas.width = Math.round(crop.width * scale);
346
+ canvas.height = Math.round(crop.height * scale);
271
347
  context = canvas.getContext("2d");
272
- context.drawImage(this.video, crop.x_offset, crop.y_offset, crop.width, crop.height, 0, 0, crop.width, crop.height);
348
+ context.drawImage(this.video, crop.x_offset, crop.y_offset, crop.width, crop.height, 0, 0, Math.round(crop.width * scale), Math.round(crop.height * scale));
273
349
  snapshot._canvas = canvas;
274
350
  snapshot._mirror = mirror;
275
351
  return snapshot._quality = quality;
@@ -277,7 +353,7 @@
277
353
 
278
354
  JpegCameraHtml5.prototype._engine_display = function(snapshot) {
279
355
  if (this.displayed_canvas) {
280
- this.internal_container.removeChild(this.displayed_canvas);
356
+ this.container.removeChild(this.displayed_canvas);
281
357
  }
282
358
  this.displayed_canvas = snapshot._canvas;
283
359
  this.displayed_canvas.style.width = "" + (this._view_width()) + "px";
@@ -286,8 +362,25 @@
286
362
  this.displayed_canvas.style.left = 0;
287
363
  this.displayed_canvas.style.position = "absolute";
288
364
  this.displayed_canvas.style.zIndex = 2;
289
- this._add_prefixed_style(this.displayed_canvas, "transform", "scalex(-1.0)");
290
- return this.internal_container.appendChild(this.displayed_canvas);
365
+ JpegCamera._add_prefixed_style(this.displayed_canvas, "transform", "scalex(-1.0)");
366
+ return this.container.appendChild(this.displayed_canvas);
367
+ };
368
+
369
+ JpegCameraHtml5.prototype._engine_get_canvas = function(snapshot) {
370
+ var canvas, context;
371
+ canvas = document.createElement("canvas");
372
+ canvas.width = snapshot._canvas.width;
373
+ canvas.height = snapshot._canvas.height;
374
+ context = canvas.getContext("2d");
375
+ context.drawImage(snapshot._canvas, 0, 0);
376
+ return canvas;
377
+ };
378
+
379
+ JpegCameraHtml5.prototype._engine_get_image_data = function(snapshot) {
380
+ var canvas, context;
381
+ canvas = snapshot._canvas;
382
+ context = canvas.getContext("2d");
383
+ return context.getImageData(0, 0, canvas.width, canvas.height);
291
384
  };
292
385
 
293
386
  JpegCameraHtml5.prototype._engine_discard = function(snapshot) {
@@ -301,7 +394,7 @@
301
394
 
302
395
  JpegCameraHtml5.prototype._engine_show_stream = function() {
303
396
  if (this.displayed_canvas) {
304
- this.internal_container.removeChild(this.displayed_canvas);
397
+ this.container.removeChild(this.displayed_canvas);
305
398
  this.displayed_canvas = null;
306
399
  }
307
400
  return this.video_container.style.display = "block";
@@ -406,16 +499,6 @@
406
499
 
407
500
  JpegCameraHtml5.prototype._status_checks_count = 0;
408
501
 
409
- JpegCameraHtml5.prototype._add_prefixed_style = function(element, style, value) {
410
- var uppercase_style;
411
- uppercase_style = style.charAt(0).toUpperCase() + style.slice(1);
412
- element.style[style] = value;
413
- element.style["Webkit" + uppercase_style] = value;
414
- element.style["Moz" + uppercase_style] = value;
415
- element.style["ms" + uppercase_style] = value;
416
- return element.style["O" + uppercase_style] = value;
417
- };
418
-
419
502
  JpegCameraHtml5.prototype._get_video_crop = function() {
420
503
  var scaled_video_height, scaled_video_width, video_ratio, video_scale, view_height, view_ratio, view_width;
421
504
  view_width = this._view_width();
@@ -482,6 +565,10 @@
482
565
 
483
566
  supported_flash_version = '9';
484
567
 
568
+ if (!window.swfobject) {
569
+ throw "JpegCamera: SWFObject is not loaded";
570
+ }
571
+
485
572
  if (!window.JpegCamera && window.swfobject && swfobject.hasFlashPlayerVersion(supported_flash_version)) {
486
573
  JpegCameraFlash = (function(_super) {
487
574
  __extends(JpegCameraFlash, _super);
@@ -506,7 +593,7 @@
506
593
  JpegCameraFlash._next_id = 1;
507
594
 
508
595
  JpegCameraFlash.prototype._engine_init = function() {
509
- var attributes, callback, flash_object_id, flashvars, height, params, that, width;
596
+ var attributes, callback, container_to_be_replaced, flash_object_id, flashvars, height, params, that, width;
510
597
  this._debug("Using Flash engine");
511
598
  this._id = this.constructor._next_id++;
512
599
  this.constructor._instances[this._id] = this;
@@ -544,26 +631,68 @@
544
631
  return that._flash = document.getElementById(flash_object_id);
545
632
  }
546
633
  };
547
- this.internal_container = document.createElement("div");
548
- this.internal_container.id = "jpeg_camera_flash_" + this._id;
549
- this.internal_container.style.width = "100%";
550
- this.internal_container.style.height = "100%";
551
- this.container.appendChild(this.internal_container);
552
- return swfobject.embedSWF(this.options.swf_url, this.internal_container.id, width, height, '9', null, flashvars, params, attributes, callback);
634
+ container_to_be_replaced = document.createElement("div");
635
+ container_to_be_replaced.id = "jpeg_camera_flash_" + this._id;
636
+ container_to_be_replaced.style.width = "100%";
637
+ container_to_be_replaced.style.height = "100%";
638
+ this.container.appendChild(container_to_be_replaced);
639
+ return swfobject.embedSWF(this.options.swf_url, container_to_be_replaced.id, width, height, '9', null, flashvars, params, attributes, callback);
553
640
  };
554
641
 
555
642
  JpegCameraFlash.prototype._engine_play_shutter_sound = function() {
556
643
  return this._flash._play_shutter();
557
644
  };
558
645
 
559
- JpegCameraFlash.prototype._engine_capture = function(snapshot, mirror, quality) {
560
- return this._flash._capture(snapshot.id, mirror, quality);
646
+ JpegCameraFlash.prototype._engine_capture = function(snapshot, mirror, quality, scale) {
647
+ return this._flash._capture(snapshot.id, mirror, quality, scale);
561
648
  };
562
649
 
563
650
  JpegCameraFlash.prototype._engine_display = function(snapshot) {
564
651
  return this._flash._display(snapshot.id);
565
652
  };
566
653
 
654
+ JpegCameraFlash.prototype._engine_get_canvas = function(snapshot) {
655
+ var canvas, context;
656
+ snapshot._image_data || (snapshot._image_data = this._engine_get_image_data(snapshot));
657
+ canvas = document.createElement("canvas");
658
+ canvas.width = snapshot._image_data.width;
659
+ canvas.height = snapshot._image_data.height;
660
+ context = canvas.getContext("2d");
661
+ context.putImageData(snapshot._image_data, 0, 0);
662
+ return canvas;
663
+ };
664
+
665
+ JpegCameraFlash.prototype._engine_get_image_data = function(snapshot) {
666
+ var blue, canvas, context, flash_data, green, i, index, pixel, red, result, _i, _len, _ref2;
667
+ flash_data = this._flash._get_image_data(snapshot.id);
668
+ if (JpegCamera.canvas_supported()) {
669
+ canvas = document.createElement("canvas");
670
+ canvas.width = flash_data.width;
671
+ canvas.height = flash_data.height;
672
+ context = canvas.getContext("2d");
673
+ result = context.createImageData(flash_data.width, flash_data.height);
674
+ } else {
675
+ result = {
676
+ data: [],
677
+ width: flash_data.width,
678
+ height: flash_data.height
679
+ };
680
+ }
681
+ _ref2 = flash_data.data;
682
+ for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) {
683
+ pixel = _ref2[i];
684
+ index = i * 4;
685
+ red = pixel >> 16 & 0xff;
686
+ green = pixel >> 8 & 0xff;
687
+ blue = pixel & 0xff;
688
+ result.data[index + 0] = red;
689
+ result.data[index + 1] = green;
690
+ result.data[index + 2] = blue;
691
+ result.data[index + 3] = 255;
692
+ }
693
+ return result;
694
+ };
695
+
567
696
  JpegCameraFlash.prototype._engine_discard = function(snapshot) {
568
697
  return this._flash._discard(snapshot.id);
569
698
  };
@@ -577,6 +706,7 @@
577
706
  };
578
707
 
579
708
  JpegCameraFlash.prototype._flash_prepared = function() {
709
+ this._block_element_access();
580
710
  return this._prepared();
581
711
  };
582
712
 
@@ -626,6 +756,48 @@
626
756
  return this;
627
757
  };
628
758
 
759
+ Snapshot.prototype.get_stats = function(callback) {
760
+ if (this._discarded) {
761
+ raise("discarded snapshot cannot be used");
762
+ }
763
+ return this.get_image_data(function(data) {
764
+ return this._get_stats(data, callback);
765
+ });
766
+ };
767
+
768
+ Snapshot.prototype.get_canvas = function(callback) {
769
+ var that;
770
+ if (this._discarded) {
771
+ raise("discarded snapshot cannot be used");
772
+ }
773
+ if (!JpegCamera._canvas_supported) {
774
+ false;
775
+ }
776
+ that = this;
777
+ setTimeout(function() {
778
+ that._extra_canvas || (that._extra_canvas = that.camera._engine_get_canvas(that));
779
+ JpegCamera._add_prefixed_style(that._extra_canvas, "transform", "scalex(-1.0)");
780
+ return callback.call(that, that._extra_canvas);
781
+ }, 10);
782
+ return true;
783
+ };
784
+
785
+ Snapshot.prototype._extra_canvas = null;
786
+
787
+ Snapshot.prototype.get_image_data = function(callback) {
788
+ var that;
789
+ if (this._discarded) {
790
+ raise("discarded snapshot cannot be used");
791
+ }
792
+ that = this;
793
+ return setTimeout(function() {
794
+ that._image_data || (that._image_data = that.camera._engine_get_image_data(that));
795
+ return callback.call(that, that._image_data);
796
+ }, 5);
797
+ };
798
+
799
+ Snapshot.prototype._image_data = null;
800
+
629
801
  Snapshot.prototype.upload = function(options) {
630
802
  var cache;
631
803
  if (options == null) {
@@ -713,9 +885,38 @@
713
885
  this._fail = false;
714
886
  this._status = null;
715
887
  this._error_message = null;
716
- return this.camera._upload(this, cache.api_url, csrf_token, cache.timeout);
888
+ return this.camera._engine_upload(this, cache.api_url, csrf_token, cache.timeout);
717
889
  };
718
890
 
891
+ Snapshot.prototype._get_stats = function(data, callback) {
892
+ var gray, gray_values, i, index, mean, n, sum, sum_of_square_distances, _i, _j, _len;
893
+ if (!this._stats) {
894
+ n = data.width * data.height;
895
+ sum = 0.0;
896
+ gray_values = new Array(n);
897
+ for (i = _i = 0; _i < n; i = _i += 1) {
898
+ index = i * 4;
899
+ gray = 0.2126 * data.data[index + 0] + 0.7152 * data.data[index + 1] + 0.0722 * data.data[index + 2];
900
+ gray = Math.round(gray);
901
+ sum += gray;
902
+ gray_values[i] = gray;
903
+ }
904
+ mean = Math.round(sum / n);
905
+ sum_of_square_distances = 0;
906
+ for (_j = 0, _len = gray_values.length; _j < _len; _j++) {
907
+ gray = gray_values[_j];
908
+ sum_of_square_distances += Math.pow(gray - mean, 2);
909
+ }
910
+ this._stats = {
911
+ mean: mean,
912
+ std: Math.round(Math.sqrt(sum_of_square_distances / n))
913
+ };
914
+ }
915
+ return callback.call(this, this._stats);
916
+ };
917
+
918
+ Snapshot.prototype._stats = null;
919
+
719
920
  Snapshot.prototype._upload_done = function() {
720
921
  var cache, delay, retry_decision, that;
721
922
  this.camera._debug("Upload completed with status " + this._status);
@@ -1,4 +1,4 @@
1
- /*! JpegCamera 1.0.2 | 2013-07-30
1
+ /*! JpegCamera 1.1.1 | 2013-08-05
2
2
  (c) 2013 Adam Wrobel
3
3
  http://amw.github.io/jpeg_camera */
4
- !function(){var a,b,c,d,e,f,g,h={}.hasOwnProperty,i=function(a,b){function c(){this.constructor=a}for(var d in b)h.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};a=function(){function a(a,b){if(this.container="string"==typeof a?document.querySelector(a):a,!this.container||!this.container.offsetWidth)throw"JpegCamera: invalid container";this.container.innerHTML="",this.options=this._extend({},this.constructor.DefaultOptions,b),this._engine_init()}return a.DefaultOptions={shutter_url:"/jpeg_camera/shutter.mp3",swf_url:"/jpeg_camera/jpeg_camera.swf",on_debug:function(a){return console&&console.log?console.log("JpegCamera: "+a):void 0},quality:.9,shutter:!0,mirror:!1,timeout:0,retry_success:!1},a.prototype.ready=function(a){return this.options.on_ready=a,this.options.on_ready&&this._is_ready&&this.options.on_ready.call(this),this},a.prototype._is_ready=!1,a.prototype.error=function(a){return this.options.on_error=a,this.options.on_error&&this._error_occured&&this.options.on_error.call(this,this._error_occured),this},a.prototype._error_occured=!1,a.prototype.capture=function(a){var b,c;return null==a&&(a={}),b=new d(this,a),this._snapshots[b.id]=b,c=b._options(),c.shutter&&this._engine_play_shutter_sound(),this._engine_capture(b,c.mirror,c.quality),b},a.prototype._snapshots={},a.prototype.show_stream=function(){return this._engine_show_stream(),this._displayed_snapshot=null,this},a.prototype.discard_all=function(){var a,b,c;this._displayed_snapshot&&this.show_stream(),c=this._snapshots;for(a in c)b=c[a],this._engine_discard(b),b._discarded=!0;return this._snapshots={},this},a.prototype._extend=function(a){var b,c,d,e,f,g;for(d=Array.prototype.slice.call(arguments,1),f=0,g=d.length;g>f;f++)if(c=d[f])for(b in c)e=c[b],a[b]=e;return a},a.prototype._debug=function(a){return this.options.on_debug?this.options.on_debug.call(this,a):void 0},a.prototype._view_width=function(){return parseInt(this.container.offsetWidth,10)},a.prototype._view_height=function(){return parseInt(this.container.offsetHeight,10)},a.prototype._display=function(a){return this._engine_display(a),this._displayed_snapshot=a},a.prototype._displayed_snapshot=null,a.prototype._upload=function(a,b,c,d){return this._engine_upload(a,b,c,d)},a.prototype._discard=function(a){return this._displayed_snapshot===a&&this.show_stream(),this._engine_discard(a),a._discarded=!0,delete this._snapshots[a.id]},a.prototype._prepared=function(){return this._is_ready=!0,this.options.on_ready?this.options.on_ready.call(this):void 0},a.prototype._got_error=function(a){return this._debug("Error - "+a),this._error_occured=a,this.options.on_error?this.options.on_error.call(this,this._error_occured):void 0},a}(),navigator.getUserMedia||(navigator.getUserMedia=navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia),navigator.getUserMedia&&(c=function(a){function b(){return f=b.__super__.constructor.apply(this,arguments)}return i(b,a),b.prototype._engine_init=function(){var a,b,c,d;return this._debug("Using HTML5 engine"),this.internal_container=document.createElement("div"),this.internal_container.style.width="100%",this.internal_container.style.height="100%",this.internal_container.style.position="relative",this.container.appendChild(this.internal_container),d=Math.floor(.2*this._view_height()),b=Math.floor(.2*this._view_width()),this.message=document.createElement("div"),this.message["class"]="message",this.message.style.width="100%",this.message.style.height="100%",this._add_prefixed_style(this.message,"boxSizing","border-box"),this.message.style.overflow="hidden",this.message.style.textAlign="center",this.message.style.paddingTop=""+d+"px",this.message.style.paddingBottom=""+d+"px",this.message.style.paddingLeft=""+b+"px",this.message.style.paddingRight=""+b+"px",this.message.style.position="absolute",this.message.style.zIndex=3,this.message.innerHTML="Please allow camera access when prompted by the browser.",this.internal_container.appendChild(this.message),this.video_container=document.createElement("div"),this.video_container.style.width=""+this._view_width()+"px",this.video_container.style.height=""+this._view_height()+"px",this.video_container.style.overflow="hidden",this.video_container.style.position="absolute",this.video_container.style.zIndex=1,this.internal_container.appendChild(this.video_container),this.video=document.createElement("video"),this.video.autoplay=!0,this._add_prefixed_style(this.video,"transform","scalex(-1.0)"),window.AudioContext||(window.AudioContext=window.webkitAudioContext),window.AudioContext&&this._load_shutter_sound(),a={video:{optional:[{minWidth:1280},{minWidth:640},{minWidth:480},{minWidth:360}]}},c=this,navigator.getUserMedia(a,function(a){return c._remove_message(),c.video.src=window.URL?URL.createObjectURL(a):a,c._wait_for_video_ready()},function(a){var b,d,e;b=a.code;for(d in a)if(e=a[d],"code"!==d)return c._got_error(d),void 0;return c._got_error("UNKNOWN ERROR")})},b.prototype._engine_play_shutter_sound=function(){var a;if(this.shutter_buffer)return a=this.audio_context.createBufferSource(),a.buffer=this.shutter_buffer,a.connect(this.audio_context.destination),a.start(0)},b.prototype._engine_capture=function(a,b,c){var d,e,f;return f=this._get_capture_crop(),d=document.createElement("canvas"),d.width=f.width,d.height=f.height,e=d.getContext("2d"),e.drawImage(this.video,f.x_offset,f.y_offset,f.width,f.height,0,0,f.width,f.height),a._canvas=d,a._mirror=b,a._quality=c},b.prototype._engine_display=function(a){return this.displayed_canvas&&this.internal_container.removeChild(this.displayed_canvas),this.displayed_canvas=a._canvas,this.displayed_canvas.style.width=""+this._view_width()+"px",this.displayed_canvas.style.height=""+this._view_height()+"px",this.displayed_canvas.style.top=0,this.displayed_canvas.style.left=0,this.displayed_canvas.style.position="absolute",this.displayed_canvas.style.zIndex=2,this._add_prefixed_style(this.displayed_canvas,"transform","scalex(-1.0)"),this.internal_container.appendChild(this.displayed_canvas)},b.prototype._engine_discard=function(a){return a._xhr&&a._xhr.abort(),delete a._xhr,delete a._canvas,delete a._jpeg_blob},b.prototype._engine_show_stream=function(){return this.displayed_canvas&&(this.internal_container.removeChild(this.displayed_canvas),this.displayed_canvas=null),this.video_container.style.display="block"},b.prototype._engine_upload=function(a,b,c,d){var e,f,g,h,i;return h=this,a._jpeg_blob?(this._debug("Uploading the file"),g=function(b){return delete a._xhr,a._status=b.target.status,a._response=b.target.responseText,a._status>=200&&a._status<300?a._upload_done():(a._error_message=b.target.statusText||"Unknown error",a._upload_fail())},i=new XMLHttpRequest,i.open("POST",b),i.timeout=d,c&&i.setRequestHeader("X-CSRF-Token",c),i.onload=g,i.onerror=g,i.onabort=g,i.send(a._jpeg_blob),a._xhr=i):(this._debug("Generating JPEG file"),a._mirror?(e=document.createElement("canvas"),e.width=a._canvas.width,e.height=a._canvas.height,f=e.getContext("2d"),f.setTransform(1,0,0,1,0,0),f.translate(e.width,0),f.scale(-1,1),f.drawImage(a._canvas,0,0)):e=a._canvas,e.toBlob(function(e){return a._jpeg_blob=e,h._engine_upload(a,b,c,d)},"image/jpeg",this.quality))},b.prototype._remove_message=function(){return this.message.style.display="none"},b.prototype._load_shutter_sound=function(){var a,b;if(!this.audio_context)return this.audio_context=new AudioContext,a=new XMLHttpRequest,a.open("GET",this.options.shutter_url,!0),a.responseType="arraybuffer",b=this,a.onload=function(){return b.audio_context.decodeAudioData(a.response,function(a){return b.shutter_buffer=a})},a.send()},b.prototype._wait_for_video_ready=function(){var a,b,c,d;return d=parseInt(this.video.videoWidth),c=parseInt(this.video.videoHeight),d>0&&c>0?(this.video_container.appendChild(this.video),this.video_width=d,this.video_height=c,this._debug("Camera resolution "+this.video_width+"x"+this.video_height+"px"),a=this._get_video_crop(),this.video.style.position="relative",this.video.style.width=""+a.width+"px",this.video.style.height=""+a.height+"px",this.video.style.left=""+a.x_offset+"px",this.video.style.top=""+a.y_offset+"px",this._prepared()):this._status_checks_count>100?this._got_error("Camera failed to initialize in 10 seconds"):(this._status_checks_count++,b=this,setTimeout(function(){return b._wait_for_video_ready()},100))},b.prototype._status_checks_count=0,b.prototype._add_prefixed_style=function(a,b,c){var d;return d=b.charAt(0).toUpperCase()+b.slice(1),a.style[b]=c,a.style["Webkit"+d]=c,a.style["Moz"+d]=c,a.style["ms"+d]=c,a.style["O"+d]=c},b.prototype._get_video_crop=function(){var a,b,c,d,e,f,g;return g=this._view_width(),e=this._view_height(),c=this.video_width/this.video_height,f=g/e,c>=f?(this._debug("Filling height"),d=e/this.video_height,b=Math.round(this.video_width*d),{width:b,height:e,x_offset:-Math.floor((b-g)/2),y_offset:0}):(this._debug("Filling width"),d=g/this.video_width,a=Math.round(this.video_height*d),{width:g,height:a,x_offset:0,y_offset:-Math.floor((a-e)/2)})},b.prototype._get_capture_crop=function(){var a,b,c,d,e,f;return f=this._view_width(),d=this._view_height(),c=this.video_width/this.video_height,e=f/d,c>=e?(b=Math.round(this.video_height*e),{width:b,height:this.video_height,x_offset:Math.floor((this.video_width-b)/2),y_offset:0}):(a=Math.round(this.video_width/e),{width:this.video_width,height:a,x_offset:0,y_offset:Math.floor((this.video_height-a)/2)})},b}(a),window.JpegCamera=c),e="9",!window.JpegCamera&&window.swfobject&&swfobject.hasFlashPlayerVersion(e)&&(b=function(a){function b(){return g=b.__super__.constructor.apply(this,arguments)}return i(b,a),b._send_message=function(a,b){var c,d;return(d=this._instances[parseInt(a)])?(c=Array.prototype.slice.call(arguments,2),this.prototype[b].apply(d,c)):void 0},b._instances={},b._next_id=1,b.prototype._engine_init=function(){var a,b,c,d,e,f,g,h;return this._debug("Using Flash engine"),this._id=this.constructor._next_id++,this.constructor._instances[this._id]=this,h=this._view_width(),e=this._view_height(),215>h||138>e?(this._got_error("camera is too small to display privacy dialog"),void 0):(c="flash_object_"+this._id,f={loop:"false",allowScriptAccess:"always",allowFullScreen:"false",quality:"best",wmode:"opaque",menu:"false"},a={id:c,align:"middle"},d={id:this._id,width:h,height:e,shutter_url:this.options.shutter_url},g=this,b=function(a){return a.success?(g._debug("Flash loaded"),g._flash=document.getElementById(c)):g._got_error("Flash loading failed.")},this.internal_container=document.createElement("div"),this.internal_container.id="jpeg_camera_flash_"+this._id,this.internal_container.style.width="100%",this.internal_container.style.height="100%",this.container.appendChild(this.internal_container),swfobject.embedSWF(this.options.swf_url,this.internal_container.id,h,e,"9",null,d,f,a,b))},b.prototype._engine_play_shutter_sound=function(){return this._flash._play_shutter()},b.prototype._engine_capture=function(a,b,c){return this._flash._capture(a.id,b,c)},b.prototype._engine_display=function(a){return this._flash._display(a.id)},b.prototype._engine_discard=function(a){return this._flash._discard(a.id)},b.prototype._engine_show_stream=function(){return this._flash._show_stream()},b.prototype._engine_upload=function(a,b,c,d){return this._flash._upload(a.id,b,c,d)},b.prototype._flash_prepared=function(){return this._prepared()},b.prototype._flash_upload_complete=function(a,b,c,d){var e;return a=parseInt(a),e=this._snapshots[a],e._status=parseInt(b),e._response=d,e._status>=200&&e._status<300?e._upload_done():(e._error_message=c,e._upload_fail())},b}(a),window.JpegCamera=b),d=function(){function a(a,b){this.camera=a,this.options=b,this.id=this.constructor._next_snapshot_id++}return a._next_snapshot_id=1,a.prototype._discarded=!1,a.prototype.show=function(){return this._discarded&&raise("discarded snapshot cannot be used"),this.camera._display(this),this},a.prototype.hide=function(){return this.camera.displayed_snapshot()===this&&this.camera.show_stream(),this},a.prototype.upload=function(a){var b;if(null==a&&(a={}),this._discarded&&raise("discarded snapshot cannot be used"),this._uploading)return this.camera._debug("Upload already in progress"),void 0;if(this._uploading=!0,this._retry=1,this._upload_options=a,b=this._options(),!b.api_url)throw this.camera._debug("Snapshot#upload called without valid api_url"),"Snapshot#upload called without valid api_url";return this._start_upload(b),this},a.prototype._upload_options={},a.prototype._uploading=!1,a.prototype._retry=1,a.prototype.done=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_done=a,b=this._options(),b.on_upload_done&&this._done&&b.on_upload_done.call(this,this._response),this},a.prototype._done=!1,a.prototype._response=null,a.prototype.fail=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_fail=a,b=this._options(),b.on_upload_fail&&this._fail&&b.on_upload_fail.call(this,this._status,this._error_message,this._response),this},a.prototype._fail=!1,a.prototype._status=null,a.prototype._error_message=null,a.prototype.discard=function(){return this.camera._discard(this),void 0},a.prototype._options=function(){return this.camera._extend({},this.camera.options,this.options,this._upload_options)},a.prototype._start_upload=function(a){var b;return b="string"==typeof a.csrf_token&&a.csrf_token.length>0?a.csrf_token:null,this._done=!1,this._response=null,this._fail=!1,this._status=null,this._error_message=null,this.camera._upload(this,a.api_url,b,a.timeout)},a.prototype._upload_done=function(){var a,b,c,d;return this.camera._debug("Upload completed with status "+this._status),this._done=!0,a=this._options(),c=a.retry_success&&a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_done?a.on_upload_done.call(this,this._response):void 0)},a.prototype._upload_fail=function(){var a,b,c,d;return this.camera._debug("Upload failed with status "+this._status),this._fail=!0,a=this._options(),c=a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_fail?a.on_upload_fail.call(this,this._status,this._error_message,this._response):void 0)},a}()}.call(this);
4
+ !function(){var a,b,c,d,e,f,g,h,i={}.hasOwnProperty,j=function(a,b){function c(){this.constructor=a}for(var d in b)i.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};if(a=function(){function a(a,b){if("string"==typeof a&&(a=document.getElementById(a.replace("#",""))),!a||!a.offsetWidth)throw"JpegCamera: invalid container";a.innerHTML="",this.container=document.createElement("div"),this.container.style.width="100%",this.container.style.height="100%",this.container.style.position="relative",a.appendChild(this.container),this.options=this._extend({},this.constructor.DefaultOptions,b),this._engine_init()}return a.DefaultOptions={shutter_url:"/jpeg_camera/shutter.mp3",swf_url:"/jpeg_camera/jpeg_camera.swf",on_debug:function(a){return console&&console.log?console.log("JpegCamera: "+a):void 0},quality:.9,shutter:!0,mirror:!1,timeout:0,retry_success:!1},a._canvas_supported=!!document.createElement("canvas").getContext,a.canvas_supported=function(){return this._canvas_supported},a.prototype.ready=function(a){return this.options.on_ready=a,this.options.on_ready&&this._is_ready&&this.options.on_ready.call(this),this},a.prototype._is_ready=!1,a.prototype.error=function(a){return this.options.on_error=a,this.options.on_error&&this._error_occured&&this.options.on_error.call(this,this._error_occured),this},a.prototype._error_occured=!1,a.StatsCaptureScale=.2,a.prototype.get_stats=function(b){var c,e;return c=new d(this,{}),this._engine_capture(c,!1,.1,a.StatsCaptureScale),e=this,c.get_stats(function(a){return b.call(e,a)})},a.prototype.capture=function(a){var b,c;return null==a&&(a={}),b=new d(this,a),this._snapshots[b.id]=b,c=b._options(),c.shutter&&this._engine_play_shutter_sound(),this._engine_capture(b,c.mirror,c.quality,1),b},a.prototype._snapshots={},a.prototype.show_stream=function(){return this._engine_show_stream(),this._displayed_snapshot=null,this},a.prototype.discard_all=function(){var a,b,c;this._displayed_snapshot&&this.show_stream(),c=this._snapshots;for(a in c)b=c[a],this._engine_discard(b),b._discarded=!0;return this._snapshots={},this},a.prototype._extend=function(a){var b,c,d,e,f,g;for(d=Array.prototype.slice.call(arguments,1),f=0,g=d.length;g>f;f++)if(c=d[f])for(b in c)e=c[b],a[b]=e;return a},a.prototype._debug=function(a){return this.options.on_debug?this.options.on_debug.call(this,a):void 0},a.prototype._view_width=function(){return parseInt(this.container.offsetWidth,10)},a.prototype._view_height=function(){return parseInt(this.container.offsetHeight,10)},a.prototype._display=function(a){return this._engine_display(a),this._displayed_snapshot=a},a.prototype._displayed_snapshot=null,a.prototype._discard=function(a){return this._displayed_snapshot===a&&this.show_stream(),this._engine_discard(a),a._discarded=!0,delete this._snapshots[a.id]},a.prototype._prepared=function(){var a;return a=this,setTimeout(function(){return a._wait_until_stream_looks_ok(!0)},1)},a.prototype._wait_until_stream_looks_ok=function(a){return this.get_stats(function(b){var c;return b.std>2?(this._debug("Stream mean gray value = "+b.mean+" standard deviation = "+b.std),this._debug("Camera is ready"),this._is_ready=!0,this.options.on_ready?this.options.on_ready.call(this):void 0):(a&&this._debug("Stream mean gray value = "+b.mean+" standard deviation = "+b.std),c=this,setTimeout(function(){return c._wait_until_stream_looks_ok(!1)},100))})},a.prototype._got_error=function(a){return this._debug("Error - "+a),this._error_occured=a,this.options.on_error?this.options.on_error.call(this,this._error_occured):void 0},a.prototype._block_element_access=function(){return this._overlay=document.createElement("div"),this._overlay.style.width="100%",this._overlay.style.height="100%",this._overlay.style.position="absolute",this._overlay.style.top=0,this._overlay.style.left=0,this._overlay.style.zIndex=2,this.container.appendChild(this._overlay)},a.prototype._overlay=null,a._add_prefixed_style=function(a,b,c){var d;return d=b.charAt(0).toUpperCase()+b.slice(1),a.style[b]=c,a.style["Webkit"+d]=c,a.style["Moz"+d]=c,a.style["ms"+d]=c,a.style["O"+d]=c},a}(),navigator.getUserMedia||(navigator.getUserMedia=navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia),e=function(){var a;if(a=document.createElement("canvas"),a.getContext&&!a.toBlob)throw"JpegCamera: Canvas-to-Blob is not loaded"},navigator.getUserMedia&&(e(),c=function(b){function c(){return g=c.__super__.constructor.apply(this,arguments)}return j(c,b),c.prototype._engine_init=function(){var b,c,d,e,f,g,h;this._debug("Using HTML5 engine"),h=Math.floor(.2*this._view_height()),e=Math.floor(.2*this._view_width()),this.message=document.createElement("div"),this.message["class"]="message",this.message.style.width="100%",this.message.style.height="100%",a._add_prefixed_style(this.message,"boxSizing","border-box"),this.message.style.overflow="hidden",this.message.style.textAlign="center",this.message.style.paddingTop=""+h+"px",this.message.style.paddingBottom=""+h+"px",this.message.style.paddingLeft=""+e+"px",this.message.style.paddingRight=""+e+"px",this.message.style.position="absolute",this.message.style.zIndex=3,this.message.innerHTML="Please allow camera access when prompted by the browser.<br><br>Look for camera icon around your address bar.",this.container.appendChild(this.message),this.video_container=document.createElement("div"),this.video_container.style.width=""+this._view_width()+"px",this.video_container.style.height=""+this._view_height()+"px",this.video_container.style.overflow="hidden",this.video_container.style.position="absolute",this.video_container.style.zIndex=1,this.container.appendChild(this.video_container),this.video=document.createElement("video"),this.video.autoplay=!0,a._add_prefixed_style(this.video,"transform","scalex(-1.0)"),window.AudioContext||(window.AudioContext=window.webkitAudioContext),window.AudioContext&&this._load_shutter_sound(),d={video:{optional:[{minWidth:1280},{minWidth:640},{minWidth:480},{minWidth:360}]}},g=this,f=function(a){return g._remove_message(),g.video.src=window.URL?URL.createObjectURL(a):a,g._block_element_access(),g._wait_for_video_ready()},c=function(a){var b,c,d;g.message.innerHTML='<span style="color: red;">You have denied camera access.</span><br><br>Look for camera icon around your address bar to change your decision.',b=a.code;for(c in a)if(d=a[c],"code"!==c)return g._got_error(c),void 0;return g._got_error("UNKNOWN ERROR")};try{return navigator.getUserMedia(d,f,c)}catch(i){return b=i,navigator.getUserMedia("video",f,c)}},c.prototype._engine_play_shutter_sound=function(){var a;if(this.shutter_buffer)return a=this.audio_context.createBufferSource(),a.buffer=this.shutter_buffer,a.connect(this.audio_context.destination),a.start(0)},c.prototype._engine_capture=function(a,b,c,d){var e,f,g;return g=this._get_capture_crop(),e=document.createElement("canvas"),e.width=Math.round(g.width*d),e.height=Math.round(g.height*d),f=e.getContext("2d"),f.drawImage(this.video,g.x_offset,g.y_offset,g.width,g.height,0,0,Math.round(g.width*d),Math.round(g.height*d)),a._canvas=e,a._mirror=b,a._quality=c},c.prototype._engine_display=function(b){return this.displayed_canvas&&this.container.removeChild(this.displayed_canvas),this.displayed_canvas=b._canvas,this.displayed_canvas.style.width=""+this._view_width()+"px",this.displayed_canvas.style.height=""+this._view_height()+"px",this.displayed_canvas.style.top=0,this.displayed_canvas.style.left=0,this.displayed_canvas.style.position="absolute",this.displayed_canvas.style.zIndex=2,a._add_prefixed_style(this.displayed_canvas,"transform","scalex(-1.0)"),this.container.appendChild(this.displayed_canvas)},c.prototype._engine_get_canvas=function(a){var b,c;return b=document.createElement("canvas"),b.width=a._canvas.width,b.height=a._canvas.height,c=b.getContext("2d"),c.drawImage(a._canvas,0,0),b},c.prototype._engine_get_image_data=function(a){var b,c;return b=a._canvas,c=b.getContext("2d"),c.getImageData(0,0,b.width,b.height)},c.prototype._engine_discard=function(a){return a._xhr&&a._xhr.abort(),delete a._xhr,delete a._canvas,delete a._jpeg_blob},c.prototype._engine_show_stream=function(){return this.displayed_canvas&&(this.container.removeChild(this.displayed_canvas),this.displayed_canvas=null),this.video_container.style.display="block"},c.prototype._engine_upload=function(a,b,c,d){var e,f,g,h,i;return h=this,a._jpeg_blob?(this._debug("Uploading the file"),g=function(b){return delete a._xhr,a._status=b.target.status,a._response=b.target.responseText,a._status>=200&&a._status<300?a._upload_done():(a._error_message=b.target.statusText||"Unknown error",a._upload_fail())},i=new XMLHttpRequest,i.open("POST",b),i.timeout=d,c&&i.setRequestHeader("X-CSRF-Token",c),i.onload=g,i.onerror=g,i.onabort=g,i.send(a._jpeg_blob),a._xhr=i):(this._debug("Generating JPEG file"),a._mirror?(e=document.createElement("canvas"),e.width=a._canvas.width,e.height=a._canvas.height,f=e.getContext("2d"),f.setTransform(1,0,0,1,0,0),f.translate(e.width,0),f.scale(-1,1),f.drawImage(a._canvas,0,0)):e=a._canvas,e.toBlob(function(e){return a._jpeg_blob=e,h._engine_upload(a,b,c,d)},"image/jpeg",this.quality))},c.prototype._remove_message=function(){return this.message.style.display="none"},c.prototype._load_shutter_sound=function(){var a,b;if(!this.audio_context)return this.audio_context=new AudioContext,a=new XMLHttpRequest,a.open("GET",this.options.shutter_url,!0),a.responseType="arraybuffer",b=this,a.onload=function(){return b.audio_context.decodeAudioData(a.response,function(a){return b.shutter_buffer=a})},a.send()},c.prototype._wait_for_video_ready=function(){var a,b,c,d;return d=parseInt(this.video.videoWidth),c=parseInt(this.video.videoHeight),d>0&&c>0?(this.video_container.appendChild(this.video),this.video_width=d,this.video_height=c,this._debug("Camera resolution "+this.video_width+"x"+this.video_height+"px"),a=this._get_video_crop(),this.video.style.position="relative",this.video.style.width=""+a.width+"px",this.video.style.height=""+a.height+"px",this.video.style.left=""+a.x_offset+"px",this.video.style.top=""+a.y_offset+"px",this._prepared()):this._status_checks_count>100?this._got_error("Camera failed to initialize in 10 seconds"):(this._status_checks_count++,b=this,setTimeout(function(){return b._wait_for_video_ready()},100))},c.prototype._status_checks_count=0,c.prototype._get_video_crop=function(){var a,b,c,d,e,f,g;return g=this._view_width(),e=this._view_height(),c=this.video_width/this.video_height,f=g/e,c>=f?(this._debug("Filling height"),d=e/this.video_height,b=Math.round(this.video_width*d),{width:b,height:e,x_offset:-Math.floor((b-g)/2),y_offset:0}):(this._debug("Filling width"),d=g/this.video_width,a=Math.round(this.video_height*d),{width:g,height:a,x_offset:0,y_offset:-Math.floor((a-e)/2)})},c.prototype._get_capture_crop=function(){var a,b,c,d,e,f;return f=this._view_width(),d=this._view_height(),c=this.video_width/this.video_height,e=f/d,c>=e?(b=Math.round(this.video_height*e),{width:b,height:this.video_height,x_offset:Math.floor((this.video_width-b)/2),y_offset:0}):(a=Math.round(this.video_width/e),{width:this.video_width,height:a,x_offset:0,y_offset:Math.floor((this.video_height-a)/2)})},c}(a),window.JpegCamera=c),f="9",!window.swfobject)throw"JpegCamera: SWFObject is not loaded";!window.JpegCamera&&window.swfobject&&swfobject.hasFlashPlayerVersion(f)&&(b=function(b){function c(){return h=c.__super__.constructor.apply(this,arguments)}return j(c,b),c._send_message=function(a,b){var c,d;return(d=this._instances[parseInt(a)])?(c=Array.prototype.slice.call(arguments,2),this.prototype[b].apply(d,c)):void 0},c._instances={},c._next_id=1,c.prototype._engine_init=function(){var a,b,c,d,e,f,g,h,i;return this._debug("Using Flash engine"),this._id=this.constructor._next_id++,this.constructor._instances[this._id]=this,i=this._view_width(),f=this._view_height(),215>i||138>f?(this._got_error("camera is too small to display privacy dialog"),void 0):(d="flash_object_"+this._id,g={loop:"false",allowScriptAccess:"always",allowFullScreen:"false",quality:"best",wmode:"opaque",menu:"false"},a={id:d,align:"middle"},e={id:this._id,width:i,height:f,shutter_url:this.options.shutter_url},h=this,b=function(a){return a.success?(h._debug("Flash loaded"),h._flash=document.getElementById(d)):h._got_error("Flash loading failed.")},c=document.createElement("div"),c.id="jpeg_camera_flash_"+this._id,c.style.width="100%",c.style.height="100%",this.container.appendChild(c),swfobject.embedSWF(this.options.swf_url,c.id,i,f,"9",null,e,g,a,b))},c.prototype._engine_play_shutter_sound=function(){return this._flash._play_shutter()},c.prototype._engine_capture=function(a,b,c,d){return this._flash._capture(a.id,b,c,d)},c.prototype._engine_display=function(a){return this._flash._display(a.id)},c.prototype._engine_get_canvas=function(a){var b,c;return a._image_data||(a._image_data=this._engine_get_image_data(a)),b=document.createElement("canvas"),b.width=a._image_data.width,b.height=a._image_data.height,c=b.getContext("2d"),c.putImageData(a._image_data,0,0),b},c.prototype._engine_get_image_data=function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o;for(f=this._flash._get_image_data(b.id),a.canvas_supported()?(d=document.createElement("canvas"),d.width=f.width,d.height=f.height,e=d.getContext("2d"),l=e.createImageData(f.width,f.height)):l={data:[],width:f.width,height:f.height},o=f.data,h=m=0,n=o.length;n>m;h=++m)j=o[h],i=4*h,k=255&j>>16,g=255&j>>8,c=255&j,l.data[i+0]=k,l.data[i+1]=g,l.data[i+2]=c,l.data[i+3]=255;return l},c.prototype._engine_discard=function(a){return this._flash._discard(a.id)},c.prototype._engine_show_stream=function(){return this._flash._show_stream()},c.prototype._engine_upload=function(a,b,c,d){return this._flash._upload(a.id,b,c,d)},c.prototype._flash_prepared=function(){return this._block_element_access(),this._prepared()},c.prototype._flash_upload_complete=function(a,b,c,d){var e;return a=parseInt(a),e=this._snapshots[a],e._status=parseInt(b),e._response=d,e._status>=200&&e._status<300?e._upload_done():(e._error_message=c,e._upload_fail())},c}(a),window.JpegCamera=b),d=function(){function b(a,b){this.camera=a,this.options=b,this.id=this.constructor._next_snapshot_id++}return b._next_snapshot_id=1,b.prototype._discarded=!1,b.prototype.show=function(){return this._discarded&&raise("discarded snapshot cannot be used"),this.camera._display(this),this},b.prototype.hide=function(){return this.camera.displayed_snapshot()===this&&this.camera.show_stream(),this},b.prototype.get_stats=function(a){return this._discarded&&raise("discarded snapshot cannot be used"),this.get_image_data(function(b){return this._get_stats(b,a)})},b.prototype.get_canvas=function(b){var c;return this._discarded&&raise("discarded snapshot cannot be used"),!a._canvas_supported,c=this,setTimeout(function(){return c._extra_canvas||(c._extra_canvas=c.camera._engine_get_canvas(c)),a._add_prefixed_style(c._extra_canvas,"transform","scalex(-1.0)"),b.call(c,c._extra_canvas)},10),!0},b.prototype._extra_canvas=null,b.prototype.get_image_data=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),b=this,setTimeout(function(){return b._image_data||(b._image_data=b.camera._engine_get_image_data(b)),a.call(b,b._image_data)},5)},b.prototype._image_data=null,b.prototype.upload=function(a){var b;if(null==a&&(a={}),this._discarded&&raise("discarded snapshot cannot be used"),this._uploading)return this.camera._debug("Upload already in progress"),void 0;if(this._uploading=!0,this._retry=1,this._upload_options=a,b=this._options(),!b.api_url)throw this.camera._debug("Snapshot#upload called without valid api_url"),"Snapshot#upload called without valid api_url";return this._start_upload(b),this},b.prototype._upload_options={},b.prototype._uploading=!1,b.prototype._retry=1,b.prototype.done=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_done=a,b=this._options(),b.on_upload_done&&this._done&&b.on_upload_done.call(this,this._response),this},b.prototype._done=!1,b.prototype._response=null,b.prototype.fail=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_fail=a,b=this._options(),b.on_upload_fail&&this._fail&&b.on_upload_fail.call(this,this._status,this._error_message,this._response),this},b.prototype._fail=!1,b.prototype._status=null,b.prototype._error_message=null,b.prototype.discard=function(){return this.camera._discard(this),void 0},b.prototype._options=function(){return this.camera._extend({},this.camera.options,this.options,this._upload_options)},b.prototype._start_upload=function(a){var b;return b="string"==typeof a.csrf_token&&a.csrf_token.length>0?a.csrf_token:null,this._done=!1,this._response=null,this._fail=!1,this._status=null,this._error_message=null,this.camera._engine_upload(this,a.api_url,b,a.timeout)},b.prototype._get_stats=function(a,b){var c,d,e,f,g,h,i,j,k,l,m;if(!this._stats){for(h=a.width*a.height,i=0,d=new Array(h),e=k=0;h>k;e=k+=1)f=4*e,c=.2126*a.data[f+0]+.7152*a.data[f+1]+.0722*a.data[f+2],c=Math.round(c),i+=c,d[e]=c;for(g=Math.round(i/h),j=0,l=0,m=d.length;m>l;l++)c=d[l],j+=Math.pow(c-g,2);this._stats={mean:g,std:Math.round(Math.sqrt(j/h))}}return b.call(this,this._stats)},b.prototype._stats=null,b.prototype._upload_done=function(){var a,b,c,d;return this.camera._debug("Upload completed with status "+this._status),this._done=!0,a=this._options(),c=a.retry_success&&a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_done?a.on_upload_done.call(this,this._response):void 0)},b.prototype._upload_fail=function(){var a,b,c,d;return this.camera._debug("Upload failed with status "+this._status),this._fail=!0,a=this._options(),c=a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_fail?a.on_upload_fail.call(this,this._status,this._error_message,this._response):void 0)},b}()}.call(this);
@@ -1,8 +1,8 @@
1
- /*! JpegCamera 1.0.2 | 2013-07-30
1
+ /*! JpegCamera 1.1.1 | 2013-08-05
2
2
  (c) 2013 Adam Wrobel
3
3
  http://amw.github.io/jpeg_camera */
4
4
  (function() {
5
- var JpegCamera, JpegCameraHtml5, Snapshot, _ref,
5
+ var JpegCamera, JpegCameraHtml5, Snapshot, check_canvas_to_blob, _ref,
6
6
  __hasProp = {}.hasOwnProperty,
7
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
8
 
@@ -22,16 +22,25 @@
22
22
  retry_success: false
23
23
  };
24
24
 
25
+ JpegCamera._canvas_supported = !!document.createElement('canvas').getContext;
26
+
27
+ JpegCamera.canvas_supported = function() {
28
+ return this._canvas_supported;
29
+ };
30
+
25
31
  function JpegCamera(container, options) {
26
32
  if ("string" === typeof container) {
27
- this.container = document.querySelector(container);
28
- } else {
29
- this.container = container;
33
+ container = document.getElementById(container.replace("#", ""));
30
34
  }
31
- if (!(this.container && this.container.offsetWidth)) {
35
+ if (!(container && container.offsetWidth)) {
32
36
  throw "JpegCamera: invalid container";
33
37
  }
34
- this.container.innerHTML = "";
38
+ container.innerHTML = "";
39
+ this.container = document.createElement("div");
40
+ this.container.style.width = "100%";
41
+ this.container.style.height = "100%";
42
+ this.container.style.position = "relative";
43
+ container.appendChild(this.container);
35
44
  this.options = this._extend({}, this.constructor.DefaultOptions, options);
36
45
  this._engine_init();
37
46
  }
@@ -56,6 +65,18 @@
56
65
 
57
66
  JpegCamera.prototype._error_occured = false;
58
67
 
68
+ JpegCamera.StatsCaptureScale = 0.2;
69
+
70
+ JpegCamera.prototype.get_stats = function(callback) {
71
+ var snapshot, that;
72
+ snapshot = new Snapshot(this, {});
73
+ this._engine_capture(snapshot, false, 0.1, JpegCamera.StatsCaptureScale);
74
+ that = this;
75
+ return snapshot.get_stats(function(stats) {
76
+ return callback.call(that, stats);
77
+ });
78
+ };
79
+
59
80
  JpegCamera.prototype.capture = function(options) {
60
81
  var snapshot, _options;
61
82
  if (options == null) {
@@ -67,7 +88,7 @@
67
88
  if (_options.shutter) {
68
89
  this._engine_play_shutter_sound();
69
90
  }
70
- this._engine_capture(snapshot, _options.mirror, _options.quality);
91
+ this._engine_capture(snapshot, _options.mirror, _options.quality, 1.0);
71
92
  return snapshot;
72
93
  };
73
94
 
@@ -130,10 +151,6 @@
130
151
 
131
152
  JpegCamera.prototype._displayed_snapshot = null;
132
153
 
133
- JpegCamera.prototype._upload = function(snapshot, api_url, csrf_token, timeout) {
134
- return this._engine_upload(snapshot, api_url, csrf_token, timeout);
135
- };
136
-
137
154
  JpegCamera.prototype._discard = function(snapshot) {
138
155
  if (this._displayed_snapshot === snapshot) {
139
156
  this.show_stream();
@@ -144,10 +161,33 @@
144
161
  };
145
162
 
146
163
  JpegCamera.prototype._prepared = function() {
147
- this._is_ready = true;
148
- if (this.options.on_ready) {
149
- return this.options.on_ready.call(this);
150
- }
164
+ var that;
165
+ that = this;
166
+ return setTimeout((function() {
167
+ return that._wait_until_stream_looks_ok(true);
168
+ }), 1);
169
+ };
170
+
171
+ JpegCamera.prototype._wait_until_stream_looks_ok = function(show_debug) {
172
+ return this.get_stats(function(stats) {
173
+ var that;
174
+ if (stats.std > 2) {
175
+ this._debug("Stream mean gray value = " + stats.mean + " standard deviation = " + stats.std);
176
+ this._debug("Camera is ready");
177
+ this._is_ready = true;
178
+ if (this.options.on_ready) {
179
+ return this.options.on_ready.call(this);
180
+ }
181
+ } else {
182
+ if (show_debug) {
183
+ this._debug("Stream mean gray value = " + stats.mean + " standard deviation = " + stats.std);
184
+ }
185
+ that = this;
186
+ return setTimeout((function() {
187
+ return that._wait_until_stream_looks_ok(false);
188
+ }), 100);
189
+ }
190
+ });
151
191
  };
152
192
 
153
193
  JpegCamera.prototype._got_error = function(error) {
@@ -158,13 +198,45 @@
158
198
  }
159
199
  };
160
200
 
201
+ JpegCamera.prototype._block_element_access = function() {
202
+ this._overlay = document.createElement("div");
203
+ this._overlay.style.width = "100%";
204
+ this._overlay.style.height = "100%";
205
+ this._overlay.style.position = "absolute";
206
+ this._overlay.style.top = 0;
207
+ this._overlay.style.left = 0;
208
+ this._overlay.style.zIndex = 2;
209
+ return this.container.appendChild(this._overlay);
210
+ };
211
+
212
+ JpegCamera.prototype._overlay = null;
213
+
214
+ JpegCamera._add_prefixed_style = function(element, style, value) {
215
+ var uppercase_style;
216
+ uppercase_style = style.charAt(0).toUpperCase() + style.slice(1);
217
+ element.style[style] = value;
218
+ element.style["Webkit" + uppercase_style] = value;
219
+ element.style["Moz" + uppercase_style] = value;
220
+ element.style["ms" + uppercase_style] = value;
221
+ return element.style["O" + uppercase_style] = value;
222
+ };
223
+
161
224
  return JpegCamera;
162
225
 
163
226
  })();
164
227
 
165
228
  navigator.getUserMedia || (navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
166
229
 
230
+ check_canvas_to_blob = function() {
231
+ var canvas;
232
+ canvas = document.createElement("canvas");
233
+ if (canvas.getContext && !canvas.toBlob) {
234
+ throw "JpegCamera: Canvas-to-Blob is not loaded";
235
+ }
236
+ };
237
+
167
238
  if (navigator.getUserMedia) {
239
+ check_canvas_to_blob();
168
240
  JpegCameraHtml5 = (function(_super) {
169
241
  __extends(JpegCameraHtml5, _super);
170
242
 
@@ -174,20 +246,15 @@
174
246
  }
175
247
 
176
248
  JpegCameraHtml5.prototype._engine_init = function() {
177
- var get_user_media_options, horizontal_padding, that, vertical_padding;
249
+ var error, failure, get_user_media_options, horizontal_padding, success, that, vertical_padding;
178
250
  this._debug("Using HTML5 engine");
179
- this.internal_container = document.createElement("div");
180
- this.internal_container.style.width = "100%";
181
- this.internal_container.style.height = "100%";
182
- this.internal_container.style.position = "relative";
183
- this.container.appendChild(this.internal_container);
184
251
  vertical_padding = Math.floor(this._view_height() * 0.2);
185
252
  horizontal_padding = Math.floor(this._view_width() * 0.2);
186
253
  this.message = document.createElement("div");
187
254
  this.message["class"] = "message";
188
255
  this.message.style.width = "100%";
189
256
  this.message.style.height = "100%";
190
- this._add_prefixed_style(this.message, "boxSizing", "border-box");
257
+ JpegCamera._add_prefixed_style(this.message, "boxSizing", "border-box");
191
258
  this.message.style.overflow = "hidden";
192
259
  this.message.style.textAlign = "center";
193
260
  this.message.style.paddingTop = "" + vertical_padding + "px";
@@ -196,18 +263,18 @@
196
263
  this.message.style.paddingRight = "" + horizontal_padding + "px";
197
264
  this.message.style.position = "absolute";
198
265
  this.message.style.zIndex = 3;
199
- this.message.innerHTML = "Please allow camera access when prompted by the browser.";
200
- this.internal_container.appendChild(this.message);
266
+ this.message.innerHTML = "Please allow camera access when prompted by the browser.<br><br>" + "Look for camera icon around your address bar.";
267
+ this.container.appendChild(this.message);
201
268
  this.video_container = document.createElement("div");
202
269
  this.video_container.style.width = "" + (this._view_width()) + "px";
203
270
  this.video_container.style.height = "" + (this._view_height()) + "px";
204
271
  this.video_container.style.overflow = "hidden";
205
272
  this.video_container.style.position = "absolute";
206
273
  this.video_container.style.zIndex = 1;
207
- this.internal_container.appendChild(this.video_container);
274
+ this.container.appendChild(this.video_container);
208
275
  this.video = document.createElement('video');
209
276
  this.video.autoplay = true;
210
- this._add_prefixed_style(this.video, "transform", "scalex(-1.0)");
277
+ JpegCamera._add_prefixed_style(this.video, "transform", "scalex(-1.0)");
211
278
  window.AudioContext || (window.AudioContext = window.webkitAudioContext);
212
279
  if (window.AudioContext) {
213
280
  this._load_shutter_sound();
@@ -228,16 +295,19 @@
228
295
  }
229
296
  };
230
297
  that = this;
231
- return navigator.getUserMedia(get_user_media_options, function(stream) {
298
+ success = function(stream) {
232
299
  that._remove_message();
233
300
  if (window.URL) {
234
301
  that.video.src = URL.createObjectURL(stream);
235
302
  } else {
236
303
  that.video.src = stream;
237
304
  }
305
+ that._block_element_access();
238
306
  return that._wait_for_video_ready();
239
- }, function(error) {
307
+ };
308
+ failure = function(error) {
240
309
  var code, key, value;
310
+ that.message.innerHTML = "<span style=\"color: red;\">" + "You have denied camera access." + "</span><br><br>" + "Look for camera icon around your address bar to change your " + "decision.";
241
311
  code = error.code;
242
312
  for (key in error) {
243
313
  value = error[key];
@@ -248,7 +318,13 @@
248
318
  return;
249
319
  }
250
320
  return that._got_error("UNKNOWN ERROR");
251
- });
321
+ };
322
+ try {
323
+ return navigator.getUserMedia(get_user_media_options, success, failure);
324
+ } catch (_error) {
325
+ error = _error;
326
+ return navigator.getUserMedia("video", success, failure);
327
+ }
252
328
  };
253
329
 
254
330
  JpegCameraHtml5.prototype._engine_play_shutter_sound = function() {
@@ -262,14 +338,14 @@
262
338
  return source.start(0);
263
339
  };
264
340
 
265
- JpegCameraHtml5.prototype._engine_capture = function(snapshot, mirror, quality) {
341
+ JpegCameraHtml5.prototype._engine_capture = function(snapshot, mirror, quality, scale) {
266
342
  var canvas, context, crop;
267
343
  crop = this._get_capture_crop();
268
344
  canvas = document.createElement("canvas");
269
- canvas.width = crop.width;
270
- canvas.height = crop.height;
345
+ canvas.width = Math.round(crop.width * scale);
346
+ canvas.height = Math.round(crop.height * scale);
271
347
  context = canvas.getContext("2d");
272
- context.drawImage(this.video, crop.x_offset, crop.y_offset, crop.width, crop.height, 0, 0, crop.width, crop.height);
348
+ context.drawImage(this.video, crop.x_offset, crop.y_offset, crop.width, crop.height, 0, 0, Math.round(crop.width * scale), Math.round(crop.height * scale));
273
349
  snapshot._canvas = canvas;
274
350
  snapshot._mirror = mirror;
275
351
  return snapshot._quality = quality;
@@ -277,7 +353,7 @@
277
353
 
278
354
  JpegCameraHtml5.prototype._engine_display = function(snapshot) {
279
355
  if (this.displayed_canvas) {
280
- this.internal_container.removeChild(this.displayed_canvas);
356
+ this.container.removeChild(this.displayed_canvas);
281
357
  }
282
358
  this.displayed_canvas = snapshot._canvas;
283
359
  this.displayed_canvas.style.width = "" + (this._view_width()) + "px";
@@ -286,8 +362,25 @@
286
362
  this.displayed_canvas.style.left = 0;
287
363
  this.displayed_canvas.style.position = "absolute";
288
364
  this.displayed_canvas.style.zIndex = 2;
289
- this._add_prefixed_style(this.displayed_canvas, "transform", "scalex(-1.0)");
290
- return this.internal_container.appendChild(this.displayed_canvas);
365
+ JpegCamera._add_prefixed_style(this.displayed_canvas, "transform", "scalex(-1.0)");
366
+ return this.container.appendChild(this.displayed_canvas);
367
+ };
368
+
369
+ JpegCameraHtml5.prototype._engine_get_canvas = function(snapshot) {
370
+ var canvas, context;
371
+ canvas = document.createElement("canvas");
372
+ canvas.width = snapshot._canvas.width;
373
+ canvas.height = snapshot._canvas.height;
374
+ context = canvas.getContext("2d");
375
+ context.drawImage(snapshot._canvas, 0, 0);
376
+ return canvas;
377
+ };
378
+
379
+ JpegCameraHtml5.prototype._engine_get_image_data = function(snapshot) {
380
+ var canvas, context;
381
+ canvas = snapshot._canvas;
382
+ context = canvas.getContext("2d");
383
+ return context.getImageData(0, 0, canvas.width, canvas.height);
291
384
  };
292
385
 
293
386
  JpegCameraHtml5.prototype._engine_discard = function(snapshot) {
@@ -301,7 +394,7 @@
301
394
 
302
395
  JpegCameraHtml5.prototype._engine_show_stream = function() {
303
396
  if (this.displayed_canvas) {
304
- this.internal_container.removeChild(this.displayed_canvas);
397
+ this.container.removeChild(this.displayed_canvas);
305
398
  this.displayed_canvas = null;
306
399
  }
307
400
  return this.video_container.style.display = "block";
@@ -406,16 +499,6 @@
406
499
 
407
500
  JpegCameraHtml5.prototype._status_checks_count = 0;
408
501
 
409
- JpegCameraHtml5.prototype._add_prefixed_style = function(element, style, value) {
410
- var uppercase_style;
411
- uppercase_style = style.charAt(0).toUpperCase() + style.slice(1);
412
- element.style[style] = value;
413
- element.style["Webkit" + uppercase_style] = value;
414
- element.style["Moz" + uppercase_style] = value;
415
- element.style["ms" + uppercase_style] = value;
416
- return element.style["O" + uppercase_style] = value;
417
- };
418
-
419
502
  JpegCameraHtml5.prototype._get_video_crop = function() {
420
503
  var scaled_video_height, scaled_video_width, video_ratio, video_scale, view_height, view_ratio, view_width;
421
504
  view_width = this._view_width();
@@ -506,6 +589,48 @@
506
589
  return this;
507
590
  };
508
591
 
592
+ Snapshot.prototype.get_stats = function(callback) {
593
+ if (this._discarded) {
594
+ raise("discarded snapshot cannot be used");
595
+ }
596
+ return this.get_image_data(function(data) {
597
+ return this._get_stats(data, callback);
598
+ });
599
+ };
600
+
601
+ Snapshot.prototype.get_canvas = function(callback) {
602
+ var that;
603
+ if (this._discarded) {
604
+ raise("discarded snapshot cannot be used");
605
+ }
606
+ if (!JpegCamera._canvas_supported) {
607
+ false;
608
+ }
609
+ that = this;
610
+ setTimeout(function() {
611
+ that._extra_canvas || (that._extra_canvas = that.camera._engine_get_canvas(that));
612
+ JpegCamera._add_prefixed_style(that._extra_canvas, "transform", "scalex(-1.0)");
613
+ return callback.call(that, that._extra_canvas);
614
+ }, 10);
615
+ return true;
616
+ };
617
+
618
+ Snapshot.prototype._extra_canvas = null;
619
+
620
+ Snapshot.prototype.get_image_data = function(callback) {
621
+ var that;
622
+ if (this._discarded) {
623
+ raise("discarded snapshot cannot be used");
624
+ }
625
+ that = this;
626
+ return setTimeout(function() {
627
+ that._image_data || (that._image_data = that.camera._engine_get_image_data(that));
628
+ return callback.call(that, that._image_data);
629
+ }, 5);
630
+ };
631
+
632
+ Snapshot.prototype._image_data = null;
633
+
509
634
  Snapshot.prototype.upload = function(options) {
510
635
  var cache;
511
636
  if (options == null) {
@@ -593,9 +718,38 @@
593
718
  this._fail = false;
594
719
  this._status = null;
595
720
  this._error_message = null;
596
- return this.camera._upload(this, cache.api_url, csrf_token, cache.timeout);
721
+ return this.camera._engine_upload(this, cache.api_url, csrf_token, cache.timeout);
597
722
  };
598
723
 
724
+ Snapshot.prototype._get_stats = function(data, callback) {
725
+ var gray, gray_values, i, index, mean, n, sum, sum_of_square_distances, _i, _j, _len;
726
+ if (!this._stats) {
727
+ n = data.width * data.height;
728
+ sum = 0.0;
729
+ gray_values = new Array(n);
730
+ for (i = _i = 0; _i < n; i = _i += 1) {
731
+ index = i * 4;
732
+ gray = 0.2126 * data.data[index + 0] + 0.7152 * data.data[index + 1] + 0.0722 * data.data[index + 2];
733
+ gray = Math.round(gray);
734
+ sum += gray;
735
+ gray_values[i] = gray;
736
+ }
737
+ mean = Math.round(sum / n);
738
+ sum_of_square_distances = 0;
739
+ for (_j = 0, _len = gray_values.length; _j < _len; _j++) {
740
+ gray = gray_values[_j];
741
+ sum_of_square_distances += Math.pow(gray - mean, 2);
742
+ }
743
+ this._stats = {
744
+ mean: mean,
745
+ std: Math.round(Math.sqrt(sum_of_square_distances / n))
746
+ };
747
+ }
748
+ return callback.call(this, this._stats);
749
+ };
750
+
751
+ Snapshot.prototype._stats = null;
752
+
599
753
  Snapshot.prototype._upload_done = function() {
600
754
  var cache, delay, retry_decision, that;
601
755
  this.camera._debug("Upload completed with status " + this._status);
@@ -1,4 +1,4 @@
1
- /*! JpegCamera 1.0.2 | 2013-07-30
1
+ /*! JpegCamera 1.1.1 | 2013-08-05
2
2
  (c) 2013 Adam Wrobel
3
3
  http://amw.github.io/jpeg_camera */
4
- !function(){var a,b,c,d,e={}.hasOwnProperty,f=function(a,b){function c(){this.constructor=a}for(var d in b)e.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};a=function(){function a(a,b){if(this.container="string"==typeof a?document.querySelector(a):a,!this.container||!this.container.offsetWidth)throw"JpegCamera: invalid container";this.container.innerHTML="",this.options=this._extend({},this.constructor.DefaultOptions,b),this._engine_init()}return a.DefaultOptions={shutter_url:"/jpeg_camera/shutter.mp3",swf_url:"/jpeg_camera/jpeg_camera.swf",on_debug:function(a){return console&&console.log?console.log("JpegCamera: "+a):void 0},quality:.9,shutter:!0,mirror:!1,timeout:0,retry_success:!1},a.prototype.ready=function(a){return this.options.on_ready=a,this.options.on_ready&&this._is_ready&&this.options.on_ready.call(this),this},a.prototype._is_ready=!1,a.prototype.error=function(a){return this.options.on_error=a,this.options.on_error&&this._error_occured&&this.options.on_error.call(this,this._error_occured),this},a.prototype._error_occured=!1,a.prototype.capture=function(a){var b,d;return null==a&&(a={}),b=new c(this,a),this._snapshots[b.id]=b,d=b._options(),d.shutter&&this._engine_play_shutter_sound(),this._engine_capture(b,d.mirror,d.quality),b},a.prototype._snapshots={},a.prototype.show_stream=function(){return this._engine_show_stream(),this._displayed_snapshot=null,this},a.prototype.discard_all=function(){var a,b,c;this._displayed_snapshot&&this.show_stream(),c=this._snapshots;for(a in c)b=c[a],this._engine_discard(b),b._discarded=!0;return this._snapshots={},this},a.prototype._extend=function(a){var b,c,d,e,f,g;for(d=Array.prototype.slice.call(arguments,1),f=0,g=d.length;g>f;f++)if(c=d[f])for(b in c)e=c[b],a[b]=e;return a},a.prototype._debug=function(a){return this.options.on_debug?this.options.on_debug.call(this,a):void 0},a.prototype._view_width=function(){return parseInt(this.container.offsetWidth,10)},a.prototype._view_height=function(){return parseInt(this.container.offsetHeight,10)},a.prototype._display=function(a){return this._engine_display(a),this._displayed_snapshot=a},a.prototype._displayed_snapshot=null,a.prototype._upload=function(a,b,c,d){return this._engine_upload(a,b,c,d)},a.prototype._discard=function(a){return this._displayed_snapshot===a&&this.show_stream(),this._engine_discard(a),a._discarded=!0,delete this._snapshots[a.id]},a.prototype._prepared=function(){return this._is_ready=!0,this.options.on_ready?this.options.on_ready.call(this):void 0},a.prototype._got_error=function(a){return this._debug("Error - "+a),this._error_occured=a,this.options.on_error?this.options.on_error.call(this,this._error_occured):void 0},a}(),navigator.getUserMedia||(navigator.getUserMedia=navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia),navigator.getUserMedia&&(b=function(a){function b(){return d=b.__super__.constructor.apply(this,arguments)}return f(b,a),b.prototype._engine_init=function(){var a,b,c,d;return this._debug("Using HTML5 engine"),this.internal_container=document.createElement("div"),this.internal_container.style.width="100%",this.internal_container.style.height="100%",this.internal_container.style.position="relative",this.container.appendChild(this.internal_container),d=Math.floor(.2*this._view_height()),b=Math.floor(.2*this._view_width()),this.message=document.createElement("div"),this.message["class"]="message",this.message.style.width="100%",this.message.style.height="100%",this._add_prefixed_style(this.message,"boxSizing","border-box"),this.message.style.overflow="hidden",this.message.style.textAlign="center",this.message.style.paddingTop=""+d+"px",this.message.style.paddingBottom=""+d+"px",this.message.style.paddingLeft=""+b+"px",this.message.style.paddingRight=""+b+"px",this.message.style.position="absolute",this.message.style.zIndex=3,this.message.innerHTML="Please allow camera access when prompted by the browser.",this.internal_container.appendChild(this.message),this.video_container=document.createElement("div"),this.video_container.style.width=""+this._view_width()+"px",this.video_container.style.height=""+this._view_height()+"px",this.video_container.style.overflow="hidden",this.video_container.style.position="absolute",this.video_container.style.zIndex=1,this.internal_container.appendChild(this.video_container),this.video=document.createElement("video"),this.video.autoplay=!0,this._add_prefixed_style(this.video,"transform","scalex(-1.0)"),window.AudioContext||(window.AudioContext=window.webkitAudioContext),window.AudioContext&&this._load_shutter_sound(),a={video:{optional:[{minWidth:1280},{minWidth:640},{minWidth:480},{minWidth:360}]}},c=this,navigator.getUserMedia(a,function(a){return c._remove_message(),c.video.src=window.URL?URL.createObjectURL(a):a,c._wait_for_video_ready()},function(a){var b,d,e;b=a.code;for(d in a)if(e=a[d],"code"!==d)return c._got_error(d),void 0;return c._got_error("UNKNOWN ERROR")})},b.prototype._engine_play_shutter_sound=function(){var a;if(this.shutter_buffer)return a=this.audio_context.createBufferSource(),a.buffer=this.shutter_buffer,a.connect(this.audio_context.destination),a.start(0)},b.prototype._engine_capture=function(a,b,c){var d,e,f;return f=this._get_capture_crop(),d=document.createElement("canvas"),d.width=f.width,d.height=f.height,e=d.getContext("2d"),e.drawImage(this.video,f.x_offset,f.y_offset,f.width,f.height,0,0,f.width,f.height),a._canvas=d,a._mirror=b,a._quality=c},b.prototype._engine_display=function(a){return this.displayed_canvas&&this.internal_container.removeChild(this.displayed_canvas),this.displayed_canvas=a._canvas,this.displayed_canvas.style.width=""+this._view_width()+"px",this.displayed_canvas.style.height=""+this._view_height()+"px",this.displayed_canvas.style.top=0,this.displayed_canvas.style.left=0,this.displayed_canvas.style.position="absolute",this.displayed_canvas.style.zIndex=2,this._add_prefixed_style(this.displayed_canvas,"transform","scalex(-1.0)"),this.internal_container.appendChild(this.displayed_canvas)},b.prototype._engine_discard=function(a){return a._xhr&&a._xhr.abort(),delete a._xhr,delete a._canvas,delete a._jpeg_blob},b.prototype._engine_show_stream=function(){return this.displayed_canvas&&(this.internal_container.removeChild(this.displayed_canvas),this.displayed_canvas=null),this.video_container.style.display="block"},b.prototype._engine_upload=function(a,b,c,d){var e,f,g,h,i;return h=this,a._jpeg_blob?(this._debug("Uploading the file"),g=function(b){return delete a._xhr,a._status=b.target.status,a._response=b.target.responseText,a._status>=200&&a._status<300?a._upload_done():(a._error_message=b.target.statusText||"Unknown error",a._upload_fail())},i=new XMLHttpRequest,i.open("POST",b),i.timeout=d,c&&i.setRequestHeader("X-CSRF-Token",c),i.onload=g,i.onerror=g,i.onabort=g,i.send(a._jpeg_blob),a._xhr=i):(this._debug("Generating JPEG file"),a._mirror?(e=document.createElement("canvas"),e.width=a._canvas.width,e.height=a._canvas.height,f=e.getContext("2d"),f.setTransform(1,0,0,1,0,0),f.translate(e.width,0),f.scale(-1,1),f.drawImage(a._canvas,0,0)):e=a._canvas,e.toBlob(function(e){return a._jpeg_blob=e,h._engine_upload(a,b,c,d)},"image/jpeg",this.quality))},b.prototype._remove_message=function(){return this.message.style.display="none"},b.prototype._load_shutter_sound=function(){var a,b;if(!this.audio_context)return this.audio_context=new AudioContext,a=new XMLHttpRequest,a.open("GET",this.options.shutter_url,!0),a.responseType="arraybuffer",b=this,a.onload=function(){return b.audio_context.decodeAudioData(a.response,function(a){return b.shutter_buffer=a})},a.send()},b.prototype._wait_for_video_ready=function(){var a,b,c,d;return d=parseInt(this.video.videoWidth),c=parseInt(this.video.videoHeight),d>0&&c>0?(this.video_container.appendChild(this.video),this.video_width=d,this.video_height=c,this._debug("Camera resolution "+this.video_width+"x"+this.video_height+"px"),a=this._get_video_crop(),this.video.style.position="relative",this.video.style.width=""+a.width+"px",this.video.style.height=""+a.height+"px",this.video.style.left=""+a.x_offset+"px",this.video.style.top=""+a.y_offset+"px",this._prepared()):this._status_checks_count>100?this._got_error("Camera failed to initialize in 10 seconds"):(this._status_checks_count++,b=this,setTimeout(function(){return b._wait_for_video_ready()},100))},b.prototype._status_checks_count=0,b.prototype._add_prefixed_style=function(a,b,c){var d;return d=b.charAt(0).toUpperCase()+b.slice(1),a.style[b]=c,a.style["Webkit"+d]=c,a.style["Moz"+d]=c,a.style["ms"+d]=c,a.style["O"+d]=c},b.prototype._get_video_crop=function(){var a,b,c,d,e,f,g;return g=this._view_width(),e=this._view_height(),c=this.video_width/this.video_height,f=g/e,c>=f?(this._debug("Filling height"),d=e/this.video_height,b=Math.round(this.video_width*d),{width:b,height:e,x_offset:-Math.floor((b-g)/2),y_offset:0}):(this._debug("Filling width"),d=g/this.video_width,a=Math.round(this.video_height*d),{width:g,height:a,x_offset:0,y_offset:-Math.floor((a-e)/2)})},b.prototype._get_capture_crop=function(){var a,b,c,d,e,f;return f=this._view_width(),d=this._view_height(),c=this.video_width/this.video_height,e=f/d,c>=e?(b=Math.round(this.video_height*e),{width:b,height:this.video_height,x_offset:Math.floor((this.video_width-b)/2),y_offset:0}):(a=Math.round(this.video_width/e),{width:this.video_width,height:a,x_offset:0,y_offset:Math.floor((this.video_height-a)/2)})},b}(a),window.JpegCamera=b),c=function(){function a(a,b){this.camera=a,this.options=b,this.id=this.constructor._next_snapshot_id++}return a._next_snapshot_id=1,a.prototype._discarded=!1,a.prototype.show=function(){return this._discarded&&raise("discarded snapshot cannot be used"),this.camera._display(this),this},a.prototype.hide=function(){return this.camera.displayed_snapshot()===this&&this.camera.show_stream(),this},a.prototype.upload=function(a){var b;if(null==a&&(a={}),this._discarded&&raise("discarded snapshot cannot be used"),this._uploading)return this.camera._debug("Upload already in progress"),void 0;if(this._uploading=!0,this._retry=1,this._upload_options=a,b=this._options(),!b.api_url)throw this.camera._debug("Snapshot#upload called without valid api_url"),"Snapshot#upload called without valid api_url";return this._start_upload(b),this},a.prototype._upload_options={},a.prototype._uploading=!1,a.prototype._retry=1,a.prototype.done=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_done=a,b=this._options(),b.on_upload_done&&this._done&&b.on_upload_done.call(this,this._response),this},a.prototype._done=!1,a.prototype._response=null,a.prototype.fail=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_fail=a,b=this._options(),b.on_upload_fail&&this._fail&&b.on_upload_fail.call(this,this._status,this._error_message,this._response),this},a.prototype._fail=!1,a.prototype._status=null,a.prototype._error_message=null,a.prototype.discard=function(){return this.camera._discard(this),void 0},a.prototype._options=function(){return this.camera._extend({},this.camera.options,this.options,this._upload_options)},a.prototype._start_upload=function(a){var b;return b="string"==typeof a.csrf_token&&a.csrf_token.length>0?a.csrf_token:null,this._done=!1,this._response=null,this._fail=!1,this._status=null,this._error_message=null,this.camera._upload(this,a.api_url,b,a.timeout)},a.prototype._upload_done=function(){var a,b,c,d;return this.camera._debug("Upload completed with status "+this._status),this._done=!0,a=this._options(),c=a.retry_success&&a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_done?a.on_upload_done.call(this,this._response):void 0)},a.prototype._upload_fail=function(){var a,b,c,d;return this.camera._debug("Upload failed with status "+this._status),this._fail=!0,a=this._options(),c=a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_fail?a.on_upload_fail.call(this,this._status,this._error_message,this._response):void 0)},a}()}.call(this);
4
+ !function(){var a,b,c,d,e,f={}.hasOwnProperty,g=function(a,b){function c(){this.constructor=a}for(var d in b)f.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};a=function(){function a(a,b){if("string"==typeof a&&(a=document.getElementById(a.replace("#",""))),!a||!a.offsetWidth)throw"JpegCamera: invalid container";a.innerHTML="",this.container=document.createElement("div"),this.container.style.width="100%",this.container.style.height="100%",this.container.style.position="relative",a.appendChild(this.container),this.options=this._extend({},this.constructor.DefaultOptions,b),this._engine_init()}return a.DefaultOptions={shutter_url:"/jpeg_camera/shutter.mp3",swf_url:"/jpeg_camera/jpeg_camera.swf",on_debug:function(a){return console&&console.log?console.log("JpegCamera: "+a):void 0},quality:.9,shutter:!0,mirror:!1,timeout:0,retry_success:!1},a._canvas_supported=!!document.createElement("canvas").getContext,a.canvas_supported=function(){return this._canvas_supported},a.prototype.ready=function(a){return this.options.on_ready=a,this.options.on_ready&&this._is_ready&&this.options.on_ready.call(this),this},a.prototype._is_ready=!1,a.prototype.error=function(a){return this.options.on_error=a,this.options.on_error&&this._error_occured&&this.options.on_error.call(this,this._error_occured),this},a.prototype._error_occured=!1,a.StatsCaptureScale=.2,a.prototype.get_stats=function(b){var d,e;return d=new c(this,{}),this._engine_capture(d,!1,.1,a.StatsCaptureScale),e=this,d.get_stats(function(a){return b.call(e,a)})},a.prototype.capture=function(a){var b,d;return null==a&&(a={}),b=new c(this,a),this._snapshots[b.id]=b,d=b._options(),d.shutter&&this._engine_play_shutter_sound(),this._engine_capture(b,d.mirror,d.quality,1),b},a.prototype._snapshots={},a.prototype.show_stream=function(){return this._engine_show_stream(),this._displayed_snapshot=null,this},a.prototype.discard_all=function(){var a,b,c;this._displayed_snapshot&&this.show_stream(),c=this._snapshots;for(a in c)b=c[a],this._engine_discard(b),b._discarded=!0;return this._snapshots={},this},a.prototype._extend=function(a){var b,c,d,e,f,g;for(d=Array.prototype.slice.call(arguments,1),f=0,g=d.length;g>f;f++)if(c=d[f])for(b in c)e=c[b],a[b]=e;return a},a.prototype._debug=function(a){return this.options.on_debug?this.options.on_debug.call(this,a):void 0},a.prototype._view_width=function(){return parseInt(this.container.offsetWidth,10)},a.prototype._view_height=function(){return parseInt(this.container.offsetHeight,10)},a.prototype._display=function(a){return this._engine_display(a),this._displayed_snapshot=a},a.prototype._displayed_snapshot=null,a.prototype._discard=function(a){return this._displayed_snapshot===a&&this.show_stream(),this._engine_discard(a),a._discarded=!0,delete this._snapshots[a.id]},a.prototype._prepared=function(){var a;return a=this,setTimeout(function(){return a._wait_until_stream_looks_ok(!0)},1)},a.prototype._wait_until_stream_looks_ok=function(a){return this.get_stats(function(b){var c;return b.std>2?(this._debug("Stream mean gray value = "+b.mean+" standard deviation = "+b.std),this._debug("Camera is ready"),this._is_ready=!0,this.options.on_ready?this.options.on_ready.call(this):void 0):(a&&this._debug("Stream mean gray value = "+b.mean+" standard deviation = "+b.std),c=this,setTimeout(function(){return c._wait_until_stream_looks_ok(!1)},100))})},a.prototype._got_error=function(a){return this._debug("Error - "+a),this._error_occured=a,this.options.on_error?this.options.on_error.call(this,this._error_occured):void 0},a.prototype._block_element_access=function(){return this._overlay=document.createElement("div"),this._overlay.style.width="100%",this._overlay.style.height="100%",this._overlay.style.position="absolute",this._overlay.style.top=0,this._overlay.style.left=0,this._overlay.style.zIndex=2,this.container.appendChild(this._overlay)},a.prototype._overlay=null,a._add_prefixed_style=function(a,b,c){var d;return d=b.charAt(0).toUpperCase()+b.slice(1),a.style[b]=c,a.style["Webkit"+d]=c,a.style["Moz"+d]=c,a.style["ms"+d]=c,a.style["O"+d]=c},a}(),navigator.getUserMedia||(navigator.getUserMedia=navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia),d=function(){var a;if(a=document.createElement("canvas"),a.getContext&&!a.toBlob)throw"JpegCamera: Canvas-to-Blob is not loaded"},navigator.getUserMedia&&(d(),b=function(b){function c(){return e=c.__super__.constructor.apply(this,arguments)}return g(c,b),c.prototype._engine_init=function(){var b,c,d,e,f,g,h;this._debug("Using HTML5 engine"),h=Math.floor(.2*this._view_height()),e=Math.floor(.2*this._view_width()),this.message=document.createElement("div"),this.message["class"]="message",this.message.style.width="100%",this.message.style.height="100%",a._add_prefixed_style(this.message,"boxSizing","border-box"),this.message.style.overflow="hidden",this.message.style.textAlign="center",this.message.style.paddingTop=""+h+"px",this.message.style.paddingBottom=""+h+"px",this.message.style.paddingLeft=""+e+"px",this.message.style.paddingRight=""+e+"px",this.message.style.position="absolute",this.message.style.zIndex=3,this.message.innerHTML="Please allow camera access when prompted by the browser.<br><br>Look for camera icon around your address bar.",this.container.appendChild(this.message),this.video_container=document.createElement("div"),this.video_container.style.width=""+this._view_width()+"px",this.video_container.style.height=""+this._view_height()+"px",this.video_container.style.overflow="hidden",this.video_container.style.position="absolute",this.video_container.style.zIndex=1,this.container.appendChild(this.video_container),this.video=document.createElement("video"),this.video.autoplay=!0,a._add_prefixed_style(this.video,"transform","scalex(-1.0)"),window.AudioContext||(window.AudioContext=window.webkitAudioContext),window.AudioContext&&this._load_shutter_sound(),d={video:{optional:[{minWidth:1280},{minWidth:640},{minWidth:480},{minWidth:360}]}},g=this,f=function(a){return g._remove_message(),g.video.src=window.URL?URL.createObjectURL(a):a,g._block_element_access(),g._wait_for_video_ready()},c=function(a){var b,c,d;g.message.innerHTML='<span style="color: red;">You have denied camera access.</span><br><br>Look for camera icon around your address bar to change your decision.',b=a.code;for(c in a)if(d=a[c],"code"!==c)return g._got_error(c),void 0;return g._got_error("UNKNOWN ERROR")};try{return navigator.getUserMedia(d,f,c)}catch(i){return b=i,navigator.getUserMedia("video",f,c)}},c.prototype._engine_play_shutter_sound=function(){var a;if(this.shutter_buffer)return a=this.audio_context.createBufferSource(),a.buffer=this.shutter_buffer,a.connect(this.audio_context.destination),a.start(0)},c.prototype._engine_capture=function(a,b,c,d){var e,f,g;return g=this._get_capture_crop(),e=document.createElement("canvas"),e.width=Math.round(g.width*d),e.height=Math.round(g.height*d),f=e.getContext("2d"),f.drawImage(this.video,g.x_offset,g.y_offset,g.width,g.height,0,0,Math.round(g.width*d),Math.round(g.height*d)),a._canvas=e,a._mirror=b,a._quality=c},c.prototype._engine_display=function(b){return this.displayed_canvas&&this.container.removeChild(this.displayed_canvas),this.displayed_canvas=b._canvas,this.displayed_canvas.style.width=""+this._view_width()+"px",this.displayed_canvas.style.height=""+this._view_height()+"px",this.displayed_canvas.style.top=0,this.displayed_canvas.style.left=0,this.displayed_canvas.style.position="absolute",this.displayed_canvas.style.zIndex=2,a._add_prefixed_style(this.displayed_canvas,"transform","scalex(-1.0)"),this.container.appendChild(this.displayed_canvas)},c.prototype._engine_get_canvas=function(a){var b,c;return b=document.createElement("canvas"),b.width=a._canvas.width,b.height=a._canvas.height,c=b.getContext("2d"),c.drawImage(a._canvas,0,0),b},c.prototype._engine_get_image_data=function(a){var b,c;return b=a._canvas,c=b.getContext("2d"),c.getImageData(0,0,b.width,b.height)},c.prototype._engine_discard=function(a){return a._xhr&&a._xhr.abort(),delete a._xhr,delete a._canvas,delete a._jpeg_blob},c.prototype._engine_show_stream=function(){return this.displayed_canvas&&(this.container.removeChild(this.displayed_canvas),this.displayed_canvas=null),this.video_container.style.display="block"},c.prototype._engine_upload=function(a,b,c,d){var e,f,g,h,i;return h=this,a._jpeg_blob?(this._debug("Uploading the file"),g=function(b){return delete a._xhr,a._status=b.target.status,a._response=b.target.responseText,a._status>=200&&a._status<300?a._upload_done():(a._error_message=b.target.statusText||"Unknown error",a._upload_fail())},i=new XMLHttpRequest,i.open("POST",b),i.timeout=d,c&&i.setRequestHeader("X-CSRF-Token",c),i.onload=g,i.onerror=g,i.onabort=g,i.send(a._jpeg_blob),a._xhr=i):(this._debug("Generating JPEG file"),a._mirror?(e=document.createElement("canvas"),e.width=a._canvas.width,e.height=a._canvas.height,f=e.getContext("2d"),f.setTransform(1,0,0,1,0,0),f.translate(e.width,0),f.scale(-1,1),f.drawImage(a._canvas,0,0)):e=a._canvas,e.toBlob(function(e){return a._jpeg_blob=e,h._engine_upload(a,b,c,d)},"image/jpeg",this.quality))},c.prototype._remove_message=function(){return this.message.style.display="none"},c.prototype._load_shutter_sound=function(){var a,b;if(!this.audio_context)return this.audio_context=new AudioContext,a=new XMLHttpRequest,a.open("GET",this.options.shutter_url,!0),a.responseType="arraybuffer",b=this,a.onload=function(){return b.audio_context.decodeAudioData(a.response,function(a){return b.shutter_buffer=a})},a.send()},c.prototype._wait_for_video_ready=function(){var a,b,c,d;return d=parseInt(this.video.videoWidth),c=parseInt(this.video.videoHeight),d>0&&c>0?(this.video_container.appendChild(this.video),this.video_width=d,this.video_height=c,this._debug("Camera resolution "+this.video_width+"x"+this.video_height+"px"),a=this._get_video_crop(),this.video.style.position="relative",this.video.style.width=""+a.width+"px",this.video.style.height=""+a.height+"px",this.video.style.left=""+a.x_offset+"px",this.video.style.top=""+a.y_offset+"px",this._prepared()):this._status_checks_count>100?this._got_error("Camera failed to initialize in 10 seconds"):(this._status_checks_count++,b=this,setTimeout(function(){return b._wait_for_video_ready()},100))},c.prototype._status_checks_count=0,c.prototype._get_video_crop=function(){var a,b,c,d,e,f,g;return g=this._view_width(),e=this._view_height(),c=this.video_width/this.video_height,f=g/e,c>=f?(this._debug("Filling height"),d=e/this.video_height,b=Math.round(this.video_width*d),{width:b,height:e,x_offset:-Math.floor((b-g)/2),y_offset:0}):(this._debug("Filling width"),d=g/this.video_width,a=Math.round(this.video_height*d),{width:g,height:a,x_offset:0,y_offset:-Math.floor((a-e)/2)})},c.prototype._get_capture_crop=function(){var a,b,c,d,e,f;return f=this._view_width(),d=this._view_height(),c=this.video_width/this.video_height,e=f/d,c>=e?(b=Math.round(this.video_height*e),{width:b,height:this.video_height,x_offset:Math.floor((this.video_width-b)/2),y_offset:0}):(a=Math.round(this.video_width/e),{width:this.video_width,height:a,x_offset:0,y_offset:Math.floor((this.video_height-a)/2)})},c}(a),window.JpegCamera=b),c=function(){function b(a,b){this.camera=a,this.options=b,this.id=this.constructor._next_snapshot_id++}return b._next_snapshot_id=1,b.prototype._discarded=!1,b.prototype.show=function(){return this._discarded&&raise("discarded snapshot cannot be used"),this.camera._display(this),this},b.prototype.hide=function(){return this.camera.displayed_snapshot()===this&&this.camera.show_stream(),this},b.prototype.get_stats=function(a){return this._discarded&&raise("discarded snapshot cannot be used"),this.get_image_data(function(b){return this._get_stats(b,a)})},b.prototype.get_canvas=function(b){var c;return this._discarded&&raise("discarded snapshot cannot be used"),!a._canvas_supported,c=this,setTimeout(function(){return c._extra_canvas||(c._extra_canvas=c.camera._engine_get_canvas(c)),a._add_prefixed_style(c._extra_canvas,"transform","scalex(-1.0)"),b.call(c,c._extra_canvas)},10),!0},b.prototype._extra_canvas=null,b.prototype.get_image_data=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),b=this,setTimeout(function(){return b._image_data||(b._image_data=b.camera._engine_get_image_data(b)),a.call(b,b._image_data)},5)},b.prototype._image_data=null,b.prototype.upload=function(a){var b;if(null==a&&(a={}),this._discarded&&raise("discarded snapshot cannot be used"),this._uploading)return this.camera._debug("Upload already in progress"),void 0;if(this._uploading=!0,this._retry=1,this._upload_options=a,b=this._options(),!b.api_url)throw this.camera._debug("Snapshot#upload called without valid api_url"),"Snapshot#upload called without valid api_url";return this._start_upload(b),this},b.prototype._upload_options={},b.prototype._uploading=!1,b.prototype._retry=1,b.prototype.done=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_done=a,b=this._options(),b.on_upload_done&&this._done&&b.on_upload_done.call(this,this._response),this},b.prototype._done=!1,b.prototype._response=null,b.prototype.fail=function(a){var b;return this._discarded&&raise("discarded snapshot cannot be used"),this._upload_options.on_upload_fail=a,b=this._options(),b.on_upload_fail&&this._fail&&b.on_upload_fail.call(this,this._status,this._error_message,this._response),this},b.prototype._fail=!1,b.prototype._status=null,b.prototype._error_message=null,b.prototype.discard=function(){return this.camera._discard(this),void 0},b.prototype._options=function(){return this.camera._extend({},this.camera.options,this.options,this._upload_options)},b.prototype._start_upload=function(a){var b;return b="string"==typeof a.csrf_token&&a.csrf_token.length>0?a.csrf_token:null,this._done=!1,this._response=null,this._fail=!1,this._status=null,this._error_message=null,this.camera._engine_upload(this,a.api_url,b,a.timeout)},b.prototype._get_stats=function(a,b){var c,d,e,f,g,h,i,j,k,l,m;if(!this._stats){for(h=a.width*a.height,i=0,d=new Array(h),e=k=0;h>k;e=k+=1)f=4*e,c=.2126*a.data[f+0]+.7152*a.data[f+1]+.0722*a.data[f+2],c=Math.round(c),i+=c,d[e]=c;for(g=Math.round(i/h),j=0,l=0,m=d.length;m>l;l++)c=d[l],j+=Math.pow(c-g,2);this._stats={mean:g,std:Math.round(Math.sqrt(j/h))}}return b.call(this,this._stats)},b.prototype._stats=null,b.prototype._upload_done=function(){var a,b,c,d;return this.camera._debug("Upload completed with status "+this._status),this._done=!0,a=this._options(),c=a.retry_success&&a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_done?a.on_upload_done.call(this,this._response):void 0)},b.prototype._upload_fail=function(){var a,b,c,d;return this.camera._debug("Upload failed with status "+this._status),this._fail=!0,a=this._options(),c=a.retry_if&&a.retry_if.call(this,this._status,this._error_message,this._response,this._retry),!0===c&&(c=0),"number"==typeof c?(this._retry++,c>0?(b=parseInt(c),this.camera._debug("Will retry the upload in "+b+"ms (attempt #"+this._retry+")"),d=this,setTimeout(function(){return d._start_upload(a)},b)):(this.camera._debug("Will retry the upload immediately (attempt #"+this._retry+")"),this._start_upload(a))):(this._uploading=!1,a.on_upload_fail?a.on_upload_fail.call(this,this._status,this._error_message,this._response):void 0)},b}()}.call(this);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jpeg_camera
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Wróbel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-30 00:00:00.000000000 Z
11
+ date: 2013-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties