-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
caa0ef4
commit 0bee43b
Showing
7 changed files
with
551 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
// Based on @sergeche's work on the emmet plugin for atom | ||
// TODO: Move to https://github.com/emmetio/image-size | ||
|
||
'use strict'; | ||
|
||
import * as path from 'path'; | ||
import * as http from 'http'; | ||
import * as https from 'https'; | ||
import { parse as parseUrl } from 'url'; | ||
import * as sizeOf from 'image-size'; | ||
|
||
const reUrl = /^https?:/; | ||
|
||
/** | ||
* Get size of given image file. Supports files from local filesystem, | ||
* as well as URLs | ||
* @param {String} file Path to local file or URL | ||
* @return {Promise} | ||
*/ | ||
export function getImageSize(file) { | ||
file = file.replace(/^file:\/\//, ''); | ||
return reUrl.test(file) ? getImageSizeFromURL(file) : getImageSizeFromFile(file); | ||
} | ||
|
||
/** | ||
* Get image size from file on local file system | ||
* @param {String} file | ||
* @return {Promise} | ||
*/ | ||
function getImageSizeFromFile(file) { | ||
return new Promise((resolve, reject) => { | ||
const isDataUrl = file.match(/^data:.+?;base64,/); | ||
|
||
if (isDataUrl) { | ||
// NB should use sync version of `sizeOf()` for buffers | ||
try { | ||
const data = Buffer.from(file.slice(isDataUrl[0].length), 'base64'); | ||
return resolve(sizeForFileName('', sizeOf(data))); | ||
} catch (err) { | ||
return reject(err); | ||
} | ||
} | ||
|
||
sizeOf(file, (err, size) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(sizeForFileName(path.basename(file), size)); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Get image size from given remove URL | ||
* @param {String} url | ||
* @return {Promise} | ||
*/ | ||
function getImageSizeFromURL(url) { | ||
return new Promise((resolve, reject) => { | ||
url = parseUrl(url); | ||
const getTransport = url.protocol === 'https:' ? https.get : http.get; | ||
|
||
getTransport(url, resp => { | ||
const chunks = []; | ||
let bufSize = 0; | ||
|
||
const trySize = chunks => { | ||
try { | ||
const size = sizeOf(Buffer.concat(chunks, bufSize)); | ||
resp.removeListener('data', onData); | ||
resp.destroy(); // no need to read further | ||
resolve(sizeForFileName(path.basename(url.pathname), size)); | ||
} catch (err) { | ||
// might not have enough data, skip error | ||
} | ||
}; | ||
|
||
const onData = chunk => { | ||
bufSize += chunk.length; | ||
chunks.push(chunk); | ||
trySize(chunks); | ||
}; | ||
|
||
resp | ||
.on('data', onData) | ||
.on('end', () => trySize(chunks)) | ||
.once('error', err => { | ||
resp.removeListener('data', onData); | ||
reject(err); | ||
}); | ||
}) | ||
.once('error', reject); | ||
}); | ||
} | ||
|
||
/** | ||
* Returns size object for given file name. If file name contains `@Nx` token, | ||
* the final dimentions will be downscaled by N | ||
* @param {String} fileName | ||
* @param {Object} size | ||
* @return {Object} | ||
*/ | ||
function sizeForFileName(fileName, size) { | ||
const m = fileName.match(/@(\d+)x\./); | ||
const scale = m ? +m[1] : 1; | ||
|
||
return { | ||
realWidth: size.width, | ||
realHeight: size.height, | ||
width: Math.floor(size.width / scale), | ||
height: Math.floor(size.height / scale) | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
// Based on @sergeche's work on the emmet plugin for atom | ||
// TODO: Move to https://github.com/emmetio/file-utils | ||
'use strict'; | ||
|
||
import * as path from 'path'; | ||
import * as fs from 'fs'; | ||
|
||
const reAbsolute = /^\/+/; | ||
|
||
/** | ||
* Locates given `filePath` on user’s file system and returns absolute path to it. | ||
* This method expects either URL, or relative/absolute path to resource | ||
* @param {String} basePath Base path to use if filePath is not absoulte | ||
* @param {String} filePath File to locate. | ||
* @return {Promise} | ||
*/ | ||
export function locateFile(base: string, filePath: string): Promise<string> { | ||
if (/^\w+:/.test(filePath)) { | ||
// path with protocol, already absolute | ||
return Promise.resolve(filePath); | ||
} | ||
|
||
filePath = path.normalize(filePath); | ||
|
||
return reAbsolute.test(filePath) | ||
? resolveAbsolute(base, filePath) | ||
: resolveRelative(base, filePath); | ||
} | ||
|
||
/** | ||
* Resolves relative file path | ||
* @param {TextEditor|String} base | ||
* @param {String} filePath | ||
* @return {Promise} | ||
*/ | ||
function resolveRelative(basePath, filePath): Promise<string> { | ||
return tryFile(path.resolve(basePath, filePath)); | ||
} | ||
|
||
/** | ||
* Resolves absolute file path agaist given editor: tries to find file in every | ||
* parent of editor’s file | ||
* @param {TextEditor|String} base | ||
* @param {String} filePath | ||
* @return {Promise} | ||
*/ | ||
function resolveAbsolute(basePath, filePath): Promise<string> { | ||
return new Promise((resolve, reject) => { | ||
filePath = filePath.replace(reAbsolute, ''); | ||
|
||
const next = ctx => { | ||
tryFile(path.resolve(ctx, filePath)) | ||
.then(resolve, err => { | ||
const dir = path.dirname(ctx); | ||
if (!dir || dir === ctx) { | ||
return reject(`Unable to locate absolute file ${filePath}`); | ||
} | ||
|
||
next(dir); | ||
}); | ||
}; | ||
|
||
next(basePath); | ||
}); | ||
} | ||
|
||
/** | ||
* Check if given file exists and it’s a file, not directory | ||
* @param {String} file | ||
* @return {Promise} | ||
*/ | ||
function tryFile(file): Promise<string> { | ||
return new Promise((resolve, reject) => { | ||
fs.stat(file, (err, stat) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
|
||
if (!stat.isFile()) { | ||
return reject(new Error(`${file} is not a file`)); | ||
} | ||
|
||
resolve(file); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.