| Marc Kupietz | ce1aa0c | 2023-06-15 07:50:23 +0200 | [diff] [blame] | 1 | #!/bin/sh -eu |
| Marc Kupietz | fcb7d47 | 2025-06-17 18:07:57 +0200 | [diff] [blame] | 2 | in=$1 |
| 3 | |
| Marc Kupietz | d13544d | 2026-07-17 11:04:45 +0200 | [diff] [blame] | 4 | # Optional second argument: explicit output file. Made absolute here because we |
| 5 | # may cd into the input's directory below. Further arguments are ignored. |
| 6 | out_arg="" |
| 7 | if [ $# -ge 2 ]; then |
| 8 | out_arg=", output='$(realpath -m "$2")'" |
| 9 | fi |
| 10 | |
| 11 | doc=$in |
| 12 | backup_file="" |
| 13 | poster_lang=en |
| 14 | |
| 15 | # For local files (not URLs): temporarily inject CSS that forces exact A0 |
| 16 | # dimensions and prevents Chrome's print shrinking, and work from the file's |
| 17 | # directory so relative links (e.g. skeleton_files/) resolve. |
| 18 | if [ -f "$in" ]; then |
| 19 | abs_in=$(realpath "$in") |
| 20 | work_dir=$(dirname "$abs_in") |
| 21 | |
| 22 | # Language the poster is written in, from <html lang="…"> (posterdown copies |
| 23 | # it from the Rmd `lang:` field). Used for the hyphenation check below. |
| 24 | poster_lang=$(sed -n 's/.*<html[^>]*[[:space:]]lang="\([A-Za-z-]*\)".*/\1/p' "$in" | head -n1) |
| 25 | poster_lang=${poster_lang:-en} |
| 26 | |
| 27 | backup_file="${abs_in}.backup" |
| 28 | cp "$abs_in" "$backup_file" |
| 29 | # Restore the original file when we exit, also on failure. |
| 30 | trap '[ -n "$backup_file" ] && mv "$backup_file" "$abs_in"' EXIT |
| 31 | |
| 32 | sed -i '/<\/head>/i\ |
| 33 | <style>\ |
| 34 | @page { size: 841mm 1189mm !important; margin: 0mm 0mm 20mm 0mm !important; }\ |
| 35 | html { width: 841mm !important; height: 1189mm !important; transform-origin: 0 0; }\ |
| 36 | body { width: 841mm !important; height: 1189mm !important; margin: 0 !important; padding: 0 !important; overflow: hidden !important; line-height: 1.2 !important; }\ |
| 37 | .poster { width: 841mm !important; height: 1189mm !important; }\ |
| 38 | * { line-height: 1.2 !important; }\ |
| 39 | p, div, span, li, ul, ol, td, th, a, strong, em, blockquote, caption, h1, h2, h3, h4, h5, h6 { line-height: 1.2 !important; }\ |
| 40 | </style>' "$abs_in" |
| 41 | |
| 42 | cd "$work_dir" |
| 43 | doc=$(basename "$abs_in") |
| 44 | fi |
| 45 | |
| 46 | # --- Automatic hyphenation --------------------------------------------------- |
| 47 | # The template HTML carries `hyphens: auto` plus an <html lang="…"> attribute. |
| 48 | # Whether Chrome actually hyphenates depends on where it finds its hyphenation |
| 49 | # dictionaries: |
| 50 | # |
| 51 | # * chrome-headless-shell (used in CI) BUNDLES the dictionaries in a |
| 52 | # `hyphen-data` folder next to the binary and loads them automatically, so |
| 53 | # hyphenation already works there without any help from us. |
| 54 | # * full google-chrome (typical locally) ships the dictionaries as a |
| 55 | # *component* living in the normal browser profile |
| 56 | # (~/.config/google-chrome/hyphen-data). pagedown::chrome_print() launches |
| 57 | # Chrome with a throwaway --user-data-dir that has no such component, so |
| 58 | # hyphenation silently does nothing. |
| 59 | # |
| 60 | # For the local case we seed a persistent profile with that component and point |
| 61 | # Chrome at it: extra_args are appended after pagedown's own --user-data-dir and |
| 62 | # Chrome honours the last value of a repeated switch. We symlink the whole |
| 63 | # hyphen-data tree (all languages), so whatever `lang:` the poster declares is |
| 64 | # respected -- nothing here is English-specific. |
| 65 | lang_base=${poster_lang%%-*} |
| 66 | |
| 67 | chrome_profile="${CHROME_PROFILE_DIR:-$HOME/.cache/pagedown-chrome-profile}" |
| 68 | user_data_dir_arg="" |
| 69 | for hyphen_src in \ |
| 70 | "$HOME/.config/google-chrome/hyphen-data" \ |
| 71 | "$HOME/.config/google-chrome-beta/hyphen-data" \ |
| 72 | "$HOME/.config/chromium/hyphen-data"; do |
| 73 | [ -d "$hyphen_src" ] || continue |
| 74 | mkdir -p "$chrome_profile" |
| 75 | ln -sfn "$hyphen_src" "$chrome_profile/hyphen-data" |
| 76 | # Only override the profile when we have something to seed; otherwise leave |
| 77 | # pagedown's default (throwaway) profile so CI's bundled dictionaries load. |
| 78 | user_data_dir_arg=",'--user-data-dir=$chrome_profile'" |
| 79 | break |
| 80 | done |
| 81 | |
| 82 | # Warn at build time if no dictionary for the poster's language is reachable, |
| 83 | # either from the seeded profile or bundled next to the Chrome binary pagedown |
| 84 | # will launch. Better a clear warning than a silently un-hyphenated poster. |
| 85 | chrome_bin=$(R --slave -e 'cat(pagedown::find_chrome())' 2>/dev/null || true) |
| 86 | bundled_dir="/nonexistent" |
| 87 | [ -n "$chrome_bin" ] && bundled_dir="$(dirname "$(readlink -f "$chrome_bin")")/hyphen-data" |
| 88 | have_dict=false |
| 89 | for dict in "$chrome_profile"/hyphen-data/*/hyph-"$lang_base"*.hyb \ |
| 90 | "$bundled_dir"/hyph-"$lang_base"*.hyb; do |
| 91 | # Unmatched globs stay literal, so the file test simply fails for them. |
| 92 | [ -e "$dict" ] && { have_dict=true; break; } |
| 93 | done |
| 94 | if $have_dict; then |
| 95 | echo "html2pdf: hyphenation enabled for lang='$poster_lang'." >&2 |
| 96 | else |
| 97 | echo "html2pdf: WARNING - no hyphenation dictionary for lang='$poster_lang'; the PDF will not be hyphenated." >&2 |
| 98 | fi |
| 99 | |
| 100 | R -e "pagedown::chrome_print('$doc'$out_arg, |
| Marc Kupietz | fcb7d47 | 2025-06-17 18:07:57 +0200 | [diff] [blame] | 101 | options=list( |
| 102 | pageRanges='1', |
| 103 | paperWidth=33.11, |
| 104 | paperHeight=46.81, |
| 105 | marginTop=0, |
| 106 | marginBottom=0, |
| 107 | marginLeft=0, |
| 108 | marginRight=0, |
| 109 | printBackground=TRUE, |
| 110 | scale=0.98, # Compensate for ~2% print scaling |
| 111 | displayHeaderFooter=FALSE, |
| 112 | preferCSSPageSize=TRUE |
| 113 | ), |
| 114 | extra_args = c( |
| 115 | '--disable-gpu', |
| 116 | '--no-sandbox', |
| 117 | '--disable-dev-shm-usage', |
| 118 | '--force-device-scale-factor=1', |
| 119 | '--disable-print-preview', |
| 120 | '--disable-background-timer-throttling', |
| 121 | '--allow-file-access-from-files', |
| 122 | '--force-color-profile=srgb', |
| 123 | '--disable-lcd-text', |
| 124 | '--disable-font-subpixel-positioning', |
| Marc Kupietz | d13544d | 2026-07-17 11:04:45 +0200 | [diff] [blame] | 125 | '--run-all-compositor-stages-before-draw'$user_data_dir_arg |
| Marc Kupietz | fcb7d47 | 2025-06-17 18:07:57 +0200 | [diff] [blame] | 126 | ) |
| 127 | )" |