处理文件

在文件里除了文件数据本身还有些额外的数据,比如音频,视频文件里可能会包含内容的作者、专辑、版权等信息,在照片文件里可能会包含设备、型号、大小、镜头、日期等等,设计一个接口方便客户端可以调取这些数据。

读取图像文件的附加信息

安装 jimp

1
npm install jimp

file.middleware.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
import { Request, Response, NextFunction } from "express";
import multer from "multer";
import Jimp from "jimp";

/**
* 创建一个multer
*/
const fileUpload = multer({
dest: "uploads/",
});

/**
* 文件拦截器
*/
export const fileInterceptor = fileUpload.single("file");

/**
* 文件处理器
*/
export const fileProcessor = async (
request: Request,
response: Response,
next: NextFunction
) => {
//文件路径
const { path } = request.file;

let image: Jimp;

try {
//读取图像文件
image = await Jimp.read(path);
} catch (error) {
return next(error);
}

console.log(image);

//下一步
next();
};
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
import express from "express";
import { authGuard } from "../auth/auth.middleware";
import * as fileController from "./file.controller";
import { fileInterceptor, fileProcessor } from "./file.middleware";

const router = express.Router();

/**
* 上传文件
*/
router.post(
"/files",
authGuard,
fileInterceptor,
fileProcessor,
fileController.store
);

/**
* 文件服务
*/
router.get("/files/:fileId/serve", fileController.serve);

/**
* 导出路由
*/
export default router;

存储图像的附加信息

设置类型 types/express.d.ts:

1
2
3
4
5
6
7
8
9
10
import { TokenPayload } from "../src/auth/auto.interface";

declare global {
namespace Express {
export interface Request {
user: TokenPayload;
fileMetaData: { width?: number; height?: number; metadata?: {} };
}
}
}

file.middleware.ts 中加入:

1
2
3
4
5
6
// 在请求中添加文件数据
request.fileMetaData = {
width: imageSize.width,
height: imageSize.height,
metadata: JSON.stringify(tags),
};

file.controller.ts 中加入:

1
2
3
4
5
6
7
//保存文件信息
const data = await createFile({
...fileInfo,
userId,
postId,
...request.fileMetaData,
});

定义调取图像信息的接口

file.controller.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
/**
* 文件信息
*/
export const metadata = async (
request: Request,
response: Response,
next: NextFunction
) => {
//文件ID
const { fileId } = request.params;

try {
//查询文件数据
const file = await findFileById(parseInt(fileId, 10));

//准备响应数据
const data = _.pick(file, ["id", "size", "width", "height", "metadata"]);

//做出响应
response.send(data);
} catch (error) {
next(error);
}
};

file.router.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
import express from "express";
import { authGuard } from "../auth/auth.middleware";
import * as fileController from "./file.controller";
import { fileInterceptor, fileProcessor } from "./file.middleware";

const router = express.Router();

/**
* 上传文件
*/
router.post(
"/files",
authGuard,
fileInterceptor,
fileProcessor,
fileController.store
);

/**
* 文件服务
*/
router.get("/files/:fileId/serve", fileController.serve);

/**
* 文件信息
*/
router.get("/files/:fileId/metadata", fileController.metadata);

/**
* 导出路由
*/
export default router;

调整图像尺寸

file.service.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
import path from "path";
import Jimp from "jimp";
import { connection } from "../app/database/mysql";
import { FileModel } from "./file.model";
/**
* 调整图像尺寸
*/
export const imageResizer = async (image: Jimp, file: Express.Multer.File) => {
//图像尺寸
const { imageSize } = image["_exif"];

//文件路径
const filePath = path.join(file.destination, "resized", file.filename);

// 大尺寸
if (imageSize.width > 1280) {
image
.resize(1280, Jimp.AUTO)
.quality(85)
.write(`${filePath}-large`);
}

// 中等尺寸
if (imageSize.width > 640) {
image
.resize(640, Jimp.AUTO)
.quality(85)
.write(`${filePath}-medium`);
}

// 缩略图
if (imageSize.width > 320) {
image
.resize(320, Jimp.AUTO)
.quality(85)
.write(`${filePath}-thumbnail`);
}
};

file.middleware.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
import { Request, Response, NextFunction } from "express";
import multer from "multer";
import Jimp from "jimp";
import { imageResizer } from "./file.service";
/**
* 文件处理器
*/
export const fileProcessor = async (
request: Request,
response: Response,
next: NextFunction
) => {
//文件路径
const { path } = request.file;

let image: Jimp;

try {
//读取图像文件
image = await Jimp.read(path);
} catch (error) {
return next(error);
}

//准备文件数据
const { imageSize, tags } = image["_exif"];

// 在请求中添加文件数据
request.fileMetaData = {
width: imageSize.width,
height: imageSize.height,
metadata: JSON.stringify(tags),
};

//调整图像尺寸
imageResizer(image, request.file);

//下一步
next();
};