1 | 'use strict';
|
---|
2 |
|
---|
3 | // based on https://developers.google.com/speed/webp/docs/riff_container
|
---|
4 |
|
---|
5 | function isWebP (buffer) {
|
---|
6 | var riffHeader = 'RIFF' === buffer.toString('ascii', 0, 4);
|
---|
7 | var webpHeader = 'WEBP' === buffer.toString('ascii', 8, 12);
|
---|
8 | var vp8Header = 'VP8' === buffer.toString('ascii', 12, 15);
|
---|
9 | return (riffHeader && webpHeader && vp8Header);
|
---|
10 | }
|
---|
11 |
|
---|
12 | function calculate (buffer) {
|
---|
13 | var chunkHeader = buffer.toString('ascii', 12, 16);
|
---|
14 | buffer = buffer.slice(20, 30);
|
---|
15 |
|
---|
16 | // Extended webp stream signature
|
---|
17 | if (chunkHeader === 'VP8X') {
|
---|
18 | var extendedHeader = buffer[0];
|
---|
19 | var validStart = (extendedHeader & 0xc0) === 0;
|
---|
20 | var validEnd = (extendedHeader & 0x01) === 0;
|
---|
21 | if (validStart && validEnd) {
|
---|
22 | return calculateExtended(buffer);
|
---|
23 | } else {
|
---|
24 | return false;
|
---|
25 | }
|
---|
26 | }
|
---|
27 |
|
---|
28 | // Lossless webp stream signature
|
---|
29 | if (chunkHeader === 'VP8 ' && buffer[0] !== 0x2f) {
|
---|
30 | return calculateLossy(buffer);
|
---|
31 | }
|
---|
32 |
|
---|
33 | // Lossy webp stream signature
|
---|
34 | var signature = buffer.toString('hex', 3, 6);
|
---|
35 | if (chunkHeader === 'VP8L' && signature !== '9d012a') {
|
---|
36 | return calculateLossless(buffer);
|
---|
37 | }
|
---|
38 |
|
---|
39 | return false;
|
---|
40 | }
|
---|
41 |
|
---|
42 | function calculateExtended (buffer) {
|
---|
43 | return {
|
---|
44 | 'width': 1 + buffer.readUIntLE(4, 3),
|
---|
45 | 'height': 1 + buffer.readUIntLE(7, 3)
|
---|
46 | }
|
---|
47 | }
|
---|
48 |
|
---|
49 | function calculateLossless (buffer) {
|
---|
50 | return {
|
---|
51 | 'width': 1 + (((buffer[2] & 0x3F) << 8) | buffer[1]),
|
---|
52 | 'height': 1 + (((buffer[4] & 0xF) << 10) | (buffer[3] << 2) |
|
---|
53 | ((buffer[2] & 0xC0) >> 6))
|
---|
54 | };
|
---|
55 | }
|
---|
56 |
|
---|
57 | function calculateLossy (buffer) {
|
---|
58 | // `& 0x3fff` returns the last 14 bits
|
---|
59 | // TO-DO: include webp scaling in the calculations
|
---|
60 | return {
|
---|
61 | 'width': buffer.readInt16LE(6) & 0x3fff,
|
---|
62 | 'height': buffer.readInt16LE(8) & 0x3fff
|
---|
63 | };
|
---|
64 | }
|
---|
65 |
|
---|
66 | module.exports = {
|
---|
67 | 'detect': isWebP,
|
---|
68 | 'calculate': calculate
|
---|
69 | };
|
---|