Home | History | Annotate | Download | only in metadata
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 /* Base class for image metadata parsers that only need to look at a short
      8   fragment at the start of the file */
      9 function SimpleImageParser(parent, type, urlFilter, headerSize) {
     10   ImageParser.call(this, parent, type, urlFilter);
     11   this.headerSize = headerSize;
     12 }
     13 
     14 SimpleImageParser.prototype = {__proto__: ImageParser.prototype};
     15 
     16 /**
     17  * @param {File} file  // TODO(JSDOC).
     18  * @param {Object} metadata  // TODO(JSDOC).
     19  * @param {function(Object)} callback  // TODO(JSDOC).
     20  * @param {function(string)} errorCallback  // TODO(JSDOC).
     21  */
     22 SimpleImageParser.prototype.parse = function(
     23     file, metadata, callback, errorCallback) {
     24   var self = this;
     25   util.readFileBytes(file, 0, this.headerSize,
     26     function(file, br) {
     27       try {
     28         self.parseHeader(metadata, br);
     29         callback(metadata);
     30       } catch (e) {
     31         errorCallback(e.toString());
     32       }
     33     },
     34     errorCallback);
     35 };
     36 
     37 
     38 function PngParser(parent) {
     39   SimpleImageParser.call(this, parent, 'png', /\.png$/i, 24);
     40 }
     41 
     42 PngParser.prototype = {__proto__: SimpleImageParser.prototype};
     43 
     44 /**
     45  * @param {Object} metadata  // TODO(JSDOC).
     46  * @param {ByteReader} br  // TODO(JSDOC).
     47  */
     48 PngParser.prototype.parseHeader = function(metadata, br) {
     49   br.setByteOrder(ByteReader.BIG_ENDIAN);
     50 
     51   var signature = br.readString(8);
     52   if (signature != '\x89PNG\x0D\x0A\x1A\x0A')
     53     throw new Error('Invalid PNG signature: ' + signature);
     54 
     55   br.seek(12);
     56   var ihdr = br.readString(4);
     57   if (ihdr != 'IHDR')
     58     throw new Error('Missing IHDR chunk');
     59 
     60   metadata.width = br.readScalar(4);
     61   metadata.height = br.readScalar(4);
     62 };
     63 
     64 MetadataDispatcher.registerParserClass(PngParser);
     65 
     66 
     67 function BmpParser(parent) {
     68   SimpleImageParser.call(this, parent, 'bmp', /\.bmp$/i, 28);
     69 }
     70 
     71 BmpParser.prototype = {__proto__: SimpleImageParser.prototype};
     72 
     73 /**
     74  * @param {Object} metadata  // TODO(JSDOC).
     75  * @param {ByteReader} br  // TODO(JSDOC).
     76  */
     77 BmpParser.prototype.parseHeader = function(metadata, br) {
     78   br.setByteOrder(ByteReader.LITTLE_ENDIAN);
     79 
     80   var signature = br.readString(2);
     81   if (signature != 'BM')
     82     throw new Error('Invalid BMP signature: ' + signature);
     83 
     84   br.seek(18);
     85   metadata.width = br.readScalar(4);
     86   metadata.height = br.readScalar(4);
     87 };
     88 
     89 MetadataDispatcher.registerParserClass(BmpParser);
     90 
     91 
     92 function GifParser(parent) {
     93   SimpleImageParser.call(this, parent, 'gif', /\.Gif$/i, 10);
     94 }
     95 
     96 GifParser.prototype = {__proto__: SimpleImageParser.prototype};
     97 
     98 /**
     99  * @param {Object} metadata  // TODO(JSDOC).
    100  * @param {ByteReader} br  // TODO(JSDOC).
    101  */
    102 GifParser.prototype.parseHeader = function(metadata, br) {
    103   br.setByteOrder(ByteReader.LITTLE_ENDIAN);
    104 
    105   var signature = br.readString(6);
    106   if (!signature.match(/GIF8(7|9)a/))
    107     throw new Error('Invalid GIF signature: ' + signature);
    108 
    109   metadata.width = br.readScalar(2);
    110   metadata.height = br.readScalar(2);
    111 };
    112 
    113 MetadataDispatcher.registerParserClass(GifParser);
    114 
    115 
    116 function WebpParser(parent) {
    117   SimpleImageParser.call(this, parent, 'webp', /\.webp$/i, 30);
    118 }
    119 
    120 WebpParser.prototype = {__proto__: SimpleImageParser.prototype};
    121 
    122 /**
    123  * @param {Object} metadata  // TODO(JSDOC).
    124  * @param {ByteReader} br  // TODO(JSDOC).
    125  */
    126 WebpParser.prototype.parseHeader = function(metadata, br) {
    127   br.setByteOrder(ByteReader.LITTLE_ENDIAN);
    128 
    129   var riffSignature = br.readString(4);
    130   if (riffSignature != 'RIFF')
    131     throw new Error('Invalid RIFF signature: ' + riffSignature);
    132 
    133   br.seek(8);
    134   var webpSignature = br.readString(4);
    135   if (webpSignature != 'WEBP')
    136     throw new Error('Invalid WEBP signature: ' + webpSignature);
    137 
    138   var chunkFormat = br.readString(4);
    139   if (chunkFormat != 'VP8 ' && chunkFormat != 'VP8L')
    140     throw new Error('Invalid chunk format: ' + chunkFormat);
    141 
    142   if (chunkFormat == 'VP8 ') {
    143     // VP8 lossy bitstream format.
    144     br.seek(23);
    145     var lossySignature = br.readScalar(2) | (br.readScalar(1) << 16);
    146     if (lossySignature != 0x2a019d)
    147       throw new Error('Invalid VP8 lossy bitstream signature: ' +
    148         lossySignature);
    149 
    150     var dimensionBits = br.readScalar(4);
    151     metadata.width = dimensionBits & 0x3fff;
    152     metadata.height = (dimensionBits >> 16) & 0x3fff;
    153   } else {
    154     // VP8 lossless bitstream format.
    155     br.seek(20);
    156     var losslessSignature = br.readScalar(1);
    157     if (losslessSignature != 0x2f)
    158       throw new Error('Invalid VP8 lossless bitstream signature: ' +
    159         losslessSignature);
    160 
    161     var dimensionBits = br.readScalar(4);
    162     metadata.width = (dimensionBits & 0x3fff) + 1;
    163     metadata.height = ((dimensionBits >> 14) & 0x3fff) + 1;
    164   }
    165 };
    166 
    167 MetadataDispatcher.registerParserClass(WebpParser);
    168