├── .bowerrc
├── .gitignore
├── README.md
├── bower.json
├── build
├── talking-image.js
└── talking-image.min.js
├── demos
├── index.js
└── public
│ ├── 2001.html
│ ├── 2001.jpg
│ ├── bruce.gif
│ ├── bruce.html
│ ├── demos.html
│ ├── johnny.gif
│ ├── johnny.html
│ ├── nyan-safari.gif
│ ├── nyan-safari.html
│ ├── nyan.gif
│ └── nyan.html
├── gruntfile.js
├── lib
├── jbinary.js
└── jdataview.js
├── package.json
├── resources
├── 2001.jpg
├── 2001.mp3
├── 2001.ogg
├── bruce.gif
├── bruce.mp3
├── bruce.ogg
├── johnny.gif
├── johnny.mp3
├── johnny.ogg
├── nyan.gif
├── nyan.mp3
└── nyan.ogg
└── src
└── talking-image.js
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "libs"
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | libs/*
3 | .DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Talking Image
2 | =============
3 |
4 | *Add audio to Web images*
5 |
6 | ## What is Talking Image?
7 |
8 | Talking Image is a JavaScript library for playing audio appended to GIF, JPEG, and PNG images. Include the [talking-image.min.js](https://raw.github.com/hacksparrow/talking-image/master/build/talking-image.min.js) on a webpage with a talking image (image with appended audio) and hear the sound come alive.
9 |
10 | ## Give me a quick demo!
11 |
12 | Demos be here: [http://hacksparrow.github.io/talking-image/](http://hacksparrow.github.io/talking-image/)
13 |
14 | To see the demos from the repo, make sure you have Node.js installed on your system. Clone the repo and run the demo server to see the demos. Follow these instructions:
15 |
16 | $ git clone git@github.com:hacksparrow/talking-image.git
17 | $ npm install
18 | $ node demos
19 |
20 | Then load [http://localhost:3000/demos.html](http://localhost:3000/demos.html).
21 |
22 | If you don't want to clone the repo, download [talking-image.min.js](https://raw.github.com/hacksparrow/talking-image/master/build/talking-image.min.js) and the files from the [demo/public](https://github.com/hacksparrow/talking-image/tree/master/demos/public) directory and host them on any HTTP server of your own.
23 |
24 | ## What is a talking image
25 |
26 | Talking image refers to an image with an audio payload appended at the end of image data. Currently OGG and MP3 audio formats are supported.
27 |
28 | ## How do I add talking images to my webpage?
29 |
30 | You use the regular `
` tag but add an additional attribute called `data-audio`, in which you set the options. Eg: `
`.
31 |
32 | **Options for the `audio` attribute**
33 |
34 | 1. *autoplay* - start playing the audio as soon as possible. If autoplay is not set, you will have to click on the image to start playing the sound.
35 | 2. *sync* - try to sync the animation and the audio. There is no guarantee they will be in sync.
36 | 3. *loop* - loop the audio
37 | 4. *volume* - specify the volume. 1 for max volume. Eg: `
`
38 |
39 | Note: You can click on the image to mute the audio any time you want.
40 |
41 | ## Where can I find some talking images?
42 |
43 | This project hosts some talking images in the [public directory](https://github.com/hacksparrow/talking-image/tree/master/demos/public) under the `demos` directory.
44 |
45 | ## How can I create talking images?
46 |
47 | The idea behind talking images is to append OGG or MP3 data to an existing image file - nothing more than that.
48 |
49 | On Linux / Mac:
50 |
51 | $ cat music.ogg >> funny.gif
52 | or
53 |
54 | $ cat beethoven.mp3 >> welcome.jpg
55 |
56 | On Windows:
57 |
58 | > copy /b funny.gif + music.ogg funny-music.gif
59 |
60 | There are some 'clean' images and audio snippets in the `resources` directory, play around with it.
61 |
62 | **Note:** Audio file should be appended to the image file to create a valid talking file. Reversing the order will generate a corrupted file.
63 |
64 | ## Why is it called Talking Image?
65 |
66 | Images on the Web have been 'mute' so far, the technique described here and the library add sound to Web images. The 'talking' in Talking Image comes from [talkies](http://en.wikipedia.org/wiki/Sound_film).
67 |
68 | ## Is it of any use?
69 |
70 | Now you can enjoy the audio-visual experience of [Nyan Cat](http://nyancatmusical.neocities.org/) for infinite hours without loading a YouTube video.
71 |
72 | ## How does it work?
73 |
74 | Using binary data in the browser powered by [jDataView](http://github.com/jDataView/jDataView) and [jBinary](https://github.com/jDataView/jBinary).
75 |
76 | ## License (MIT)
77 |
78 | Copyright (c) 2012 Hage Yaapa <[http://www.hacksparrow.com](http://www.hacksparrow.com)>
79 |
80 | Permission is hereby granted, free of charge, to any person obtaining a copy
81 | of this software and associated documentation files (the "Software"), to deal
82 | in the Software without restriction, including without limitation the rights
83 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
84 | copies of the Software, and to permit persons to whom the Software is
85 | furnished to do so, subject to the following conditions:
86 |
87 | The above copyright notice and this permission notice shall be included in
88 | all copies or substantial portions of the Software.
89 |
90 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
91 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
92 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
93 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
94 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
95 |
96 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "talking-image",
3 | "dependencies": {
4 | "jdataview": "latest",
5 | "jbinary": "latest"
6 | }
7 | }
--------------------------------------------------------------------------------
/build/talking-image.js:
--------------------------------------------------------------------------------
1 | //
2 | // jDataView by Vjeux - Jan 2010
3 | // Continued by RReverser - Feb 2013
4 | //
5 | // A unique way to work with a binary file in the browser
6 | // http://github.com/jDataView/jDataView
7 | // http://jDataView.github.io/
8 |
9 | (function (global) {
10 |
11 | 'use strict';
12 |
13 | var compatibility = {
14 | // NodeJS Buffer in v0.5.5 and newer
15 | NodeBuffer: 'Buffer' in global && 'readInt16LE' in Buffer.prototype,
16 | DataView: 'DataView' in global && (
17 | 'getFloat64' in DataView.prototype || // Chrome
18 | 'getFloat64' in new DataView(new ArrayBuffer(1)) // Node
19 | ),
20 | ArrayBuffer: 'ArrayBuffer' in global,
21 | PixelData: 'CanvasPixelArray' in global && 'ImageData' in global && 'document' in global
22 | };
23 |
24 | // we don't want to bother with old Buffer implementation
25 | if (compatibility.NodeBuffer) {
26 | (function (buffer) {
27 | try {
28 | buffer.writeFloatLE(Infinity, 0);
29 | } catch (e) {
30 | compatibility.NodeBuffer = false;
31 | }
32 | })(new Buffer(4));
33 | }
34 |
35 | if (compatibility.PixelData) {
36 | var createPixelData = function (byteLength, buffer) {
37 | var data = createPixelData.context2d.createImageData((byteLength + 3) / 4, 1).data;
38 | data.byteLength = byteLength;
39 | if (buffer !== undefined) {
40 | for (var i = 0; i < byteLength; i++) {
41 | data[i] = buffer[i];
42 | }
43 | }
44 | return data;
45 | };
46 | createPixelData.context2d = document.createElement('canvas').getContext('2d');
47 | }
48 |
49 | var dataTypes = {
50 | 'Int8': 1,
51 | 'Int16': 2,
52 | 'Int32': 4,
53 | 'Uint8': 1,
54 | 'Uint16': 2,
55 | 'Uint32': 4,
56 | 'Float32': 4,
57 | 'Float64': 8
58 | };
59 |
60 | var nodeNaming = {
61 | 'Int8': 'Int8',
62 | 'Int16': 'Int16',
63 | 'Int32': 'Int32',
64 | 'Uint8': 'UInt8',
65 | 'Uint16': 'UInt16',
66 | 'Uint32': 'UInt32',
67 | 'Float32': 'Float',
68 | 'Float64': 'Double'
69 | };
70 |
71 | function arrayFrom(arrayLike, forceCopy) {
72 | return (!forceCopy && (arrayLike instanceof Array)) ? arrayLike : Array.prototype.slice.call(arrayLike);
73 | }
74 |
75 | function defined(value, defaultValue) {
76 | return value !== undefined ? value : defaultValue;
77 | }
78 |
79 | function jDataView(buffer, byteOffset, byteLength, littleEndian) {
80 | /* jshint validthis:true */
81 |
82 | if (buffer instanceof jDataView) {
83 | var result = buffer.slice(byteOffset, byteOffset + byteLength);
84 | result._littleEndian = defined(littleEndian, result._littleEndian);
85 | return result;
86 | }
87 |
88 | if (!(this instanceof jDataView)) {
89 | return new jDataView(buffer, byteOffset, byteLength, littleEndian);
90 | }
91 |
92 | this.buffer = buffer = jDataView.wrapBuffer(buffer);
93 |
94 | // Check parameters and existing functionnalities
95 | this._isArrayBuffer = compatibility.ArrayBuffer && buffer instanceof ArrayBuffer;
96 | this._isPixelData = compatibility.PixelData && buffer instanceof CanvasPixelArray;
97 | this._isDataView = compatibility.DataView && this._isArrayBuffer;
98 | this._isNodeBuffer = compatibility.NodeBuffer && buffer instanceof Buffer;
99 |
100 | // Handle Type Errors
101 | if (!this._isNodeBuffer && !this._isArrayBuffer && !this._isPixelData && !(buffer instanceof Array)) {
102 | throw new TypeError('jDataView buffer has an incompatible type');
103 | }
104 |
105 | // Default Values
106 | this._littleEndian = !!littleEndian;
107 |
108 | var bufferLength = 'byteLength' in buffer ? buffer.byteLength : buffer.length;
109 | this.byteOffset = byteOffset = defined(byteOffset, 0);
110 | this.byteLength = byteLength = defined(byteLength, bufferLength - byteOffset);
111 |
112 | if (!this._isDataView) {
113 | this._checkBounds(byteOffset, byteLength, bufferLength);
114 | } else {
115 | this._view = new DataView(buffer, byteOffset, byteLength);
116 | }
117 |
118 | // Create uniform methods (action wrappers) for the following data types
119 |
120 | this._engineAction =
121 | this._isDataView
122 | ? this._dataViewAction
123 | : this._isNodeBuffer
124 | ? this._nodeBufferAction
125 | : this._isArrayBuffer
126 | ? this._arrayBufferAction
127 | : this._arrayAction;
128 | }
129 |
130 | function getCharCodes(string) {
131 | if (compatibility.NodeBuffer) {
132 | return new Buffer(string, 'binary');
133 | }
134 |
135 | var Type = compatibility.ArrayBuffer ? Uint8Array : Array,
136 | codes = new Type(string.length);
137 |
138 | for (var i = 0, length = string.length; i < length; i++) {
139 | codes[i] = string.charCodeAt(i) & 0xff;
140 | }
141 | return codes;
142 | }
143 |
144 | // mostly internal function for wrapping any supported input (String or Array-like) to best suitable buffer format
145 | jDataView.wrapBuffer = function (buffer) {
146 | switch (typeof buffer) {
147 | case 'number':
148 | if (compatibility.NodeBuffer) {
149 | buffer = new Buffer(buffer);
150 | buffer.fill(0);
151 | } else
152 | if (compatibility.ArrayBuffer) {
153 | buffer = new Uint8Array(buffer).buffer;
154 | } else
155 | if (compatibility.PixelData) {
156 | buffer = createPixelData(buffer);
157 | } else {
158 | buffer = new Array(buffer);
159 | for (var i = 0; i < buffer.length; i++) {
160 | buffer[i] = 0;
161 | }
162 | }
163 | return buffer;
164 |
165 | case 'string':
166 | buffer = getCharCodes(buffer);
167 | /* falls through */
168 | default:
169 | if ('length' in buffer && !((compatibility.NodeBuffer && buffer instanceof Buffer) || (compatibility.ArrayBuffer && buffer instanceof ArrayBuffer) || (compatibility.PixelData && buffer instanceof CanvasPixelArray))) {
170 | if (compatibility.NodeBuffer) {
171 | buffer = new Buffer(buffer);
172 | } else
173 | if (compatibility.ArrayBuffer) {
174 | if (!(buffer instanceof ArrayBuffer)) {
175 | buffer = buffer instanceof Uint8Array ? buffer.buffer : new Uint8Array(buffer).buffer;
176 | }
177 | } else
178 | if (compatibility.PixelData) {
179 | buffer = createPixelData(buffer.length, buffer);
180 | } else {
181 | buffer = arrayFrom(buffer);
182 | }
183 | }
184 | return buffer;
185 | }
186 | };
187 |
188 | function pow2(n) {
189 | return (n >= 0 && n < 31) ? (1 << n) : (pow2[n] || (pow2[n] = Math.pow(2, n)));
190 | }
191 |
192 | // left for backward compatibility
193 | jDataView.createBuffer = function () {
194 | return jDataView.wrapBuffer(arguments);
195 | };
196 |
197 | function Uint64(lo, hi) {
198 | this.lo = lo;
199 | this.hi = hi;
200 | }
201 |
202 | jDataView.Uint64 = Uint64;
203 |
204 | Uint64.prototype = {
205 | valueOf: function () {
206 | return this.lo + pow2(32) * this.hi;
207 | },
208 |
209 | toString: function () {
210 | return Number.prototype.toString.apply(this.valueOf(), arguments);
211 | }
212 | };
213 |
214 | Uint64.fromNumber = function (number) {
215 | var hi = Math.floor(number / pow2(32)),
216 | lo = number - hi * pow2(32);
217 |
218 | return new Uint64(lo, hi);
219 | };
220 |
221 | function Int64(lo, hi) {
222 | Uint64.apply(this, arguments);
223 | }
224 |
225 | jDataView.Int64 = Int64;
226 |
227 | Int64.prototype = 'create' in Object ? Object.create(Uint64.prototype) : new Uint64();
228 |
229 | Int64.prototype.valueOf = function () {
230 | if (this.hi < pow2(31)) {
231 | return Uint64.prototype.valueOf.apply(this, arguments);
232 | }
233 | return -((pow2(32) - this.lo) + pow2(32) * (pow2(32) - 1 - this.hi));
234 | };
235 |
236 | Int64.fromNumber = function (number) {
237 | var lo, hi;
238 | if (number >= 0) {
239 | var unsigned = Uint64.fromNumber(number);
240 | lo = unsigned.lo;
241 | hi = unsigned.hi;
242 | } else {
243 | hi = Math.floor(number / pow2(32));
244 | lo = number - hi * pow2(32);
245 | hi += pow2(32);
246 | }
247 | return new Int64(lo, hi);
248 | };
249 |
250 | jDataView.prototype = {
251 | _offset: 0,
252 | _bitOffset: 0,
253 |
254 | compatibility: compatibility,
255 |
256 | _checkBounds: function (byteOffset, byteLength, maxLength) {
257 | // Do additional checks to simulate DataView
258 | if (typeof byteOffset !== 'number') {
259 | throw new TypeError('Offset is not a number.');
260 | }
261 | if (typeof byteLength !== 'number') {
262 | throw new TypeError('Size is not a number.');
263 | }
264 | if (byteLength < 0) {
265 | throw new RangeError('Length is negative.');
266 | }
267 | if (byteOffset < 0 || byteOffset + byteLength > defined(maxLength, this.byteLength)) {
268 | throw new RangeError('Offsets are out of bounds.');
269 | }
270 | },
271 |
272 | _action: function (type, isReadAction, byteOffset, littleEndian, value) {
273 | return this._engineAction(
274 | type,
275 | isReadAction,
276 | defined(byteOffset, this._offset),
277 | defined(littleEndian, this._littleEndian),
278 | value
279 | );
280 | },
281 |
282 | _dataViewAction: function (type, isReadAction, byteOffset, littleEndian, value) {
283 | // Move the internal offset forward
284 | this._offset = byteOffset + dataTypes[type];
285 | return isReadAction ? this._view['get' + type](byteOffset, littleEndian) : this._view['set' + type](byteOffset, value, littleEndian);
286 | },
287 |
288 | _nodeBufferAction: function (type, isReadAction, byteOffset, littleEndian, value) {
289 | // Move the internal offset forward
290 | this._offset = byteOffset + dataTypes[type];
291 | var nodeName = nodeNaming[type] + ((type === 'Int8' || type === 'Uint8') ? '' : littleEndian ? 'LE' : 'BE');
292 | byteOffset += this.byteOffset;
293 | return isReadAction ? this.buffer['read' + nodeName](byteOffset) : this.buffer['write' + nodeName](value, byteOffset);
294 | },
295 |
296 | _arrayBufferAction: function (type, isReadAction, byteOffset, littleEndian, value) {
297 | var size = dataTypes[type], TypedArray = global[type + 'Array'], typedArray;
298 |
299 | littleEndian = defined(littleEndian, this._littleEndian);
300 |
301 | // ArrayBuffer: we use a typed array of size 1 from original buffer if alignment is good and from slice when it's not
302 | if (size === 1 || ((this.byteOffset + byteOffset) % size === 0 && littleEndian)) {
303 | typedArray = new TypedArray(this.buffer, this.byteOffset + byteOffset, 1);
304 | this._offset = byteOffset + size;
305 | return isReadAction ? typedArray[0] : (typedArray[0] = value);
306 | } else {
307 | var bytes = new Uint8Array(isReadAction ? this.getBytes(size, byteOffset, littleEndian, true) : size);
308 | typedArray = new TypedArray(bytes.buffer, 0, 1);
309 |
310 | if (isReadAction) {
311 | return typedArray[0];
312 | } else {
313 | typedArray[0] = value;
314 | this._setBytes(byteOffset, bytes, littleEndian);
315 | }
316 | }
317 | },
318 |
319 | _arrayAction: function (type, isReadAction, byteOffset, littleEndian, value) {
320 | return isReadAction ? this['_get' + type](byteOffset, littleEndian) : this['_set' + type.replace('Uint', 'Int')](byteOffset, value, littleEndian);
321 | },
322 |
323 | // Helpers
324 |
325 | _getBytes: function (length, byteOffset, littleEndian) {
326 | littleEndian = defined(littleEndian, this._littleEndian);
327 | byteOffset = defined(byteOffset, this._offset);
328 | length = defined(length, this.byteLength - byteOffset);
329 |
330 | this._checkBounds(byteOffset, length);
331 |
332 | byteOffset += this.byteOffset;
333 |
334 | this._offset = byteOffset - this.byteOffset + length;
335 |
336 | var result = this._isArrayBuffer
337 | ? new Uint8Array(this.buffer, byteOffset, length)
338 | : (this.buffer.slice || Array.prototype.slice).call(this.buffer, byteOffset, byteOffset + length);
339 |
340 | return littleEndian || length <= 1 ? result : arrayFrom(result).reverse();
341 | },
342 |
343 | // wrapper for external calls (do not return inner buffer directly to prevent it's modifying)
344 | getBytes: function (length, byteOffset, littleEndian, toArray) {
345 | var result = this._getBytes(length, byteOffset, defined(littleEndian, true));
346 | return toArray ? arrayFrom(result) : result;
347 | },
348 |
349 | _setBytes: function (byteOffset, bytes, littleEndian) {
350 | var length = bytes.length;
351 |
352 | // needed for Opera
353 | if (length === 0) {
354 | return;
355 | }
356 |
357 | littleEndian = defined(littleEndian, this._littleEndian);
358 | byteOffset = defined(byteOffset, this._offset);
359 |
360 | this._checkBounds(byteOffset, length);
361 |
362 | if (!littleEndian && length > 1) {
363 | bytes = arrayFrom(bytes, true).reverse();
364 | }
365 |
366 | byteOffset += this.byteOffset;
367 |
368 | if (this._isArrayBuffer) {
369 | new Uint8Array(this.buffer, byteOffset, length).set(bytes);
370 | }
371 | else {
372 | if (this._isNodeBuffer) {
373 | new Buffer(bytes).copy(this.buffer, byteOffset);
374 | } else {
375 | for (var i = 0; i < length; i++) {
376 | this.buffer[byteOffset + i] = bytes[i];
377 | }
378 | }
379 | }
380 |
381 | this._offset = byteOffset - this.byteOffset + length;
382 | },
383 |
384 | setBytes: function (byteOffset, bytes, littleEndian) {
385 | this._setBytes(byteOffset, bytes, defined(littleEndian, true));
386 | },
387 |
388 | writeBytes: function (bytes, littleEndian) {
389 | this.setBytes(undefined, bytes, littleEndian);
390 | },
391 |
392 | getString: function (byteLength, byteOffset, encoding) {
393 | if (this._isNodeBuffer) {
394 | byteOffset = defined(byteOffset, this._offset);
395 | byteLength = defined(byteLength, this.byteLength - byteOffset);
396 |
397 | this._checkBounds(byteOffset, byteLength);
398 |
399 | this._offset = byteOffset + byteLength;
400 | return this.buffer.toString(encoding || 'binary', this.byteOffset + byteOffset, this.byteOffset + this._offset);
401 | }
402 | var bytes = this._getBytes(byteLength, byteOffset, true), string = '';
403 | byteLength = bytes.length;
404 | for (var i = 0; i < byteLength; i++) {
405 | string += String.fromCharCode(bytes[i]);
406 | }
407 | if (encoding === 'utf8') {
408 | string = decodeURIComponent(escape(string));
409 | }
410 | return string;
411 | },
412 |
413 | setString: function (byteOffset, subString, encoding) {
414 | if (this._isNodeBuffer) {
415 | byteOffset = defined(byteOffset, this._offset);
416 | this._checkBounds(byteOffset, subString.length);
417 | this._offset = byteOffset + this.buffer.write(subString, this.byteOffset + byteOffset, encoding || 'binary');
418 | return;
419 | }
420 | if (encoding === 'utf8') {
421 | subString = unescape(encodeURIComponent(subString));
422 | }
423 | this._setBytes(byteOffset, getCharCodes(subString), true);
424 | },
425 |
426 | writeString: function (subString, encoding) {
427 | this.setString(undefined, subString, encoding);
428 | },
429 |
430 | getChar: function (byteOffset) {
431 | return this.getString(1, byteOffset);
432 | },
433 |
434 | setChar: function (byteOffset, character) {
435 | this.setString(byteOffset, character);
436 | },
437 |
438 | writeChar: function (character) {
439 | this.setChar(undefined, character);
440 | },
441 |
442 | tell: function () {
443 | return this._offset;
444 | },
445 |
446 | seek: function (byteOffset) {
447 | this._checkBounds(byteOffset, 0);
448 | /* jshint boss: true */
449 | return this._offset = byteOffset;
450 | },
451 |
452 | skip: function (byteLength) {
453 | return this.seek(this._offset + byteLength);
454 | },
455 |
456 | slice: function (start, end, forceCopy) {
457 | return forceCopy
458 | ? new jDataView(this.getBytes(end - start, start, true, true), undefined, undefined, this._littleEndian)
459 | : new jDataView(this.buffer, this.byteOffset + start, end - start, this._littleEndian);
460 | },
461 |
462 | // Compatibility functions
463 |
464 | _getFloat64: function (byteOffset, littleEndian) {
465 | var b = this._getBytes(8, byteOffset, littleEndian),
466 |
467 | sign = 1 - (2 * (b[7] >> 7)),
468 | exponent = ((((b[7] << 1) & 0xff) << 3) | (b[6] >> 4)) - ((1 << 10) - 1),
469 |
470 | // Binary operators such as | and << operate on 32 bit values, using + and Math.pow(2) instead
471 | mantissa = ((b[6] & 0x0f) * pow2(48)) + (b[5] * pow2(40)) + (b[4] * pow2(32)) +
472 | (b[3] * pow2(24)) + (b[2] * pow2(16)) + (b[1] * pow2(8)) + b[0];
473 |
474 | if (exponent === 1024) {
475 | if (mantissa !== 0) {
476 | return NaN;
477 | } else {
478 | return sign * Infinity;
479 | }
480 | }
481 |
482 | if (exponent === -1023) { // Denormalized
483 | return sign * mantissa * pow2(-1022 - 52);
484 | }
485 |
486 | return sign * (1 + mantissa * pow2(-52)) * pow2(exponent);
487 | },
488 |
489 | _getFloat32: function (byteOffset, littleEndian) {
490 | var b = this._getBytes(4, byteOffset, littleEndian),
491 |
492 | sign = 1 - (2 * (b[3] >> 7)),
493 | exponent = (((b[3] << 1) & 0xff) | (b[2] >> 7)) - 127,
494 | mantissa = ((b[2] & 0x7f) << 16) | (b[1] << 8) | b[0];
495 |
496 | if (exponent === 128) {
497 | if (mantissa !== 0) {
498 | return NaN;
499 | } else {
500 | return sign * Infinity;
501 | }
502 | }
503 |
504 | if (exponent === -127) { // Denormalized
505 | return sign * mantissa * pow2(-126 - 23);
506 | }
507 |
508 | return sign * (1 + mantissa * pow2(-23)) * pow2(exponent);
509 | },
510 |
511 | _get64: function (Type, byteOffset, littleEndian) {
512 | littleEndian = defined(littleEndian, this._littleEndian);
513 | byteOffset = defined(byteOffset, this._offset);
514 |
515 | var parts = littleEndian ? [0, 4] : [4, 0];
516 |
517 | for (var i = 0; i < 2; i++) {
518 | parts[i] = this.getUint32(byteOffset + parts[i], littleEndian);
519 | }
520 |
521 | this._offset = byteOffset + 8;
522 |
523 | return new Type(parts[0], parts[1]);
524 | },
525 |
526 | getInt64: function (byteOffset, littleEndian) {
527 | return this._get64(Int64, byteOffset, littleEndian);
528 | },
529 |
530 | getUint64: function (byteOffset, littleEndian) {
531 | return this._get64(Uint64, byteOffset, littleEndian);
532 | },
533 |
534 | _getInt32: function (byteOffset, littleEndian) {
535 | var b = this._getBytes(4, byteOffset, littleEndian);
536 | return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
537 | },
538 |
539 | _getUint32: function (byteOffset, littleEndian) {
540 | return this._getInt32(byteOffset, littleEndian) >>> 0;
541 | },
542 |
543 | _getInt16: function (byteOffset, littleEndian) {
544 | return (this._getUint16(byteOffset, littleEndian) << 16) >> 16;
545 | },
546 |
547 | _getUint16: function (byteOffset, littleEndian) {
548 | var b = this._getBytes(2, byteOffset, littleEndian);
549 | return (b[1] << 8) | b[0];
550 | },
551 |
552 | _getInt8: function (byteOffset) {
553 | return (this._getUint8(byteOffset) << 24) >> 24;
554 | },
555 |
556 | _getUint8: function (byteOffset) {
557 | return this._getBytes(1, byteOffset)[0];
558 | },
559 |
560 | getSigned: function (bitLength, byteOffset) {
561 | var shift = 32 - bitLength;
562 | return (this.getUnsigned(bitLength, byteOffset) << shift) >> shift;
563 | },
564 |
565 | getUnsigned: function (bitLength, byteOffset) {
566 | var startBit = (defined(byteOffset, this._offset) << 3) + this._bitOffset,
567 | endBit = startBit + bitLength,
568 | start = startBit >>> 3,
569 | end = (endBit + 7) >>> 3,
570 | b = this._getBytes(end - start, start, true),
571 | value = 0;
572 |
573 | /* jshint boss: true */
574 | if (this._bitOffset = endBit & 7) {
575 | this._bitOffset -= 8;
576 | }
577 |
578 | for (var i = 0, length = b.length; i < length; i++) {
579 | value = (value << 8) | b[i];
580 | }
581 |
582 | value >>>= -this._bitOffset;
583 |
584 | return bitLength < 32 ? (value & ~(-1 << bitLength)) : value;
585 | },
586 |
587 | _setBinaryFloat: function (byteOffset, value, mantSize, expSize, littleEndian) {
588 | var signBit = value < 0 ? 1 : 0,
589 | exponent,
590 | mantissa,
591 | eMax = ~(-1 << (expSize - 1)),
592 | eMin = 1 - eMax;
593 |
594 | if (value < 0) {
595 | value = -value;
596 | }
597 |
598 | if (value === 0) {
599 | exponent = 0;
600 | mantissa = 0;
601 | } else if (isNaN(value)) {
602 | exponent = 2 * eMax + 1;
603 | mantissa = 1;
604 | } else if (value === Infinity) {
605 | exponent = 2 * eMax + 1;
606 | mantissa = 0;
607 | } else {
608 | exponent = Math.floor(Math.log(value) / Math.LN2);
609 | if (exponent >= eMin && exponent <= eMax) {
610 | mantissa = Math.floor((value * pow2(-exponent) - 1) * pow2(mantSize));
611 | exponent += eMax;
612 | } else {
613 | mantissa = Math.floor(value / pow2(eMin - mantSize));
614 | exponent = 0;
615 | }
616 | }
617 |
618 | var b = [];
619 | while (mantSize >= 8) {
620 | b.push(mantissa % 256);
621 | mantissa = Math.floor(mantissa / 256);
622 | mantSize -= 8;
623 | }
624 | exponent = (exponent << mantSize) | mantissa;
625 | expSize += mantSize;
626 | while (expSize >= 8) {
627 | b.push(exponent & 0xff);
628 | exponent >>>= 8;
629 | expSize -= 8;
630 | }
631 | b.push((signBit << expSize) | exponent);
632 |
633 | this._setBytes(byteOffset, b, littleEndian);
634 | },
635 |
636 | _setFloat32: function (byteOffset, value, littleEndian) {
637 | this._setBinaryFloat(byteOffset, value, 23, 8, littleEndian);
638 | },
639 |
640 | _setFloat64: function (byteOffset, value, littleEndian) {
641 | this._setBinaryFloat(byteOffset, value, 52, 11, littleEndian);
642 | },
643 |
644 | _set64: function (Type, byteOffset, value, littleEndian) {
645 | if (!(value instanceof Type)) {
646 | value = Type.fromNumber(value);
647 | }
648 |
649 | littleEndian = defined(littleEndian, this._littleEndian);
650 | byteOffset = defined(byteOffset, this._offset);
651 |
652 | var parts = littleEndian ? {lo: 0, hi: 4} : {lo: 4, hi: 0};
653 |
654 | for (var partName in parts) {
655 | this.setUint32(byteOffset + parts[partName], value[partName], littleEndian);
656 | }
657 |
658 | this._offset = byteOffset + 8;
659 | },
660 |
661 | setInt64: function (byteOffset, value, littleEndian) {
662 | this._set64(Int64, byteOffset, value, littleEndian);
663 | },
664 |
665 | writeInt64: function (value, littleEndian) {
666 | this.setInt64(undefined, value, littleEndian);
667 | },
668 |
669 | setUint64: function (byteOffset, value, littleEndian) {
670 | this._set64(Uint64, byteOffset, value, littleEndian);
671 | },
672 |
673 | writeUint64: function (value, littleEndian) {
674 | this.setUint64(undefined, value, littleEndian);
675 | },
676 |
677 | _setInt32: function (byteOffset, value, littleEndian) {
678 | this._setBytes(byteOffset, [
679 | value & 0xff,
680 | (value >>> 8) & 0xff,
681 | (value >>> 16) & 0xff,
682 | value >>> 24
683 | ], littleEndian);
684 | },
685 |
686 | _setInt16: function (byteOffset, value, littleEndian) {
687 | this._setBytes(byteOffset, [
688 | value & 0xff,
689 | (value >>> 8) & 0xff
690 | ], littleEndian);
691 | },
692 |
693 | _setInt8: function (byteOffset, value) {
694 | this._setBytes(byteOffset, [value & 0xff]);
695 | }
696 | };
697 |
698 | var proto = jDataView.prototype;
699 |
700 | for (var type in dataTypes) {
701 | (function (type) {
702 | proto['get' + type] = function (byteOffset, littleEndian) {
703 | return this._action(type, true, byteOffset, littleEndian);
704 | };
705 | proto['set' + type] = function (byteOffset, value, littleEndian) {
706 | this._action(type, false, byteOffset, littleEndian, value);
707 | };
708 | proto['write' + type] = function (value, littleEndian) {
709 | this['set' + type](undefined, value, littleEndian);
710 | };
711 | })(type);
712 | }
713 |
714 | if (typeof module === 'object' && module && typeof module.exports === 'object') {
715 | module.exports = jDataView;
716 | } else
717 | if (typeof define === 'function' && define.amd) {
718 | define([], function () { return jDataView });
719 | } else {
720 | global.jDataView = jDataView;
721 | }
722 |
723 | })((function () { /* jshint strict: false */ return this })());;(function (global) {
724 |
725 | 'use strict';
726 |
727 | // https://github.com/davidchambers/Base64.js (modified)
728 | if (!('atob' in global) || !('btoa' in global)) {
729 | // jshint:skipline
730 | (function(){var t=global,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",n=function(){try{document.createElement("$")}catch(t){return t}}();t.btoa||(t.btoa=function(t){for(var o,e,a=0,c=r,f="";t.charAt(0|a)||(c="=",a%1);f+=c.charAt(63&o>>8-8*(a%1))){if(e=t.charCodeAt(a+=.75),e>255)throw n;o=o<<8|e}return f}),t.atob||(t.atob=function(t){if(t=t.replace(/=+$/,""),1==t.length%4)throw n;for(var o,e,a=0,c=0,f="";e=t.charAt(c++);~e&&(o=a%4?64*o+e:e,a++%4)?f+=String.fromCharCode(255&o>>(6&-2*a)):0)e=r.indexOf(e);return f})})();
731 | }
732 |
733 | function hasNodeRequire(name) {
734 | return typeof require === 'function' && !require.isBrowser && require(name);
735 | }
736 |
737 | var jDataView;
738 |
739 | function extend(obj) {
740 | for (var i = 1, length = arguments.length; i < length; ++i) {
741 | var source = arguments[i];
742 | for (var prop in source) {
743 | if (source[prop] !== undefined) {
744 | obj[prop] = source[prop];
745 | }
746 | }
747 | }
748 | return obj;
749 | }
750 |
751 | var _inherit = Object.create || function (obj) {
752 | var ClonedObject = function () {};
753 | ClonedObject.prototype = obj;
754 | return new ClonedObject();
755 | };
756 |
757 | function inherit(obj) {
758 | arguments[0] = _inherit(obj);
759 | return extend.apply(null, arguments);
760 | }
761 |
762 | function toValue(obj, binary, value) {
763 | return value instanceof Function ? value.call(obj, binary.contexts[0]) : value;
764 | }
765 |
766 | function jBinary(view, typeSet) {
767 | /* jshint validthis:true */
768 | if (!(view instanceof jDataView)) {
769 | view = new jDataView(view, undefined, undefined, typeSet ? typeSet['jBinary.littleEndian'] : undefined);
770 | }
771 |
772 | if (!(this instanceof jBinary)) {
773 | return new jBinary(view, typeSet);
774 | }
775 |
776 | this.view = view;
777 | this.view.seek(0);
778 | this._bitShift = 0;
779 | this.contexts = [];
780 |
781 | if (typeSet) {
782 | this.typeSet = (proto.typeSet === typeSet || proto.typeSet.isPrototypeOf(typeSet)) ? typeSet : inherit(proto.typeSet, typeSet);
783 | this.cacheKey = this._getCached(typeSet, function () { return proto.cacheKey + '.' + (++proto.id) }, true);
784 | }
785 | }
786 |
787 | var proto = jBinary.prototype;
788 |
789 | proto.cacheKey = 'jBinary.Cache';
790 | proto.id = 0;
791 |
792 | var defineProperty = Object.defineProperty;
793 |
794 | if (defineProperty) {
795 | // this is needed to detect DOM-only version of Object.defineProperty in IE8:
796 | try {
797 | defineProperty({}, 'x', {});
798 | } catch (e) {
799 | defineProperty = null;
800 | }
801 | }
802 |
803 | if (!defineProperty) {
804 | defineProperty = function (obj, key, descriptor, allowVisible) {
805 | if (allowVisible) {
806 | obj[key] = descriptor.value;
807 | }
808 | };
809 | }
810 |
811 | proto._getCached = function (obj, valueAccessor, allowVisible) {
812 | if (!obj.hasOwnProperty(this.cacheKey)) {
813 | var value = valueAccessor.call(this, obj);
814 | defineProperty(obj, this.cacheKey, {value: value}, allowVisible);
815 | return value;
816 | } else {
817 | return obj[this.cacheKey];
818 | }
819 | };
820 |
821 | proto.getContext = function (filter) {
822 | switch (typeof filter) {
823 | case 'undefined':
824 | filter = 0;
825 | /* falls through */
826 | case 'number':
827 | return this.contexts[filter];
828 |
829 | case 'string':
830 | return this.getContext(function (context) { return filter in context });
831 |
832 | case 'function':
833 | for (var i = 0, length = this.contexts.length; i < length; i++) {
834 | var context = this.contexts[i];
835 | if (filter.call(this, context)) {
836 | return context;
837 | }
838 | }
839 | return;
840 | }
841 | };
842 |
843 | proto.inContext = function (newContext, callback) {
844 | this.contexts.unshift(newContext);
845 | var result = callback.call(this);
846 | this.contexts.shift();
847 | return result;
848 | };
849 |
850 | jBinary.Type = function (config) {
851 | return inherit(jBinary.Type.prototype, config);
852 | };
853 |
854 | jBinary.Type.prototype = {
855 | inherit: function (args, getType) {
856 | var _type = this, type;
857 |
858 | function withProp(name, callback) {
859 | var value = _type[name];
860 | if (value) {
861 | if (!type) {
862 | type = inherit(_type);
863 | }
864 | callback.call(type, value);
865 | type[name] = null;
866 | }
867 | }
868 |
869 | withProp('params', function (params) {
870 | for (var i = 0, length = Math.min(params.length, args.length); i < length; i++) {
871 | this[params[i]] = args[i];
872 | }
873 | });
874 |
875 | withProp('setParams', function (setParams) {
876 | setParams.apply(this, args);
877 | });
878 |
879 | withProp('typeParams', function (typeParams) {
880 | for (var i = 0, length = typeParams.length; i < length; i++) {
881 | var param = typeParams[i], descriptor = this[param];
882 | if (descriptor) {
883 | this[param] = getType(descriptor);
884 | }
885 | }
886 | });
887 |
888 | withProp('resolve', function (resolve) {
889 | resolve.call(this, getType);
890 | });
891 |
892 | return type || _type;
893 | },
894 | createProperty: function (binary) {
895 | return inherit(this, {binary: binary});
896 | },
897 | toValue: function (val, allowResolve) {
898 | if (allowResolve !== false && typeof val === 'string') {
899 | return this.binary.getContext(val)[val];
900 | }
901 | return toValue(this, this.binary, val);
902 | }
903 | };
904 |
905 | jBinary.Template = function (config) {
906 | return inherit(jBinary.Template.prototype, config, {
907 | createProperty: function (binary) {
908 | var property = (config.createProperty || jBinary.Template.prototype.createProperty).apply(this, arguments);
909 | if (property.getBaseType) {
910 | property.baseType = property.binary.getType(property.getBaseType(property.binary.contexts[0]));
911 | }
912 | return property;
913 | }
914 | });
915 | };
916 |
917 | jBinary.Template.prototype = inherit(jBinary.Type.prototype, {
918 | setParams: function () {
919 | if (this.baseType) {
920 | this.typeParams = ['baseType'].concat(this.typeParams || []);
921 | }
922 | },
923 | baseRead: function () {
924 | return this.binary.read(this.baseType);
925 | },
926 | baseWrite: function (value) {
927 | return this.binary.write(this.baseType, value);
928 | }
929 | });
930 | jBinary.Template.prototype.read = jBinary.Template.prototype.baseRead;
931 | jBinary.Template.prototype.write = jBinary.Template.prototype.baseWrite;
932 |
933 | proto.typeSet = {
934 | 'extend': jBinary.Type({
935 | setParams: function () {
936 | this.parts = arguments;
937 | },
938 | resolve: function (getType) {
939 | var parts = this.parts, length = parts.length, partTypes = new Array(length);
940 | for (var i = 0; i < length; i++) {
941 | partTypes[i] = getType(parts[i]);
942 | }
943 | this.parts = partTypes;
944 | },
945 | read: function () {
946 | var parts = this.parts, obj = this.binary.read(parts[0]);
947 | this.binary.inContext(obj, function () {
948 | for (var i = 1, length = parts.length; i < length; i++) {
949 | extend(obj, this.read(parts[i]));
950 | }
951 | });
952 | return obj;
953 | },
954 | write: function (obj) {
955 | var parts = this.parts;
956 | this.binary.inContext(obj, function () {
957 | for (var i = 0, length = parts.length; i < length; i++) {
958 | this.write(parts[i], obj);
959 | }
960 | });
961 | }
962 | }),
963 | 'enum': jBinary.Template({
964 | params: ['baseType', 'matches'],
965 | setParams: function (baseType, matches) {
966 | this.backMatches = {};
967 | for (var key in matches) {
968 | this.backMatches[matches[key]] = key;
969 | }
970 | },
971 | read: function () {
972 | var value = this.baseRead();
973 | return value in this.matches ? this.matches[value] : value;
974 | },
975 | write: function (value) {
976 | this.baseWrite(value in this.backMatches ? this.backMatches[value] : value);
977 | }
978 | }),
979 | 'string': jBinary.Template({
980 | params: ['length', 'encoding'],
981 | read: function () {
982 | return this.binary.view.getString(this.toValue(this.length), undefined, this.encoding);
983 | },
984 | write: function (value) {
985 | this.binary.view.writeString(value, this.encoding);
986 | }
987 | }),
988 | 'string0': jBinary.Type({
989 | params: ['length', 'encoding'],
990 | read: function () {
991 | var view = this.binary.view, maxLength = this.length;
992 | if (maxLength === undefined) {
993 | var startPos = view.tell(), length = 0, code;
994 | maxLength = view.byteLength - startPos;
995 | while (length < maxLength && (code = view.getUint8())) {
996 | length++;
997 | }
998 | var string = view.getString(length, startPos, this.encoding);
999 | if (length < maxLength) {
1000 | view.skip(1);
1001 | }
1002 | return string;
1003 | } else {
1004 | return view.getString(maxLength, undefined, this.encoding).replace(/\0.*$/, '');
1005 | }
1006 | },
1007 | write: function (value) {
1008 | var view = this.binary.view, zeroLength = this.length === undefined ? 1 : this.length - value.length;
1009 | view.writeString(value, undefined, this.encoding);
1010 | if (zeroLength > 0) {
1011 | view.writeUint8(0);
1012 | view.skip(zeroLength - 1);
1013 | }
1014 | }
1015 | }),
1016 | 'array': jBinary.Template({
1017 | params: ['baseType', 'length'],
1018 | read: function () {
1019 | var length = this.toValue(this.length);
1020 | if (this.baseType === proto.typeSet.uint8) {
1021 | return this.binary.view.getBytes(length, undefined, true, true);
1022 | }
1023 | var results;
1024 | if (length !== undefined) {
1025 | results = new Array(length);
1026 | for (var i = 0; i < length; i++) {
1027 | results[i] = this.baseRead();
1028 | }
1029 | } else {
1030 | var end = this.binary.view.byteLength;
1031 | results = [];
1032 | while (this.binary.tell() < end) {
1033 | results.push(this.baseRead());
1034 | }
1035 | }
1036 | return results;
1037 | },
1038 | write: function (values) {
1039 | if (this.baseType === proto.typeSet.uint8) {
1040 | return this.binary.view.writeBytes(values);
1041 | }
1042 | for (var i = 0, length = values.length; i < length; i++) {
1043 | this.baseWrite(values[i]);
1044 | }
1045 | }
1046 | }),
1047 | 'object': jBinary.Type({
1048 | params: ['structure', 'proto'],
1049 | resolve: function (getType) {
1050 | var structure = {};
1051 | for (var key in this.structure) {
1052 | structure[key] =
1053 | !(this.structure[key] instanceof Function)
1054 | ? getType(this.structure[key])
1055 | : this.structure[key];
1056 | }
1057 | this.structure = structure;
1058 | },
1059 | read: function () {
1060 | var self = this, structure = this.structure, output = this.proto ? inherit(this.proto) : {};
1061 | this.binary.inContext(output, function () {
1062 | for (var key in structure) {
1063 | var value = !(structure[key] instanceof Function)
1064 | ? this.read(structure[key])
1065 | : structure[key].call(self, this.contexts[0]);
1066 | // skipping undefined call results (useful for 'if' statement)
1067 | if (value !== undefined) {
1068 | output[key] = value;
1069 | }
1070 | }
1071 | });
1072 | return output;
1073 | },
1074 | write: function (data) {
1075 | var self = this, structure = this.structure;
1076 | this.binary.inContext(data, function () {
1077 | for (var key in structure) {
1078 | if (!(structure[key] instanceof Function)) {
1079 | this.write(structure[key], data[key]);
1080 | } else {
1081 | data[key] = structure[key].call(self, this.contexts[0]);
1082 | }
1083 | }
1084 | });
1085 | }
1086 | }),
1087 | 'bitfield': jBinary.Type({
1088 | params: ['bitSize'],
1089 | read: function () {
1090 | var bitSize = this.bitSize,
1091 | binary = this.binary,
1092 | fieldValue = 0;
1093 |
1094 | if (binary._bitShift < 0 || binary._bitShift >= 8) {
1095 | var byteShift = binary._bitShift >> 3; // Math.floor(_bitShift / 8)
1096 | binary.skip(byteShift);
1097 | binary._bitShift &= 7; // _bitShift + 8 * Math.floor(_bitShift / 8)
1098 | }
1099 | if (binary._bitShift > 0 && bitSize >= 8 - binary._bitShift) {
1100 | fieldValue = binary.view.getUint8() & ~(-1 << (8 - binary._bitShift));
1101 | bitSize -= 8 - binary._bitShift;
1102 | binary._bitShift = 0;
1103 | }
1104 | while (bitSize >= 8) {
1105 | fieldValue = binary.view.getUint8() | (fieldValue << 8);
1106 | bitSize -= 8;
1107 | }
1108 | if (bitSize > 0) {
1109 | fieldValue = ((binary.view.getUint8() >>> (8 - (binary._bitShift + bitSize))) & ~(-1 << bitSize)) | (fieldValue << bitSize);
1110 | binary._bitShift += bitSize - 8; // passing negative value for next pass
1111 | }
1112 |
1113 | return fieldValue >>> 0;
1114 | },
1115 | write: function (value) {
1116 | var bitSize = this.bitSize,
1117 | binary = this.binary,
1118 | pos,
1119 | curByte;
1120 |
1121 | if (binary._bitShift < 0 || binary._bitShift >= 8) {
1122 | var byteShift = binary._bitShift >> 3; // Math.floor(_bitShift / 8)
1123 | binary.skip(byteShift);
1124 | binary._bitShift &= 7; // _bitShift + 8 * Math.floor(_bitShift / 8)
1125 | }
1126 | if (binary._bitShift > 0 && bitSize >= 8 - binary._bitShift) {
1127 | pos = binary.tell();
1128 | curByte = binary.view.getUint8(pos) & (-1 << (8 - binary._bitShift));
1129 | curByte |= value >>> (bitSize - (8 - binary._bitShift));
1130 | binary.view.setUint8(pos, curByte);
1131 | bitSize -= 8 - binary._bitShift;
1132 | binary._bitShift = 0;
1133 | }
1134 | while (bitSize >= 8) {
1135 | binary.view.writeUint8((value >>> (bitSize - 8)) & 0xff);
1136 | bitSize -= 8;
1137 | }
1138 | if (bitSize > 0) {
1139 | pos = binary.tell();
1140 | curByte = binary.view.getUint8(pos) & ~(~(-1 << bitSize) << (8 - (binary._bitShift + bitSize)));
1141 | curByte |= (value & ~(-1 << bitSize)) << (8 - (binary._bitShift + bitSize));
1142 | binary.view.setUint8(pos, curByte);
1143 | binary._bitShift += bitSize - 8; // passing negative value for next pass
1144 | }
1145 | }
1146 | }),
1147 | 'if': jBinary.Template({
1148 | params: ['condition', 'trueType', 'falseType'],
1149 | typeParams: ['trueType', 'falseType'],
1150 | getBaseType: function (context) {
1151 | return this.toValue(this.condition) ? this.trueType : this.falseType;
1152 | }
1153 | }),
1154 | 'if_not': jBinary.Template({
1155 | setParams: function (condition, falseType, trueType) {
1156 | this.baseType = ['if', condition, trueType, falseType];
1157 | }
1158 | }),
1159 | 'const': jBinary.Template({
1160 | params: ['baseType', 'value', 'strict'],
1161 | read: function () {
1162 | var value = this.baseRead();
1163 | if (this.strict && value !== this.value) {
1164 | if (this.strict instanceof Function) {
1165 | return this.strict(value);
1166 | } else {
1167 | throw new TypeError('Unexpected value.');
1168 | }
1169 | }
1170 | return value;
1171 | },
1172 | write: function (value) {
1173 | this.baseWrite((this.strict || value === undefined) ? this.value : value);
1174 | }
1175 | }),
1176 | 'skip': jBinary.Type({
1177 | setParams: function (length) {
1178 | this.read = this.write = function () {
1179 | this.binary.view.skip(this.toValue(length));
1180 | };
1181 | }
1182 | }),
1183 | 'blob': jBinary.Type({
1184 | params: ['length'],
1185 | read: function () {
1186 | return this.binary.view.getBytes(this.toValue(this.length));
1187 | },
1188 | write: function (bytes) {
1189 | this.binary.view.writeBytes(bytes, true);
1190 | }
1191 | }),
1192 | 'binary': jBinary.Template({
1193 | params: ['length', 'typeSet'],
1194 | read: function () {
1195 | var startPos = this.binary.tell();
1196 | var endPos = this.binary.skip(this.toValue(this.length));
1197 | var view = this.binary.view.slice(startPos, endPos);
1198 | return new jBinary(view, this.typeSet);
1199 | },
1200 | write: function (binary) {
1201 | this.binary.write('blob', binary.read('blob', 0));
1202 | }
1203 | }),
1204 | 'lazy': jBinary.Template({
1205 | marker: 'jBinary.Lazy',
1206 | params: ['innerType'],
1207 | setParams: function (innerType, length) {
1208 | this.baseType = ['binary', length];
1209 | },
1210 | typeParams: ['innerType'],
1211 | read: function () {
1212 | var accessor = function (newValue) {
1213 | if (arguments.length === 0) {
1214 | // returning cached or resolving value
1215 | return 'value' in accessor ? accessor.value : (accessor.value = accessor.binary.read(accessor.innerType));
1216 | } else {
1217 | // marking resolver as dirty for `write` method
1218 | return extend(accessor, {
1219 | wasChanged: true,
1220 | value: newValue
1221 | }).value;
1222 | }
1223 | };
1224 | accessor[this.marker] = true;
1225 | return extend(accessor, {
1226 | binary: this.baseRead(),
1227 | innerType: this.innerType
1228 | });
1229 | },
1230 | write: function (accessor) {
1231 | if (accessor.wasChanged || !accessor[this.marker]) {
1232 | // resolving value if it was changed or given accessor is external
1233 | this.binary.write(this.innerType, accessor());
1234 | } else {
1235 | // copying blob from original binary slice otherwise
1236 | this.baseWrite(accessor.binary);
1237 | }
1238 | }
1239 | })
1240 | };
1241 |
1242 | var dataTypes = [
1243 | 'Uint8',
1244 | 'Uint16',
1245 | 'Uint32',
1246 | 'Uint64',
1247 | 'Int8',
1248 | 'Int16',
1249 | 'Int32',
1250 | 'Int64',
1251 | 'Float32',
1252 | 'Float64',
1253 | 'Char'
1254 | ];
1255 |
1256 | var simpleType = jBinary.Type({
1257 | params: ['littleEndian'],
1258 | read: function () {
1259 | return this.binary.view['get' + this.dataType](undefined, this.littleEndian);
1260 | },
1261 | write: function (value) {
1262 | this.binary.view['write' + this.dataType](value, this.littleEndian);
1263 | }
1264 | });
1265 |
1266 | for (var i = 0, length = dataTypes.length; i < length; i++) {
1267 | var dataType = dataTypes[i];
1268 | proto.typeSet[dataType.toLowerCase()] = inherit(simpleType, {dataType: dataType});
1269 | }
1270 |
1271 | extend(proto.typeSet, {
1272 | 'byte': proto.typeSet.uint8,
1273 | 'float': proto.typeSet.float32,
1274 | 'double': proto.typeSet.float64
1275 | });
1276 |
1277 | proto.toValue = function (value) {
1278 | return toValue(this, this, value);
1279 | };
1280 |
1281 | proto.seek = function (position, callback) {
1282 | position = this.toValue(position);
1283 | if (callback !== undefined) {
1284 | var oldPos = this.view.tell();
1285 | this.view.seek(position);
1286 | var result = callback.call(this);
1287 | this.view.seek(oldPos);
1288 | return result;
1289 | } else {
1290 | return this.view.seek(position);
1291 | }
1292 | };
1293 |
1294 | proto.tell = function () {
1295 | return this.view.tell();
1296 | };
1297 |
1298 | proto.skip = function (offset, callback) {
1299 | return this.seek(this.tell() + this.toValue(offset), callback);
1300 | };
1301 |
1302 | proto.getType = function (type, args) {
1303 | switch (typeof type) {
1304 | case 'string':
1305 | if (!(type in this.typeSet)) {
1306 | throw new ReferenceError('Unknown type `' + type + '`');
1307 | }
1308 | return this.getType(this.typeSet[type], args);
1309 |
1310 | case 'number':
1311 | return this.getType(proto.typeSet.bitfield, [type]);
1312 |
1313 | case 'object':
1314 | if (type instanceof jBinary.Type) {
1315 | var binary = this;
1316 | return type.inherit(args || [], function (type) { return binary.getType(type) });
1317 | } else {
1318 | var isArray = type instanceof Array;
1319 | return this._getCached(
1320 | type,
1321 | (
1322 | isArray
1323 | ? function (type) { return this.getType(type[0], type.slice(1)) }
1324 | : function (structure) { return this.getType(proto.typeSet.object, [structure]) }
1325 | ),
1326 | isArray
1327 | );
1328 | }
1329 | }
1330 | };
1331 |
1332 | proto.createProperty = function (type) {
1333 | return this.getType(type).createProperty(this);
1334 | };
1335 |
1336 | proto._action = function (type, offset, callback) {
1337 | if (type === undefined) {
1338 | return;
1339 | }
1340 | return offset !== undefined ? this.seek(offset, callback) : callback.call(this);
1341 | };
1342 |
1343 | proto.read = function (type, offset) {
1344 | return this._action(
1345 | type,
1346 | offset,
1347 | function () { return this.createProperty(type).read(this.contexts[0]) }
1348 | );
1349 | };
1350 |
1351 | proto.write = function (type, data, offset) {
1352 | this._action(
1353 | type,
1354 | offset,
1355 | function () { this.createProperty(type).write(data, this.contexts[0]) }
1356 | );
1357 | };
1358 |
1359 | proto._toURI =
1360 | ('URL' in global && 'createObjectURL' in URL)
1361 | ? function (type) {
1362 | var data = this.seek(0, function () { return this.view.getBytes() });
1363 | return URL.createObjectURL(new Blob([data], {type: type}));
1364 | }
1365 | : function (type) {
1366 | var string = this.seek(0, function () { return this.view.getString(undefined, undefined, this.view._isNodeBuffer ? 'base64' : 'binary') });
1367 | return 'data:' + type + ';base64,' + (this.view._isNodeBuffer ? string : btoa(string));
1368 | };
1369 |
1370 | proto.toURI = function (mimeType) {
1371 | return this._toURI(mimeType || this.typeSet['jBinary.mimeType']);
1372 | };
1373 |
1374 | proto.slice = function (start, end, forceCopy) {
1375 | return new jBinary(this.view.slice(start, end, forceCopy), this.typeSet);
1376 | };
1377 |
1378 | var hasStreamSupport = hasNodeRequire('stream') && require('stream').Readable;
1379 |
1380 | jBinary.loadData = function (source, callback) {
1381 | if ('Blob' in global && source instanceof Blob) {
1382 | var reader = new FileReader();
1383 | reader.onload = reader.onerror = function() { callback(this.error, this.result) };
1384 | reader.readAsArrayBuffer(source);
1385 | } else
1386 | if (hasStreamSupport && source instanceof require('stream').Readable) {
1387 | var buffers = [];
1388 |
1389 | source
1390 | .on('readable', function () { buffers.push(this.read()) })
1391 | .on('end', function () { callback(null, Buffer.concat(buffers)) })
1392 | .on('error', callback);
1393 | } else {
1394 | if (typeof source !== 'string') {
1395 | return callback(new TypeError('Unsupported source type.'));
1396 | }
1397 |
1398 | var dataParts = source.match(/^data:(.+?)(;base64)?,(.*)$/);
1399 | if (dataParts) {
1400 | var isBase64 = dataParts[2],
1401 | content = dataParts[3];
1402 |
1403 | try {
1404 | callback(
1405 | null,
1406 | (
1407 | (isBase64 && jDataView.prototype.compatibility.NodeBuffer)
1408 | ? new Buffer(content, 'base64')
1409 | : (isBase64 ? atob : decodeURIComponent)(content)
1410 | )
1411 | );
1412 | } catch (e) {
1413 | callback(e);
1414 | }
1415 | } else
1416 | if ('XMLHttpRequest' in global) {
1417 | var xhr = new XMLHttpRequest();
1418 | xhr.open('GET', source, true);
1419 |
1420 | // new browsers (XMLHttpRequest2-compliant)
1421 | if ('responseType' in xhr) {
1422 | xhr.responseType = 'arraybuffer';
1423 | }
1424 | // old browsers (XMLHttpRequest-compliant)
1425 | else if ('overrideMimeType' in xhr) {
1426 | xhr.overrideMimeType('text/plain; charset=x-user-defined');
1427 | }
1428 | // IE9 (Microsoft.XMLHTTP-compliant)
1429 | else {
1430 | xhr.setRequestHeader('Accept-Charset', 'x-user-defined');
1431 | }
1432 |
1433 | // shim for onload for old IE
1434 | if (!('onload' in xhr)) {
1435 | xhr.onreadystatechange = function () {
1436 | if (this.readyState === 4) {
1437 | this.onload();
1438 | }
1439 | };
1440 | }
1441 |
1442 | xhr.onload = function() {
1443 | if (this.status !== 0 && this.status !== 200) {
1444 | return callback(new Error('HTTP Error #' + this.status + ': ' + this.statusText));
1445 | }
1446 |
1447 | // emulating response field for IE9
1448 | if (!('response' in this)) {
1449 | this.response = new VBArray(this.responseBody).toArray();
1450 | }
1451 |
1452 | callback(null, this.response);
1453 | };
1454 |
1455 | xhr.send();
1456 | } else {
1457 | var isHTTP = /^(https?):\/\//.test(source);
1458 |
1459 | if (isHTTP && hasNodeRequire('request')) {
1460 | require('request').get({
1461 | uri: source,
1462 | encoding: null
1463 | }, function (error, response, body) {
1464 | if (!error && response.statusCode !== 200) {
1465 | var statusText = require('http').STATUS_CODES[response.statusCode];
1466 | error = new Error('HTTP Error #' + response.statusCode + ': ' + statusText);
1467 | }
1468 | callback(error, body);
1469 | });
1470 | } else
1471 | if (!isHTTP && hasNodeRequire('fs')) {
1472 | require('fs').readFile(source, callback);
1473 | } else {
1474 | callback(new TypeError('Unsupported source type.'));
1475 | }
1476 | }
1477 | }
1478 | };
1479 |
1480 | function setJDataView(_jDataView) {
1481 | jDataView = _jDataView;
1482 | jDataView.prototype.toBinary = function (typeSet) {
1483 | return new jBinary(this, typeSet);
1484 | };
1485 | }
1486 |
1487 | if (typeof module === 'object' && module && typeof module.exports === 'object') {
1488 | setJDataView(require('jdataview'));
1489 | module.exports = jBinary;
1490 | } else
1491 | if (typeof define === 'function' && define.amd) {
1492 | define(['jdataview'], function (_jDataView) {
1493 | setJDataView(_jDataView);
1494 | return jBinary;
1495 | });
1496 | } else {
1497 | setJDataView(global.jDataView);
1498 | global.jBinary = jBinary;
1499 | }
1500 |
1501 | })((function () { /* jshint strict: false */ return this })());
1502 | ;/*********************************************************
1503 | * Talking Image by Hage Yaapa *
1504 | * License: MIT *
1505 | **********************************************************/
1506 |
1507 | /*jshint newcap: false */
1508 |
1509 | ;(function(TalkingImage, global) {
1510 |
1511 | global.TalkingImage = TalkingImage;
1512 |
1513 | window.addEventListener('load', function() {
1514 | var images = document.querySelectorAll('img[data-audio]');
1515 | Array.prototype.forEach.call(images, function(image) {
1516 | TalkingImage(image);
1517 | });
1518 | });
1519 |
1520 | })(function(img) {
1521 |
1522 | 'use strict';
1523 |
1524 | var
1525 |
1526 | VERSION = '0.1.0',
1527 | hasOwnProp = Object.prototype.hasOwnProperty,
1528 |
1529 | audio = { volume: 1 },
1530 |
1531 | formats = {
1532 | 'mp3': '\x49\x44\x33\x03\x00\x00\x00\x00',
1533 | 'ogg': '\x4F\x67\x67\x53\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00'
1534 | },
1535 |
1536 | url = img.getAttribute('src'),
1537 | options = img.getAttribute('data-audio'),
1538 |
1539 | is_set = function(option, options) {
1540 | return options.indexOf(option) > -1;
1541 | },
1542 |
1543 | detectFormat = function(d) {
1544 | var i, ii, j, n, format;
1545 | for (i = 0, ii = d.byteLength; i < ii; i++) {
1546 | for (j in formats) {
1547 | format = true;
1548 | if (hasOwnProp.call(formats, j) && formats[j].length + i < ii) {
1549 | for (n = 0; n < formats[j].length; n++) {
1550 | if (d.getChar(i + n) !== formats[j][n]) {
1551 | format = false;
1552 | break;
1553 | }
1554 | }
1555 | if (format) {
1556 | audio.format = j;
1557 | audio.offset = i;
1558 | return true;
1559 | }
1560 | }
1561 | }
1562 | }
1563 | return false;
1564 | };
1565 |
1566 | jBinary.loadData(url, function(err, data) {
1567 | var d = new jDataView(data);
1568 | if (!err && detectFormat(d)) {
1569 | // Reset the cursor
1570 | d.seek(0);
1571 | // Extract the audio data
1572 | d.getString(audio.offset);
1573 | // Convert binary data to base64 encoded string and assign it to the audio object usind Data URI
1574 | var audio_data = 'data:audio/'+ audio.format +';base64,' + window.btoa(d.getString());
1575 | var audio_el = new Audio(audio_data);
1576 |
1577 | if (is_set('sync', options)) img.style.visibility = 'hidden';
1578 |
1579 | // Apply options
1580 | if (is_set('controls', options)) audio_el.setAttribute('controls', 'controls');
1581 | if (is_set('autoplay', options)) audio_el.setAttribute('autoplay', 'true');
1582 | if (is_set('loop', options)) audio_el.setAttribute('loop', 'true');
1583 | if (is_set('volume', options)) {
1584 | var volume = options.split('volume=')[1].split(' ')[0];
1585 | // We are prefxing with + to convert string to int
1586 | audio.volume = +volume;
1587 | audio_el.volume = +volume;
1588 | }
1589 |
1590 | if (is_set('sync', options)) {
1591 | // Reset the animation by re-loading the image
1592 | img.setAttribute('src', url);
1593 | img.style.visibility = 'visible';
1594 | }
1595 |
1596 | // The sound can be muted by clicked on the image, and toggled - we don't pause because GIF images don't pause
1597 | img.addEventListener('click', function() {
1598 | if (audio_el.paused) {
1599 | audio_el.play();
1600 | } else {
1601 | audio_el.volume = audio_el.volume === 0 ? audio_el.volume = audio.volume : 0;
1602 | }
1603 | });
1604 | }
1605 | });
1606 |
1607 | }, this);
--------------------------------------------------------------------------------
/build/talking-image.min.js:
--------------------------------------------------------------------------------
1 | /*! Talking Image v0.1.0 by Hage Yaapa . Built on 09-09-2013 */
2 | !function(a){"use strict";function b(a,b){return!b&&a instanceof Array?a:Array.prototype.slice.call(a)}function c(a,b){return void 0!==a?a:b}function d(a,b,e,f){if(a instanceof d){var g=a.slice(b,b+e);return g._littleEndian=c(f,g._littleEndian),g}if(!(this instanceof d))return new d(a,b,e,f);if(this.buffer=a=d.wrapBuffer(a),this._isArrayBuffer=i.ArrayBuffer&&a instanceof ArrayBuffer,this._isPixelData=i.PixelData&&a instanceof CanvasPixelArray,this._isDataView=i.DataView&&this._isArrayBuffer,this._isNodeBuffer=i.NodeBuffer&&a instanceof Buffer,!(this._isNodeBuffer||this._isArrayBuffer||this._isPixelData||a instanceof Array))throw new TypeError("jDataView buffer has an incompatible type");this._littleEndian=!!f;var h="byteLength"in a?a.byteLength:a.length;this.byteOffset=b=c(b,0),this.byteLength=e=c(e,h-b),this._isDataView?this._view=new DataView(a,b,e):this._checkBounds(b,e,h),this._engineAction=this._isDataView?this._dataViewAction:this._isNodeBuffer?this._nodeBufferAction:this._isArrayBuffer?this._arrayBufferAction:this._arrayAction}function e(a){if(i.NodeBuffer)return new Buffer(a,"binary");for(var b=i.ArrayBuffer?Uint8Array:Array,c=new b(a.length),d=0,e=a.length;e>d;d++)c[d]=255&a.charCodeAt(d);return c}function f(a){return a>=0&&31>a?1<d;d++)c[d]=b[d];return c};j.context2d=document.createElement("canvas").getContext("2d")}var k={Int8:1,Int16:2,Int32:4,Uint8:1,Uint16:2,Uint32:4,Float32:4,Float64:8},l={Int8:"Int8",Int16:"Int16",Int32:"Int32",Uint8:"UInt8",Uint16:"UInt16",Uint32:"UInt32",Float32:"Float",Float64:"Double"};d.wrapBuffer=function(a){switch(typeof a){case"number":if(i.NodeBuffer)a=new Buffer(a),a.fill(0);else if(i.ArrayBuffer)a=new Uint8Array(a).buffer;else if(i.PixelData)a=j(a);else{a=new Array(a);for(var c=0;c=0){var d=g.fromNumber(a);b=d.lo,c=d.hi}else c=Math.floor(a/f(32)),b=a-c*f(32),c+=f(32);return new h(b,c)},d.prototype={_offset:0,_bitOffset:0,compatibility:i,_checkBounds:function(a,b,d){if("number"!=typeof a)throw new TypeError("Offset is not a number.");if("number"!=typeof b)throw new TypeError("Size is not a number.");if(0>b)throw new RangeError("Length is negative.");if(0>a||a+b>c(d,this.byteLength))throw new RangeError("Offsets are out of bounds.")},_action:function(a,b,d,e,f){return this._engineAction(a,b,c(d,this._offset),c(e,this._littleEndian),f)},_dataViewAction:function(a,b,c,d,e){return this._offset=c+k[a],b?this._view["get"+a](c,d):this._view["set"+a](c,e,d)},_nodeBufferAction:function(a,b,c,d,e){this._offset=c+k[a];var f=l[a]+("Int8"===a||"Uint8"===a?"":d?"LE":"BE");return c+=this.byteOffset,b?this.buffer["read"+f](c):this.buffer["write"+f](e,c)},_arrayBufferAction:function(b,d,e,f,g){var h,i=k[b],j=a[b+"Array"];if(f=c(f,this._littleEndian),1===i||0===(this.byteOffset+e)%i&&f)return h=new j(this.buffer,this.byteOffset+e,1),this._offset=e+i,d?h[0]:h[0]=g;var l=new Uint8Array(d?this.getBytes(i,e,f,!0):i);return h=new j(l.buffer,0,1),d?h[0]:(h[0]=g,this._setBytes(e,l,f),void 0)},_arrayAction:function(a,b,c,d,e){return b?this["_get"+a](c,d):this["_set"+a.replace("Uint","Int")](c,e,d)},_getBytes:function(a,d,e){e=c(e,this._littleEndian),d=c(d,this._offset),a=c(a,this.byteLength-d),this._checkBounds(d,a),d+=this.byteOffset,this._offset=d-this.byteOffset+a;var f=this._isArrayBuffer?new Uint8Array(this.buffer,d,a):(this.buffer.slice||Array.prototype.slice).call(this.buffer,d,d+a);return e||1>=a?f:b(f).reverse()},getBytes:function(a,d,e,f){var g=this._getBytes(a,d,c(e,!0));return f?b(g):g},_setBytes:function(a,d,e){var f=d.length;if(0!==f){if(e=c(e,this._littleEndian),a=c(a,this._offset),this._checkBounds(a,f),!e&&f>1&&(d=b(d,!0).reverse()),a+=this.byteOffset,this._isArrayBuffer)new Uint8Array(this.buffer,a,f).set(d);else if(this._isNodeBuffer)new Buffer(d).copy(this.buffer,a);else for(var g=0;f>g;g++)this.buffer[a+g]=d[g];this._offset=a-this.byteOffset+f}},setBytes:function(a,b,d){this._setBytes(a,b,c(d,!0))},writeBytes:function(a,b){this.setBytes(void 0,a,b)},getString:function(a,b,d){if(this._isNodeBuffer)return b=c(b,this._offset),a=c(a,this.byteLength-b),this._checkBounds(b,a),this._offset=b+a,this.buffer.toString(d||"binary",this.byteOffset+b,this.byteOffset+this._offset);var e=this._getBytes(a,b,!0),f="";a=e.length;for(var g=0;a>g;g++)f+=String.fromCharCode(e[g]);return"utf8"===d&&(f=decodeURIComponent(escape(f))),f},setString:function(a,b,d){return this._isNodeBuffer?(a=c(a,this._offset),this._checkBounds(a,b.length),this._offset=a+this.buffer.write(b,this.byteOffset+a,d||"binary"),void 0):("utf8"===d&&(b=unescape(encodeURIComponent(b))),this._setBytes(a,e(b),!0),void 0)},writeString:function(a,b){this.setString(void 0,a,b)},getChar:function(a){return this.getString(1,a)},setChar:function(a,b){this.setString(a,b)},writeChar:function(a){this.setChar(void 0,a)},tell:function(){return this._offset},seek:function(a){return this._checkBounds(a,0),this._offset=a},skip:function(a){return this.seek(this._offset+a)},slice:function(a,b,c){return c?new d(this.getBytes(b-a,a,!0,!0),void 0,void 0,this._littleEndian):new d(this.buffer,this.byteOffset+a,b-a,this._littleEndian)},_getFloat64:function(a,b){var c=this._getBytes(8,a,b),d=1-2*(c[7]>>7),e=((255&c[7]<<1)<<3|c[6]>>4)-1023,g=(15&c[6])*f(48)+c[5]*f(40)+c[4]*f(32)+c[3]*f(24)+c[2]*f(16)+c[1]*f(8)+c[0];return 1024===e?0!==g?0/0:1/0*d:-1023===e?d*g*f(-1074):d*(1+g*f(-52))*f(e)},_getFloat32:function(a,b){var c=this._getBytes(4,a,b),d=1-2*(c[3]>>7),e=(255&c[3]<<1|c[2]>>7)-127,g=(127&c[2])<<16|c[1]<<8|c[0];return 128===e?0!==g?0/0:1/0*d:-127===e?d*g*f(-149):d*(1+g*f(-23))*f(e)},_get64:function(a,b,d){d=c(d,this._littleEndian),b=c(b,this._offset);for(var e=d?[0,4]:[4,0],f=0;2>f;f++)e[f]=this.getUint32(b+e[f],d);return this._offset=b+8,new a(e[0],e[1])},getInt64:function(a,b){return this._get64(h,a,b)},getUint64:function(a,b){return this._get64(g,a,b)},_getInt32:function(a,b){var c=this._getBytes(4,a,b);return c[3]<<24|c[2]<<16|c[1]<<8|c[0]},_getUint32:function(a,b){return this._getInt32(a,b)>>>0},_getInt16:function(a,b){return this._getUint16(a,b)<<16>>16},_getUint16:function(a,b){var c=this._getBytes(2,a,b);return c[1]<<8|c[0]},_getInt8:function(a){return this._getUint8(a)<<24>>24},_getUint8:function(a){return this._getBytes(1,a)[0]},getSigned:function(a,b){var c=32-a;return this.getUnsigned(a,b)<>c},getUnsigned:function(a,b){var d=(c(b,this._offset)<<3)+this._bitOffset,e=d+a,f=d>>>3,g=e+7>>>3,h=this._getBytes(g-f,f,!0),i=0;(this._bitOffset=7&e)&&(this._bitOffset-=8);for(var j=0,k=h.length;k>j;j++)i=i<<8|h[j];return i>>>=-this._bitOffset,32>a?i&~(-1<b?1:0,j=~(-1<b&&(b=-b),0===b?(g=0,h=0):isNaN(b)?(g=2*j+1,h=1):1/0===b?(g=2*j+1,h=0):(g=Math.floor(Math.log(b)/Math.LN2),g>=k&&j>=g?(h=Math.floor((b*f(-g)-1)*f(c)),g+=j):(h=Math.floor(b/f(k-c)),g=0));for(var l=[];c>=8;)l.push(h%256),h=Math.floor(h/256),c-=8;for(g=g<=8;)l.push(255&g),g>>>=8,d-=8;l.push(i<>>8,255&b>>>16,b>>>24],c)},_setInt16:function(a,b,c){this._setBytes(a,[255&b,255&b>>>8],c)},_setInt8:function(a,b){this._setBytes(a,[255&b])}};var m=d.prototype;for(var n in k)!function(a){m["get"+a]=function(b,c){return this._action(a,!0,b,c)},m["set"+a]=function(b,c,d){this._action(a,!1,b,d,c)},m["write"+a]=function(b,c){this["set"+a](void 0,b,c)}}(n);"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=d:"function"==typeof define&&define.amd?define([],function(){return d}):a.jDataView=d}(function(){return this}()),function(a){"use strict";function b(a){return"function"==typeof require&&!require.isBrowser&&require(a)}function c(a){for(var b=1,c=arguments.length;c>b;++b){var d=arguments[b];for(var e in d)void 0!==d[e]&&(a[e]=d[e])}return a}function d(a){return arguments[0]=i(a),c.apply(null,arguments)}function e(a,b,c){return c instanceof Function?c.call(a,b.contexts[0]):c}function f(a,b){return a instanceof h||(a=new h(a,void 0,void 0,b?b["jBinary.littleEndian"]:void 0)),this instanceof f?(this.view=a,this.view.seek(0),this._bitShift=0,this.contexts=[],b&&(this.typeSet=j.typeSet===b||j.typeSet.isPrototypeOf(b)?b:d(j.typeSet,b),this.cacheKey=this._getCached(b,function(){return j.cacheKey+"."+ ++j.id},!0)),void 0):new f(a,b)}function g(a){h=a,h.prototype.toBinary=function(a){return new f(this,a)}}"atob"in a&&"btoa"in a||!function(){var b=a,c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",d=function(){try{document.createElement("$")}catch(a){return a}}();b.btoa||(b.btoa=function(a){for(var b,e,f=0,g=c,h="";a.charAt(0|f)||(g="=",f%1);h+=g.charAt(63&b>>8-8*(f%1))){if(e=a.charCodeAt(f+=.75),e>255)throw d;b=b<<8|e}return h}),b.atob||(b.atob=function(a){if(a=a.replace(/=+$/,""),1==a.length%4)throw d;for(var b,e,f=0,g=0,h="";e=a.charAt(g++);~e&&(b=f%4?64*b+e:e,f++%4)?h+=String.fromCharCode(255&b>>(6&-2*f)):0)e=c.indexOf(e);return h})}();var h,i=Object.create||function(a){var b=function(){};return b.prototype=a,new b},j=f.prototype;j.cacheKey="jBinary.Cache",j.id=0;var k=Object.defineProperty;if(k)try{k({},"x",{})}catch(l){k=null}k||(k=function(a,b,c,d){d&&(a[b]=c.value)}),j._getCached=function(a,b,c){if(a.hasOwnProperty(this.cacheKey))return a[this.cacheKey];var d=b.call(this,a);return k(a,this.cacheKey,{value:d},c),d},j.getContext=function(a){switch(typeof a){case"undefined":a=0;case"number":return this.contexts[a];case"string":return this.getContext(function(b){return a in b});case"function":for(var b=0,c=this.contexts.length;c>b;b++){var d=this.contexts[b];if(a.call(this,d))return d}return}},j.inContext=function(a,b){this.contexts.unshift(a);var c=b.call(this);return this.contexts.shift(),c},f.Type=function(a){return d(f.Type.prototype,a)},f.Type.prototype={inherit:function(a,b){function c(a,b){var c=f[a];c&&(e||(e=d(f)),b.call(e,c),e[a]=null)}var e,f=this;return c("params",function(b){for(var c=0,d=Math.min(b.length,a.length);d>c;c++)this[b[c]]=a[c]}),c("setParams",function(b){b.apply(this,a)}),c("typeParams",function(a){for(var c=0,d=a.length;d>c;c++){var e=a[c],f=this[e];f&&(this[e]=b(f))}}),c("resolve",function(a){a.call(this,b)}),e||f},createProperty:function(a){return d(this,{binary:a})},toValue:function(a,b){return b!==!1&&"string"==typeof a?this.binary.getContext(a)[a]:e(this,this.binary,a)}},f.Template=function(a){return d(f.Template.prototype,a,{createProperty:function(){var b=(a.createProperty||f.Template.prototype.createProperty).apply(this,arguments);return b.getBaseType&&(b.baseType=b.binary.getType(b.getBaseType(b.binary.contexts[0]))),b}})},f.Template.prototype=d(f.Type.prototype,{setParams:function(){this.baseType&&(this.typeParams=["baseType"].concat(this.typeParams||[]))},baseRead:function(){return this.binary.read(this.baseType)},baseWrite:function(a){return this.binary.write(this.baseType,a)}}),f.Template.prototype.read=f.Template.prototype.baseRead,f.Template.prototype.write=f.Template.prototype.baseWrite,j.typeSet={extend:f.Type({setParams:function(){this.parts=arguments},resolve:function(a){for(var b=this.parts,c=b.length,d=new Array(c),e=0;c>e;e++)d[e]=a(b[e]);this.parts=d},read:function(){var a=this.parts,b=this.binary.read(a[0]);return this.binary.inContext(b,function(){for(var d=1,e=a.length;e>d;d++)c(b,this.read(a[d]))}),b},write:function(a){var b=this.parts;this.binary.inContext(a,function(){for(var c=0,d=b.length;d>c;c++)this.write(b[c],a)})}}),"enum":f.Template({params:["baseType","matches"],setParams:function(a,b){this.backMatches={};for(var c in b)this.backMatches[b[c]]=c},read:function(){var a=this.baseRead();return a in this.matches?this.matches[a]:a},write:function(a){this.baseWrite(a in this.backMatches?this.backMatches[a]:a)}}),string:f.Template({params:["length","encoding"],read:function(){return this.binary.view.getString(this.toValue(this.length),void 0,this.encoding)},write:function(a){this.binary.view.writeString(a,this.encoding)}}),string0:f.Type({params:["length","encoding"],read:function(){var a=this.binary.view,b=this.length;if(void 0===b){var c,d=a.tell(),e=0;for(b=a.byteLength-d;b>e&&(c=a.getUint8());)e++;var f=a.getString(e,d,this.encoding);return b>e&&a.skip(1),f}return a.getString(b,void 0,this.encoding).replace(/\0.*$/,"")},write:function(a){var b=this.binary.view,c=void 0===this.length?1:this.length-a.length;b.writeString(a,void 0,this.encoding),c>0&&(b.writeUint8(0),b.skip(c-1))}}),array:f.Template({params:["baseType","length"],read:function(){var a=this.toValue(this.length);if(this.baseType===j.typeSet.uint8)return this.binary.view.getBytes(a,void 0,!0,!0);var b;if(void 0!==a){b=new Array(a);for(var c=0;a>c;c++)b[c]=this.baseRead()}else{var d=this.binary.view.byteLength;for(b=[];this.binary.tell()b;b++)this.baseWrite(a[b])}}),object:f.Type({params:["structure","proto"],resolve:function(a){var b={};for(var c in this.structure)b[c]=this.structure[c]instanceof Function?this.structure[c]:a(this.structure[c]);this.structure=b},read:function(){var a=this,b=this.structure,c=this.proto?d(this.proto):{};return this.binary.inContext(c,function(){for(var d in b){var e=b[d]instanceof Function?b[d].call(a,this.contexts[0]):this.read(b[d]);void 0!==e&&(c[d]=e)}}),c},write:function(a){var b=this,c=this.structure;this.binary.inContext(a,function(){for(var d in c)c[d]instanceof Function?a[d]=c[d].call(b,this.contexts[0]):this.write(c[d],a[d])})}}),bitfield:f.Type({params:["bitSize"],read:function(){var a=this.bitSize,b=this.binary,c=0;if(b._bitShift<0||b._bitShift>=8){var d=b._bitShift>>3;b.skip(d),b._bitShift&=7}for(b._bitShift>0&&a>=8-b._bitShift&&(c=b.view.getUint8()&~(-1<<8-b._bitShift),a-=8-b._bitShift,b._bitShift=0);a>=8;)c=b.view.getUint8()|c<<8,a-=8;return a>0&&(c=b.view.getUint8()>>>8-(b._bitShift+a)&~(-1<>>0},write:function(a){var b,c,d=this.bitSize,e=this.binary;if(e._bitShift<0||e._bitShift>=8){var f=e._bitShift>>3;e.skip(f),e._bitShift&=7}for(e._bitShift>0&&d>=8-e._bitShift&&(b=e.tell(),c=e.view.getUint8(b)&-1<<8-e._bitShift,c|=a>>>d-(8-e._bitShift),e.view.setUint8(b,c),d-=8-e._bitShift,e._bitShift=0);d>=8;)e.view.writeUint8(255&a>>>d-8),d-=8;d>0&&(b=e.tell(),c=e.view.getUint8(b)&~(~(-1<o;o++){var q=m[o];j.typeSet[q.toLowerCase()]=d(n,{dataType:q})}c(j.typeSet,{"byte":j.typeSet.uint8,"float":j.typeSet.float32,"double":j.typeSet.float64}),j.toValue=function(a){return e(this,this,a)},j.seek=function(a,b){if(a=this.toValue(a),void 0!==b){var c=this.view.tell();this.view.seek(a);var d=b.call(this);return this.view.seek(c),d}return this.view.seek(a)},j.tell=function(){return this.view.tell()},j.skip=function(a,b){return this.seek(this.tell()+this.toValue(a),b)},j.getType=function(a,b){switch(typeof a){case"string":if(!(a in this.typeSet))throw new ReferenceError("Unknown type `"+a+"`");return this.getType(this.typeSet[a],b);case"number":return this.getType(j.typeSet.bitfield,[a]);case"object":if(a instanceof f.Type){var c=this;return a.inherit(b||[],function(a){return c.getType(a)})}var d=a instanceof Array;return this._getCached(a,d?function(a){return this.getType(a[0],a.slice(1))}:function(a){return this.getType(j.typeSet.object,[a])},d)}},j.createProperty=function(a){return this.getType(a).createProperty(this)},j._action=function(a,b,c){return void 0!==a?void 0!==b?this.seek(b,c):c.call(this):void 0},j.read=function(a,b){return this._action(a,b,function(){return this.createProperty(a).read(this.contexts[0])})},j.write=function(a,b,c){this._action(a,c,function(){this.createProperty(a).write(b,this.contexts[0])})},j._toURI="URL"in a&&"createObjectURL"in URL?function(a){var b=this.seek(0,function(){return this.view.getBytes()});return URL.createObjectURL(new Blob([b],{type:a}))}:function(a){var b=this.seek(0,function(){return this.view.getString(void 0,void 0,this.view._isNodeBuffer?"base64":"binary")});return"data:"+a+";base64,"+(this.view._isNodeBuffer?b:btoa(b))},j.toURI=function(a){return this._toURI(a||this.typeSet["jBinary.mimeType"])},j.slice=function(a,b,c){return new f(this.view.slice(a,b,c),this.typeSet)};var r=b("stream")&&require("stream").Readable;f.loadData=function(c,d){if("Blob"in a&&c instanceof Blob){var e=new FileReader;e.onload=e.onerror=function(){d(this.error,this.result)},e.readAsArrayBuffer(c)}else if(r&&c instanceof require("stream").Readable){var f=[];c.on("readable",function(){f.push(this.read())}).on("end",function(){d(null,Buffer.concat(f))}).on("error",d)}else{if("string"!=typeof c)return d(new TypeError("Unsupported source type."));var g=c.match(/^data:(.+?)(;base64)?,(.*)$/);if(g){var i=g[2],j=g[3];try{d(null,i&&h.prototype.compatibility.NodeBuffer?new Buffer(j,"base64"):(i?atob:decodeURIComponent)(j))}catch(k){d(k)}}else if("XMLHttpRequest"in a){var l=new XMLHttpRequest;l.open("GET",c,!0),"responseType"in l?l.responseType="arraybuffer":"overrideMimeType"in l?l.overrideMimeType("text/plain; charset=x-user-defined"):l.setRequestHeader("Accept-Charset","x-user-defined"),"onload"in l||(l.onreadystatechange=function(){4===this.readyState&&this.onload()}),l.onload=function(){return 0!==this.status&&200!==this.status?d(new Error("HTTP Error #"+this.status+": "+this.statusText)):("response"in this||(this.response=new VBArray(this.responseBody).toArray()),d(null,this.response),void 0)},l.send()}else{var m=/^(https?):\/\//.test(c);m&&b("request")?require("request").get({uri:c,encoding:null},function(a,b,c){if(!a&&200!==b.statusCode){var e=require("http").STATUS_CODES[b.statusCode];a=new Error("HTTP Error #"+b.statusCode+": "+e)}d(a,c)}):!m&&b("fs")?require("fs").readFile(c,d):d(new TypeError("Unsupported source type."))}}},"object"==typeof module&&module&&"object"==typeof module.exports?(g(require("jdataview")),module.exports=f):"function"==typeof define&&define.amd?define(["jdataview"],function(a){return g(a),f}):(g(a.jDataView),a.jBinary=f)}(function(){return this}()),function(a,b){b.TalkingImage=a,window.addEventListener("load",function(){var b=document.querySelectorAll("img[data-audio]");Array.prototype.forEach.call(b,function(b){a(b)})})}(function(a){"use strict";var b=Object.prototype.hasOwnProperty,c={volume:1},d={mp3:"ID3\x00\x00\x00\x00",ogg:"OggS\x00\x00\x00\x00\x00\x00\x00\x00\x00"},e=a.getAttribute("src"),f=a.getAttribute("data-audio"),g=function(a,b){return b.indexOf(a)>-1},h=function(a){var e,f,g,h,i;for(e=0,f=a.byteLength;f>e;e++)for(g in d)if(i=!0,b.call(d,g)&&d[g].length+e
2 |
3 | Talking Image Demo - 2001: A Space Odyssey
4 |
5 |
6 |
7 | Home
8 | 2001: A Space Odyssey
9 |
10 |
11 | <img src="2001.jpg" data-audio="autoplay sync">
12 |
13 |