1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 | function isWhiteSpace(chr) {
|
6 | return chr === 0x20 || chr === 0x09 || chr === 0x0D || chr === 0x0A;
|
7 | }
|
8 |
|
9 |
|
10 | function isFinitePositive(val) {
|
11 | return typeof val === 'number' && isFinite(val) && val > 0;
|
12 | }
|
13 |
|
14 | function canBeSvg(buf) {
|
15 | var i = 0, max = buf.length;
|
16 |
|
17 | while (i < max && isWhiteSpace(buf[i])) i++;
|
18 |
|
19 | if (i === max) return false;
|
20 | return buf[i] === 0x3c;
|
21 | }
|
22 |
|
23 |
|
24 | var SVG_HEADER_RE = /<svg\s[^>]+>/;
|
25 | var SVG_WIDTH_RE = /[^-]\bwidth="([^%]+?)"|[^-]\bwidth='([^%]+?)'/;
|
26 | var SVG_HEIGHT_RE = /\bheight="([^%]+?)"|\bheight='([^%]+?)'/;
|
27 | var SVG_VIEWBOX_RE = /\bview[bB]ox="(.+?)"|\bview[bB]ox='(.+?)'/;
|
28 | var SVG_UNITS_RE = /in$|mm$|cm$|pt$|pc$|px$|em$|ex$/;
|
29 |
|
30 | function svgAttrs(str) {
|
31 | var width = str.match(SVG_WIDTH_RE);
|
32 | var height = str.match(SVG_HEIGHT_RE);
|
33 | var viewbox = str.match(SVG_VIEWBOX_RE);
|
34 |
|
35 | return {
|
36 | width: width && (width[1] || width[2]),
|
37 | height: height && (height[1] || height[2]),
|
38 | viewbox: viewbox && (viewbox[1] || viewbox[2])
|
39 | };
|
40 | }
|
41 |
|
42 |
|
43 | function units(str) {
|
44 | if (!SVG_UNITS_RE.test(str)) return 'px';
|
45 |
|
46 | return str.match(SVG_UNITS_RE)[0];
|
47 | }
|
48 |
|
49 |
|
50 | module.exports = function (data) {
|
51 | if (!canBeSvg(data)) return;
|
52 |
|
53 | var str = '';
|
54 |
|
55 | for (var i = 0; i < data.length; i++) {
|
56 |
|
57 |
|
58 | str += String.fromCharCode(data[i]);
|
59 | }
|
60 |
|
61 | if (!SVG_HEADER_RE.test(str)) return;
|
62 |
|
63 | var attrs = svgAttrs(str.match(SVG_HEADER_RE)[0]);
|
64 | var width = parseFloat(attrs.width);
|
65 | var height = parseFloat(attrs.height);
|
66 |
|
67 |
|
68 |
|
69 | if (attrs.width && attrs.height) {
|
70 | if (!isFinitePositive(width) || !isFinitePositive(height)) return;
|
71 |
|
72 | return {
|
73 | width: width,
|
74 | height: height,
|
75 | type: 'svg',
|
76 | mime: 'image/svg+xml',
|
77 | wUnits: units(attrs.width),
|
78 | hUnits: units(attrs.height)
|
79 | };
|
80 | }
|
81 |
|
82 |
|
83 |
|
84 | var parts = (attrs.viewbox || '').split(' ');
|
85 | var viewbox = {
|
86 | width: parts[2],
|
87 | height: parts[3]
|
88 | };
|
89 | var vbWidth = parseFloat(viewbox.width);
|
90 | var vbHeight = parseFloat(viewbox.height);
|
91 |
|
92 | if (!isFinitePositive(vbWidth) || !isFinitePositive(vbHeight)) return;
|
93 | if (units(viewbox.width) !== units(viewbox.height)) return;
|
94 |
|
95 | var ratio = vbWidth / vbHeight;
|
96 |
|
97 | if (attrs.width) {
|
98 | if (!isFinitePositive(width)) return;
|
99 |
|
100 | return {
|
101 | width: width,
|
102 | height: width / ratio,
|
103 | type: 'svg',
|
104 | mime: 'image/svg+xml',
|
105 | wUnits: units(attrs.width),
|
106 | hUnits: units(attrs.width)
|
107 | };
|
108 | }
|
109 |
|
110 | if (attrs.height) {
|
111 | if (!isFinitePositive(height)) return;
|
112 |
|
113 | return {
|
114 | width: height * ratio,
|
115 | height: height,
|
116 | type: 'svg',
|
117 | mime: 'image/svg+xml',
|
118 | wUnits: units(attrs.height),
|
119 | hUnits: units(attrs.height)
|
120 | };
|
121 | }
|
122 |
|
123 | return {
|
124 | width: vbWidth,
|
125 | height: vbHeight,
|
126 | type: 'svg',
|
127 | mime: 'image/svg+xml',
|
128 | wUnits: units(viewbox.width),
|
129 | hUnits: units(viewbox.height)
|
130 | };
|
131 | };
|