Skip to content

Commit 1319f38

Browse files
Add web_site/scripts folder to repository main branch
1 parent 1776b3c commit 1319f38

2 files changed

Lines changed: 200 additions & 0 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import fs from "node:fs";
2+
import path from "node:path";
3+
import { fileURLToPath } from "node:url";
4+
5+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
6+
const repoRoot = path.resolve(scriptDir, "..");
7+
const secDir = path.join(repoRoot, "Paper", "sec");
8+
const outputPath = path.join(repoRoot, "Frontend", "data", "usedFigures.json");
9+
10+
const texFiles = fs
11+
.readdirSync(secDir)
12+
.filter((name) => name.endsWith(".tex"))
13+
.sort();
14+
15+
const includePattern = /\\includegraphics(?:\[[^\]]*\])?\{([^}]+)\}/g;
16+
const refs = new Map();
17+
18+
for (const texFile of texFiles) {
19+
const abs = path.join(secDir, texFile);
20+
const content = fs.readFileSync(abs, "utf8");
21+
22+
let match;
23+
while ((match = includePattern.exec(content)) !== null) {
24+
const raw = match[1].trim();
25+
const normalized = raw.replace(/\\/g, "/").replace(/^\.\//, "");
26+
27+
if (!normalized.startsWith("figures/")) {
28+
continue;
29+
}
30+
31+
const file = path.basename(normalized);
32+
refs.set(file, {
33+
file,
34+
path: normalized,
35+
referencedIn: texFile
36+
});
37+
}
38+
}
39+
40+
const used = Array.from(refs.values()).sort((a, b) => a.file.localeCompare(b.file));
41+
42+
const payload = {
43+
generatedAt: new Date().toISOString(),
44+
from: "Paper/sec/*.tex",
45+
count: used.length,
46+
figures: used
47+
};
48+
49+
fs.writeFileSync(outputPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
50+
console.log(`Wrote ${used.length} entries to ${path.relative(repoRoot, outputPath)}`);

web_site/scripts/pdf_to_png.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Batch-convert PDF files to PNG images.
4+
5+
Default behavior:
6+
- Input directory: Paper/figures
7+
- Output directory: same as input
8+
- Resolution: 300 DPI
9+
10+
Dependency:
11+
pip install pypdfium2
12+
"""
13+
14+
from __future__ import annotations
15+
16+
import argparse
17+
import sys
18+
from pathlib import Path
19+
20+
21+
def parse_args() -> argparse.Namespace:
22+
parser = argparse.ArgumentParser(
23+
description="Batch convert PDF files to PNG files."
24+
)
25+
parser.add_argument(
26+
"-i",
27+
"--input-dir",
28+
default="Paper/figures",
29+
help="Directory containing PDF files. Default: Paper/figures",
30+
)
31+
parser.add_argument(
32+
"-o",
33+
"--output-dir",
34+
default=None,
35+
help="Directory to write PNG files. Default: same as input directory",
36+
)
37+
parser.add_argument(
38+
"--dpi",
39+
type=int,
40+
default=300,
41+
help="Render resolution in DPI. Default: 300",
42+
)
43+
parser.add_argument(
44+
"--overwrite",
45+
action="store_true",
46+
help="Overwrite existing PNG files.",
47+
)
48+
parser.add_argument(
49+
"--first-page-only",
50+
action="store_true",
51+
help="Only convert the first page of each PDF.",
52+
)
53+
return parser.parse_args()
54+
55+
56+
def convert_pdf_file(
57+
pdf_path: Path,
58+
output_dir: Path,
59+
scale: float,
60+
overwrite: bool,
61+
first_page_only: bool,
62+
) -> tuple[int, int]:
63+
import pypdfium2 as pdfium
64+
65+
pdf = pdfium.PdfDocument(str(pdf_path))
66+
page_count = len(pdf)
67+
if page_count == 0:
68+
return 0, 0
69+
70+
pages_to_convert = 1 if first_page_only else page_count
71+
saved = 0
72+
73+
for page_index in range(pages_to_convert):
74+
page = pdf[page_index]
75+
bitmap = page.render(scale=scale)
76+
image = bitmap.to_pil()
77+
78+
if pages_to_convert == 1:
79+
out_name = f"{pdf_path.stem}.png"
80+
else:
81+
out_name = f"{pdf_path.stem}-p{page_index + 1}.png"
82+
out_path = output_dir / out_name
83+
84+
if out_path.exists() and not overwrite:
85+
print(f"Skip existing: {out_path}")
86+
continue
87+
88+
image.save(out_path, format="PNG")
89+
saved += 1
90+
print(f"Saved: {out_path}")
91+
92+
return saved, pages_to_convert
93+
94+
95+
def main() -> int:
96+
args = parse_args()
97+
98+
input_dir = Path(args.input_dir).resolve()
99+
output_dir = Path(args.output_dir).resolve() if args.output_dir else input_dir
100+
101+
if not input_dir.exists() or not input_dir.is_dir():
102+
print(f"Input directory not found: {input_dir}", file=sys.stderr)
103+
return 1
104+
105+
output_dir.mkdir(parents=True, exist_ok=True)
106+
107+
if args.dpi <= 0:
108+
print("--dpi must be a positive integer.", file=sys.stderr)
109+
return 1
110+
scale = args.dpi / 72.0
111+
112+
pdf_files = sorted(input_dir.glob("*.pdf"))
113+
if not pdf_files:
114+
print(f"No PDF files found in: {input_dir}")
115+
return 0
116+
117+
try:
118+
import pypdfium2 # noqa: F401
119+
except ImportError:
120+
print(
121+
"Missing dependency: pypdfium2\n"
122+
"Install with: pip install pypdfium2",
123+
file=sys.stderr,
124+
)
125+
return 2
126+
127+
total_saved = 0
128+
total_candidates = 0
129+
130+
for pdf_path in pdf_files:
131+
saved, candidates = convert_pdf_file(
132+
pdf_path=pdf_path,
133+
output_dir=output_dir,
134+
scale=scale,
135+
overwrite=args.overwrite,
136+
first_page_only=args.first_page_only,
137+
)
138+
total_saved += saved
139+
total_candidates += candidates
140+
141+
print(
142+
f"\nDone. PDFs: {len(pdf_files)}, "
143+
f"target pages: {total_candidates}, "
144+
f"newly saved PNGs: {total_saved}"
145+
)
146+
return 0
147+
148+
149+
if __name__ == "__main__":
150+
raise SystemExit(main())

0 commit comments

Comments
 (0)