Generating PDFs for Problem Statements
LCOJ can export problem statements to PDF, which is useful for onsite contests where contestants receive printed problem statements.
Note:
- This feature is optional
- This guide covers bare metal installs
- With Docker, you need to set up Pdfoid separately on the host or in another container
Installing Pdfoid
Pdfoid is a service that converts HTML to PDF.
Step 1: Install dependencies
apt update
apt install chromium-driver exiftoolStep 2: Clone Pdfoid
git clone https://github.com/DMOJ/pdfoid.git
cd pdfoidStep 3: Create a virtual environment
python3 -m venv env
source env/bin/activate
pip install -e .Step 4: Run Pdfoid
export CHROME_PATH=/usr/bin/chromium
export CHROMEDRIVER_PATH=/usr/bin/chromedriver
export EXIFTOOL_PATH=/usr/bin/exiftool
env/bin/pdfoid --port=8888If these programs are already in your $PATH, you do not need the exports.
Configuring LCOJ
Add to local_settings.py:
# Pdfoid URL
DMOJ_PDF_PDFOID_URL = 'http://localhost:8888'
# Timeout (seconds)
DMOJ_PDF_PROBLEM_TIMEOUT = 30Restart
Docker:
docker compose restart siteBare metal:
supervisorctl restart siteUsage
Generate a PDF for a problem
Go to: https://luyencode.net/problem/<problem_code>/pdf
Example: https://luyencode.net/problem/APLUSB/pdf
Generate PDFs for multiple problems
To generate PDFs for all problems in a contest:
- Go to the contest page
- Click Download problems as PDF
- Select the problems to download
- Click Generate PDF
Running Pdfoid with Supervisor
Create the file /etc/supervisor/conf.d/pdfoid.conf:
[program:pdfoid]
command=/path/to/pdfoid/env/bin/pdfoid --port=8888
directory=/path/to/pdfoid
user=pdfoid
environment=CHROME_PATH="/usr/bin/chromium",CHROMEDRIVER_PATH="/usr/bin/chromedriver",EXIFTOOL_PATH="/usr/bin/exiftool"
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/pdfoid.logStart it:
supervisorctl update
supervisorctl start pdfoidCustomizing PDFs
Custom CSS
Add PDF-specific CSS in local_settings.py:
DMOJ_PDF_PROBLEM_EXTRA_CSS = """
@page {
size: A4;
margin: 2cm;
}
body {
font-family: "Times New Roman", serif;
font-size: 12pt;
}
"""Header/Footer
DMOJ_PDF_PROBLEM_HEADER = """
<div style="text-align: center; font-size: 10pt;">
LuyenCode Online Judge
</div>
"""
DMOJ_PDF_PROBLEM_FOOTER = """
<div style="text-align: center; font-size: 10pt;">
Page <span class="pageNumber"></span> / <span class="totalPages"></span>
</div>
"""Troubleshooting
PDF generation fails:
- Check that Pdfoid is running:
curl http://localhost:8888 - Check that Chrome/Chromium is installed
- View Pdfoid logs (Docker):
docker compose logs -f pdfoid(if running in Docker) - View Pdfoid logs (bare metal):
supervisorctl tail -f pdfoid
PDF has font issues:
- Install the required fonts:
apt install fonts-liberation fonts-dejavuTimeout:
- Increase
DMOJ_PDF_PROBLEM_TIMEOUT - Check that the server has enough RAM
Images do not appear:
- Make sure images use absolute URLs (not relative paths)
- Check that the images are accessible from the server
Optimization
Cache PDFs
To avoid regenerating PDFs repeatedly:
DMOJ_PDF_PROBLEM_CACHE = '/home/lcoj/pdf_cache'
DMOJ_PDF_PROBLEM_CACHE_TIME = 3600 # 1 hourCreate the directory:
mkdir -p /home/lcoj/pdf_cache
chown www-data:www-data /home/lcoj/pdf_cacheReduce PDF size
DMOJ_PDF_PROBLEM_COMPRESS = TrueParallel processing
If you need to generate many PDFs at once, run multiple Pdfoid instances:
# Instance 1
env/bin/pdfoid --port=8888
# Instance 2
env/bin/pdfoid --port=8889Configure load balancing in local_settings.py:
DMOJ_PDF_PDFOID_URLS = [
'http://localhost:8888',
'http://localhost:8889',
]Printing PDFs
Print settings
When printing PDFs, we recommend that you:
- Choose A4 paper
- Set 2cm margins on each side
- Print double-sided to save paper
- Check the print preview before printing
Quantity
Calculate the number of copies needed:
- Number of contestants × Number of problems
- Add 10% as a buffer
- Add copies for the judges
Example Workflow
Preparing an onsite contest
- Create a contest with the problems
- Check that the problem statements render correctly
- Generate a PDF for each problem
- Review the PDFs
- Print the PDFs
- Package the problem statements
Automation script
#!/bin/bash
CONTEST="contest_key"
PROBLEMS=("APLUSB" "SORTING" "GRAPH")
for problem in "${PROBLEMS[@]}"; do
curl "https://luyencode.net/problem/$problem/pdf" \
-o "${problem}.pdf"
echo "Downloaded $problem.pdf"
done