summaryrefslogtreecommitdiffstats
path: root/src/server/img.ts
blob: 7006c3da50971e601bd59d88d576963d7e0c6fff (plain) (blame)
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
import sharp from "sharp"
import { createReadStream } from "node:fs"
import { extname, join } from "node:path"
import createError from "http-errors"
import type express from "express"

function transform(format: keyof sharp.FormatEnum, width?: number, height?: number): sharp.Sharp {
	var transform = sharp().withMetadata()

	if (format) {
		transform = transform.toFormat(format)
	}

	if (width || height) {
		transform = transform.resize({ width, height })
	}

	return transform
}

function errorHand(next: express.NextFunction) {
	return function (err: NodeJS.ErrnoException) {
		switch (err.code) {
			case "ENOENT":
				next()
				break
			case "EISDIR":
			case "EPERM":
				next(createError(401))
				break
			default:
				next(err)
		}
	}
}

export default function (path: string) {
	return async function (req: express.Request, res: express.Response, next: express.NextFunction) {
		const err_handler = errorHand(next)

		const filepath = join(path, req.path)
		const ext = extname(filepath).substring(1)
		if (![
			"svg", "heic", "heif", "avif", "jpeg", "jpg", "jpe", "tile", "dz",
			"png", "raw", "tiff", "tif", "webp", "gif", "jp2", "jpx", "j2k",
			"j2c", "jxl"
		].includes(ext)) {
			return next()
		}
		const width = parseInt(String(req.query['width']))
		const height = parseInt(String(req.query['height']))
		var { format = ext } = req.query as { format?: string }
		if (format == "svg") {
			if (ext == "svg") {
				const stream = createReadStream(filepath)
				stream.on("error", err_handler)
				res.format({
					[format]: function () {
						return stream.pipe(res)
					}
				})
			} else {
				return next(createError(400))
			}
			return
		}

		const stream = createReadStream(filepath)
		stream.on("error", err_handler)
		res.format({
			[format]: function () {
				return stream.pipe(
					transform(
						format as keyof sharp.FormatEnum,
						!isNaN(width) ? width : undefined,
						!isNaN(height) ? height : undefined
					)
				).pipe(res)
			}
		})
	}
}