Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/emmet/src/imageSizeHelper.ts
5241 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
// Based on @sergeche's work on the emmet plugin for atom
7
8
import * as path from 'path';
9
import * as http from 'http';
10
import * as https from 'https';
11
import { URL } from 'url';
12
import { imageSize } from 'image-size';
13
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
14
15
const reUrl = /^https?:/;
16
export type ImageInfoWithScale = {
17
realWidth: number;
18
realHeight: number;
19
width: number;
20
height: number;
21
};
22
23
/**
24
* Get size of given image file. Supports files from local filesystem,
25
* as well as URLs
26
*/
27
export function getImageSize(file: string): Promise<ImageInfoWithScale | undefined> {
28
file = file.replace(/^file:\/\//, '');
29
return reUrl.test(file) ? getImageSizeFromURL(file) : getImageSizeFromFile(file);
30
}
31
32
/**
33
* Get image size from file on local file system
34
*/
35
function getImageSizeFromFile(file: string): Promise<ImageInfoWithScale | undefined> {
36
return new Promise((resolve, reject) => {
37
const isDataUrl = file.match(/^data:.+?;base64,/);
38
39
if (isDataUrl) {
40
// NB should use sync version of `sizeOf()` for buffers
41
try {
42
const data = Buffer.from(file.slice(isDataUrl[0].length), 'base64');
43
return resolve(sizeForFileName('', imageSize(data)));
44
} catch (err) {
45
return reject(err);
46
}
47
}
48
49
imageSize(file, (err: Error | null, size?: ISizeCalculationResult) => {
50
if (err) {
51
reject(err);
52
} else {
53
resolve(sizeForFileName(path.basename(file), size));
54
}
55
});
56
});
57
}
58
59
/**
60
* Get image size from given remove URL
61
*/
62
function getImageSizeFromURL(urlStr: string): Promise<ImageInfoWithScale | undefined> {
63
return new Promise((resolve, reject) => {
64
const url = new URL(urlStr);
65
const getTransport = url.protocol === 'https:' ? https.get : http.get;
66
67
if (!url.pathname) {
68
return reject('Given url doesnt have pathname property');
69
}
70
const urlPath: string = url.pathname;
71
72
getTransport(url, resp => {
73
const chunks: Buffer[] = [];
74
let bufSize = 0;
75
76
const trySize = (chunks: Buffer[]) => {
77
try {
78
const size: ISizeCalculationResult = imageSize(Buffer.concat(chunks, bufSize));
79
resp.removeListener('data', onData);
80
resp.destroy(); // no need to read further
81
resolve(sizeForFileName(path.basename(urlPath), size));
82
} catch (err) {
83
// might not have enough data, skip error
84
}
85
};
86
87
const onData = (chunk: Buffer) => {
88
bufSize += chunk.length;
89
chunks.push(chunk);
90
trySize(chunks);
91
};
92
93
resp
94
.on('data', onData)
95
.on('end', () => trySize(chunks))
96
.once('error', err => {
97
resp.removeListener('data', onData);
98
reject(err);
99
});
100
}).once('error', reject);
101
});
102
}
103
104
/**
105
* Returns size object for given file name. If file name contains `@Nx` token,
106
* the final dimentions will be downscaled by N
107
*/
108
function sizeForFileName(fileName: string, size?: ISizeCalculationResult): ImageInfoWithScale | undefined {
109
const m = fileName.match(/@(\d+)x\./);
110
const scale = m ? +m[1] : 1;
111
112
if (!size || !size.width || !size.height) {
113
return;
114
}
115
116
return {
117
realWidth: size.width,
118
realHeight: size.height,
119
width: Math.floor(size.width / scale),
120
height: Math.floor(size.height / scale)
121
};
122
}
123
124