-
Notifications
You must be signed in to change notification settings - Fork 87
/
file.ts
121 lines (109 loc) · 3.61 KB
/
file.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { MagickInputFile, MagickOutputFile, MagickFile } from '..'
import { execute } from '../execute';
function blobToUint8Array(blob: Blob): Promise<Uint8Array> {
return new Promise(resolve => {
const fileReader = new FileReader()
fileReader.onload = event => {
const result = (event.target as any).result as ArrayBuffer
resolve(new Uint8Array(result))
}
fileReader.readAsArrayBuffer(blob)
})
}
export function blobToString(blb: Blob): Promise<string> {
return new Promise(resolve => {
const reader = new FileReader()
reader.addEventListener('loadend', e => {
const text = (e.srcElement as any).result as string
resolve(text)
})
reader.readAsText(blb)
})
}
export function isInputFile(file: MagickFile): file is MagickInputFile {
return !!(file as MagickInputFile).content
}
export function isOutputFile(file: MagickFile): file is MagickOutputFile {
return !!(file as MagickOutputFile).blob
}
function uint8ArrayToString(arr: Uint8Array, charset: string = 'utf-8'): string {
return new TextDecoder(charset).decode(arr)
}
/**
* Read files as string. Useful when files contains plain text like in the output file info.txt of `convert logo: -format '%[pixel:p{0,0}]' info:info.txt`
*/
export async function readFileAsText(file: MagickFile): Promise<string> {
if (isInputFile(file)) {
return uint8ArrayToString(file.content)
}
if (isOutputFile(file)) {
return await blobToString(file.blob)
}
}
export async function isImage(file: MagickFile): Promise<boolean> {
const {exitCode} = await execute({inputFiles: [await asInputFile(file)], commands: `identify ${file.name}`})
return exitCode===0
}
/**
* Builds a new {@link MagickInputFile} by fetching the content of given url and optionally naming the file using given name
* or extracting the file name from the url otherwise.
*/
export async function buildInputFile(url: string, name: string = getFileName(url)): Promise<MagickInputFile> {
const fetchedSourceImage = await fetch(url)
const arrayBuffer = await fetchedSourceImage.arrayBuffer()
const content = new Uint8Array(arrayBuffer)
return { name, content }
}
function uint8ArrayToBlob(arr: Uint8Array): Blob {
return new Blob([arr])
}
async function outputFileToInputFile(file: MagickOutputFile, name: string = file.name): Promise<MagickInputFile> {
return {
name,
content: await blobToUint8Array(file.blob),
}
}
function inputFileToOutputFile(file: MagickInputFile, name: string = file.name): MagickOutputFile {
return {
name,
blob: uint8ArrayToBlob(file.content),
}
}
export async function asInputFile(f: MagickFile, name: string = f.name): Promise<MagickInputFile> {
let inputFile: MagickInputFile
if (isOutputFile(f)) {
inputFile = await outputFileToInputFile(f)
}
else {
inputFile = f as MagickInputFile
}
inputFile.name = name
return inputFile
}
export async function asOutputFile(f: MagickFile, name: string = f.name): Promise<MagickOutputFile> {
let outputFile: MagickOutputFile
if (isInputFile(f)) {
outputFile = inputFileToOutputFile(f)
}
else {
outputFile = f as MagickOutputFile
}
outputFile.name = name
return outputFile
}
export function getFileName(url: string): string {
try {
return decodeURIComponent(new URL(url).pathname.split('/').pop())
} catch (error) {
const s = `http://foo.com/${url}`
try {
return decodeURIComponent(new URL(s).pathname.split('/').pop())
} catch (error) {
return url
}
}
}
export function getFileNameExtension(filePathOrUrl: string) {
const s = getFileName(filePathOrUrl)
return s.substring(s.lastIndexOf('.') + 1, s.length)
}