OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 cr.define('options', function() { | 5 cr.define('options', function() { |
6 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; | 6 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; |
7 /** @const */ var Grid = cr.ui.Grid; | 7 /** @const */ var Grid = cr.ui.Grid; |
8 /** @const */ var GridItem = cr.ui.GridItem; | 8 /** @const */ var GridItem = cr.ui.GridItem; |
9 /** @const */ var GridSelectionController = cr.ui.GridSelectionController; | 9 /** @const */ var GridSelectionController = cr.ui.GridSelectionController; |
10 /** @const */ var ListSingleSelectionModel = cr.ui.ListSingleSelectionModel; | 10 /** @const */ var ListSingleSelectionModel = cr.ui.ListSingleSelectionModel; |
11 | 11 |
12 /** | |
13 * Number of frames recorded by takeVideo(). | |
14 * @const | |
15 */ | |
16 var RECORD_FRAMES = 48; | |
17 | |
18 /** | |
19 * FPS at which camera stream is recorded. | |
20 * @const | |
21 */ | |
22 var RECORD_FPS = 16; | |
23 | |
24 /** | 12 /** |
25 * Dimensions for camera capture. | 13 * Dimensions for camera capture. |
26 * @const | 14 * @const |
27 */ | 15 */ |
28 var CAPTURE_SIZE = { | 16 var CAPTURE_SIZE = { |
29 height: 480, | 17 height: 480, |
30 width: 480 | 18 width: 480 |
31 }; | 19 }; |
32 | 20 |
33 /** | 21 /** |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 previewClassList[value == 'default' ? 'add' : 'remove']('default-image'); | 297 previewClassList[value == 'default' ? 'add' : 'remove']('default-image'); |
310 previewClassList[value == 'profile' ? 'add' : 'remove']('profile-image'); | 298 previewClassList[value == 'profile' ? 'add' : 'remove']('profile-image'); |
311 previewClassList[value == 'camera' ? 'add' : 'remove']('camera'); | 299 previewClassList[value == 'camera' ? 'add' : 'remove']('camera'); |
312 | 300 |
313 var setFocusIfLost = function() { | 301 var setFocusIfLost = function() { |
314 // Set focus to the grid, if focus is not on UI. | 302 // Set focus to the grid, if focus is not on UI. |
315 if (!document.activeElement || | 303 if (!document.activeElement || |
316 document.activeElement.tagName == 'BODY') { | 304 document.activeElement.tagName == 'BODY') { |
317 $('user-image-grid').focus(); | 305 $('user-image-grid').focus(); |
318 } | 306 } |
319 } | 307 }; |
320 // Timeout guarantees processing AFTER style changes display attribute. | 308 // Timeout guarantees processing AFTER style changes display attribute. |
321 setTimeout(setFocusIfLost, 0); | 309 setTimeout(setFocusIfLost, 0); |
322 }, | 310 }, |
323 | 311 |
324 /** | 312 /** |
325 * Current image captured from camera as data URL. Setting to null will | 313 * Current image captured from camera as data URL. Setting to null will |
326 * return to the live camera stream. | 314 * return to the live camera stream. |
327 * @type {string=} | 315 * @type {string=} |
328 */ | 316 */ |
329 get cameraImage() { | 317 get cameraImage() { |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 this.cameraImage = previewImg.src; | 472 this.cameraImage = previewImg.src; |
485 }.bind(this)); | 473 }.bind(this)); |
486 previewImg.src = canvas.toDataURL('image/png'); | 474 previewImg.src = canvas.toDataURL('image/png'); |
487 var e = new Event('phototaken'); | 475 var e = new Event('phototaken'); |
488 e.dataURL = this.flipPhoto ? this.flipFrame_(canvas) : previewImg.src; | 476 e.dataURL = this.flipPhoto ? this.flipFrame_(canvas) : previewImg.src; |
489 this.dispatchEvent(e); | 477 this.dispatchEvent(e); |
490 return true; | 478 return true; |
491 }, | 479 }, |
492 | 480 |
493 /** | 481 /** |
494 * Performs video capture from the live camera stream. | |
495 * @param {function=} opt_callback Callback that receives taken video as | |
496 * data URL of a vertically stacked PNG sprite. | |
497 */ | |
498 takeVideo: function(opt_callback) { | |
499 var canvas = document.createElement('canvas'); | |
500 canvas.width = CAPTURE_SIZE.width; | |
501 canvas.height = CAPTURE_SIZE.height * RECORD_FRAMES; | |
502 var ctx = canvas.getContext('2d'); | |
503 // Force canvas initialization to prevent FPS lag on the first frame. | |
504 ctx.fillRect(0, 0, 1, 1); | |
505 var captureData = { | |
506 callback: opt_callback, | |
507 canvas: canvas, | |
508 ctx: ctx, | |
509 frameNo: 0, | |
510 lastTimestamp: new Date().getTime() | |
511 }; | |
512 captureData.timer = window.setInterval( | |
513 this.captureVideoFrame_.bind(this, captureData), 1000 / RECORD_FPS); | |
514 }, | |
515 | |
516 /** | |
517 * Discard current photo and return to the live camera stream. | 482 * Discard current photo and return to the live camera stream. |
518 */ | 483 */ |
519 discardPhoto: function() { | 484 discardPhoto: function() { |
520 this.cameraTitle_ = this.placeholderTitle_; | 485 this.cameraTitle_ = this.placeholderTitle_; |
521 this.cameraImage = null; | 486 this.cameraImage = null; |
522 }, | 487 }, |
523 | 488 |
524 /** | 489 /** |
525 * Capture a single still frame from a <video> element, placing it at the | 490 * Capture a single still frame from a <video> element, placing it at the |
526 * current drawing origin of a canvas context. | 491 * current drawing origin of a canvas context. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
563 canvas.width = CAPTURE_SIZE.width; | 528 canvas.width = CAPTURE_SIZE.width; |
564 canvas.height = CAPTURE_SIZE.height; | 529 canvas.height = CAPTURE_SIZE.height; |
565 var ctx = canvas.getContext('2d'); | 530 var ctx = canvas.getContext('2d'); |
566 ctx.translate(CAPTURE_SIZE.width, 0); | 531 ctx.translate(CAPTURE_SIZE.width, 0); |
567 ctx.scale(-1.0, 1.0); | 532 ctx.scale(-1.0, 1.0); |
568 ctx.drawImage(source, 0, 0); | 533 ctx.drawImage(source, 0, 0); |
569 return canvas.toDataURL('image/png'); | 534 return canvas.toDataURL('image/png'); |
570 }, | 535 }, |
571 | 536 |
572 /** | 537 /** |
573 * Capture next frame of the video being recorded after a takeVideo() call. | |
574 * @param {Object} data Property bag with the recorder details. | |
575 * @private | |
576 */ | |
577 captureVideoFrame_: function(data) { | |
578 var lastTimestamp = new Date().getTime(); | |
579 var delayMs = lastTimestamp - data.lastTimestamp; | |
580 console.error('Delay: ' + delayMs + ' (' + (1000 / delayMs + ' FPS)')); | |
581 data.lastTimestamp = lastTimestamp; | |
582 | |
583 this.captureFrame_(this.cameraVideo_, data.ctx, CAPTURE_SIZE); | |
584 data.ctx.translate(0, CAPTURE_SIZE.height); | |
585 | |
586 if (++data.frameNo == RECORD_FRAMES) { | |
587 window.clearTimeout(data.timer); | |
588 if (data.callback && typeof data.callback == 'function') | |
589 data.callback(data.canvas.toDataURL('image/png')); | |
590 } | |
591 }, | |
592 | |
593 /** | |
594 * Adds new image to the user image grid. | 538 * Adds new image to the user image grid. |
595 * @param {string} src Image URL. | 539 * @param {string} src Image URL. |
596 * @param {string=} opt_title Image tooltip. | 540 * @param {string=} opt_title Image tooltip. |
597 * @param {function=} opt_clickHandler Image click handler. | 541 * @param {function=} opt_clickHandler Image click handler. |
598 * @param {number=} opt_position If given, inserts new image into | 542 * @param {number=} opt_position If given, inserts new image into |
599 * that position (0-based) in image list. | 543 * that position (0-based) in image list. |
600 * @param {function=} opt_decorateFn Function called with the list element | 544 * @param {function=} opt_decorateFn Function called with the list element |
601 * as argument to do any final decoration. | 545 * as argument to do any final decoration. |
602 * @return {!Object} Image data inserted into the data model. | 546 * @return {!Object} Image data inserted into the data model. |
603 */ | 547 */ |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
694 UserImagesGrid.ButtonImages = { | 638 UserImagesGrid.ButtonImages = { |
695 TAKE_PHOTO: 'chrome://theme/IDR_BUTTON_USER_IMAGE_TAKE_PHOTO', | 639 TAKE_PHOTO: 'chrome://theme/IDR_BUTTON_USER_IMAGE_TAKE_PHOTO', |
696 CHOOSE_FILE: 'chrome://theme/IDR_BUTTON_USER_IMAGE_CHOOSE_FILE', | 640 CHOOSE_FILE: 'chrome://theme/IDR_BUTTON_USER_IMAGE_CHOOSE_FILE', |
697 PROFILE_PICTURE: 'chrome://theme/IDR_PROFILE_PICTURE_LOADING' | 641 PROFILE_PICTURE: 'chrome://theme/IDR_PROFILE_PICTURE_LOADING' |
698 }; | 642 }; |
699 | 643 |
700 return { | 644 return { |
701 UserImagesGrid: UserImagesGrid | 645 UserImagesGrid: UserImagesGrid |
702 }; | 646 }; |
703 }); | 647 }); |
OLD | NEW |