UNPKG

3.83 kBJavaScriptView Raw
1
2
3/*!
4 * Stylus - plugin - url
5 * Copyright (c) Automattic <developer.wordpress.com>
6 * MIT Licensed
7 */
8
9/**
10 * Module dependencies.
11 */
12
13var utils = require('../utils')
14 , nodes = require('../nodes')
15 , Buffer = require('safer-buffer').Buffer
16 , fs = require('fs')
17 , path = require('path')
18 , sax = require('sax');
19
20/**
21 * Initialize a new `Image` with the given `ctx` and `path.
22 *
23 * @param {Evaluator} ctx
24 * @param {String} path
25 * @api private
26 */
27
28var Image = module.exports = function Image(ctx, path) {
29 this.ctx = ctx;
30 this.path = utils.lookup(path, ctx.paths);
31 if (!this.path) throw new Error('failed to locate file ' + path);
32};
33
34/**
35 * Open the image for reading.
36 *
37 * @api private
38 */
39
40Image.prototype.open = function(){
41 this.fd = fs.openSync(this.path, 'r');
42 this.length = fs.fstatSync(this.fd).size;
43 this.extname = path.extname(this.path).slice(1);
44};
45
46/**
47 * Close the file.
48 *
49 * @api private
50 */
51
52Image.prototype.close = function(){
53 if (this.fd) fs.closeSync(this.fd);
54};
55
56/**
57 * Return the type of image, supports:
58 *
59 * - gif
60 * - png
61 * - jpeg
62 * - svg
63 *
64 * @return {String}
65 * @api private
66 */
67
68Image.prototype.type = function(){
69 var type
70 , buf = Buffer.alloc(4);
71
72 fs.readSync(this.fd, buf, 0, 4, 0);
73
74 // GIF
75 if (0x47 == buf[0] && 0x49 == buf[1] && 0x46 == buf[2]) type = 'gif';
76
77 // PNG
78 else if (0x50 == buf[1] && 0x4E == buf[2] && 0x47 == buf[3]) type = 'png';
79
80 // JPEG
81 else if (0xff == buf[0] && 0xd8 == buf[1]) type = 'jpeg';
82
83 // SVG
84 else if ('svg' == this.extname) type = this.extname;
85
86 return type;
87};
88
89/**
90 * Return image dimensions `[width, height]`.
91 *
92 * @return {Array}
93 * @api private
94 */
95
96Image.prototype.size = function(){
97 var type = this.type()
98 , width
99 , height
100 , buf
101 , offset
102 , blockSize
103 , parser;
104
105 function uint16(b) { return b[1] << 8 | b[0]; }
106 function uint32(b) { return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; }
107
108 // Determine dimensions
109 switch (type) {
110 case 'jpeg':
111 buf = Buffer.alloc(this.length);
112 fs.readSync(this.fd, buf, 0, this.length, 0);
113 offset = 4;
114 blockSize = buf[offset] << 8 | buf[offset + 1];
115
116 while (offset < this.length) {
117 offset += blockSize;
118 if (offset >= this.length || 0xff != buf[offset]) break;
119 // SOF0 or SOF2 (progressive)
120 if (0xc0 == buf[offset + 1] || 0xc2 == buf[offset + 1]) {
121 height = buf[offset + 5] << 8 | buf[offset + 6];
122 width = buf[offset + 7] << 8 | buf[offset + 8];
123 } else {
124 offset += 2;
125 blockSize = buf[offset] << 8 | buf[offset + 1];
126 }
127 }
128 break;
129 case 'png':
130 buf = Buffer.alloc(8);
131 // IHDR chunk width / height uint32_t big-endian
132 fs.readSync(this.fd, buf, 0, 8, 16);
133 width = uint32(buf);
134 height = uint32(buf.slice(4, 8));
135 break;
136 case 'gif':
137 buf = Buffer.alloc(4);
138 // width / height uint16_t little-endian
139 fs.readSync(this.fd, buf, 0, 4, 6);
140 width = uint16(buf);
141 height = uint16(buf.slice(2, 4));
142 break;
143 case 'svg':
144 offset = Math.min(this.length, 1024);
145 buf = Buffer.alloc(offset);
146 fs.readSync(this.fd, buf, 0, offset, 0);
147 buf = buf.toString('utf8');
148 parser = sax.parser(true);
149 parser.onopentag = function(node) {
150 if ('svg' == node.name && node.attributes.width && node.attributes.height) {
151 width = parseInt(node.attributes.width, 10);
152 height = parseInt(node.attributes.height, 10);
153 }
154 };
155 parser.write(buf).close();
156 break;
157 }
158
159 if ('number' != typeof width) throw new Error('failed to find width of "' + this.path + '"');
160 if ('number' != typeof height) throw new Error('failed to find height of "' + this.path + '"');
161
162 return [width, height];
163};