123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /*!
- * Stylus - plugin - url
- * Copyright (c) Automattic <developer.wordpress.com>
- * MIT Licensed
- */
- /**
- * Module dependencies.
- */
- var utils = require('../utils')
- , nodes = require('../nodes')
- , Buffer = require('safer-buffer').Buffer
- , fs = require('fs')
- , path = require('path')
- , sax = require('sax');
- /**
- * Initialize a new `Image` with the given `ctx` and `path.
- *
- * @param {Evaluator} ctx
- * @param {String} path
- * @api private
- */
- var Image = module.exports = function Image(ctx, path) {
- this.ctx = ctx;
- this.path = utils.lookup(path, ctx.paths);
- if (!this.path) throw new Error('failed to locate file ' + path);
- };
- /**
- * Open the image for reading.
- *
- * @api private
- */
- Image.prototype.open = function(){
- this.fd = fs.openSync(this.path, 'r');
- this.length = fs.fstatSync(this.fd).size;
- this.extname = path.extname(this.path).slice(1);
- };
- /**
- * Close the file.
- *
- * @api private
- */
- Image.prototype.close = function(){
- if (this.fd) fs.closeSync(this.fd);
- };
- /**
- * Return the type of image, supports:
- *
- * - gif
- * - png
- * - jpeg
- * - svg
- *
- * @return {String}
- * @api private
- */
- Image.prototype.type = function(){
- var type
- , buf = Buffer.alloc(4);
-
- fs.readSync(this.fd, buf, 0, 4, 0);
- // GIF
- if (0x47 == buf[0] && 0x49 == buf[1] && 0x46 == buf[2]) type = 'gif';
- // PNG
- else if (0x50 == buf[1] && 0x4E == buf[2] && 0x47 == buf[3]) type = 'png';
- // JPEG
- else if (0xff == buf[0] && 0xd8 == buf[1]) type = 'jpeg';
- // SVG
- else if ('svg' == this.extname) type = this.extname;
- return type;
- };
- /**
- * Return image dimensions `[width, height]`.
- *
- * @return {Array}
- * @api private
- */
- Image.prototype.size = function(){
- var type = this.type()
- , width
- , height
- , buf
- , offset
- , blockSize
- , parser;
- function uint16(b) { return b[1] << 8 | b[0]; }
- function uint32(b) { return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; }
- // Determine dimensions
- switch (type) {
- case 'jpeg':
- buf = Buffer.alloc(this.length);
- fs.readSync(this.fd, buf, 0, this.length, 0);
- offset = 4;
- blockSize = buf[offset] << 8 | buf[offset + 1];
- while (offset < this.length) {
- offset += blockSize;
- if (offset >= this.length || 0xff != buf[offset]) break;
- // SOF0 or SOF2 (progressive)
- if (0xc0 == buf[offset + 1] || 0xc2 == buf[offset + 1]) {
- height = buf[offset + 5] << 8 | buf[offset + 6];
- width = buf[offset + 7] << 8 | buf[offset + 8];
- } else {
- offset += 2;
- blockSize = buf[offset] << 8 | buf[offset + 1];
- }
- }
- break;
- case 'png':
- buf = Buffer.alloc(8);
- // IHDR chunk width / height uint32_t big-endian
- fs.readSync(this.fd, buf, 0, 8, 16);
- width = uint32(buf);
- height = uint32(buf.slice(4, 8));
- break;
- case 'gif':
- buf = Buffer.alloc(4);
- // width / height uint16_t little-endian
- fs.readSync(this.fd, buf, 0, 4, 6);
- width = uint16(buf);
- height = uint16(buf.slice(2, 4));
- break;
- case 'svg':
- offset = Math.min(this.length, 1024);
- buf = Buffer.alloc(offset);
- fs.readSync(this.fd, buf, 0, offset, 0);
- buf = buf.toString('utf8');
- parser = sax.parser(true);
- parser.onopentag = function(node) {
- if ('svg' == node.name && node.attributes.width && node.attributes.height) {
- width = parseInt(node.attributes.width, 10);
- height = parseInt(node.attributes.height, 10);
- }
- };
- parser.write(buf).close();
- break;
- }
- if ('number' != typeof width) throw new Error('failed to find width of "' + this.path + '"');
- if ('number' != typeof height) throw new Error('failed to find height of "' + this.path + '"');
- return [width, height];
- };
|