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 */ 9function SimpleImageParser(parent, type, urlFilter, headerSize) { 10 ImageParser.call(this, parent, type, urlFilter); 11 this.headerSize = headerSize; 12} 13 14SimpleImageParser.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 */ 22SimpleImageParser.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 38function PngParser(parent) { 39 SimpleImageParser.call(this, parent, 'png', /\.png$/i, 24); 40} 41 42PngParser.prototype = {__proto__: SimpleImageParser.prototype}; 43 44/** 45 * @param {Object} metadata // TODO(JSDOC). 46 * @param {ByteReader} br // TODO(JSDOC). 47 */ 48PngParser.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 64MetadataDispatcher.registerParserClass(PngParser); 65 66 67function BmpParser(parent) { 68 SimpleImageParser.call(this, parent, 'bmp', /\.bmp$/i, 28); 69} 70 71BmpParser.prototype = {__proto__: SimpleImageParser.prototype}; 72 73/** 74 * @param {Object} metadata // TODO(JSDOC). 75 * @param {ByteReader} br // TODO(JSDOC). 76 */ 77BmpParser.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 89MetadataDispatcher.registerParserClass(BmpParser); 90 91 92function GifParser(parent) { 93 SimpleImageParser.call(this, parent, 'gif', /\.Gif$/i, 10); 94} 95 96GifParser.prototype = {__proto__: SimpleImageParser.prototype}; 97 98/** 99 * @param {Object} metadata // TODO(JSDOC). 100 * @param {ByteReader} br // TODO(JSDOC). 101 */ 102GifParser.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 113MetadataDispatcher.registerParserClass(GifParser); 114 115 116function WebpParser(parent) { 117 SimpleImageParser.call(this, parent, 'webp', /\.webp$/i, 30); 118} 119 120WebpParser.prototype = {__proto__: SimpleImageParser.prototype}; 121 122/** 123 * @param {Object} metadata // TODO(JSDOC). 124 * @param {ByteReader} br // TODO(JSDOC). 125 */ 126WebpParser.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 167MetadataDispatcher.registerParserClass(WebpParser); 168 169/** 170 * Parser for the header of .ico icon files. 171 * @param {MetadataDispatcher} parent Parent metadata dispatcher object. 172 * @constructor 173 * @extends SimpleImageParser 174 */ 175function IcoParser(parent) { 176 SimpleImageParser.call(this, parent, 'ico', /\.ico$/i, 8); 177} 178 179IcoParser.prototype = {__proto__: SimpleImageParser.prototype}; 180 181/** 182 * Parse the binary data as a ico header and stores to metadata. 183 * @param {Object} metadata Dictionary to store the parser metadata. 184 * @param {ByteReader} byteReader Reader for header binary data. 185 */ 186IcoParser.prototype.parseHeader = function(metadata, byteReader) { 187 byteReader.setByteOrder(ByteReader.LITTLE_ENDIAN); 188 189 var signature = byteReader.readString(4); 190 if (signature !== '\x00\x00\x00\x01') 191 throw new Error('Invalid ICO signature: ' + signature); 192 193 byteReader.seek(2); 194 metadata.width = byteReader.readScalar(1); 195 metadata.height = byteReader.readScalar(1); 196}; 197 198MetadataDispatcher.registerParserClass(IcoParser); 199