├── Makefile
├── README.md
├── bower.json
├── jquery.webcam.js
├── jquery.webcam.min.js
├── jscam.swf
├── jscam_canvas_only.swf
├── src
├── BitString.as
├── JPGEncoder.as
├── jscam.as
└── jscam.xml
└── webcam.jquery.json
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | SWFMILL := swfmill
3 | MTASC := mtasc
4 |
5 | MTASCSTDLIB := /usr/share/mtasc/std
6 |
7 | main:
8 | $(SWFMILL) simple src/jscam.xml jscam.swf
9 | $(MTASC) -v -swf jscam.swf -main jscam.as -version 8 -cp src -cp $(MTASCSTDLIB)
10 |
11 | clean:
12 | rm -f jscam.swf
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jQuery Webcam Plugin
2 | ====================
3 | [](https://cdnjs.com/libraries/jQuery-webcam)
4 |
5 |
6 | Description
7 | -----------
8 | A small wrapper library to be able to communicate with a Flash webcam via JavaScript.
9 |
10 |
11 | Example
12 | ------
13 |
14 | Please note: The camera doesn't work if you have any dom-errors on your page!
15 |
16 | The Flash object will be embedded into the following Div:
17 |
18 | ```html
19 |
20 | ```
21 |
22 | ```javascript
23 |
24 | jQuery("#webcam").webcam({
25 |
26 | width: 320,
27 | height: 240,
28 | mode: "callback",
29 | swffile: "/jscam_canvas_only.swf", // canvas only doesn't implement a jpeg encoder, so the file is much smaller
30 |
31 | onTick: function(remain) {
32 |
33 | if (0 == remain) {
34 | jQuery("#status").text("Cheese!");
35 | } else {
36 | jQuery("#status").text(remain + " seconds remaining...");
37 | }
38 | },
39 |
40 | onSave: function(data) {
41 |
42 | var col = data.split(";");
43 | // Work with the picture. Picture-data is encoded as an array of arrays... Not really nice, though =/
44 | },
45 |
46 | onCapture: function () {
47 | webcam.save();
48 |
49 | // Show a flash for example
50 | },
51 |
52 | debug: function (type, string) {
53 | // Write debug information to console.log() or a div, ...
54 | },
55 |
56 | onLoad: function () {
57 | // Page load
58 | var cams = webcam.getCameraList();
59 | for(var i in cams) {
60 | jQuery("#cams").append("" + cams[i] + "");
61 | }
62 | }
63 | });
64 |
65 |
66 | ```
67 |
68 | If you want to draw the picture onto a canvas, have a look at the source of the page on my blog, linked below.
69 |
70 |
71 | Further examples and documentation
72 | ==========================
73 | For further details and code examples take a look at the demonstration and documentation page on:
74 |
75 | [https://raw.org/article/camara-support-in-html5-and-javascript/](https://raw.org/article/camara-support-in-html5-and-javascript/)
76 |
77 | License
78 | ======
79 | Copyright (c) 2013, [Robert Eisele](https://raw.org/)
80 | Dual licensed under the MIT or GPL Version 2 licenses.
81 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webcam",
3 | "main": "jquery.webcam.js",
4 | "version": "1.0.0",
5 | "homepage": "http://www.xarg.org/project/jquery-webcam-plugin/",
6 | "description": "A webcam wrapper plugin for jQuery.",
7 | "keywords": [
8 | "webcam",
9 | "camera",
10 | "flash"
11 | ],
12 | "authors": [
13 | "Robert Eisele "
14 | ],
15 | "dependencies": {
16 | "jquery": ">=1.5"
17 | },
18 | "license": [
19 | "MIT",
20 | "GPL"
21 | ],
22 | "repository": {
23 | "type": "git",
24 | "url": "git://github.com/infusion/jQuery-webcam.git"
25 | }
26 | }
--------------------------------------------------------------------------------
/jquery.webcam.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license jQuery webcam plugin v1.0.0 09/12/2010
3 | * http://www.xarg.org/project/jquery-webcam-plugin/
4 | *
5 | * Copyright (c) 2010, Robert Eisele (robert@xarg.org)
6 | * Dual licensed under the MIT or GPL Version 2 licenses.
7 | **/
8 |
9 | (function ($) {
10 |
11 | var webcam = {
12 |
13 | "extern": null, // external select token to support jQuery dialogs
14 | "append": true, // append object instead of overwriting
15 |
16 | "width": 320,
17 | "height": 240,
18 |
19 | "mode": "callback", // callback | save | stream
20 |
21 | "swffile": "jscam.swf",
22 | "quality": 85,
23 |
24 | "debug": function () {},
25 | "onCapture": function () {},
26 | "onTick": function () {},
27 | "onSave": function () {},
28 | "onLoad": function () {}
29 | };
30 |
31 | window["webcam"] = webcam;
32 |
33 | $["fn"]["webcam"] = function(options) {
34 |
35 | if (typeof options === "object") {
36 | for (var ndx in webcam) {
37 | if (options[ndx] !== undefined) {
38 | webcam[ndx] = options[ndx];
39 | }
40 | }
41 | }
42 |
43 | var source = '';
44 |
45 | if (null !== webcam["extern"]) {
46 | $(webcam["extern"])[webcam["append"] ? "append" : "html"](source);
47 | } else {
48 | this[webcam["append"] ? "append" : "html"](source);
49 | }
50 |
51 | var run = 3;
52 | (_register = function() {
53 | var cam = document.getElementById('XwebcamXobjectX');
54 |
55 | if (cam && cam["capture"] !== undefined) {
56 |
57 | /* Simple callback methods are not allowed :-/ */
58 | webcam["capture"] = function(x) {
59 | try {
60 | return cam["capture"](x);
61 | } catch(e) {}
62 | }
63 | webcam["save"] = function(x) {
64 | try {
65 | return cam["save"](x);
66 | } catch(e) {}
67 | }
68 | webcam["setCamera"] = function(x) {
69 | try {
70 | return cam["setCamera"](x);
71 | } catch(e) {}
72 | }
73 | webcam["getCameraList"] = function() {
74 | try {
75 | return cam["getCameraList"]();
76 | } catch(e) {}
77 | }
78 | webcam["pauseCamera"] = function() {
79 | try {
80 | return cam["pauseCamera"]();
81 | } catch(e) {}
82 | }
83 | webcam["resumeCamera"] = function() {
84 | try {
85 | return cam["resumeCamera"]();
86 | } catch(e) {}
87 | }
88 | webcam["onLoad"]();
89 | } else if (0 == run) {
90 | webcam["debug"]("error", "Flash movie not yet registered!");
91 | } else {
92 | /* Flash interface not ready yet */
93 | run--;
94 | window.setTimeout(_register, 1000 * (4 - run));
95 | }
96 | })();
97 | }
98 |
99 | })(jQuery);
100 |
--------------------------------------------------------------------------------
/jquery.webcam.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | jQuery webcam plugin v1.0.0 09/12/2010
3 | http://www.xarg.org/project/jquery-webcam-plugin/
4 |
5 | Copyright (c) 2010, Robert Eisele (robert@xarg.org)
6 | Dual licensed under the MIT or GPL Version 2 licenses.
7 | */
8 | (function(f){var a={extern:null,append:!0,width:320,height:240,mode:"callback",swffile:"jscam.swf",quality:85,debug:function(){},onCapture:function(){},onTick:function(){},onSave:function(){},onLoad:function(){}};window.webcam=a;f.fn.webcam=function(b){if("object"===typeof b)for(var d in a)void 0!==b[d]&&(a[d]=b[d]);b='';if(null!==a.extern)f(a.extern)[a.append?"append":"html"](b);else this[a.append?"append":"html"](b);var e=3;(_register=function(){var c=document.getElementById("XwebcamXobjectX");c&&void 0!==c.capture?(a.capture=function(a){try{return c.capture(a)}catch(b){}},a.save=function(a){try{return c.save(a)}catch(b){}},a.setCamera=function(a){try{return c.setCamera(a)}catch(b){}},a.getCameraList=function(){try{return c.getCameraList()}catch(a){}},
10 | a.pauseCamera=function(){try{return c.pauseCamera()}catch(a){}},a.resumeCamera=function(){try{return c.resumeCamera()}catch(a){}},a.onLoad()):0==e?a.debug("error","Flash movie not yet registered!"):(e--,window.setTimeout(_register,1E3*(4-e)))})()}})(jQuery);
11 |
--------------------------------------------------------------------------------
/jscam.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infusion/jQuery-webcam/96fff101c8bd0346ce7ea42c67fde2ba9e33278a/jscam.swf
--------------------------------------------------------------------------------
/jscam_canvas_only.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infusion/jQuery-webcam/96fff101c8bd0346ce7ea42c67fde2ba9e33278a/jscam_canvas_only.swf
--------------------------------------------------------------------------------
/src/BitString.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | /**
34 | * AS2 Port
35 | * Copyright (c) 2010, Robert Eisele (robert@xarg.org)
36 | */
37 |
38 | class BitString
39 | {
40 | public var len:Number = 0;
41 | public var val:Number = 0;
42 | }
43 |
--------------------------------------------------------------------------------
/src/JPGEncoder.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | /**
34 | * AS2 Port
35 | * Copyright (c) 2010, Robert Eisele (robert@xarg.org)
36 | */
37 |
38 | import flash.display.BitmapData;
39 | import BitString;
40 | import JPEGEncoder;
41 |
42 | /**
43 | * Class that converts BitmapData into a valid JPEG
44 | */
45 | class JPGEncoder
46 | {
47 |
48 | // Static table initialization
49 |
50 | private var ZigZag:Array = [
51 | 0, 1, 5, 6,14,15,27,28,
52 | 2, 4, 7,13,16,26,29,42,
53 | 3, 8,12,17,25,30,41,43,
54 | 9,11,18,24,31,40,44,53,
55 | 10,19,23,32,39,45,52,54,
56 | 20,22,33,38,46,51,55,60,
57 | 21,34,37,47,50,56,59,61,
58 | 35,36,48,49,57,58,62,63
59 | ];
60 |
61 | private var YTable:Array = new Array(64);
62 | private var UVTable:Array = new Array(64);
63 | private var fdtbl_Y:Array = new Array(64);
64 | private var fdtbl_UV:Array = new Array(64);
65 |
66 | private function initQuantTables(sf:Number):Void
67 | {
68 | var i:Number;
69 | var t:Number;
70 | var YQT:Array = [
71 | 16, 11, 10, 16, 24, 40, 51, 61,
72 | 12, 12, 14, 19, 26, 58, 60, 55,
73 | 14, 13, 16, 24, 40, 57, 69, 56,
74 | 14, 17, 22, 29, 51, 87, 80, 62,
75 | 18, 22, 37, 56, 68,109,103, 77,
76 | 24, 35, 55, 64, 81,104,113, 92,
77 | 49, 64, 78, 87,103,121,120,101,
78 | 72, 92, 95, 98,112,100,103, 99
79 | ];
80 | for (i = 0; i < 64; i++) {
81 | t = Math.floor((YQT[i]*sf+50)/100);
82 | if (t < 1) {
83 | t = 1;
84 | } else if (t > 255) {
85 | t = 255;
86 | }
87 | YTable[ZigZag[i]] = t;
88 | }
89 | var UVQT:Array = [
90 | 17, 18, 24, 47, 99, 99, 99, 99,
91 | 18, 21, 26, 66, 99, 99, 99, 99,
92 | 24, 26, 56, 99, 99, 99, 99, 99,
93 | 47, 66, 99, 99, 99, 99, 99, 99,
94 | 99, 99, 99, 99, 99, 99, 99, 99,
95 | 99, 99, 99, 99, 99, 99, 99, 99,
96 | 99, 99, 99, 99, 99, 99, 99, 99,
97 | 99, 99, 99, 99, 99, 99, 99, 99
98 | ];
99 | for (i = 0; i < 64; i++) {
100 | t = Math.floor((UVQT[i]*sf+50)/100);
101 | if (t < 1) {
102 | t = 1;
103 | } else if (t > 255) {
104 | t = 255;
105 | }
106 | UVTable[ZigZag[i]] = t;
107 | }
108 | var aasf:Array = [
109 | 1.0, 1.387039845, 1.306562965, 1.175875602,
110 | 1.0, 0.785694958, 0.541196100, 0.275899379
111 | ];
112 | i = 0;
113 | for (var row:Number = 0; row < 8; row++)
114 | {
115 | for (var col:Number = 0; col < 8; col++)
116 | {
117 | fdtbl_Y[i] = (1.0 / (YTable [ZigZag[i]] * aasf[row] * aasf[col] * 8.0));
118 | fdtbl_UV[i] = (1.0 / (UVTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0));
119 | i++;
120 | }
121 | }
122 | }
123 |
124 | private var YDC_HT:Array;
125 | private var UVDC_HT:Array;
126 | private var YAC_HT:Array;
127 | private var UVAC_HT:Array;
128 |
129 | private function computeHuffmanTbl(nrcodes:Array, std_table:Array):Array
130 | {
131 | var codevalue:Number = 0;
132 | var pos_in_table:Number = 0;
133 | var HT:Array = new Array();
134 | for (var k:Number=1; k<=16; k++) {
135 | for (var j:Number=1; j<=nrcodes[k]; j++) {
136 | HT[std_table[pos_in_table]] = new BitString();
137 | HT[std_table[pos_in_table]].val = codevalue;
138 | HT[std_table[pos_in_table]].len = k;
139 | pos_in_table++;
140 | codevalue++;
141 | }
142 | codevalue*=2;
143 | }
144 | return HT;
145 | }
146 |
147 | private var std_dc_luminance_nrcodes:Array = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];
148 | private var std_dc_luminance_values:Array = [0,1,2,3,4,5,6,7,8,9,10,11];
149 | private var std_ac_luminance_nrcodes:Array = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];
150 | private var std_ac_luminance_values:Array = [
151 | 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,
152 | 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
153 | 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
154 | 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
155 | 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,
156 | 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
157 | 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,
158 | 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
159 | 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
160 | 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
161 | 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
162 | 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
163 | 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
164 | 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
165 | 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
166 | 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
167 | 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,
168 | 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
169 | 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
170 | 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
171 | 0xf9,0xfa
172 | ];
173 |
174 | private var std_dc_chrominance_nrcodes:Array = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];
175 | private var std_dc_chrominance_values:Array = [0,1,2,3,4,5,6,7,8,9,10,11];
176 | private var std_ac_chrominance_nrcodes:Array = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];
177 | private var std_ac_chrominance_values:Array = [
178 | 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,
179 | 0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
180 | 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
181 | 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
182 | 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,
183 | 0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
184 | 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,
185 | 0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
186 | 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
187 | 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,
188 | 0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,
189 | 0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
190 | 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,
191 | 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,
192 | 0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
193 | 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
194 | 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,
195 | 0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
196 | 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,
197 | 0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
198 | 0xf9,0xfa
199 | ];
200 |
201 | private function initHuffmanTbl():Void
202 | {
203 | YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);
204 | UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);
205 | YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);
206 | UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);
207 | }
208 |
209 | private var bitcode:Array = new Array(65535);
210 | private var category:Array = new Array(65535);
211 |
212 | private function initCategoryNumber():Void
213 | {
214 | var nrlower:Number = 1;
215 | var nrupper:Number = 2;
216 | var nr:Number;
217 | for (var cat:Number=1; cat<=15; cat++) {
218 | //Positive numbers
219 | for (nr=nrlower; nr= 0 ) {
248 | if (value & (1 << posval) ) {
249 | bytenew |= (1 << bytepos);
250 | }
251 | posval--;
252 | bytepos--;
253 | if (bytepos < 0) {
254 | if (bytenew == 0xFF) {
255 | writeByte(0xFF);
256 | writeByte(0);
257 | }
258 | else {
259 | writeByte(bytenew);
260 | }
261 | bytepos=7;
262 | bytenew=0;
263 | }
264 | }
265 | }
266 |
267 | private function writeByte(value:Number):Void
268 | {
269 | var c:Array = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ];
270 |
271 | byteout+= c[(value >> 4) & 0xf];
272 | byteout+= c[ value & 0xf];
273 |
274 | //byteout+= "\t" + chr(value) + "\n";
275 |
276 |
277 |
278 | }
279 |
280 | private function writeWord(value:Number):Void
281 | {
282 | writeByte((value>>8)&0xFF);
283 | writeByte((value )&0xFF);
284 | }
285 |
286 | // DCT & quantization core
287 |
288 | private function fDCTQuant(data:Array, fdtbl:Array):Array
289 | {
290 | var tmp0:Number, tmp1:Number, tmp2:Number, tmp3:Number, tmp4:Number, tmp5:Number, tmp6:Number, tmp7:Number;
291 | var tmp10:Number, tmp11:Number, tmp12:Number, tmp13:Number;
292 | var z1:Number, z2:Number, z3:Number, z4:Number, z5:Number, z11:Number, z13:Number;
293 | var i:Number;
294 | /* Pass 1: process rows. */
295 | var dataOff:Number=0;
296 | for (i=0; i<8; i++) {
297 | tmp0 = data[dataOff+0] + data[dataOff+7];
298 | tmp7 = data[dataOff+0] - data[dataOff+7];
299 | tmp1 = data[dataOff+1] + data[dataOff+6];
300 | tmp6 = data[dataOff+1] - data[dataOff+6];
301 | tmp2 = data[dataOff+2] + data[dataOff+5];
302 | tmp5 = data[dataOff+2] - data[dataOff+5];
303 | tmp3 = data[dataOff+3] + data[dataOff+4];
304 | tmp4 = data[dataOff+3] - data[dataOff+4];
305 |
306 | /* Even part */
307 | tmp10 = tmp0 + tmp3; /* phase 2 */
308 | tmp13 = tmp0 - tmp3;
309 | tmp11 = tmp1 + tmp2;
310 | tmp12 = tmp1 - tmp2;
311 |
312 | data[dataOff+0] = tmp10 + tmp11; /* phase 3 */
313 | data[dataOff+4] = tmp10 - tmp11;
314 |
315 | z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */
316 | data[dataOff+2] = tmp13 + z1; /* phase 5 */
317 | data[dataOff+6] = tmp13 - z1;
318 |
319 | /* Odd part */
320 | tmp10 = tmp4 + tmp5; /* phase 2 */
321 | tmp11 = tmp5 + tmp6;
322 | tmp12 = tmp6 + tmp7;
323 |
324 | /* The rotator is modified from fig 4-8 to avoid extra negations. */
325 | z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */
326 | z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */
327 | z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */
328 | z3 = tmp11 * 0.707106781; /* c4 */
329 |
330 | z11 = tmp7 + z3; /* phase 5 */
331 | z13 = tmp7 - z3;
332 |
333 | data[dataOff+5] = z13 + z2; /* phase 6 */
334 | data[dataOff+3] = z13 - z2;
335 | data[dataOff+1] = z11 + z4;
336 | data[dataOff+7] = z11 - z4;
337 |
338 | dataOff += 8; /* advance pointer to next row */
339 | }
340 |
341 | /* Pass 2: process columns. */
342 | dataOff = 0;
343 | for (i=0; i<8; i++) {
344 | tmp0 = data[dataOff+ 0] + data[dataOff+56];
345 | tmp7 = data[dataOff+ 0] - data[dataOff+56];
346 | tmp1 = data[dataOff+ 8] + data[dataOff+48];
347 | tmp6 = data[dataOff+ 8] - data[dataOff+48];
348 | tmp2 = data[dataOff+16] + data[dataOff+40];
349 | tmp5 = data[dataOff+16] - data[dataOff+40];
350 | tmp3 = data[dataOff+24] + data[dataOff+32];
351 | tmp4 = data[dataOff+24] - data[dataOff+32];
352 |
353 | /* Even part */
354 | tmp10 = tmp0 + tmp3; /* phase 2 */
355 | tmp13 = tmp0 - tmp3;
356 | tmp11 = tmp1 + tmp2;
357 | tmp12 = tmp1 - tmp2;
358 |
359 | data[dataOff+ 0] = tmp10 + tmp11; /* phase 3 */
360 | data[dataOff+32] = tmp10 - tmp11;
361 |
362 | z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */
363 | data[dataOff+16] = tmp13 + z1; /* phase 5 */
364 | data[dataOff+48] = tmp13 - z1;
365 |
366 | /* Odd part */
367 | tmp10 = tmp4 + tmp5; /* phase 2 */
368 | tmp11 = tmp5 + tmp6;
369 | tmp12 = tmp6 + tmp7;
370 |
371 | /* The rotator is modified from fig 4-8 to avoid extra negations. */
372 | z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */
373 | z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */
374 | z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */
375 | z3 = tmp11 * 0.707106781; /* c4 */
376 |
377 | z11 = tmp7 + z3; /* phase 5 */
378 | z13 = tmp7 - z3;
379 |
380 | data[dataOff+40] = z13 + z2; /* phase 6 */
381 | data[dataOff+24] = z13 - z2;
382 | data[dataOff+ 8] = z11 + z4;
383 | data[dataOff+56] = z11 - z4;
384 |
385 | dataOff++; /* advance pointer to next column */
386 | }
387 |
388 | // Quantize/descale the coefficients
389 | for (i=0; i<64; i++) {
390 | // Apply the quantization and scaling factor & Round to nearest integer
391 | data[i] = Math.round((data[i]*fdtbl[i]));
392 | }
393 | return data;
394 | }
395 |
396 | // Chunk writing
397 |
398 | private function writeAPP0():Void
399 | {
400 | writeWord(0xFFE0); // marker
401 | writeWord(16); // length
402 | writeByte(0x4A); // J
403 | writeByte(0x46); // F
404 | writeByte(0x49); // I
405 | writeByte(0x46); // F
406 | writeByte(0); // = "JFIF",'\0'
407 | writeByte(1); // versionhi
408 | writeByte(1); // versionlo
409 | writeByte(0); // xyunits
410 | writeWord(1); // xdensity
411 | writeWord(1); // ydensity
412 | writeByte(0); // thumbnwidth
413 | writeByte(0); // thumbnheight
414 | }
415 |
416 | private function writeSOF0(width:Number, height:Number):Void
417 | {
418 | writeWord(0xFFC0); // marker
419 | writeWord(17); // length, truecolor YUV JPG
420 | writeByte(8); // precision
421 | writeWord(height);
422 | writeWord(width);
423 | writeByte(3); // nrofcomponents
424 | writeByte(1); // IdY
425 | writeByte(0x11); // HVY
426 | writeByte(0); // QTY
427 | writeByte(2); // IdU
428 | writeByte(0x11); // HVU
429 | writeByte(1); // QTU
430 | writeByte(3); // IdV
431 | writeByte(0x11); // HVV
432 | writeByte(1); // QTV
433 | }
434 |
435 | private function writeDQT():Void
436 | {
437 | writeWord(0xFFDB); // marker
438 | writeWord(132); // length
439 | writeByte(0);
440 | var i:Number;
441 | for (i=0; i<64; i++) {
442 | writeByte(YTable[i]);
443 | }
444 | writeByte(1);
445 | for (i=0; i<64; i++) {
446 | writeByte(UVTable[i]);
447 | }
448 | }
449 |
450 | private function writeDHT():Void
451 | {
452 | writeWord(0xFFC4); // marker
453 | writeWord(0x01A2); // length
454 | var i:Number;
455 |
456 | writeByte(0); // HTYDCinfo
457 | for (i=0; i<16; i++) {
458 | writeByte(std_dc_luminance_nrcodes[i+1]);
459 | }
460 | for (i=0; i<=11; i++) {
461 | writeByte(std_dc_luminance_values[i]);
462 | }
463 |
464 | writeByte(0x10); // HTYACinfo
465 | for (i=0; i<16; i++) {
466 | writeByte(std_ac_luminance_nrcodes[i+1]);
467 | }
468 | for (i=0; i<=161; i++) {
469 | writeByte(std_ac_luminance_values[i]);
470 | }
471 |
472 | writeByte(1); // HTUDCinfo
473 | for (i=0; i<16; i++) {
474 | writeByte(std_dc_chrominance_nrcodes[i+1]);
475 | }
476 | for (i=0; i<=11; i++) {
477 | writeByte(std_dc_chrominance_values[i]);
478 | }
479 |
480 | writeByte(0x11); // HTUACinfo
481 | for (i=0; i<16; i++) {
482 | writeByte(std_ac_chrominance_nrcodes[i+1]);
483 | }
484 | for (i=0; i<=161; i++) {
485 | writeByte(std_ac_chrominance_values[i]);
486 | }
487 | }
488 |
489 | private function writeSOS():Void
490 | {
491 | writeWord(0xFFDA); // marker
492 | writeWord(12); // length
493 | writeByte(3); // nrofcomponents
494 | writeByte(1); // IdY
495 | writeByte(0); // HTY
496 | writeByte(2); // IdU
497 | writeByte(0x11); // HTU
498 | writeByte(3); // IdV
499 | writeByte(0x11); // HTV
500 | writeByte(0); // Ss
501 | writeByte(0x3f); // Se
502 | writeByte(0); // Bf
503 | }
504 |
505 | // Core processing
506 | private var DU:Array = new Array(64);
507 |
508 | private function processDU(CDU:Array, fdtbl:Array, DC:Number, HTDC:Array, HTAC:Array):Number
509 | {
510 | var EOB:BitString = HTAC[0x00];
511 | var M16zeroes:BitString = HTAC[0xF0];
512 | var i:Number;
513 |
514 | var DU_DCT:Array = fDCTQuant(CDU, fdtbl);
515 | //ZigZag reorder
516 | for (i=0;i<64;i++) {
517 | DU[ZigZag[i]]=DU_DCT[i];
518 | }
519 | var Diff:Number = DU[0] - DC; DC = DU[0];
520 | //Encode DC
521 | if (Diff==0) {
522 | writeBits(HTDC[0]); // Diff might be 0
523 | } else {
524 | writeBits(HTDC[category[32767+Diff]]);
525 | writeBits(bitcode[32767+Diff]);
526 | }
527 | //Encode ACs
528 | var end0pos:Number = 63;
529 | for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) {
530 | };
531 | //end0pos = first element in reverse order !=0
532 | if ( end0pos == 0) {
533 | writeBits(EOB);
534 | return DC;
535 | }
536 | i = 1;
537 | while ( i <= end0pos ) {
538 | var startpos:Number = i;
539 | for (; (DU[i]==0) && (i<=end0pos); i++) {
540 | }
541 | var nrzeroes:Number = i-startpos;
542 | if ( nrzeroes >= 16 ) {
543 | for (var nrmarker:Number=1; nrmarker <= nrzeroes/16; nrmarker++) {
544 | writeBits(M16zeroes);
545 | }
546 | nrzeroes = int(nrzeroes&0xF);
547 | }
548 | writeBits(HTAC[nrzeroes*16+category[32767+DU[i]]]);
549 | writeBits(bitcode[32767+DU[i]]);
550 | i++;
551 | }
552 | if ( end0pos != 63 ) {
553 | writeBits(EOB);
554 | }
555 | return DC;
556 | }
557 |
558 | private var YDU:Array = new Array(64);
559 | private var UDU:Array = new Array(64);
560 | private var VDU:Array = new Array(64);
561 |
562 | private function RGB2YUV(img:BitmapData, xpos:Number, ypos:Number):Void
563 | {
564 | var pos:Number=0;
565 | for (var y:Number=0; y<8; y++) {
566 | for (var x:Number=0; x<8; x++) {
567 | var P:Number = img.getPixel32(xpos+x,ypos+y);
568 | var R:Number = Number((P>>16)&0xFF);
569 | var G:Number = Number((P>> 8)&0xFF);
570 | var B:Number = Number((P )&0xFF);
571 | YDU[pos]=((( 0.29900)*R+( 0.58700)*G+( 0.11400)*B))-128;
572 | UDU[pos]=(((-0.16874)*R+(-0.33126)*G+( 0.50000)*B));
573 | VDU[pos]=((( 0.50000)*R+(-0.41869)*G+(-0.08131)*B));
574 | pos++;
575 | }
576 | }
577 | }
578 |
579 | /**
580 | * Constructor for JPEGEncoder class
581 | *
582 | * @param quality The quality level between 1 and 100 that detrmines the
583 | * level of compression used in the generated JPEG
584 | * @langversion ActionScript 3.0
585 | * @playerversion Flash 9.0
586 | * @tiptext
587 | */
588 | public function JPGEncoder(quality:Number)
589 | {
590 | if (!quality) {
591 | quality = 50;
592 | }
593 |
594 | if (quality <= 0) {
595 | quality = 1;
596 | }
597 | if (quality > 100) {
598 | quality = 100;
599 | }
600 | var sf:Number = 0;
601 | if (quality < 50) {
602 | sf = int(5000 / quality);
603 | } else {
604 | sf = int(200 - quality*2);
605 | }
606 | // Create tables
607 | initHuffmanTbl();
608 | initCategoryNumber();
609 | initQuantTables(sf);
610 | }
611 |
612 | /**
613 | * Created a JPEG image from the specified BitmapData
614 | *
615 | * @param image The BitmapData that will be converted into the JPEG format.
616 | * @return a ByteArray representing the JPEG encoded image data.
617 | * @langversion ActionScript 3.0
618 | * @playerversion Flash 9.0
619 | * @tiptext
620 | */
621 | public function encode(image:BitmapData):String
622 | {
623 | // Initialize bit writer
624 | byteout = "";
625 | bytenew=0;
626 | bytepos=7;
627 |
628 | // Add JPEG headers
629 | writeWord(0xFFD8); // SOI
630 | writeAPP0();
631 | writeDQT();
632 | writeSOF0(image.width,image.height);
633 | writeDHT();
634 | writeSOS();
635 |
636 |
637 | // Encode 8x8 macroblocks
638 | var DCY:Number=0;
639 | var DCU:Number=0;
640 | var DCV:Number=0;
641 | bytenew=0;
642 | bytepos=7;
643 | for (var ypos:Number=0; ypos= 0 ) {
654 | var fillbits:BitString = new BitString();
655 | fillbits.len = bytepos+1;
656 | fillbits.val = (1<<(bytepos+1))-1;
657 | writeBits(fillbits);
658 | }
659 |
660 | writeWord(0xFFD9); //EOI
661 | return byteout;
662 | }
663 | }
664 |
--------------------------------------------------------------------------------
/src/jscam.as:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery webcam
3 | * Copyright (c) 2010, Robert Eisele (robert@xarg.org)
4 | * Dual licensed under the MIT or GPL Version 2 licenses.
5 | * Date: 09/12/2010
6 | *
7 | * @author Robert Eisele
8 | * @version 1.0
9 | *
10 | * @see http://www.xarg.org/project/jquery-webcam-plugin/
11 | **/
12 |
13 | import flash.system.Security;
14 | import flash.external.ExternalInterface;
15 | import flash.display.BitmapData;
16 | import JPGEncoder;
17 |
18 | class JSCam {
19 |
20 | private static var camera:Camera = null;
21 | private static var buffer:BitmapData = null;
22 | private static var quality:Number = 85;
23 | private static var interval = null;
24 | private static var stream = null;
25 | private static var mode = "callback";
26 |
27 | public static function main():Void {
28 |
29 | System.security.allowDomain("*");
30 |
31 | if (_root.mode) {
32 | mode = _root.mode;
33 | } else {
34 | ExternalInterface.call('webcam.debug', "error", "No camera mode present, falling back...");
35 | }
36 |
37 | if (_root.quality) {
38 | quality = _root.quality;
39 | }
40 |
41 | // From: http://www.squidder.com/2009/03/09/trick-auto-select-mac-isight-in-flash/
42 | var id:Number = -1;
43 | for (var i = 0, l = Camera.names.length; i < l; i++) {
44 | if (Camera.names[i] == "USB Video Class Video") {
45 | id = i;
46 | break;
47 | }
48 | }
49 | if (id > -1) {
50 | camera = Camera.get(id);
51 | } else {
52 | camera = Camera.get();
53 | }
54 |
55 | if (null != camera) {
56 |
57 | // http://www.adobe.com/support/flash/action_scripts/actionscript_dictionary/actionscript_dictionary133.html
58 | camera.onStatus = function(info:Object) {
59 |
60 | switch (info.code) {
61 | case 'Camera.Muted':
62 | ExternalInterface.call('webcam.debug', "notify", "Camera stopped");
63 | break;
64 | case 'Camera.Unmuted' :
65 | ExternalInterface.call('webcam.debug', "notify", "Camera started");
66 | break;
67 | }
68 | }
69 |
70 | camera.setQuality(0, 100);
71 | camera.setMode(Stage.width, Stage.height, 24, false);
72 |
73 | ExternalInterface.addCallback("capture", null, capture);
74 |
75 | ExternalInterface.addCallback("save", null, save);
76 |
77 | ExternalInterface.addCallback("pauseCamera", null, pauseCamera);
78 | ExternalInterface.addCallback("resumeCamera", null, resumeCamera);
79 |
80 | ExternalInterface.addCallback("setCamera", null, setCamera);
81 | ExternalInterface.addCallback("getCameraList", null, getCameraList);
82 |
83 | _root.attachMovie("clip", "video", 1);
84 | _root.video.attachVideo(camera);
85 | _root.video._x = 0;
86 | _root.video._y = 0;
87 |
88 | } else {
89 | ExternalInterface.call('webcam.debug', "error", "No camera was detected.");
90 | }
91 | }
92 | public static function pauseCamera():Void {
93 | _root.video.attachVideo(null);
94 | }
95 | public static function resumeCamera():Void {
96 | _root.video.attachVideo(camera);
97 | }
98 |
99 |
100 | public static function capture(time:Number):Boolean {
101 |
102 | if (null != camera) {
103 |
104 | if (null != buffer) {
105 | return false;
106 | }
107 |
108 | buffer = new BitmapData(Stage.width, Stage.height);
109 | ExternalInterface.call('webcam.debug', "notify", "Capturing started.");
110 |
111 | if ("stream" == mode) {
112 | _stream();
113 | return true;
114 | }
115 |
116 | if (!time) {
117 | time = -1;
118 | } else if (time > 10) {
119 | time = 10;
120 | }
121 |
122 | _capture(time + 1);
123 |
124 | return true;
125 | }
126 | return false;
127 | }
128 |
129 | private static function _capture(time:Number):Void {
130 |
131 | if (null != interval) {
132 | clearInterval(interval);
133 | }
134 |
135 | if (0 == time) {
136 | buffer.draw(_root.video);
137 | ExternalInterface.call('webcam.onCapture');
138 | ExternalInterface.call('webcam.debug', "notify", "Capturing finished.");
139 | } else {
140 | ExternalInterface.call('webcam.onTick', time - 1);
141 | interval = setInterval(_capture, 1000, time - 1);
142 | }
143 | }
144 |
145 | public static function getCameraList():Array {
146 |
147 | var list = new Array();
148 |
149 | for (var i = 0, l = Camera.names.length; i < l; i++) {
150 | list[i] = Camera.names[i];
151 | }
152 | return list;
153 | }
154 |
155 | public static function setCamera(id:Number):Boolean {
156 |
157 | if (0 <= id && id < Camera.names.length) {
158 | camera = Camera.get(id);
159 | camera.setQuality(0, 100);
160 | camera.setMode(Stage.width, Stage.height, 24, false);
161 |
162 | _root.removeMovieClip();
163 | _root.attachMovie("clip", "video", 1);
164 | _root.video.attachVideo(camera);
165 | _root.video._x = 0;
166 | _root.video._y = 0;
167 |
168 | return true;
169 |
170 | }
171 | return false;
172 | }
173 |
174 | public static function save(file:String):Boolean {
175 |
176 | if ("stream" == mode) {
177 |
178 | return true;
179 |
180 | } else if (null != buffer) {
181 |
182 | if ("callback" == mode) {
183 |
184 | for (var i = 0; i < 240; ++i) {
185 |
186 | var row = "";
187 | for (var j=0; j < 320; ++j) {
188 | row+= buffer.getPixel(j, i);
189 | row+= ";";
190 | }
191 | ExternalInterface.call("webcam.onSave", row);
192 | }
193 |
194 | } else if ("save" == mode) {
195 |
196 | if (file) {
197 |
198 | var e = new JPGEncoder(quality);
199 |
200 | var sal = {};
201 | sal.sendAndLoad = XML.prototype.sendAndLoad;
202 | sal.contentType = "image/jpeg";
203 | sal.toString = function() {
204 | return e.encode(JSCam.buffer);
205 | }
206 |
207 | var doc = new XML();
208 | doc.onLoad = function(success) {
209 | ExternalInterface.call("webcam.onSave", "done", this.toString());
210 | }
211 |
212 | sal.sendAndLoad(file, doc);
213 | /*
214 | ExternalInterface.call('webcam.debug', "error", "No save mode compiled in.");
215 | return false;
216 | */
217 | } else {
218 | ExternalInterface.call('webcam.debug', "error", "No file name specified.");
219 | return false;
220 | }
221 |
222 | } else {
223 | ExternalInterface.call('webcam.debug', "error", "Unsupported storage mode.");
224 | }
225 |
226 | buffer = null;
227 | return true;
228 | }
229 | return false;
230 | }
231 |
232 | private static function _stream():Void {
233 |
234 | buffer.draw(_root.video);
235 |
236 | if (null != stream) {
237 | clearInterval(stream);
238 | }
239 |
240 |
241 | for (var i = 0; i < 240; ++i) {
242 |
243 | var row = "";
244 | for (var j=0; j < 320; ++j) {
245 | row+= buffer.getPixel(j, i);
246 | row+= ";";
247 | }
248 | ExternalInterface.call("webcam.onSave", row);
249 | }
250 |
251 | stream = setInterval(_stream, 10);
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/src/jscam.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/webcam.jquery.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webcam",
3 | "title": "jQuery Webcam Plugin",
4 | "description": "A webcam wrapper plugin for jQuery.",
5 | "version": "1.0.0",
6 | "keywords": [
7 | "webcam",
8 | "camera",
9 | "flash"
10 | ],
11 | "author": {
12 | "name": "Robert Eisele",
13 | "url": "http://www.xarg.org/"
14 | },
15 | "licenses": [{
16 | "type": "MIT",
17 | "url": "http://www.opensource.org/licenses/MIT"
18 | }, {
19 | "type": "GPLv2",
20 | "url": "http://www.opensource.org/licenses/GPL-2.0"
21 | }],
22 | "dependencies": {
23 | "jquery": ">=1.5"
24 | },
25 | "homepage": "https://github.com/infusion/jQuery-webcam",
26 | "demo": "http://www.xarg.org/project/jquery-webcam-plugin/"
27 | }
--------------------------------------------------------------------------------