[filestore] add pdftocairo conversion option (#31627)

Includes patches for Server Pro/CE 5.x and 6.x

GitOrigin-RevId: 67e387c96421b681339dbc1d89a8af0c34a163ef
This commit is contained in:
Miguel Serrano
2026-02-20 10:34:10 +01:00
committed by Copybot
parent 820adf568e
commit f4dd04e110
8 changed files with 292 additions and 40 deletions

View File

@@ -23,7 +23,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
&& apt-get update \
&& apt-get install -y \
unattended-upgrades \
build-essential wget net-tools unzip time imagemagick optipng strace nginx git python3 python-is-python3 zlib1g-dev libpcre3-dev gettext-base libwww-perl ca-certificates curl gnupg \
build-essential wget net-tools unzip time poppler-utils optipng strace nginx git python3 python-is-python3 zlib1g-dev libpcre3-dev gettext-base libwww-perl ca-certificates curl gnupg \
qpdf \
# upgrade base-image, batch all the upgrades together, rather than installing them on-by-one (which is slow!)
&& unattended-upgrade --verbose --no-minimal-upgrade-steps \

View File

@@ -468,6 +468,8 @@ switch (process.env.OVERLEAF_FILESTORE_BACKEND) {
}
}
settings.converter = process.env.CONVERTER || 'pdftocairo'
if (
!settings.trustedProxyIps.includes('loopback') &&
!settings.trustedProxyIps.includes('localhost') &&

View File

@@ -0,0 +1,13 @@
FROM sharelatex/sharelatex:5.5.7
# Apply security updates to base image
RUN apt update && apt install -y linux-libc-dev \
&& unattended-upgrade --verbose --no-minimal-upgrade-steps \
&& apt purge -y imagemagick \
&& apt autoremove -y \
&& apt install -y poppler-utils \
&& rm -rf /var/lib/apt/lists/*
# Update converter
COPY issue_31527.patch .
RUN patch -p0 < issue_31527.patch && rm issue_31527.patch

View File

@@ -0,0 +1,90 @@
--- services/filestore/app/js/FileConverter.js
+++ services/filestore/app/js/FileConverter.js
@@ -21,49 +21,44 @@
}
async function convert(sourcePath, requestedFormat) {
- const width = '600x'
+ const width = 1500
return await _convert(sourcePath, requestedFormat, [
- 'convert',
- '-define',
- `pdf:fit-page=${width}`,
- '-flatten',
- '-density',
- '300',
- `${sourcePath}[0]`,
+ 'pdftocairo',
+ '-png',
+ '-singlefile',
+ '-scale-to-x',
+ width.toString(),
+ '-scale-to-y',
+ '-1',
+ sourcePath,
])
}
async function thumbnail(sourcePath) {
- const width = '260x'
- return await convert(sourcePath, 'png', [
- 'convert',
- '-flatten',
- '-background',
- 'white',
- '-density',
- '300',
- '-define',
- `pdf:fit-page=${width}`,
- `${sourcePath}[0]`,
- '-resize',
- width,
+ const width = 700
+ return await _convert(sourcePath, 'png', [
+ 'pdftocairo',
+ '-png',
+ '-singlefile',
+ '-scale-to-x',
+ width.toString(),
+ '-scale-to-y',
+ '-1',
+ sourcePath,
])
}
async function preview(sourcePath) {
- const width = '548x'
- return await convert(sourcePath, 'png', [
- 'convert',
- '-flatten',
- '-background',
- 'white',
- '-density',
- '300',
- '-define',
- `pdf:fit-page=${width}`,
- `${sourcePath}[0]`,
- '-resize',
- width,
+ const width = 1000
+ return await _convert(sourcePath, 'png', [
+ 'pdftocairo',
+ '-png',
+ '-singlefile',
+ '-scale-to-x',
+ width.toString(),
+ '-scale-to-y',
+ '-1',
+ sourcePath,
])
}
@@ -77,7 +72,7 @@
const timer = new metrics.Timer('imageConvert')
const destPath = `${sourcePath}.${requestedFormat}`
- command.push(destPath)
+ command.push(sourcePath)
command = Settings.commands.convertCommandPrefix.concat(command)
try {

View File

@@ -0,0 +1,13 @@
FROM sharelatex/sharelatex:6.1.1
# Apply security updates to base image
RUN apt update && apt install -y linux-libc-dev \
&& unattended-upgrade --verbose --no-minimal-upgrade-steps \
&& apt purge -y imagemagick \
&& apt autoremove -y \
&& apt install -y poppler-utils \
&& rm -rf /var/lib/apt/lists/*
# Update converter
COPY issue_31527.patch .
RUN patch -p0 < issue_31527.patch && rm issue_31527.patch

View File

@@ -0,0 +1,91 @@
--- services/filestore/app/js/FileConverter.js
+++ services/filestore/app/js/FileConverter.js
@@ -22,49 +22,44 @@ export default {
}
async function convert(sourcePath, requestedFormat) {
- const width = '600x'
+ const width = 1500
return await _convert(sourcePath, requestedFormat, [
- 'convert',
- '-define',
- `pdf:fit-page=${width}`,
- '-flatten',
- '-density',
- '300',
- `${sourcePath}[0]`,
+ 'pdftocairo',
+ '-png',
+ '-singlefile',
+ '-scale-to-x',
+ width.toString(),
+ '-scale-to-y',
+ '-1',
+ sourcePath,
])
}
async function thumbnail(sourcePath) {
- const width = '260x'
- return await convert(sourcePath, 'png', [
- 'convert',
- '-flatten',
- '-background',
- 'white',
- '-density',
- '300',
- '-define',
- `pdf:fit-page=${width}`,
- `${sourcePath}[0]`,
- '-resize',
- width,
+ const width = 700
+ return await _convert(sourcePath, 'png', [
+ 'pdftocairo',
+ '-png',
+ '-singlefile',
+ '-scale-to-x',
+ width.toString(),
+ '-scale-to-y',
+ '-1',
+ sourcePath,
])
}
async function preview(sourcePath) {
- const width = '548x'
- return await convert(sourcePath, 'png', [
- 'convert',
- '-flatten',
- '-background',
- 'white',
- '-density',
- '300',
- '-define',
- `pdf:fit-page=${width}`,
- `${sourcePath}[0]`,
- '-resize',
- width,
+ const width = 1000
+ return await _convert(sourcePath, 'png', [
+ 'pdftocairo',
+ '-png',
+ '-singlefile',
+ '-scale-to-x',
+ width.toString(),
+ '-scale-to-y',
+ '-1',
+ sourcePath,
])
}
@@ -78,7 +73,8 @@ async function _convert(sourcePath, requestedFormat, command) {
const timer = new metrics.Timer('imageConvert')
const destPath = `${sourcePath}.${requestedFormat}`
- command.push(destPath)
+ const outputBaseName = sourcePath
+ command.push(outputBaseName)
command = Settings.commands.convertCommandPrefix.concat(command)
try {