Skip to content

Commit ef19962

Browse files
committed
feat(docker): optimize Dockerfile and enhance EXIF data extraction
- Updated Dockerfile to use Alpine base image for reduced size and added necessary runtime dependencies including exiftool. - Refactored EXIF data extraction logic to utilize exiftool with improved error handling and logging. - Simplified metadata handling by removing unnecessary checks and ensuring consistent extraction of EXIF data. Signed-off-by: Innei <tukon479@gmail.com>
1 parent fa7b953 commit ef19962

File tree

2 files changed

+41
-29
lines changed

2 files changed

+41
-29
lines changed

Dockerfile.core

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# syntax=docker/dockerfile:1.7
22

3+
# Use Alpine base image for smaller size
34
FROM node:lts-alpine AS builder
45
ENV PNPM_HOME=/pnpm
56
ENV PATH="$PNPM_HOME:$PATH"
@@ -31,10 +32,22 @@ WORKDIR /app
3132

3233
# Runtime deps for image processing:
3334
# - perl: required by exiftool-vendored on Linux
34-
# - perl-image-exiftool: provides the exiftool binary (optional but useful)
35+
# - perl-image-exiftool: provides the exiftool binary
3536
# - vips: runtime library for sharp
3637
# - libheif: enable HEIF/HEIC support in libvips when available
37-
RUN apk add --no-cache perl perl-image-exiftool vips libheif
38+
RUN apk add --no-cache \
39+
perl \
40+
exiftool \
41+
perl-image-exiftool \
42+
vips \
43+
libheif \
44+
libc6-compat \
45+
gcompat \
46+
&& EXIFTOOL_BIN="$(command -v exiftool)" \
47+
&& echo "Using exiftool binary at ${EXIFTOOL_BIN}" \
48+
&& "${EXIFTOOL_BIN}" -ver \
49+
&& ln -sf "${EXIFTOOL_BIN}" /usr/local/bin/exiftool
50+
ENV EXIFTOOL_PATH=/usr/local/bin/exiftool
3851
COPY --from=builder /workspace/be/apps/core/dist ./dist
3952
COPY --from=builder /workspace/be/packages/db/migrations ./migrations
4053
COPY --from=builder /workspace/be/apps/core/docker-entrypoint.sh ./docker-entrypoint.sh

packages/builder/src/image/exif.ts

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,29 @@ import path from 'node:path'
33

44
import { isNil, noop } from 'es-toolkit'
55
import type { ExifDateTime, Tags } from 'exiftool-vendored'
6-
import { exiftool } from 'exiftool-vendored'
7-
import type { Metadata } from 'sharp'
8-
import sharp from 'sharp'
6+
import { ExifTool } from 'exiftool-vendored'
97

108
import { getGlobalLoggers } from '../photo/logger-adapter.js'
119
import type { PickedExif } from '../types/photo.js'
1210

11+
const exiftool = new ExifTool({
12+
...(process.env.EXIFTOOL_PATH ? { exiftoolPath: process.env.EXIFTOOL_PATH } : {}),
13+
taskTimeoutMillis: 30000,
14+
})
15+
16+
let isExiftoolClosed = false
17+
const closeExiftool = () => {
18+
if (isExiftoolClosed) {
19+
return
20+
}
21+
isExiftoolClosed = true
22+
exiftool.end().catch(noop)
23+
}
24+
25+
process.once('beforeExit', closeExiftool)
26+
process.once('SIGINT', closeExiftool)
27+
process.once('SIGTERM', closeExiftool)
28+
1329
// 提取 EXIF 数据
1430
export async function extractExifData(imageBuffer: Buffer, originalBuffer?: Buffer): Promise<PickedExif | null> {
1531
const log = getGlobalLoggers().exif
@@ -18,29 +34,12 @@ export async function extractExifData(imageBuffer: Buffer, originalBuffer?: Buff
1834
const tempImagePath = path.resolve('/tmp/image_process', `${crypto.randomUUID()}.jpg`)
1935

2036
try {
21-
log.info('开始提取 EXIF 数据')
22-
23-
// 首先尝试从处理后的图片中提取 EXIF
24-
let metadata = await sharp(imageBuffer).metadata()
25-
26-
// 如果处理后的图片没有 EXIF 数据,且提供了原始 buffer,尝试从原始图片提取
27-
if (!metadata.exif && originalBuffer) {
28-
log.info('处理后的图片缺少 EXIF 数据,尝试从原始图片提取')
29-
try {
30-
metadata = await sharp(originalBuffer).metadata()
31-
} catch (error) {
32-
log.warn('从原始图片提取 EXIF 失败,可能是不支持的格式:', error)
33-
}
34-
}
35-
36-
if (!metadata.exif) {
37-
log.warn('未找到 EXIF 数据')
38-
return null
39-
}
40-
4137
await writeFile(tempImagePath, originalBuffer || imageBuffer)
38+
39+
log.info(`开始提取 EXIF 数据, 文件路径: ${tempImagePath}`)
4240
const exifData = await exiftool.read(tempImagePath)
43-
const result = handleExifData(exifData, metadata)
41+
42+
const result = handleExifData(exifData)
4443

4544
if (!exifData) {
4645
log.warn('EXIF 数据解析失败')
@@ -135,7 +134,7 @@ const pickKeys: Array<keyof Tags | (string & {})> = [
135134
'MicroVideoOffset',
136135
'MicroVideoPresentationTimestampUs',
137136
]
138-
function handleExifData(exifData: Tags, metadata: Metadata): PickedExif {
137+
function handleExifData(exifData: Tags): PickedExif {
139138
const date = {
140139
DateTimeOriginal: formatExifDate(exifData.DateTimeOriginal),
141140
DateTimeDigitized: formatExifDate(exifData.DateTimeDigitized),
@@ -177,8 +176,8 @@ function handleExifData(exifData: Tags, metadata: Metadata): PickedExif {
177176
}
178177
}
179178
const size = {
180-
ImageWidth: exifData.ExifImageWidth || metadata.width,
181-
ImageHeight: exifData.ExifImageHeight || metadata.height,
179+
ImageWidth: exifData.ExifImageWidth,
180+
ImageHeight: exifData.ExifImageHeight,
182181
}
183182
const result: any = structuredClone(exifData)
184183
for (const key in result) {

0 commit comments

Comments
 (0)