123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- 'use strict';
- // based on https://developers.google.com/speed/webp/docs/riff_container
- function isWebP (buffer) {
- var riffHeader = 'RIFF' === buffer.toString('ascii', 0, 4);
- var webpHeader = 'WEBP' === buffer.toString('ascii', 8, 12);
- var vp8Header = 'VP8' === buffer.toString('ascii', 12, 15);
- return (riffHeader && webpHeader && vp8Header);
- }
- function calculate (buffer) {
- var chunkHeader = buffer.toString('ascii', 12, 16);
- buffer = buffer.slice(20, 30);
- // Extended webp stream signature
- if (chunkHeader === 'VP8X') {
- var extendedHeader = buffer[0];
- var validStart = (extendedHeader & 0xc0) === 0;
- var validEnd = (extendedHeader & 0x01) === 0;
- if (validStart && validEnd) {
- return calculateExtended(buffer);
- } else {
- return false;
- }
- }
- // Lossless webp stream signature
- if (chunkHeader === 'VP8 ' && buffer[0] !== 0x2f) {
- return calculateLossy(buffer);
- }
- // Lossy webp stream signature
- var signature = buffer.toString('hex', 3, 6);
- if (chunkHeader === 'VP8L' && signature !== '9d012a') {
- return calculateLossless(buffer);
- }
- return false;
- }
- function calculateExtended (buffer) {
- return {
- 'width': 1 + buffer.readUIntLE(4, 3),
- 'height': 1 + buffer.readUIntLE(7, 3)
- }
- }
- function calculateLossless (buffer) {
- return {
- 'width': 1 + (((buffer[2] & 0x3F) << 8) | buffer[1]),
- 'height': 1 + (((buffer[4] & 0xF) << 10) | (buffer[3] << 2) |
- ((buffer[2] & 0xC0) >> 6))
- };
- }
- function calculateLossy (buffer) {
- // `& 0x3fff` returns the last 14 bits
- // TO-DO: include webp scaling in the calculations
- return {
- 'width': buffer.readInt16LE(6) & 0x3fff,
- 'height': buffer.readInt16LE(8) & 0x3fff
- };
- }
- module.exports = {
- 'detect': isWebP,
- 'calculate': calculate
- };
|