├── .github ├── FUNDING.yml └── workflows │ └── hugo.yml ├── .gitignore ├── .gitmodules ├── .hugo_build.lock ├── README.md ├── archetypes └── default.md ├── build-modules.sh ├── config.toml ├── content ├── Auto-portrait-0088-MLM_0774_01.jpg ├── Shoot Minh-Ly Hangar 2 - Rouge-0026-DSC_0560--WEB-LOW.jpg ├── _index.md ├── authors │ ├── aurelien-pierre │ │ └── _index.md │ └── guillaume-marty │ │ └── _index.md ├── booking.md ├── calibration-after.jpg ├── calibration-before.jpg ├── censorize-after.jpg ├── censorize-before.jpg ├── contribute │ ├── _index.md │ ├── audience.md │ ├── coding-style.md │ ├── design.md │ ├── introduction.md │ ├── organization.md │ ├── translating.md │ ├── triaging.md │ ├── website │ │ ├── index.md │ │ ├── obsidian-screenshots-available-links.jpg │ │ ├── obsidian-screenshots-available-tags.jpg │ │ ├── obsidian-screenshots-broken-links.jpg │ │ ├── obsidian-screenshots-document-outline.jpg │ │ └── obsidian-screenshots-external-links.jpg │ └── workflows.md ├── darkroom.jpg ├── dehaze-after.jpg ├── dehaze-before.jpg ├── denoise-after.jpg ├── denoise-before.jpg ├── filmic-after.jpg ├── filmic-before.jpg ├── grading-after.jpg ├── grading-before.jpg ├── highlights-after.jpg ├── highlights-before.jpg ├── lighttable.jpg ├── masking-after.jpg ├── masking-before.jpg ├── matching-after.jpg ├── matching-before.jpg ├── news │ ├── _index.md │ ├── changes-appimage.md │ ├── darktable-dans-le-mur-au-ralenti │ │ ├── index.md │ │ ├── module-groups.jpg │ │ ├── more-modules.png │ │ ├── shortcuts-broken.png │ │ └── shortcuts.png │ ├── dev-diary-1.md │ ├── dev-diary-2.md │ ├── fixing-pipe-cache-10-yo-bugs.md │ ├── implementing-kill-switch.md │ ├── modules-groups-redesign │ │ ├── ansel-lighttable-modules.png │ │ ├── ansel-module-groups.png │ │ ├── index.md │ │ ├── module-ansel.png │ │ ├── organization.png │ │ └── shortcuts.png │ ├── new-build-options-linux.md │ ├── rewriting-import │ │ ├── ansel-import-autocompletion.jpg │ │ ├── ansel-import-calendar.jpg │ │ ├── ansel-import-copy.jpg │ │ ├── ansel-import-date-validation.jpg │ │ ├── ansel-import-menu.jpg │ │ ├── ansel-import-pattern.jpg │ │ ├── ansel-import-recursive.jpg │ │ ├── ansel-import-search.jpg │ │ ├── ansel-import-window.jpg │ │ ├── darktable-import-images.jpg │ │ ├── darktable-import-module.jpg │ │ ├── darktable-import-window.jpg │ │ ├── darktable-wtf.jpg │ │ └── index.md │ ├── undarktable-ing-gui-controls.md │ ├── welcome-ansel-gpt.md │ └── welcome-dev-docs │ │ ├── accelerators-after-2.jpg │ │ ├── accelerators-after.jpg │ │ ├── accelerators-before.jpg │ │ └── index.md ├── perspective-after.jpg ├── perspective-before.jpg ├── resources │ ├── _index.md │ ├── lexicon.md │ ├── misconceptions.md │ ├── readings.md │ ├── supported-cameras.md │ ├── troubleshooting-color.md │ └── white-balances │ │ ├── Black_body.svg.png │ │ ├── Color_temperature_black_body_800-12200K.svg.png │ │ ├── Cécile-DSC_0005-0004-colorchecker-off.jpg │ │ ├── Cécile-DSC_0005-0004-colorchecker-on.jpg │ │ ├── Cécile-DSC_0316-0315-off.jpg │ │ ├── Cécile-DSC_0316-0315.jpg │ │ ├── FL3.15.png │ │ ├── Planckian-locus.png │ │ ├── SpyderCheckr.jpg │ │ ├── WB-neutral-3832K-framed.jpg │ │ ├── WB-neutral-3832K-toned-framed.jpg │ │ ├── WB-neutral-3832K.jpg │ │ ├── WB-warm-4341K-framed.jpg │ │ ├── WB-warm-4341K-minus-half-ev.jpg │ │ ├── WB-warm-4341K-minus-half-saturation.jpg │ │ ├── WB-warm-4341K.jpg │ │ ├── color-checker-green-frame.jpeg │ │ ├── color-checker-green.jpeg │ │ ├── color-checker-green.jpeg.xmp │ │ ├── color-checker-vectorscope.jpg │ │ ├── index.md │ │ ├── temperature-right-corrected.jpg │ │ ├── temperature-right-uncorrected.jpg │ │ └── temperature-wrong.jpg ├── sharpen-after.jpg ├── sharpen-before.jpg ├── support.md ├── toneeq-after.jpg ├── toneeq-before.jpg └── workflows │ ├── _index.md │ ├── basic-editing.md │ ├── film-scan │ ├── film-scan.jpg │ └── index.md │ ├── monochrome-toning │ ├── index.md │ ├── toning-workflow-base.jpg │ ├── toning-workflow-cyanotype-1.jpg │ ├── toning-workflow-cyanotype-2.jpg │ ├── toning-workflow-cyanotype-3.jpg │ ├── toning-workflow-monochrome.jpg │ ├── toning-workflow-platinotype-1.jpg │ ├── toning-workflow-platinotype-2.jpg │ ├── toning-workflow-sepia.jpg │ └── toning-workflow-split-toning.jpg │ ├── printing │ ├── Shooting Minh Ly-0155-_DSC0155-Minh-Ly-bpc.jpg │ ├── Shooting Minh Ly-0155-_DSC0155-Minh-Ly-no-bpc.jpg │ ├── Shooting Minh Ly-0155-_DSC0155-Minh-Ly-resized.jpg │ ├── charte-blancs.jpg │ ├── charte-noirs.fr.jpg │ ├── charte-noirs.jpg │ ├── chartes-scan-bpc.jpg │ ├── chartes-scan.jpg │ ├── index.md │ ├── sRGB-to-printer-curve.png │ └── sRGB-to-printer-zones.png │ └── scene-referred │ ├── blur-after.jpg │ ├── blur-before.jpg │ ├── display-calibrated.jpg │ ├── display-transform.png │ ├── fl1-report.png │ ├── graphs.py │ ├── hero-scene-referred.en.svg │ ├── hero-scene-referred.fr.svg │ ├── index.md │ ├── initial.jpg │ └── raw-calibrated.jpg ├── go.mod ├── go.sum ├── i18n ├── en.toml └── fr.toml ├── po ├── content.de.po ├── content.de.txt ├── content.es.po ├── content.fr.po ├── content.fr.txt ├── content.it.po ├── content.nl.po ├── content.pl.po ├── content.pot ├── content.pt_br.po ├── content.uk.po ├── disable-languages └── po4a.conf ├── static ├── FL1-sRGB_spectrum.png ├── FL1_color.png ├── FL1_color_display.png ├── FL1_color_scene.png ├── FL1_lightspectrum.png ├── FL1_sRGB.png ├── FL1_seen_by_NikonD5100.png ├── FL1_seen_by_human.png └── _redirects ├── themes └── ansel │ ├── .hugo_build.lock │ ├── archetypes │ └── default.md │ ├── assets │ ├── css │ │ ├── all.css │ │ ├── all.min.css │ │ ├── bootstrap-grid.css │ │ ├── bootstrap-grid.css.map │ │ ├── bootstrap-grid.min.css │ │ ├── bootstrap-grid.min.css.map │ │ ├── bootstrap-grid.rtl.css │ │ ├── bootstrap-grid.rtl.css.map │ │ ├── bootstrap-grid.rtl.min.css │ │ ├── bootstrap-grid.rtl.min.css.map │ │ ├── bootstrap-reboot.css │ │ ├── bootstrap-reboot.css.map │ │ ├── bootstrap-reboot.min.css │ │ ├── bootstrap-reboot.min.css.map │ │ ├── bootstrap-reboot.rtl.css │ │ ├── bootstrap-reboot.rtl.css.map │ │ ├── bootstrap-reboot.rtl.min.css │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ ├── bootstrap-utilities.css │ │ ├── bootstrap-utilities.css.map │ │ ├── bootstrap-utilities.min.css │ │ ├── bootstrap-utilities.min.css.map │ │ ├── bootstrap-utilities.rtl.css │ │ ├── bootstrap-utilities.rtl.css.map │ │ ├── bootstrap-utilities.rtl.min.css │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ ├── bootstrap.min.css.map │ │ ├── bootstrap.rtl.css │ │ ├── bootstrap.rtl.css.map │ │ ├── bootstrap.rtl.min.css │ │ ├── bootstrap.rtl.min.css.map │ │ ├── brands.css │ │ ├── brands.min.css │ │ ├── fifty-fifty.css │ │ ├── figures.css │ │ ├── figures.min.css │ │ ├── regular.css │ │ ├── regular.min.css │ │ ├── solid.css │ │ ├── solid.min.css │ │ ├── style.css │ │ ├── style.min.css │ │ ├── svg-with-js.css │ │ ├── svg-with-js.min.css │ │ ├── v4-shims.css │ │ └── v4-shims.min.css │ └── js │ │ ├── bootstrap.bundle.js │ │ ├── bootstrap.bundle.js.map │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.bundle.min.js.map │ │ ├── bootstrap.esm.js │ │ ├── bootstrap.esm.js.map │ │ ├── bootstrap.esm.min.js │ │ ├── bootstrap.esm.min.js.map │ │ ├── bootstrap.js │ │ ├── bootstrap.js.map │ │ ├── bootstrap.min.js │ │ ├── bootstrap.min.js.map │ │ ├── fifty-fifty.js │ │ ├── fuse.js │ │ ├── fuse.min.js │ │ ├── mermaid.min.js │ │ ├── scripts.js │ │ ├── scripts.min.js │ │ ├── search.js │ │ ├── search.min.js │ │ └── tex-svg.js │ ├── go.mod │ ├── go.sum │ ├── layouts │ ├── 404.html │ ├── _default │ │ ├── _markup │ │ │ ├── render-blockquote.html │ │ │ ├── render-codeblock-mermaid.html │ │ │ ├── render-codeblock.html │ │ │ ├── render-heading.html │ │ │ ├── render-image.html │ │ │ └── render-link.html │ │ ├── baseof.html │ │ ├── index.json │ │ ├── index.md │ │ ├── list.html │ │ ├── rss.xml │ │ ├── single.html │ │ └── summary.html │ ├── index.html │ ├── partials │ │ ├── authors.html │ │ ├── breadcrumb.html │ │ ├── comments.html │ │ ├── footer.html │ │ ├── get_resource.html │ │ ├── get_sizes.html │ │ ├── get_srcset.html │ │ ├── head.html │ │ ├── header.html │ │ ├── header_thumb.html │ │ ├── i18nlist.html │ │ ├── image.html │ │ ├── metadata.html │ │ ├── metadata_common.html │ │ ├── metadata_list.html │ │ ├── navigation.html │ │ ├── offcanvas-nav.html │ │ ├── prev-next.html │ │ ├── related_posts.html │ │ ├── rss.html │ │ ├── script.html │ │ ├── search.html │ │ ├── sidebar-nav.html │ │ ├── social.html │ │ └── toc.html │ └── shortcodes │ │ ├── advice.html │ │ ├── button.html │ │ ├── calcom.html │ │ ├── card.html │ │ ├── column.html │ │ ├── compare.html │ │ ├── container.html │ │ ├── danger.html │ │ ├── divider.html │ │ ├── figure.html │ │ ├── gallery.html │ │ ├── note.html │ │ ├── quote.html │ │ ├── rawspeed.html │ │ ├── row.html │ │ ├── slideshow.html │ │ ├── table.html │ │ ├── testimonial.html │ │ ├── translators.html │ │ └── warning.html │ ├── static │ ├── .htmltest.yml │ ├── book-solid.svg │ ├── favicon.png │ ├── favicon.svg │ ├── logo.png │ ├── logo.svg │ ├── logo_128x128.ico │ ├── logo_128x128.png │ ├── logo_text.png │ ├── logo_text.svg │ ├── paint-roller-solid.svg │ └── webfonts │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.svg │ │ ├── fa-brands-400.ttf │ │ ├── fa-brands-400.woff │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.svg │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-regular-400.woff2 │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.svg │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ └── fa-solid-900.woff2 │ └── theme.toml └── tools ├── auto-translate.sh ├── build-translations.sh ├── build_page_contributors.sh ├── chatgpt-translate.py ├── clean-translations.py ├── merge-translations.py ├── requirements.txt └── update-translations.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: aurelienpierre 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/hugo.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Hugo site to GitHub Pages 2 | name: Deploy Hugo site to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["master"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Can be triggered from a webhook from ansel-docs on new commits 13 | repository_dispatch: 14 | 15 | # Update once a week at midnight on sundays 16 | # This is only to maintain an up-to-date camera support table 17 | # since it is read from Rawspeed/Libraw/Ansel source code at the time of building 18 | schedule: 19 | - cron: "0 0 * * SUN" 20 | 21 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 22 | permissions: 23 | contents: read 24 | pages: write 25 | id-token: write 26 | 27 | # Allow one concurrent deployment 28 | concurrency: 29 | group: "pages" 30 | cancel-in-progress: true 31 | 32 | jobs: 33 | # Build job 34 | build: 35 | runs-on: ubuntu-latest 36 | env: 37 | HUGO_VERSION: 0.146.7 38 | environment: 39 | name: github-pages 40 | url: ${{ steps.deployment.outputs.page_url }} 41 | steps: 42 | - name: Install Hugo CLI 43 | run: | 44 | wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ 45 | && sudo dpkg -i ${{ runner.temp }}/hugo.deb 46 | - name: Checkout 47 | uses: actions/checkout@v4 48 | with: 49 | submodules: recursive 50 | fetch-depth: 0 # needed for .LastMod using git module 51 | - name: Install deps 52 | run: | 53 | sudo apt-get install po4a 54 | - name: Fetch modules and build translations 55 | run: | 56 | sh build-modules.sh 57 | - name: Build with Hugo 58 | env: 59 | # For maximum backward compatibility with Hugo modules 60 | HUGO_ENVIRONMENT: production 61 | HUGO_ENV: production 62 | #--baseURL "${{ steps.pages.outputs.base_url }}/" 63 | run: | 64 | hugo \ 65 | --minify 66 | - name: Setup Pages 67 | id: pages 68 | uses: actions/configure-pages@v2 69 | - name: Upload page artifact 70 | uses: actions/upload-pages-artifact@v3 71 | with: 72 | path: ./public 73 | - name: Deploy to GitHub Pages 74 | id: deployment 75 | uses: actions/deploy-pages@v4 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | content/.obsidian 2 | content/doc 3 | content/doc/* 4 | */.trash 5 | public/* 6 | resources/* 7 | _vendor/* 8 | *.api_key 9 | po/footers/* 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | 2 | [submodule "Ansel-Doc"] 3 | path = Ansel-Doc 4 | url = https://github.com/Aurelien-Pierre/Ansel-Doc.git 5 | -------------------------------------------------------------------------------- /.hugo_build.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/.hugo_build.lock -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is the source code for . 2 | 3 | For the manual, see [the hosted version](https://ansel.photos/en/contribute/website) or [the source version](./content/contribute/website/index.md) 4 | -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /build-modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get the documentation module 4 | hugo mod get -u 5 | 6 | # Write it to disk locally (=vendor) 7 | hugo mod vendor 8 | 9 | # Auto-gen doc translations from module disk cache 10 | chmod 700 _vendor/github.com/aurelienpierreeng/ansel-doc/tools/build-translations.sh 11 | ./_vendor/github.com/aurelienpierreeng/ansel-doc/tools/build-translations.sh --add 12 | 13 | # Update addenda for translation contributors 14 | chmod 700 tools/update-translations.sh 15 | ./tools/update-translations.sh 16 | 17 | # Auto-gen website translations 18 | chmod 700 tools/build-translations.sh 19 | ./tools/build-translations.sh --add 20 | -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | baseURL = '/' 2 | defaultContentLanguage = 'en' 3 | copyright = '© Copyright 2022-2025 – Aurélien Pierre' 4 | title = 'Ansel' 5 | theme = 'ansel' 6 | 7 | enableGitInfo = true 8 | defaultContentLanguageInSubdir = true 9 | refLinksErrorLevel = 'warning' 10 | canonifyURLs = true 11 | removePathAccents = true 12 | timeout = "360s" 13 | 14 | ignoreLogs = ['warning-goldmark-raw-html'] 15 | 16 | [params] 17 | [params.author] 18 | name = 'Aurélien Pierre' 19 | GitHubUser = 'aurelienpierre' 20 | url = "https://aurelienpierre.com" 21 | 22 | [menu] 23 | [[menu.main]] 24 | identifier = "workflows" 25 | name = "Workflows" 26 | url = "/workflows/" 27 | weight = 3 28 | parent = "learn" 29 | 30 | [[menu.main]] 31 | identifier = "news" 32 | name = "News" 33 | url = "/news/" 34 | weight = 1 35 | 36 | [[menu.main]] 37 | identifier = "learn" 38 | name = "Learn" 39 | url = "#" 40 | weight = 2 41 | 42 | [[menu.main]] 43 | identifier = "support" 44 | name = "Support" 45 | url = "/support/" 46 | weight = 7 47 | 48 | [[menu.main]] 49 | identifier = "resources" 50 | name = "Resources" 51 | url = "/resources/" 52 | weight = 6 53 | parent = "learn" 54 | 55 | [[menu.main]] 56 | identifier = "documentation" 57 | name = "Documentation" 58 | url = "/doc/" 59 | weight = 3 60 | parent = "learn" 61 | 62 | [[menu.main]] 63 | identifier = "community" 64 | name = "Community" 65 | url = "https://community.ansel.photos/" 66 | weight = 5 67 | 68 | [[menu.main]] 69 | identifier = "contributors" 70 | name = "Contribute" 71 | url = "contribute" 72 | weight = 8 73 | 74 | [languages] 75 | [languages.en] 76 | title = 'Ansel' 77 | languagename = "English" 78 | weight = 1 79 | [languages.fr] 80 | title = 'Ansel' 81 | languagename = "Français" 82 | weight = 2 83 | [languages.de] 84 | title = 'Ansel' 85 | languagename = "Deutsch" 86 | weight = 3 87 | [languages.es] 88 | title = 'Ansel' 89 | languagename = "Español" 90 | weight = 4 91 | [languages.it] 92 | title = 'Ansel' 93 | languagename = "Italian" 94 | weight = 5 95 | [languages.pl] 96 | title = 'Ansel' 97 | languagename = "Polish" 98 | weight = 6 99 | [languages.pt_br] 100 | title = 'Ansel' 101 | languagename = "Português" 102 | weight = 7 103 | [languages.uk] 104 | title = 'Ansel' 105 | languagename = "Ukrainian" 106 | weight = 8 107 | [languages.nl] 108 | title = 'Ansel' 109 | languagename = "Dutch" 110 | weight = 9 111 | 112 | [markup] 113 | [markup.tableOfContents] 114 | startLevel = 2 115 | endLevel = 4 116 | ordered = true 117 | [markup.goldmark] 118 | [markup.goldmark.extensions] 119 | definitionList = true 120 | footnote = true 121 | linkify = true 122 | linkifyProtocol = 'https' 123 | strikethrough = true 124 | table = true 125 | taskList = true 126 | typographer = true 127 | 128 | [markup.goldmark.renderer] 129 | hardWraps = false 130 | unsafe = true 131 | xhtml = true 132 | 133 | [markup.goldmark.renderhooks.image] 134 | disableDefault = true 135 | 136 | [markup.highlight] 137 | anchorLineNos = true 138 | codeFences = true 139 | guessSyntax = true 140 | hl_Lines = '' 141 | hl_inline = false 142 | lineAnchors = '' 143 | lineNoStart = 1 144 | lineNos = true 145 | lineNumbersInTable = false 146 | noClasses = true 147 | noHl = false 148 | tabWidth = 4 149 | 150 | FootnoteReturnLinkContents = "↩" 151 | 152 | [module] 153 | [[module.mounts]] 154 | source = 'content' 155 | target = 'content' 156 | 157 | [[module.imports]] 158 | disable = false 159 | ignoreConfig = true 160 | ignoreImports = true 161 | path = "github.com/aurelienpierreeng/ansel-doc" 162 | 163 | # Get translations and auto-gen tools 164 | [[module.imports.mounts]] 165 | source = 'tools' 166 | target = 'content/doc/tools' 167 | 168 | [[module.imports.mounts]] 169 | source = 'po' 170 | target = 'content/doc/po' 171 | 172 | [[module.imports.mounts]] 173 | source = 'content' 174 | target = 'content/doc/' 175 | 176 | [[module.imports.mounts]] 177 | source = 'assets' 178 | target = 'assets' 179 | 180 | [outputs] 181 | home = ["HTML", "JSON", "RSS", "MARKDOWN"] 182 | 183 | [taxonomies] 184 | tag = "tags" 185 | author = "authors" 186 | 187 | [imaging] 188 | bgColor = '#ffffff' 189 | hint = 'photo' 190 | quality = 86 191 | resampleFilter = 'linear' 192 | 193 | [Params.Images] 194 | maxSize = 4096 195 | setSizes = [ 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800, 3000 ] 196 | sizes = "(max-width: 992px) 100vw, (max-width: 1200px) 66.67vw, 50vw" 197 | 198 | [related] 199 | includeNewer = true 200 | threshold = 20 201 | toLower = true 202 | [[related.indices]] 203 | applyFilter = false 204 | cardinalityThreshold = 0 205 | name = 'keywords' 206 | pattern = '' 207 | toLower = false 208 | type = 'basic' 209 | weight = 100 210 | [[related.indices]] 211 | applyFilter = false 212 | cardinalityThreshold = 0 213 | name = 'categories' 214 | pattern = '' 215 | toLower = false 216 | type = 'basic' 217 | weight = 100 218 | [[related.indices]] 219 | applyFilter = false 220 | cardinalityThreshold = 0 221 | name = 'date' 222 | pattern = '' 223 | toLower = false 224 | type = 'basic' 225 | weight = 10 226 | [[related.indices]] 227 | applyFilter = false 228 | cardinalityThreshold = 0 229 | name = 'tags' 230 | pattern = '' 231 | toLower = false 232 | type = 'basic' 233 | weight = 80 234 | [[related.indices]] 235 | applyFilter = false 236 | cardinalityThreshold = 0 237 | name = 'content' 238 | pattern = '' 239 | toLower = false 240 | type = 'basic' 241 | weight = 80 242 | -------------------------------------------------------------------------------- /content/Auto-portrait-0088-MLM_0774_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/Auto-portrait-0088-MLM_0774_01.jpg -------------------------------------------------------------------------------- /content/Shoot Minh-Ly Hangar 2 - Rouge-0026-DSC_0560--WEB-LOW.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/Shoot Minh-Ly Hangar 2 - Rouge-0026-DSC_0560--WEB-LOW.jpg -------------------------------------------------------------------------------- /content/authors/aurelien-pierre/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Aurélien Pierre" 3 | website: "https://photo.aurelienpierre.com" 4 | gravatar: "https://gravatar.com/avatar/34c543cded16518a500a754423124f30" 5 | bio: "Designer and maintainer of Ansel. Developer of darktable scene-referred workflow and physically-realistic modules since 2018. Image retouching educator. \"Do things accurately, or don't bother\"." 6 | --- 7 | -------------------------------------------------------------------------------- /content/authors/guillaume-marty/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Guillaume Marty" 3 | website: "https://www.gmarty.fr/" 4 | gravatar: "https://gravatar.com/avatar/00000000000000000000000000000000" 5 | bio: "" 6 | --- 7 | -------------------------------------------------------------------------------- /content/calibration-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/calibration-after.jpg -------------------------------------------------------------------------------- /content/calibration-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/calibration-before.jpg -------------------------------------------------------------------------------- /content/censorize-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/censorize-after.jpg -------------------------------------------------------------------------------- /content/censorize-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/censorize-before.jpg -------------------------------------------------------------------------------- /content/contribute/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contribute 3 | date: 2024-07-14 4 | weight: 35 5 | --- 6 | 7 | This section is dedicated to people willing to contribute to Ansel, whether by designing, fixing or triaging bugs, coding, troubleshooting bugs, writing documentation or helping users. 8 | 9 | You can also [contribute financially](https://community.ansel.photos/donations-make). 10 | -------------------------------------------------------------------------------- /content/contribute/website/obsidian-screenshots-available-links.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/contribute/website/obsidian-screenshots-available-links.jpg -------------------------------------------------------------------------------- /content/contribute/website/obsidian-screenshots-available-tags.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/contribute/website/obsidian-screenshots-available-tags.jpg -------------------------------------------------------------------------------- /content/contribute/website/obsidian-screenshots-broken-links.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/contribute/website/obsidian-screenshots-broken-links.jpg -------------------------------------------------------------------------------- /content/contribute/website/obsidian-screenshots-document-outline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/contribute/website/obsidian-screenshots-document-outline.jpg -------------------------------------------------------------------------------- /content/contribute/website/obsidian-screenshots-external-links.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/contribute/website/obsidian-screenshots-external-links.jpg -------------------------------------------------------------------------------- /content/contribute/workflows.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Automated workflows 3 | date: 2025-05-01 4 | --- 5 | 6 | Because Ansel is mostly a one-person operation, everything that could be automated was automated. This page keeps track of everything that should be maintained in the future, and where. 7 | 8 | ## Software 9 | 10 | ### Nightly builds 11 | 12 | Nightly builds prepare a compiled and packaged version of the software, every night at 6am UTC, for: 13 | 14 | - [Linux](https://github.com/aurelienpierreeng/ansel/blob/master/.github/workflows/lin-nightly.yml), 15 | - [Windows](https://github.com/aurelienpierreeng/ansel/blob/master/.github/workflows/win-nightly.yml), 16 | - MacOS is currently disabled. 17 | 18 | The newest binary files are automatically added to the [pre-release](https://github.com/aurelienpierreeng/ansel/releases/tag/v0.0.0) assets, are posted on a [Matrix channel](https://matrix.to/#/#ansel-builds:matrix.org) so users can subscribe to updates, and can be downloaded through (constantly up-to-date) permalinks at: 19 | 20 | - for the Linux AppImage, 21 | - for the Windows AppImage. 22 | 23 | ### Developer documentation 24 | 25 | The dev docs are [automatically built](https://github.com/aurelienpierreeng/ansel/blob/master/.github/workflows/docs.yml) from the source code with Doxygen, every Sunday at 00:00 UTC, then uploaded to , which is hosted on Github Pages attached to the Ansel (software) repository. 26 | 27 | ### Commits and issues 28 | 29 | Github new commits and issues are [automatically posted](https://github.com/aurelienpierreeng/ansel/blob/master/.github/workflows/matrix.yml) to a [Matrix channel](https://matrix.to/#/#ansel-dev:matrix.org) for updates. 30 | 31 | ## Website 32 | 33 | The Hugo static website is [automatically built](https://github.com/aurelienpierreeng/ansel-website/blob/master/.github/workflows/hugo.yml) on every new commit to the source code and ever Sunday at 00:00 UTC. This auto-update is intended for [camera support](https://github.com/aurelienpierreeng/ansel-website/blob/master/themes/ansel/layouts/shortcodes/rawspeed.html) which re-parses Libraw, Rawspeed and Ansel source code straight from Github, and dynamically generates the camera support table. It is uploaded to , which is hosted on Github Pages attached te the Ansel Website repository. 34 | 35 | ## Documentation 36 | 37 | The documentation is imported into the website as a Go/Git module ([see _website_](./website/index.md)). Every new commit to the documentation [fires a workflow dispatch](https://github.com/aurelienpierreeng/ansel-doc/blob/master/.github/workflows/hugo.yml) to the main website to rebuild and update it. 38 | 39 | ## Forum 40 | 41 | New posts on the forum are posted through an RSS bot to the [Matrix channel](https://matrix.to/#/#ansel-dev:matrix.org) for updates. 42 | 43 | ## Chantal 44 | 45 | The page crawler for Chantal search engine database does not yet run automated and needs manual updating. 46 | 47 | Converting web pages to their vector representation, through the language model, will probably remain too heavy for any public server and will need to be done on a powerful private server. 48 | 49 | ## Ansel GPT 50 | 51 | The [custom ChatGPT model for Ansel](https://chatgpt.com/g/g-680d2f861a608191a0f7549eadd40f2e-ansel-gpt) is meant to assist users who have questions on Ansel software (installation, compilation, usage) or color theory. It is trained with Ansel website, documentation, Github issues, Matrix chats, and other resources. It also uses Chantal AI JSON API as backend, from where it can tap into the database of 68.800+ imaging-related pages indexed there. 52 | 53 | It is configured to automatically recrawl and cache, once a week, all the following resources for all languages: 54 | 55 | - [the main website sitemap](https://ansel.photos/sitemap.xml), 56 | - each [language-centric sitemap](https://ansel.photos/en/sitemap.xml), 57 | - the [one-page aggregated website](https://ansel.photos/en/index.md) content for each language, 58 | - Github RSS feed of new commits, 59 | - Github issues, 60 | - the main Community forum RSS feed. 61 | 62 | Users can request to see the last update log by asking "show me the last update log" to GPT. 63 | -------------------------------------------------------------------------------- /content/darkroom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/darkroom.jpg -------------------------------------------------------------------------------- /content/dehaze-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/dehaze-after.jpg -------------------------------------------------------------------------------- /content/dehaze-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/dehaze-before.jpg -------------------------------------------------------------------------------- /content/denoise-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/denoise-after.jpg -------------------------------------------------------------------------------- /content/denoise-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/denoise-before.jpg -------------------------------------------------------------------------------- /content/filmic-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/filmic-after.jpg -------------------------------------------------------------------------------- /content/filmic-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/filmic-before.jpg -------------------------------------------------------------------------------- /content/grading-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/grading-after.jpg -------------------------------------------------------------------------------- /content/grading-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/grading-before.jpg -------------------------------------------------------------------------------- /content/highlights-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/highlights-after.jpg -------------------------------------------------------------------------------- /content/highlights-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/highlights-before.jpg -------------------------------------------------------------------------------- /content/lighttable.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/lighttable.jpg -------------------------------------------------------------------------------- /content/masking-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/masking-after.jpg -------------------------------------------------------------------------------- /content/masking-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/masking-before.jpg -------------------------------------------------------------------------------- /content/matching-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/matching-after.jpg -------------------------------------------------------------------------------- /content/matching-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/matching-before.jpg -------------------------------------------------------------------------------- /content/news/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: News 3 | date: 2022-12-04T01:28:32+01:00 4 | draft: false 5 | weight: 10 6 | --- 7 | -------------------------------------------------------------------------------- /content/news/changes-appimage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Changes in distribution support for Linux AppImage package 3 | date: 2023-11-18 4 | tags: 5 | - Announcement 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | Rawspeed (the library providing the decoders for camera raw files) has deprecated support for GCC < 12. As a result, I can no longer build the AppImage on Ubuntu 20.04 (using Github runners) but I have to build it on 22.04. 11 | 12 | It means any Linux distribution having libc older than 2.35 will not be able to start the new AppImages starting today. That should not affect most users running distributions upgraded in 2021 or more recently. Ubuntu 20.04 and other LTS/old stable distributions (Debian stable) may be affected. 13 | -------------------------------------------------------------------------------- /content/news/darktable-dans-le-mur-au-ralenti/module-groups.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/darktable-dans-le-mur-au-ralenti/module-groups.jpg -------------------------------------------------------------------------------- /content/news/darktable-dans-le-mur-au-ralenti/more-modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/darktable-dans-le-mur-au-ralenti/more-modules.png -------------------------------------------------------------------------------- /content/news/darktable-dans-le-mur-au-ralenti/shortcuts-broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/darktable-dans-le-mur-au-ralenti/shortcuts-broken.png -------------------------------------------------------------------------------- /content/news/darktable-dans-le-mur-au-ralenti/shortcuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/darktable-dans-le-mur-au-ralenti/shortcuts.png -------------------------------------------------------------------------------- /content/news/dev-diary-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dev diary #1 3 | date: 2023-03-19 4 | tags: 5 | - Development 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | It's been roughly 3 months that I rebranded "R&Darktable" (that nobody seemed to get right), into "Ansel", then bought the domain name and created the website from scratch with Hugo (I had never programmed in Golang before, but it's mostly template code). 11 | 12 | Then I spent a total 70 h on making the nightly packages builds for Windows and Linux work for continuous delivery, something that Darktable never got right ("you can build yourself, it's not difficult"), only to see the bug tracker blow up after release (nothing better than chaining the pre-release sprint with a post-release one to reduce your life expectancy). 13 | 14 | People keep asking for a Mac build because they have no notion of the amount of work it requires while the Brew package manager breaks lib dependencies on a weekly basis when you are not lucky. Mac OS simply requires an unreasonable amount of care, which becomes a dry loss when you know that not even 9 % of Darktable users run it. Also, for the last time, Github (actually, the Microsoft Azure instances providing Github actions runners) has no ARM system, so anyway a nightly Mac build would necessarily be on AMD64 architecture, that is old MacBook from before Apple decided once again to go full Apple on its own island. Don't expect 90 % of the free world to scurry over a tech nobody needed and barely anybody uses. 15 | 16 | From then, I have optimized the local laplacian in highlights reconstruction with a stupid trick : processing a downsized image instead of the full-resolution one. I had this idea in the back of my mind for a long time but feared the detrimental side-effects. But since clipped areas are signal-less anyway, processing a slightly blurrier version is almost invisible. Also, the shoulder of your typical S/filmic tone curve will anyway compress everything close to white, so it reduces percieved sharpness by reducing contrast in highlights no matter what. We are talking 96 % speed-up on CPU (mostly because we can process the image at once with no tiling). 17 | 18 | Using that, I developed an experimental noise and chromatic aberrations pre-filter re-using multi-scale guided laplacians. It's not bad, but again quite slow. 19 | 20 | Since February, most of the work has been spent on cleaning up the GUI by moving collections of buttons, either the full-text ones or the weird icon ones, to the global menu and rewiring the keyboard shortcuts to that. It makes feature more discoverable while reducing screen real estate. 21 | -------------------------------------------------------------------------------- /content/news/dev-diary-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Dev diary #2 : introducing Chantal' 3 | date: 2023-04-28 4 | tags: 5 | - Development 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | 2022 was so bad in terms of junk emails and noise that I started the [Virtual Secretary](https://virtualsecretary.aurelienpierre.com/), a Python framework to write intelligent email filters by crossing information between several sources to guess what incoming emails are and whether they are important/urgent or not. When I'm talking about junk emails, it's also Github notifications, pings on pixls.us (thank God I closed my account on that stupid forum), YouTube, and direct emails from people hoping to get some help in private. 11 | 12 | Having become "the face" of darktable, mostly because I'm one of the few to bother providing user education and training instead of just pissing code, I didn't see that coming, and I wasn't prepared. A lot of people now mistake me with the front desk, which doesn't help abstract thinking on coding matters, let alone taking time to actually produce art. The problem is all the time lost dealing with info/noise/input is not spent solving problems, and time is the only thing for which you cannot get a refund. 13 | 14 | After a while, I figured it would be nice to extend the Virtual Secretary with a machine-learning classifier, which would guess in what folder incoming emails should go, by extracting the content of the emails already in said folder. It's actually much easier to implement than what I thought, but the time-consuming bit is to write text filters to clean-up the input (because garbage in, garbage out, especially for spam emails which are generally improperly formatted). 15 | 16 | But the ultimate goal, in my wildest dreams, was to build an autoresponder for people asking questions already answered on one of the many websites I have contributed to over the years. It's a constant frustration to see that all the pages of doc I have written over the years are lost in Internet limbo. On FLOSS-centric forums, benevolent guys also tend to experience the same kind of fatigue : repeating again and again the same info, linking the same pages, to never-ending hords of newbies who don't know what to look for. Just look at Reddit darktable : every 14 days, someone else asks why the lighttable thumbnails don't look like the darkroom preview. Even discarding the amount of frustration and angryness here, the number of man-hours lost in repeating is outstanding. Just because information is lost. 17 | 18 | The true problem of search engines is you need to know what keywords to look for. Which is circling back to the fact that newbies don't know the slang. So they don't know what to look for. They don't have any entry point in the matrix. Except other humans. Which sucks for the ones having to do the work, usually for free. 19 | 20 | After merging a neural layer of word2vec word embedding (big words to say it's unsupervised machine learning finding how words are contextually related in sentences, that is finding syntactical structures, synonyms and the likes), as a first step in my email classifier (which is now up to 92 % accuracy), I wondered if this wouldn't been usable to build a context-aware and synonym-aware search engine, able to look past exact keywords. 21 | 22 | Turns out a couple of guys from Bing had the same idea in 2016, and published their maths, so I implemented them. Then proceeded to add a web interface on top. That gave birth to [Chantal](https://chantal.aurelienpierre.com), the AI you are kindly asked to bother before bothering me. The current version is trained against 101.000 internet pages from my own websites, darktable & Ansel docs, along with some reliable color-science ressources. It indexes 15.500 pages in French and English and can process search queries in either or both of these languages. One of its mean features is to propose you a list of keywords associated to your query, so you can refine/reorient/try things you wouldn't have thought of before. 23 | 24 | Hope that helps. 25 | 26 | That work showed me how poorly indexable many websites are. To account for the lack of XML sitemap on forums.darktable.fr and color.org, I had to write a recursive crawler. But even then, many pages don't have description meta tags and a proper date tag. It means you need to use regular expressions and indirect methods trying to identify the metadata, and manually tune the HTML parser to extract the actual content part of the webpage (discarding sidebars, menus, asides and advertising if any). 27 | 28 | Then, you get to love Q&A forums like Stack Overflow, where proper questions start a thread, proper answers follow, and the best answers are selected by the community. "Thank you" and "me too" messages are explicitly forbidden in the conditions of use. On forums like pixls.us or forums.darktable.fr, proper technical information gets lost in the middle of semi-technical rambling, life stories and bros bonding over tales of software, in a continuous thread where nothing distinguishes relevant from irrelevant, accurate from inaccurate, and gross misunderstandings of color theory. From a machine crawling perspective, there is very little to exploit here, and investing time on such platform is a dry loss. 29 | 30 | More (technical) info: 31 | 32 | - [Websites suck](https://eng.aurelienpierre.com/2023/04/websites-suck./) : on the technical challenges of crawling and indexing HTML (and… PDF) webpages, in a time where people say big things like "Web 4.0" or "Internet of Things", but basic things like providing page sitemaps or putting the date of internet publications in standard formats is still too much to ask of webmasters and CMS, 33 | - [Designing an AI search engine from scratch in the 2020's](https://eng.aurelienpierre.com/2024/03/designing-an-ai-search-engine-from-scratch-in-the-2020s/) : on how Chantal was built and how the Dumbrish synthetic language was created to generalize natural French and English, plus some regex bonanza, 34 | - [Thoughts on Word2Vec AI for information retrieval applications](https://eng.aurelienpierre.com/2025/05/thoughts-on-word2vec/) : on how the input cleanup is by far the worst time-consuming step of designing an AI and language models that become too semantically accurate don't make better search engines. 35 | -------------------------------------------------------------------------------- /content/news/implementing-kill-switch.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Implementing kill-switch on pipeline' 3 | date: 2023-11-28 4 | tags: 5 | - Development 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | I have thought, for a very long time, that there was some kill-switch mechanism on the pixel pipeline. The use case is the following : 11 | 12 | 1. you are changing a module parameter, 13 | 2. the previews (the central darkroom one and the thumbnail in left panel, also used for histogram and color pickers) recompute their pipeline to account for that change, 14 | 3. one of the previews finishes rendering before the other, and the result is obviously __not__ what you wanted, 15 | 4. you change again the module parameter, without waiting for the recomputation to finish. 16 | 17 | In that case, you want to kill all active pipelines because their output will not be used, and start recomputing everything immediately with new parameters. Except Darktable doesn't do that, it lets the pipeline finish before restarting it, and looking at the comments in the source code, it seems to be a fairly recent regression and not the originally intended behaviour. 18 | 19 | I have (re)implemented this feature in Ansel, but it's tricky because we are dealing with different threads (GUI, editing history and pipeline on CPU/OpenCL) and we need to synchronize them properly. 20 | 21 | If this goes bad, you may experience garbled previews from inconsistent cache states. This is a GUI issue only, and the mitigation strategy is to go to the global menu -> Run -> Invalidate all caches. 22 | 23 | To debug, you may start Ansel with : 24 | 25 | ``` 26 | $ ansel -d perf 27 | ``` 28 | 29 | When interacting with sliders and comboboxes in GUI (for example here in exposure module), you will get : 30 | 31 | ``` 32 | 100,407003 [dev_process_all] sending killswitch signal on running pipelines took 0,000 secs (0,000 CPU) 33 | 100,509816 [dev_pixelpipe] took 0,011 secs (0,023 CPU) processed `exposure` on GPU, blended on GPU [full] 34 | 100,510498 [dev_pixelpipe] took 0,019 secs (0,035 CPU) processed `exposure` on GPU, blended on GPU [preview] 35 | 100,533228 [dev_pixelpipe] took 0,023 secs (0,061 CPU) processed `lens correction` on GPU, blended on GPU [full] 36 | 100,558939 [dev_pixelpipe] took 0,026 secs (0,129 CPU) processed `tone equalizer` on CPU, blended on CPU [full] 37 | 100,563703 [dev_pixelpipe] took 0,005 secs (0,008 CPU) processed `unbreak input profile` on GPU, blended on GPU [full] 38 | ... 39 | ``` 40 | 41 | Normal behaviour is the `[dev_process_all] sending killswitch signal` line should appear at the time of your interaction, and should be followed by a recomputation starting at the module you interacted with (not the one before, not the one after), up to the end (display encoding module). 42 | -------------------------------------------------------------------------------- /content/news/modules-groups-redesign/ansel-lighttable-modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/modules-groups-redesign/ansel-lighttable-modules.png -------------------------------------------------------------------------------- /content/news/modules-groups-redesign/ansel-module-groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/modules-groups-redesign/ansel-module-groups.png -------------------------------------------------------------------------------- /content/news/modules-groups-redesign/module-ansel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/modules-groups-redesign/module-ansel.png -------------------------------------------------------------------------------- /content/news/modules-groups-redesign/organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/modules-groups-redesign/organization.png -------------------------------------------------------------------------------- /content/news/modules-groups-redesign/shortcuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/modules-groups-redesign/shortcuts.png -------------------------------------------------------------------------------- /content/news/new-build-options-linux.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: New build options for Linux 3 | date: 2023-06-16 4 | tags: 5 | - Development 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | I accidentally discovered that the Linux build script used a "package" build, meaning the CPU optimizations are limited to generic ones in order to produce portable binaries that can be installed on any x86-64 platform. By "using", I mean the package build was not explicitely disabled, so it was enabled by default. 11 | 12 | Anyway, this is now disabled by default, since the actual packages (.exe and .appimage) are not built through that script, which is primarily meant to help end-users. To get the previous behaviour back, you would need to run: 13 | 14 | ``` 15 | $ sh build.sh --build-package --install --sudo 16 | ``` 17 | 18 | Not using the package build option may increase performance on CPU by 20 to 30 % depending on your hardware, thanks to platform-specific optimizations. 19 | 20 | I have also introduced a new argument that will launch the Git updating commands that users seem to forget all the time. There is a caveat, though : updating the source code by calling Git from within the script doesn't update the script for the current run, so this method doesn't work when the script itself is modified. Fortunately, we don't change this script often. 21 | 22 | The argument to update the source code and the submodules (Rawspeed, Libraw) : 23 | 24 | ``` 25 | $ sh build.sh --update --install --sudo 26 | ``` 27 | 28 | I have also modified the internals of that script in order to automatically : 29 | 30 | - update the Lensfun database of lenses, 31 | - add a global system shortcut (.desktop file) so the software will be globally available from the app menus, 32 | - add a global system command so the ansel is globally available from the terminal. 33 | 34 | The goal of all these changes is obviously to make it more user-friendly to use a self-built version of the software, allowing to improve performance, especially for computers without GPU. The one-pit-stop command would be : 35 | 36 | ``` 37 | $ sh build.sh --update --install --sudo --clean-all 38 | ``` 39 | 40 | But of course, you will need to run the Git update manually one last time before, to update the script itself : 41 | 42 | ``` 43 | $ git pull --recurse-submodule 44 | ``` 45 | 46 | Alternatively, you can directly download the build script, and replace the old build.sh one at the root of the source code directory. 47 | -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-autocompletion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-autocompletion.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-calendar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-calendar.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-copy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-copy.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-date-validation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-date-validation.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-menu.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-pattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-pattern.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-recursive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-recursive.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-search.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-search.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/ansel-import-window.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/ansel-import-window.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/darktable-import-images.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/darktable-import-images.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/darktable-import-module.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/darktable-import-module.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/darktable-import-window.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/darktable-import-window.jpg -------------------------------------------------------------------------------- /content/news/rewriting-import/darktable-wtf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/rewriting-import/darktable-wtf.jpg -------------------------------------------------------------------------------- /content/news/welcome-ansel-gpt.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Welcome Ansel GPT ! 3 | date: 2025-05-03 4 | tags: 5 | - Announcement 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | After I finally [wired the whole website and docs](../contribute/translating.md) to a water-tight translation workflow (using po4a on top of Hugo), which happens to use the exact same toolset and logic as the Ansel application, I got the idea of [automating empty translations](../contribute/translating.md#auto-tools-and-helper-scripts), first from the software translation files, then through ChatGPT API, which does a very fair job at translating Markdown syntax. 11 | 12 | Working alone, you can't rely on [social loafing](https://en.wikipedia.org/wiki/Social_loafing), so you have to be clever. You can see [the list of things I have already automated](../contribute/workflows.md) in background for Ansel. 13 | 14 | Having written a whole [AI search engine myself](dev-diary-2.md), which means mostly a web crawler (because that was the most tedious part to write and debug), I got the opportunity to see this website from the eyes of a bot. Piece by piece, I modified the HTML templates and metadata to make it easier to crawl, index and search, first for the internal search engine,[^1] then for [Chantal AI](https://chantal.aurelienpierre.com). 15 | 16 | [^1]: Which actually works client-side in Javascript in your own browser, meaning it works offline too, should you install this website as a webapp to keep the documentation locally. 17 | 18 | Even with Chantal, I still get too many recurring questions regarding information that is already written somewhere. Sure, the documentation is a bit lagging behind the code, but the [commit messages](https://github.com/aurelienpierreeng/ansel/commits/master/) I write aim at being non-technical enough for power-users to understand what's going on these days in the software. 19 | 20 | I get that there is nothing worse than being trapped in your problem without a timely answer, but then I can't possibly serve as help-desk for every guy on every timezone with everything that needs cleanup in this stupid software. Which means there is still a gap to fill. 21 | 22 | The main drawback of Chantal is the language model is quite heavy to retrain, and I can't possibly automate it on some server. Then, websites can't be crawled too fast without being blocked by servers, so that doesn't take too much power but that requires some computer to be plugged-in for a week with a stable internet connection. Which means I update the language model and the web index only 4 times a year. As of now, the web index contains 63.452 pages, the language model knows 47.579 words, and I have finally managed to make it fairly compliant with the memory I/O limitations of a shared hosting. 23 | 24 | The plan, right now, is to automate website crawling on some server, because that's not too heavy, then retrain the model overnight on my own computer (which takes around 4 h of computation and almost all of my 32 GB of RAM…). 25 | 26 | Anyway, during my fiddling with ChatGPT API, I discovered that you can train your own custom GPT.[^2] This is as simple as feeding it text content it can use, and now ChatGPT can also load websites, sitemaps and can be configured to send requests to Rest API. So, without further ado [__meet Ansel GPT__](https://chatgpt.com/g/g-680d2f861a608191a0f7549eadd40f2e-ansel-gpt). 27 | 28 | [^2]: Provided you are a ChatGPT Plus subscriber, for a not-so-modest 23€/month. 29 | 30 | Ansel GPT is configured to cache and update once a week Github issues, commits, community forum posts, and all of the present website. It is able to provide complex (and fairly accurate) answers regarding what module to use, how and when, in Ansel, as well as on color theory concepts. I also configured it to use Chantal AI backend, which is (almost) a Rest API and the GPT will follow the links indexed by Chantal to improve its answers. 31 | 32 | The caveat is using Ansel GPT is reserved to ChatGPT Plus subscribers, so I feel like I worked 2 days to configure everything so OpenAI can bank on my work. But anyway, if that's at least less work for me on the semi-long run, let's call it a win. 33 | -------------------------------------------------------------------------------- /content/news/welcome-dev-docs/accelerators-after-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/welcome-dev-docs/accelerators-after-2.jpg -------------------------------------------------------------------------------- /content/news/welcome-dev-docs/accelerators-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/welcome-dev-docs/accelerators-after.jpg -------------------------------------------------------------------------------- /content/news/welcome-dev-docs/accelerators-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/news/welcome-dev-docs/accelerators-before.jpg -------------------------------------------------------------------------------- /content/perspective-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/perspective-after.jpg -------------------------------------------------------------------------------- /content/perspective-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/perspective-before.jpg -------------------------------------------------------------------------------- /content/resources/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Resources 3 | date: 2023-01-19 4 | draft: false 5 | weight: 10 6 | --- 7 | -------------------------------------------------------------------------------- /content/resources/lexicon.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Color lexicon 3 | authors: 4 | - Aurélien Pierre 5 | date: 2024-03-20 6 | type: large 7 | --- 8 | 9 | ```mermaid 10 | mindmap 11 | root((COLOR)) 12 | color appearance model 13 | uniform color space 14 | chromaticity 15 | U, V 16 | a, b 17 | lightness 18 | L 19 | delta E 20 | chromatic adaptation transform 21 | illuminant 22 | color reproduction index 23 | color temperature 24 | surround lighting 25 | background lightness 26 | dimensions 27 | Munsell 28 | hue 29 | chroma 30 | value 31 | natural color system 32 | blackness 33 | saturation 34 | hue 35 | CIE 36 | lightness 37 | brightness 38 | saturation 39 | chroma 40 | colorfulness 41 | hue 42 | measure 43 | colorimetry 44 | tristimulus 45 | sensor 46 | Luther-Ives criterion 47 | metamerism 48 | dynamic range 49 | noise 50 | mosaicing 51 | Bayer 52 | XTrans 53 | zipper artifacts 54 | spaces 55 | rgb(RGB) 56 | HSV 57 | HSL 58 | LMS 59 | Yrg 60 | XYZ 61 | Yxy 62 | Yuv 63 | Ych 64 | CYM 65 | CYMK 66 | primaries 67 | cone cells 68 | LED 69 | ITU BT.Rec 709 70 | ITU BT.Rec 2020 71 | DCI P3 72 | inks 73 | spectrometry 74 | light spectrum 75 | wavelengths 76 | energy 77 | photometry 78 | luminance 79 | correction 80 | profile 81 | matrix 82 | lookup table 83 | transfert function 84 | color grading 85 | ASC CDL 86 | channel mixer 87 | curves 88 | white balance 89 | ``` 90 | -------------------------------------------------------------------------------- /content/resources/misconceptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Common misconceptions 3 | date: 2023-01-19 4 | draft: false 5 | weight: 10 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | This page addresses most of the mistakes and misconceptions about Ansel that can be found online. 11 | 12 | 13 | 14 | ## I need to be an expert / engineer to use Ansel 15 | 16 | My [videos](https://www.youtube.com/channel/UCmsSn3fujI81EKEr4NLxrcg) and my posts typically contain both the "how to" and the "why/how" part. The "why/how" is typically technical or even theoritical, and is there to justify the "how to". There are several reasons for which I give both : 17 | 18 | 1. The accurate technical explanations are really difficult to find on the internet, and I'm pretty much the only one to link theory and practice on video. On the other hand, it's easy to find wrong information in photography, from people slightly above the average who try to help, but actually mislead others. 19 | 2. I personaly hate gurus that drop instructions without bothering to justify them. Rules always have a reason and need to be broken as soon as this reason stops being valid. You see a lot of people continuing to follow old rules because "the elders knew what they were doing" — but don't remember why they did — while circumstances have changed. 20 | 3. Understanding how tools behave allows you to predict when they will fail (because they will all fail at some point), which enables you to solve problems even before they appear, and to be ready with a plan B when it happens, 21 | 4. Most pieces of advice I give are contextual to the desired result and the type of image being worked. Removing context would make them simply wrong in general. 22 | 23 | Because of that, many people have conceived the idea that they need to understand 100 % of the technical content before being able to use the software. That is simply not true. Ultimately, Ansel is just a software with a GUI, you can push cursors or use factory presets until the picture looks good. Whatever you don't understand can be disregarded for now, and perhaps tried again later. 24 | 25 | On the other hand, if you start mixing media, like printing pictures on paper and releasing digital pictures from the same edit, or inputing your Ansel exports into another software for further manipulation, having at least a basic understanding of how an imaging pipeline works is going to help you tremendously. 26 | 27 | Like any technological object, the more you understand it and the better you control it, the least you fight it. But Ansel comes shipped with a pack of default presets and a pre-configured pipeline that should give you a proper editing base in most cases. 28 | 29 | It is true, however, that the image processing controls in the GUI tend to be more grounded into color science and optics than in other applications. The reason is processing HDR without artifacts needs more accurate color models, that take more input parameters to adapt to the dynamic range of images. The reason most applications can afford to look more simple is their color models are less performant and rely on approximations that don't really scale with dynamic range. Everything has a cost… 30 | 31 | ## Ansel processes my raw pictures in a way that makes them darker and duller 32 | 33 | The reality is actually the other way around. 34 | 35 | Raw photographs typically have a JPEG file embedded as a low-resolution thumbnail. This thumbnail is what you see in Ansel lighttable as well as on your camera back screen. You will never see a raw photograph without any kind of correction, it's simply not displayable. 36 | 37 | This thumbnail has been processed and enhanced by the camera firmware, in a way that usually brightens it a lot, adds contrast, saturation, and very often tints it for a warmer look. 38 | 39 | What you see when opening the picture in Ansel darkroom is a much less processed picture than the JPEG, closer to the raw and more neutral, meant to be a base for your personal editing. 40 | 41 | But remember that the default look when opening the darkroom is just that : a base look, a starting point. Ultimately, even the default settings can be adjusted to your liking, which is the whole point of the software. 42 | 43 | ## Deprecated modules don't work anymore 44 | 45 | Ansel is based on darktable 4.0. darktable 4.0 has deprecated many modules. Ansel has deprecated even more. Modules get deprecated when they get a better alternative introduced. 46 | 47 | But "deprecated" is a strong word to say "the widget of the module is hidden from the GUI". Both the GUI and the pixel code of the module are still in the software, and will still run for old edits using this module. For these edits, the module will show in the GUI. 48 | 49 | For new edits, the module will only be hidden from the GUI. Deprecation is only a display clean-up to limit modules proliferation. 50 | -------------------------------------------------------------------------------- /content/resources/white-balances/Black_body.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/Black_body.svg.png -------------------------------------------------------------------------------- /content/resources/white-balances/Color_temperature_black_body_800-12200K.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/Color_temperature_black_body_800-12200K.svg.png -------------------------------------------------------------------------------- /content/resources/white-balances/Cécile-DSC_0005-0004-colorchecker-off.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/Cécile-DSC_0005-0004-colorchecker-off.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/Cécile-DSC_0005-0004-colorchecker-on.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/Cécile-DSC_0005-0004-colorchecker-on.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/Cécile-DSC_0316-0315-off.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/Cécile-DSC_0316-0315-off.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/Cécile-DSC_0316-0315.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/Cécile-DSC_0316-0315.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/FL3.15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/FL3.15.png -------------------------------------------------------------------------------- /content/resources/white-balances/Planckian-locus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/Planckian-locus.png -------------------------------------------------------------------------------- /content/resources/white-balances/SpyderCheckr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/SpyderCheckr.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/WB-neutral-3832K-framed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/WB-neutral-3832K-framed.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/WB-neutral-3832K-toned-framed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/WB-neutral-3832K-toned-framed.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/WB-neutral-3832K.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/WB-neutral-3832K.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/WB-warm-4341K-framed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/WB-warm-4341K-framed.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/WB-warm-4341K-minus-half-ev.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/WB-warm-4341K-minus-half-ev.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/WB-warm-4341K-minus-half-saturation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/WB-warm-4341K-minus-half-saturation.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/WB-warm-4341K.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/WB-warm-4341K.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/color-checker-green-frame.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/color-checker-green-frame.jpeg -------------------------------------------------------------------------------- /content/resources/white-balances/color-checker-green.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/color-checker-green.jpeg -------------------------------------------------------------------------------- /content/resources/white-balances/color-checker-vectorscope.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/color-checker-vectorscope.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/temperature-right-corrected.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/temperature-right-corrected.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/temperature-right-uncorrected.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/temperature-right-uncorrected.jpg -------------------------------------------------------------------------------- /content/resources/white-balances/temperature-wrong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/resources/white-balances/temperature-wrong.jpg -------------------------------------------------------------------------------- /content/sharpen-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/sharpen-after.jpg -------------------------------------------------------------------------------- /content/sharpen-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/sharpen-before.jpg -------------------------------------------------------------------------------- /content/support.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Support 3 | date: 2022-12-04T02:19:02+01:00 4 | draft: false 5 | weight: 40 6 | --- 7 | 8 |
This page will show you how and where you can learn and get help, in particular on Ansel, but also in general on photography.
9 | 10 | ## General info 11 | 12 | Ansel is mostly a one-person operation. This is good news when it comes to keeping developement in sync with users needs and expectations, not so much when it comes to balancing the workload. So everything that could be automated [was automated](./contribute/workflows.md) for the developer's sanity, and you are asked to use the online resources first everytime it is possible. 13 | 14 | {{< warning >}} 15 | When you submit a bug report or book a training session, please upload your attachment files on my [private cloud](https://cloud.apmlt.net/s/YAdfYajPkE5nLyW) instead of using third-party hosting services with an expiration date : there is no guaranty I will download the files in time and it keeps things tidy for me. 16 | {{< /warning >}} 17 | 18 | 19 | ## Online learning resources 20 | 21 | There already is a fair deal of information around on Ansel's usage. As Ansel is based on darktable 4.0, most tutorials on darktable 4.x (and 3.x, to a lesser extent) are still relevant, even though the GUI may be slightly different. 22 | 23 | {{% row %}} 24 | {{% card title="Videos" icon="chalkboard-teacher" %}} 25 | {{< button url="https://www.youtube.com/channel/UCmsSn3fujI81EKEr4NLxrcg" icon="youtube fab" label="Youtube channel" >}} 26 | {{% /card %}} 27 | 28 | {{% card title="Documentation" icon="book" %}} 29 | {{< button url="/en/doc" icon="glasses" label="Read it, seriously" >}} 30 | {{% /card %}} 31 | {{% /row %}} 32 | 33 | {{% row %}} 34 | {{% card title="Chantal AI, search engine 🇫🇷 🇬🇧" icon="search" class="border border-info bg-info-subtle" %}} 35 | Chantal is a __bilingual AI language model__ trained specifically for open-source __image processing and photography__, coupled with a search engine that indexes more than __47.000 pages__, including Ansel docs, bug reports and forum threads. 36 | 37 | It acts as your virtual librarian and can greatly improve access to information when you are __not sure of the exact terms__ to look for because __it understands synonyms__ and context. 38 | 39 | {{< button url="https://chantal.aurelienpierre.com" icon="search" label="Search" >}} 40 | {{% /card %}} 41 | 42 | {{% card title="Ansel GPT" icon="search" %}} 43 | Ansel GPT is a custom ChatGPT model trained with all the content of the Ansel website and documentation, plus other color science resources. It can answer many questions and help you build and configure Ansel on your system. It has access to significantly fewer resources than Chantal but can form full explanations. 44 | 45 | It is available to _ChatGPT Plus_ subscribers only (as per OpenAI limitations). 46 | {{< button url="https://chatgpt.com/g/g-680d2f861a608191a0f7549eadd40f2e-ansel-gpt" icon="search" label="Search" >}} 47 | {{% /card %}} 48 | {{% /row %}} 49 | 50 | ## Support and training with the developer 51 | 52 | Getting a chance to learn how to use the tools directly with their developer is a pretty rare opportunity as far as software goes. Ansel gives it to you, with 1-on-1 personalized assistance through video-conferencing. 53 | 54 | {{% row %}} 55 | {{% card title="Training sessions" icon="chalkboard-teacher" %}} 56 | 2 hours sessions with 2 days booking heads-up 57 | {{< button url="/en/booking" icon="calendar-alt" label="Book training" >}} 58 | {{% /card %}} 59 | 60 | {{% card title="Emergency support" icon="ambulance" %}} 61 | 30 minutes sessions with 24 h booking heads-up 62 | {{< button icon="calendar-alt" label="Book support" data="data-cal-link='aurelien-pierre/emergency-ansel-support' data-cal-namespace='emergency-ansel-support'" >}} 63 | {{% /card %}} 64 | {{% /row %}} 65 | 66 | 67 | ## Community support 68 | 69 | Free user support is typically assumed by other users. 70 | 71 | {{% row %}} 72 | {{% card title="Forum" icon="comments" %}} 73 | {{< button url="https://community.ansel.photos" icon="users" label="Community discussions" >}} 74 | {{% /card %}} 75 | 76 | {{% card title="Chat" icon="comment-dots" %}} 77 | {{< button url="https://matrix.to/#/#ansel:matrix.org" icon="envelope" label="Matrix chat" >}} 78 | {{% /card %}} 79 | {{% /row %}} 80 | 81 | 82 | ## Bugs and oddities 83 | 84 | {{% row %}} 85 | {{% card title="Bugs" icon="bug" %}} 86 | Everything that leads to the software crashing, producing invalid output or unusable core features is a bug. 87 | {{< button url="https://github.com/aurelienpierreeng/ansel/issues/" icon="github fab" label="Bug tracker" >}} 88 | {{% /card %}} 89 | {{% card title="Questions" icon="question" %}} 90 | If a feature seems to have been removed or to work differently, that might be a redesign, and there is always a reason behind. 91 | {{< button url="https://community.ansel.photos/discussions-category?category=7" icon="question" label="Ask a question" >}} 92 | {{% /card %}} 93 | {{% /row %}} 94 | 95 | 96 | ## Developer support 97 | 98 | If you are considering joining forces for development and debugging, here is how I work. 99 | 100 | {{% row %}} 101 | {{% card title="Guidelines" icon="code-branch" %}} 102 | {{< button url="/en/contribute" icon="github fab" label="Dev wiki" >}} 103 | {{% /card %}} 104 | 105 | {{% card title="Dev mentorship" icon="user-friends" %}} 106 | {{< button url="https://cal.com/aurelien-pierre/developer-mentorship" icon="calendar-alt" label="Book an appointment" >}} 107 | {{% /card %}} 108 | {{% /row %}} 109 | -------------------------------------------------------------------------------- /content/toneeq-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/toneeq-after.jpg -------------------------------------------------------------------------------- /content/toneeq-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/toneeq-before.jpg -------------------------------------------------------------------------------- /content/workflows/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Workflows 3 | date: 2022-12-04T01:28:32+01:00 4 | draft: false 5 | weight: 20 6 | --- 7 | -------------------------------------------------------------------------------- /content/workflows/basic-editing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic Editing 3 | date: 2023-03-24 4 | draft: false 5 | toc: true 6 | authors: 7 | - Aurélien Pierre 8 | --- 9 | 10 | Here is how to get started with Ansel editing, going through only the most basic steps that should serve you well most of the time. 11 | 12 | 13 | 14 | The video was recorded on Darktable 3, but the same modules and principles apply to Ansel. 15 | 16 | {{< youtube 5CmsxxxsMDs >}} 17 | -------------------------------------------------------------------------------- /content/workflows/film-scan/film-scan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/film-scan/film-scan.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-base.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-base.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-cyanotype-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-cyanotype-1.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-cyanotype-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-cyanotype-2.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-cyanotype-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-cyanotype-3.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-monochrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-monochrome.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-platinotype-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-platinotype-1.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-platinotype-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-platinotype-2.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-sepia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-sepia.jpg -------------------------------------------------------------------------------- /content/workflows/monochrome-toning/toning-workflow-split-toning.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/monochrome-toning/toning-workflow-split-toning.jpg -------------------------------------------------------------------------------- /content/workflows/printing/Shooting Minh Ly-0155-_DSC0155-Minh-Ly-bpc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/Shooting Minh Ly-0155-_DSC0155-Minh-Ly-bpc.jpg -------------------------------------------------------------------------------- /content/workflows/printing/Shooting Minh Ly-0155-_DSC0155-Minh-Ly-no-bpc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/Shooting Minh Ly-0155-_DSC0155-Minh-Ly-no-bpc.jpg -------------------------------------------------------------------------------- /content/workflows/printing/Shooting Minh Ly-0155-_DSC0155-Minh-Ly-resized.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/Shooting Minh Ly-0155-_DSC0155-Minh-Ly-resized.jpg -------------------------------------------------------------------------------- /content/workflows/printing/charte-blancs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/charte-blancs.jpg -------------------------------------------------------------------------------- /content/workflows/printing/charte-noirs.fr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/charte-noirs.fr.jpg -------------------------------------------------------------------------------- /content/workflows/printing/charte-noirs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/charte-noirs.jpg -------------------------------------------------------------------------------- /content/workflows/printing/chartes-scan-bpc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/chartes-scan-bpc.jpg -------------------------------------------------------------------------------- /content/workflows/printing/chartes-scan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/chartes-scan.jpg -------------------------------------------------------------------------------- /content/workflows/printing/sRGB-to-printer-curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/sRGB-to-printer-curve.png -------------------------------------------------------------------------------- /content/workflows/printing/sRGB-to-printer-zones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/printing/sRGB-to-printer-zones.png -------------------------------------------------------------------------------- /content/workflows/scene-referred/blur-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/scene-referred/blur-after.jpg -------------------------------------------------------------------------------- /content/workflows/scene-referred/blur-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/scene-referred/blur-before.jpg -------------------------------------------------------------------------------- /content/workflows/scene-referred/display-calibrated.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/scene-referred/display-calibrated.jpg -------------------------------------------------------------------------------- /content/workflows/scene-referred/display-transform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/scene-referred/display-transform.png -------------------------------------------------------------------------------- /content/workflows/scene-referred/fl1-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/scene-referred/fl1-report.png -------------------------------------------------------------------------------- /content/workflows/scene-referred/graphs.py: -------------------------------------------------------------------------------- 1 | #pip install colour-science 2 | #pip install matplotlib 3 | 4 | import colour 5 | import colour.plotting 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | 9 | colour.plotting.plot_single_illuminant_sd("FL1") 10 | 11 | LMS = colour.sd_to_XYZ(colour.SDS_ILLUMINANTS["FL1"], colour.colorimetry.MSDS_CMFS_LMS["Stockman & Sharpe 2 Degree Cone Fundamentals"]) 12 | plt.bar(["R", "G", "B"], LMS, color=["red", "green", "blue"]) 13 | plt.show() 14 | 15 | RGB_sensor = colour.sd_to_XYZ(colour.SDS_ILLUMINANTS["FL1"], colour.MSDS_CAMERA_SENSITIVITIES["Nikon 5100 (NPL)"]) 16 | plt.bar(["R", "G", "B"], RGB_sensor, color=["red", "green", "blue"]) 17 | plt.show() 18 | 19 | colour.plotting.plot_multi_sds(colour.MSDS_CAMERA_SENSITIVITIES["Nikon 5100 (NPL)"], tight_layout=True,) 20 | 21 | # In practice, we would white-balance sensor RGB, then convert to XYZ using input color profile, then to sRGB 22 | # Here we go directly from input spectrum to sRGB, which is the end-goal of the practical operation. 23 | # Of course, it's idealized, but the point is not to illustrate the inaccuracies of the internal pipeline. 24 | sRGB = colour.XYZ_to_sRGB(colour.sd_to_XYZ(colour.SDS_ILLUMINANTS["FL1"], colour.colorimetry.MSDS_CMFS["CIE 1931 2 Degree Standard Observer"]), apply_cctf_encoding=False) 25 | plt.bar(["R", "G", "B"], sRGB, color=["red", "green", "blue"]) 26 | plt.show() 27 | 28 | """ 29 | cmfs = ( 30 | colour.MSDS_CMFS["CIE 1931 2 Degree Standard Observer"] 31 | .copy() 32 | .align(colour.recovery.SPECTRAL_SHAPE_sRGB_MALLETT2019) 33 | ) 34 | illuminant = colour.SDS_ILLUMINANTS["D65"].copy().align(cmfs.shape) 35 | """ 36 | 37 | sRGB_spectrum = colour.recovery.RGB_to_sd_Mallett2019(sRGB) 38 | colour.plotting.plot_single_sd(sRGB_spectrum, title="Light spectrum from FL1 illuminant as displayed on sRGB screen", tight_layout=True,) 39 | 40 | colour.plotting.plot_single_sd_colour_rendition_report(colour.SDS_ILLUMINANTS["FL1"]) 41 | 42 | def plot(XYZ, title): 43 | xy = colour.xy_to_Luv_uv(colour.XYZ_to_xy(XYZ)) 44 | x, y = xy 45 | print(xy) 46 | colour.plotting.plot_chromaticity_diagram_CIE1976UCS(standalone=False) 47 | plt.plot(x, y, "+", color="black", markersize=20) 48 | plt.annotate( 49 | "FL1", 50 | xy=xy, 51 | xytext=(-50, 30), 52 | textcoords="offset points", 53 | arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=-0.2"), 54 | ) 55 | colour.plotting.render( 56 | standalone=True, 57 | bounding_box=(-0.1, 0.7, -0.1, 0.7), 58 | tight_layout=True, 59 | title=title 60 | ) 61 | plt.show() 62 | 63 | return xy 64 | 65 | xy1 = plot(colour.sd_to_XYZ(colour.SDS_ILLUMINANTS["FL1"]), "Chromaticity coordinates in CIE L'u'v' 1976 (scene perception)") 66 | xy2 = plot(colour.sRGB_to_XYZ(sRGB, apply_cctf_decoding=False), "Chromaticity coordinates in CIE L'u'v' 1976 (display)") 67 | 68 | print(np.linalg.norm(xy1 - xy2) / (np.linalg.norm(xy1) + np.linalg.norm(xy2)) * 2) 69 | 70 | print(colour.colour_rendering_index(colour.SDS_ILLUMINANTS["FL1"])) 71 | -------------------------------------------------------------------------------- /content/workflows/scene-referred/initial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/scene-referred/initial.jpg -------------------------------------------------------------------------------- /content/workflows/scene-referred/raw-calibrated.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/content/workflows/scene-referred/raw-calibrated.jpg -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aurelienpierreeng/ansel-website 2 | 3 | go 1.19 4 | 5 | require github.com/aurelienpierreeng/ansel-doc v0.0.0-20250502140606-b5c6d991d52e // indirect 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20221210132230-465a05f3be8b h1:UcOA1d3bA1u08HDH3TaJUBRZuVZvOfKF8/a+DWEhbkA= 2 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20221210132230-465a05f3be8b/go.mod h1:VLh1/h8rWfg0NWQsk8UxhP0ggcOuDIAtBipa93ZHCJs= 3 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20221210145932-22a5128d8926 h1:KEgaHUBwYggXdjFo7qv0v3VZ55X9gFRdJKzcrtV5Bso= 4 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20221210145932-22a5128d8926/go.mod h1:D3pI6+bgYDqUi9+GX5/xibg86rqw+QwpP+KEuxL6/s8= 5 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20240101153448-f48a3b8e779f h1:gzkN9Ru21pWJ4lXNhoUE9BMUUYMX+LAJXuthUPP7AvQ= 6 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20240101153448-f48a3b8e779f/go.mod h1:mGToe3n4wV3XgGB/MarWwBvBU3zGUdY0kJ2hDY/k/WQ= 7 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250422224458-a9db807bf18b h1:0mPexXa1qgyuDEYFeCz+ao0uDmCX8y4I2ZZ6nhIms8k= 8 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250422224458-a9db807bf18b/go.mod h1:mGToe3n4wV3XgGB/MarWwBvBU3zGUdY0kJ2hDY/k/WQ= 9 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423143958-6e1112e5daeb h1:hbNr5On5CnE/qAdgAvgpWYbUWL9jHwRgjwjo7yuuTww= 10 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423143958-6e1112e5daeb/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 11 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423170513-714be2560153 h1:CZ9pYerS0hBn+kylcPK+aLE91uEXuETVKgROZmeLyF4= 12 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423170513-714be2560153/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 13 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423175544-48a61b167abf h1:1dDgoTzrByv8aDQqbXlRTpvtEeGOUXAuQG0NMsWQaUw= 14 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423175544-48a61b167abf/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 15 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423175927-b330b818cff9 h1:PRNxg8lhKqEyfs6ais+OQgRT+94C7WoNyYExeKTdI78= 16 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423175927-b330b818cff9/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 17 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423202838-d02839e3da1d h1:dXrstdw3trhXCPcuQGAwVgL0toiw2UnZDrSKKz+dK7U= 18 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423202838-d02839e3da1d/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 19 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423212614-5276e0188919 h1:23m1ORRTtvGezg/6tS1dz6fSdCByI8u/7UzyNqoG2H8= 20 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250423212614-5276e0188919/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 21 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424000854-b40a63728c2e h1:Bn5Ta+LHmweujJuw2m86oc571pFZKuS20KML9eFOTaw= 22 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424000854-b40a63728c2e/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 23 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424003717-c1c6f0f81d6b h1:msydD2tPB5HIe4O2rU+SsjxiFlv31t9iWXYTz0xCm4g= 24 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424003717-c1c6f0f81d6b/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 25 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424005246-a44d3c7a1c45 h1:infMXHqq+TRI8JZJa/suqPd8U8DYphYiIkKgXsR05N4= 26 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424005246-a44d3c7a1c45/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 27 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424132654-22329242e478 h1:z7/n/dQAq5N8dZ1mef99zLeraEPLoOkhiZiwRY0S6d8= 28 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424132654-22329242e478/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 29 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424151731-79e6a7d2ee98 h1:G4Qwc5W/fihdi3NxG836uKwrg5U9eKrx4HMlpQjTwCE= 30 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424151731-79e6a7d2ee98/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 31 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424152316-516d8276c5f3 h1:asCi3D7k2JjfGeewkHki/t+WBxVfsZE61BD2unW6w6c= 32 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424152316-516d8276c5f3/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 33 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424210315-e11ee24a5223 h1:UWUezGMHM7/rSYaeuZIfDkfjw0JOwcC8KsrxSDXSzps= 34 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250424210315-e11ee24a5223/go.mod h1:q18gWl3xKqLmZu/AXC8DGKX2j2DKmiujFDYCsipyUW4= 35 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250502014423-f5c150071879 h1:NmRNXyGJytRC8fUrpNtXpwQZmKXDydOVn8NKxcgWm28= 36 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250502014423-f5c150071879/go.mod h1:4rpnT4wsbDlOQjCKdBqoftSr+pK/J3hSw7PwXdwYYTI= 37 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250502140318-86d984abe4ef h1:ZJYDuJRFLiHQ4TZO3YLx2astt0/6pROxoswxCaNoRks= 38 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250502140318-86d984abe4ef/go.mod h1:4rpnT4wsbDlOQjCKdBqoftSr+pK/J3hSw7PwXdwYYTI= 39 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250502140606-b5c6d991d52e h1:LjOZj6/mquNVb3+FF0H57nxopbVCx24I+FoQJdkqykY= 40 | github.com/aurelienpierreeng/ansel-doc v0.0.0-20250502140606-b5c6d991d52e/go.mod h1:4rpnT4wsbDlOQjCKdBqoftSr+pK/J3hSw7PwXdwYYTI= 41 | -------------------------------------------------------------------------------- /i18n/en.toml: -------------------------------------------------------------------------------- 1 | [before] 2 | other = "Before" 3 | 4 | [after] 5 | other = "After" 6 | 7 | [subscribe] 8 | other = "Subscribe to this section with RSS" 9 | 10 | [author] 11 | one = "Author" 12 | other = "Authors" 13 | 14 | [community] 15 | other = "Community" 16 | 17 | [learn] 18 | other = "Learn" 19 | 20 | [contributors] 21 | other = "Contribute" 22 | 23 | [onthispage] 24 | other = "On this page" 25 | 26 | [inthissection] 27 | other = "In this section" 28 | 29 | [comments] 30 | other = "Comments & Questions" 31 | 32 | [related] 33 | other = "Related topics" 34 | 35 | [chantal] 36 | other = "Chantal is a bilingual artificial intelligence model for natural language processing, trained for Ansel, photography, image processing and color theory, and able to find relevant web pages among curated sources." 37 | 38 | [find_related] 39 | other = "Find related pages" 40 | 41 | [training] 42 | other = "Book a class" 43 | 44 | [donations] 45 | other = "Donations" 46 | 47 | [donation_pitch] 48 | other = "The Ansel project relies on your donations to keep his developer afloat while he fixes problems created by the Darktable team and its lack of project/priorities management." 49 | 50 | [donate] 51 | other = "Donate" 52 | 53 | [maker] 54 | other = "Maker" 55 | 56 | [model] 57 | other = "Model" 58 | 59 | [aliases] 60 | other = "Aliases" 61 | 62 | [format-supported] 63 | other = "RAW formats" 64 | 65 | [noiseprofiles] 66 | other = "Noise profiles" 67 | 68 | [support-quality] 69 | other = "Support quality" 70 | -------------------------------------------------------------------------------- /i18n/fr.toml: -------------------------------------------------------------------------------- 1 | [support] 2 | other = "Assistance" 3 | 4 | [news] 5 | other = "Actualités" 6 | 7 | [workflows] 8 | other = "Flux de travail" 9 | 10 | [resources] 11 | other = "Ressources" 12 | 13 | [community] 14 | other = "Communauté" 15 | 16 | [learn] 17 | other = "Apprendre" 18 | 19 | [contributors] 20 | other = "Contribuer" 21 | 22 | [before] 23 | other = "Avant" 24 | 25 | [after] 26 | other = "Après" 27 | 28 | [subscribe] 29 | other = "S'abonner à cette section par RSS" 30 | 31 | [author] 32 | one = "Auteur" 33 | other = "Auteurs" 34 | 35 | [onthispage] 36 | other = "Sur cette page" 37 | 38 | [inthissection] 39 | other = "Dans cette section" 40 | 41 | [comments] 42 | other = "Commentaires et questions" 43 | 44 | [related] 45 | other = "Sujets liés" 46 | 47 | [chantal] 48 | other = "Chantal est un modèle d'intelligence artificielle bilingue de traitement du langage naturel, entraîné pour Ansel, la photographie, le traitement d'image et la théorie de la couleur, et capable de trouver les pages web les plus pertinentes parmi des sources sélectionnées." 49 | 50 | [find_related] 51 | other = "Trouver des pages similaires" 52 | 53 | [training] 54 | other = "Réserver un cours" 55 | 56 | [donations] 57 | other = "Dons" 58 | 59 | [donation_pitch] 60 | other = "Le projet Ansel dépend de vos dons pour garder son développeur hors de l'eau pendant qu'il règle les problèmes créés par l'équipe de Darktable et son absence de gestion de projet/priorités." 61 | 62 | [donate] 63 | other = "Donner" 64 | 65 | [maker] 66 | other = "Fabricant" 67 | 68 | [model] 69 | other = "Modèle" 70 | 71 | [aliases] 72 | other = "Alias" 73 | 74 | [format-supported] 75 | other = "Formats RAW" 76 | 77 | [noiseprofiles] 78 | other = "Profils de bruit" 79 | 80 | [support-quality] 81 | other = "Qualité du support" 82 | -------------------------------------------------------------------------------- /po/content.fr.txt: -------------------------------------------------------------------------------- 1 | 2 | [11830]: "The best way to fix errors is to open the relevant `.po` file in a text editor. If you can't find the error and solve it, you can try opening the file into Poedit, but when saving, it will usually completly erase the faulty strings without fixing them, so translation will need to be started again from scratch.\n" 3 | 4 | [11836]: "Build translated Markdown files" 5 | 6 | [11842]: "For the website and documentation, [Hugo](https://gohugo.io/) handles the translations of any given page `new_page.md` using the naming convention `new_page.LANG.md`, where `LANG` is the language code. Hugo natively supports manually writing these translated files in the same folder as their original, however, here we generate them using the `.po` translation file and the program `po4a`. The `build-modules.sh` and `tools/auto-translate.sh` scripts handle this internally, but you may want to generate those file manually :\n" 7 | 8 | [11848]: "" 9 | [11849]: "1. Update the `.pot` and `.po` files with the source code :\n" 10 | [11850]: " ```bash\n" 11 | [11851]: " $ sh tools/update-translations.sh\n" 12 | [11852]: " ```\n" 13 | [11853]: "2. Create the translated `.md` files :\n" 14 | [11854]: " ```bash\n" 15 | [11855]: " $ sh tools/build-translations.sh --add\n" 16 | [11856]: " ```\n" 17 | [11857]: "2. Cleanup the translated `.md` files :\n" 18 | [11858]: " ```bash\n" 19 | [11859]: " $ sh tools/build-translations.sh --remove\n" 20 | [11860]: " ```\n" 21 | 22 | [11866]: "It is important to never commit the translated `.md` files with Git, as they are regenerated only from that script when building the website. This is only for repositiory hygiene, there is no technical drawback. Cleaning up the translated `.md` before committing ensures no mistakes.\n" 23 | -------------------------------------------------------------------------------- /po/disable-languages: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/FL1-sRGB_spectrum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1-sRGB_spectrum.png -------------------------------------------------------------------------------- /static/FL1_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1_color.png -------------------------------------------------------------------------------- /static/FL1_color_display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1_color_display.png -------------------------------------------------------------------------------- /static/FL1_color_scene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1_color_scene.png -------------------------------------------------------------------------------- /static/FL1_lightspectrum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1_lightspectrum.png -------------------------------------------------------------------------------- /static/FL1_sRGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1_sRGB.png -------------------------------------------------------------------------------- /static/FL1_seen_by_NikonD5100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1_seen_by_NikonD5100.png -------------------------------------------------------------------------------- /static/FL1_seen_by_human.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/static/FL1_seen_by_human.png -------------------------------------------------------------------------------- /static/_redirects: -------------------------------------------------------------------------------- 1 | /* /fr/:splat 302 Language=fr 2 | /* /fr/:splat 302 Language=fr-be 3 | /* /fr/:splat 302 Language=fr-ca 4 | /* /fr/:splat 302 Language=fr-ch 5 | /* /fr/:splat 302 Language=fr-fr 6 | /* /fr/:splat 302 Language=fr-lu 7 | /* /fr/:splat 302 Language=fr-mc 8 | /* /en/:splat 302 Language=en 9 | /* /en/:splat 302 10 | / /fr/ 302 Language=fr 11 | / /fr/ 302 Language=fr-be 12 | / /fr/ 302 Language=fr-ca 13 | / /fr/ 302 Language=fr-ch 14 | / /fr/ 302 Language=fr-fr 15 | / /fr/ 302 Language=fr-lu 16 | / /fr/ 302 Language=fr-mc 17 | / /en/ 302 Language=en 18 | / /en/ 302 19 | -------------------------------------------------------------------------------- /themes/ansel/.hugo_build.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/.hugo_build.lock -------------------------------------------------------------------------------- /themes/ansel/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | +++ 3 | -------------------------------------------------------------------------------- /themes/ansel/assets/css/brands.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Brands'; 7 | font-style: normal; 8 | font-weight: 400; 9 | font-display: block; 10 | src: url("/webfonts/fa-brands-400.eot"); 11 | src: url("/webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), 12 | url("/webfonts/fa-brands-400.woff2") format("woff2"), 13 | url("/webfonts/fa-brands-400.woff") format("woff"), 14 | url("/webfonts/fa-brands-400.ttf") format("truetype"), 15 | url("/webfonts/fa-brands-400.svg#fontawesome") format("svg"); } 16 | 17 | .fab { 18 | font-family: 'Font Awesome 5 Brands'; 19 | font-weight: 400; } 20 | -------------------------------------------------------------------------------- /themes/ansel/assets/css/brands.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */@font-face{font-family:'Font Awesome 5 Brands';font-style:normal;font-weight:400;font-display:block;src:url(/webfonts/fa-brands-400.eot);src:url(/webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(/webfonts/fa-brands-400.woff2) format("woff2"),url(/webfonts/fa-brands-400.woff) format("woff"),url(/webfonts/fa-brands-400.ttf) format("truetype"),url(/webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:'Font Awesome 5 Brands';font-weight:400} -------------------------------------------------------------------------------- /themes/ansel/assets/css/fifty-fifty.css: -------------------------------------------------------------------------------- 1 | /* Image comparison slider, aka fifty-fifty */ 2 | /* Extended for lightboxes */ 3 | /* From https://www.w3schools.com/howto/howto_js_image_comparison.asp */ 4 | .img-comp-wrapper, 5 | .img-wrapper, 6 | .include-wrapper { 7 | position: relative; 8 | overflow: visible; 9 | clear: both; 10 | max-width: 100%; 11 | } 12 | 13 | .img-comp-container { 14 | position: relative; 15 | width: 100%; 16 | height: auto; 17 | overflow: hidden; 18 | margin: 0 auto; 19 | } 20 | 21 | .img-container { 22 | position: relative; 23 | width: auto; 24 | height: auto; 25 | overflow: hidden; 26 | margin: 0 auto; 27 | max-width: 100%; 28 | max-height: 100%; 29 | } 30 | 31 | .img-comp-container img { 32 | display: block; 33 | width: 100%; 34 | height: auto; 35 | max-width: none; 36 | object-fit: cover; 37 | pointer-events: none; 38 | user-select: none; 39 | position: relative; 40 | } 41 | 42 | .img-container img { 43 | display: block; 44 | height: auto; 45 | /*max-width: none;*/ 46 | pointer-events: none; 47 | user-select: none; 48 | position: relative; 49 | object-fit: contain; 50 | max-width: 100%; 51 | max-height: 100%; 52 | } 53 | 54 | .img-comp-over { 55 | position: absolute; 56 | overflow: hidden; 57 | width: 100%; 58 | z-index: 2; 59 | } 60 | 61 | .img-comp-under { 62 | position: absolute; 63 | overflow: hidden; 64 | width: 100%; 65 | height: auto; 66 | } 67 | 68 | .comp-cursor { 69 | position: absolute; 70 | z-index: 9; 71 | cursor: ew-resize; 72 | top: 0; 73 | height: 100%; 74 | display: flex; 75 | flex-direction: column; 76 | justify-content: center; 77 | align-items: center; 78 | user-select: none; 79 | } 80 | 81 | .comp-cursor-button { 82 | /*set the appearance of the slider:*/ 83 | width: 2.5rem; 84 | height: 2.5rem; 85 | background: transparent; 86 | border: 2px solid #fff; 87 | border-radius: 50%; 88 | display: flex; 89 | align-items: center; 90 | justify-content: space-evenly; 91 | color: #fff; 92 | font-size: 1rem; 93 | font-weight: thin; 94 | } 95 | 96 | .comp-cursor-line { 97 | width: 2px; 98 | flex-grow: 1; 99 | background-color: #fff; 100 | } 101 | 102 | .img-comp-container .label { 103 | position: absolute; 104 | top: 1rem; 105 | z-index: 1; 106 | color: #fff; 107 | background-color: rgba(0, 0, 0, 0.33); 108 | border-radius: 0.25rem; 109 | padding: 0.5rem 0.75rem; 110 | font-size: 0.85rem; 111 | text-align: center; 112 | letter-spacing: 1px; 113 | user-select: none; 114 | opacity: 0; 115 | transition: 0.25s cubic-bezier(.68,.26,.58,1.22); 116 | } 117 | 118 | .img-comp-container:hover .label { 119 | opacity: 1; 120 | } 121 | 122 | .img-comp-container .label.label-before { 123 | left: 1rem; 124 | } 125 | 126 | .img-comp-container .label.label-after { 127 | right: 1rem; 128 | } 129 | 130 | .open-lightbox-button, 131 | .open-link-button { 132 | position: absolute; 133 | width: 2rem; 134 | height: 2rem; 135 | opacity: 0; 136 | border-radius: 50%; 137 | background-color: white; 138 | border: 1px solid var(--bs-secondary); 139 | cursor: pointer; 140 | font-size: 1rem; 141 | z-index: 999; 142 | text-align: center; 143 | vertical-align: top; 144 | line-height: 1; 145 | } 146 | 147 | .open-lightbox-button { 148 | right: 0; 149 | top: -1rem; 150 | } 151 | 152 | .open-link-button { 153 | left: 0; 154 | top: -1rem; 155 | } 156 | 157 | .open-lightbox-icon, 158 | .open-link-button { 159 | text-align: center; 160 | vertical-align: middle; 161 | } 162 | 163 | .img-wrapper:hover .open-lightbox-button, 164 | .img-wrapper:hover .open-link-button, 165 | .img-comp-wrapper:hover .open-lightbox-button, 166 | .include-wrapper:hover .open-lightbox-button { 167 | opacity: 1; 168 | } 169 | 170 | #lightbox { 171 | position: fixed; 172 | left: 0; 173 | top: 0; 174 | width: 100vw; 175 | height: 100vh; 176 | padding: 1rem; 177 | background: white; 178 | z-index: 9999; 179 | vertical-align: middle; 180 | box-sizing: border-box; 181 | } 182 | 183 | #lightbox figure { 184 | margin: auto; 185 | vertical-align: middle; 186 | box-sizing: border-box; 187 | position: absolute; 188 | top: 50%; 189 | left: 50%; 190 | -ms-transform: translateY(-50%) translateX(-50%); 191 | transform: translateY(-50%) translateX(-50%); 192 | } 193 | #lightbox .open-lightbox-button, 194 | #lightbox .open-link-button { 195 | opacity: 1; 196 | z-index: 999; 197 | } 198 | 199 | #lightbox figure figcaption { display: none } 200 | 201 | #lightbox .open-lightbox-button { 202 | right: 0; 203 | top: 0; 204 | } 205 | 206 | #lightbox .open-link-button { 207 | left: 0; 208 | top: 0; 209 | } 210 | 211 | #lightbox figure.include-wrapper, 212 | #lightbox figure.include-wrapper .include-container, 213 | #lightbox figure.include-wrapper .include-container .plotly-graph-div { 214 | width: 100%; 215 | height: 100%; 216 | } 217 | 218 | #lightbox figure.include-wrapper { 219 | position: relative; 220 | transform: none; 221 | top: 0; 222 | left: 0; 223 | } 224 | -------------------------------------------------------------------------------- /themes/ansel/assets/css/figures.css: -------------------------------------------------------------------------------- 1 | 2 | figure { 3 | display: grid; 4 | border-top: 1px solid var(--bs-secondary); 5 | border-bottom: 1px solid var(--bs-secondary); 6 | margin: 1.5rem 0; 7 | padding: 1rem 0; 8 | max-height: 100%; 9 | max-width: 100%; 10 | } 11 | 12 | figure.caption-figure, 13 | .gallery.caption-figure { 14 | } 15 | 16 | #lightbox figure 17 | { 18 | margin: 0; 19 | padding: 0; 20 | border: none; 21 | } 22 | 23 | figcaption, 24 | .gallery-caption { 25 | padding: 0; 26 | margin: 1rem 0 0 0; 27 | } 28 | 29 | figure figcaption, 30 | .gallery-caption { 31 | font-style: italic; 32 | hyphens: none; 33 | } 34 | 35 | figure figcaption p, 36 | .gallery-caption p { 37 | max-width: none!important; 38 | width: 100%; 39 | text-align: justify; 40 | } 41 | 42 | figure figcaption p:last-child, 43 | .gallery-caption p:last-child { 44 | margin-bottom: 0; 45 | } 46 | 47 | .gallery figure figcaption { 48 | margin: 0; 49 | } 50 | 51 | figure figcaption, 52 | .gallery-caption { 53 | text-align: center; 54 | } 55 | 56 | figure img { 57 | text-align: center!important; 58 | margin: 0 auto; 59 | } 60 | 61 | section > figure + figure, 62 | section > figure + .gallery, 63 | section > .gallery + figure, 64 | .gallery + .gallery { 65 | /* 2 figure elements stacked back-to-back */ 66 | border-top: none!important; 67 | margin-top: -1.5rem!important; 68 | } 69 | 70 | .image-fit { 71 | object-fit: cover; 72 | background-size: cover; 73 | object-position: center top; 74 | width: 100%; 75 | height: 100%; 76 | } 77 | 78 | .gallery { 79 | display: flex; 80 | flex-direction: row; 81 | flex-wrap: wrap; 82 | align-content: normal; 83 | justify-content: space-between; 84 | gap: 1rem; 85 | border-top: 1px solid var(--bs-secondary); 86 | border-bottom: 1px solid var(--bs-secondary); 87 | margin: 1.5rem 0; 88 | padding: 1rem 0; 89 | } 90 | 91 | .gallery hr { 92 | width: 100%; 93 | margin:0; 94 | } 95 | 96 | .gallery.gallery-cols-1 figure{ 97 | width: 100%!important; 98 | } 99 | .gallery.gallery-cols-2 figure { 100 | width: calc(50% - 1rem)!important; 101 | } 102 | .gallery.gallery-cols-3 figure { 103 | width: calc(33.3333333% - 1rem)!important; 104 | } 105 | .gallery.gallery-cols-4 figure { 106 | width: calc(25% - 1rem)!important; 107 | } 108 | .gallery.gallery-cols-5 figure { 109 | width: calc(20% - 1rem)!important; 110 | } 111 | .gallery.gallery-cols-6 figure { 112 | width: calc(16.6666666% - 1rem)!important; 113 | } 114 | 115 | .gallery figure { 116 | flex-grow: 1; 117 | border: none; 118 | background-color: rgba(0, 0, 0, 0.05); 119 | margin: 0; 120 | padding: 0; 121 | min-width: 140px; 122 | max-width: none!important; 123 | } 124 | 125 | .gallery.no-bg figure { 126 | background: transparent; 127 | } 128 | 129 | .gallery figure figcaption { 130 | padding: 0.5rem; 131 | } 132 | 133 | .gallery.no-bg figure figcaption { 134 | padding-bottom: 0; 135 | } 136 | 137 | .gallery-caption { 138 | border-top: 1px solid var(--bs-secondary); 139 | width: 100%; 140 | } 141 | 142 | .gallery > p, 143 | .gallery > br { 144 | /* Mardown parsing articfacts */ 145 | display: none; 146 | } 147 | -------------------------------------------------------------------------------- /themes/ansel/assets/css/figures.min.css: -------------------------------------------------------------------------------- 1 | figure{display:grid;border-top:1px solid var(--bs-secondary);border-bottom:1px solid var(--bs-secondary);margin:1.5rem 0;padding:1rem 0;max-height:100%;max-width:100%}#lightbox figure{margin:0;padding:0;border:none}.gallery-caption,figcaption{padding:0;margin:1rem 0 0 0}.gallery-caption,figure figcaption{font-style:italic;hyphens:none}.gallery-caption p,figure figcaption p{max-width:none!important;width:100%;text-align:justify}.gallery-caption p:last-child,figure figcaption p:last-child{margin-bottom:0}.gallery figure figcaption{margin:0}.gallery-caption,figure figcaption{text-align:center}figure img{text-align:center!important;margin:0 auto}.gallery+.gallery,section>.gallery+figure,section>figure+.gallery,section>figure+figure{border-top:none!important;margin-top:-1.5rem!important}.image-fit{object-fit:cover;background-size:cover;object-position:center top;width:100%;height:100%}.gallery{display:flex;flex-direction:row;flex-wrap:wrap;align-content:normal;justify-content:space-between;gap:1rem;border-top:1px solid var(--bs-secondary);border-bottom:1px solid var(--bs-secondary);margin:1.5rem 0;padding:1rem 0}.gallery hr{width:100%;margin:0}.gallery.gallery-cols-1 figure{width:100%!important}.gallery.gallery-cols-2 figure{width:calc(50% - 1rem)!important}.gallery.gallery-cols-3 figure{width:calc(33.3333333% - 1rem)!important}.gallery.gallery-cols-4 figure{width:calc(25% - 1rem)!important}.gallery.gallery-cols-5 figure{width:calc(20% - 1rem)!important}.gallery.gallery-cols-6 figure{width:calc(16.6666666% - 1rem)!important}.gallery figure{flex-grow:1;border:none;background-color:rgba(0,0,0,.05);margin:0;padding:0;min-width:140px;max-width:none!important}.gallery.no-bg figure{background:0 0}.gallery figure figcaption{padding:.5rem}.gallery.no-bg figure figcaption{padding-bottom:0}.gallery-caption{border-top:1px solid var(--bs-secondary);width:100%}.gallery>br,.gallery>p{display:none} -------------------------------------------------------------------------------- /themes/ansel/assets/css/regular.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 400; 9 | font-display: block; 10 | src: url("/webfonts/fa-regular-400.eot"); 11 | src: url("/webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), 12 | url("/webfonts/fa-regular-400.woff2") format("woff2"), 13 | url("/webfonts/fa-regular-400.woff") format("woff"), 14 | url("/webfonts/fa-regular-400.ttf") format("truetype"), 15 | url("/webfonts/fa-regular-400.svg#fontawesome") format("svg"); } 16 | 17 | .far { 18 | font-family: 'Font Awesome 5 Free'; 19 | font-weight: 400; } 20 | -------------------------------------------------------------------------------- /themes/ansel/assets/css/regular.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */@font-face{font-family:'Font Awesome 5 Free';font-style:normal;font-weight:400;font-display:block;src:url(/webfonts/fa-regular-400.eot);src:url(/webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(/webfonts/fa-regular-400.woff2) format("woff2"),url(/webfonts/fa-regular-400.woff) format("woff"),url(/webfonts/fa-regular-400.ttf) format("truetype"),url(/webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:'Font Awesome 5 Free';font-weight:400} -------------------------------------------------------------------------------- /themes/ansel/assets/css/solid.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 900; 9 | font-display: block; 10 | src: url("/webfonts/fa-solid-900.eot"); 11 | src: url("/webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), 12 | url("/webfonts/fa-solid-900.woff2") format("woff2"), 13 | url("/webfonts/fa-solid-900.woff") format("woff"), 14 | url("/webfonts/fa-solid-900.ttf") format("truetype"), 15 | url("/webfonts/fa-solid-900.svg#fontawesome") format("svg"); } 16 | 17 | .fa, 18 | .fas { 19 | font-family: 'Font Awesome 5 Free'; 20 | font-weight: 900; } 21 | -------------------------------------------------------------------------------- /themes/ansel/assets/css/solid.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */@font-face{font-family:'Font Awesome 5 Free';font-style:normal;font-weight:900;font-display:block;src:url(/webfonts/fa-solid-900.eot);src:url(/webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(/webfonts/fa-solid-900.woff2) format("woff2"),url(/webfonts/fa-solid-900.woff) format("woff"),url(/webfonts/fa-solid-900.ttf) format("truetype"),url(/webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:'Font Awesome 5 Free';font-weight:900} -------------------------------------------------------------------------------- /themes/ansel/assets/js/scripts.min.js: -------------------------------------------------------------------------------- 1 | var bypass_hide=!1;function force_show(){(bypass_hide=!bypass_hide)&&(el_autohide=document.querySelector(".autohide"),sidebars=document.querySelectorAll(".sidebar"),el_autohide.classList.remove("scrolled-down"),el_autohide.classList.add("scrolled-up"),sidebars.forEach(element=>element.classList.remove("move-up")),document.body.parentNode.classList.remove("move-up"))}document.addEventListener("DOMContentLoaded",(function(){if(el_autohide=document.querySelector(".autohide"),el_autohide){var last_scroll_top=0;window.addEventListener("scroll",(function(event){if(bypass_hide)return;let scroll_top=window.scrollY;scroll_top response.json()) 30 | .then(data => create_fuse(data)); 31 | } 32 | 33 | function truncate(str, n){ 34 | return (str.length > n) ? str.slice(0, n-1) + '…' : str; 35 | }; 36 | 37 | function display_result(elem) { 38 | // Get the HTML template and populate it, then add to the HTML container 39 | const tbody = document.querySelector("#search-results"); 40 | const template = document.querySelector('#search-result-template'); 41 | const clone = template.content.cloneNode(true); 42 | 43 | title = clone.querySelector("h6") 44 | title.innerHTML = title.innerHTML.replace("(title)", elem.item.title); 45 | title.innerHTML = title.innerHTML.replace("(url)", elem.item.permalink); 46 | title.innerHTML = title.innerHTML.replace("(score)", ((1. - elem.score) * 100.).toFixed(0) + " %"); 47 | 48 | summary = clone.querySelector("p"); 49 | summary.innerHTML = summary.innerHTML.replace("(summary)", truncate(elem.item.summary, 140)); 50 | summary.innerHTML = summary.innerHTML.replace("(section)", elem.item.section); 51 | 52 | tbody.appendChild(clone); 53 | } 54 | 55 | function no_result(message) { 56 | // Display a "no result found" 57 | const tbody = document.querySelector("#search-results"); 58 | const clone = document.createElement("div"); 59 | clone.innerHTML = "

" + message + "

"; 60 | tbody.appendChild(clone); 61 | } 62 | 63 | function search_results() { 64 | // Empty the HTML result list 65 | tbody = document.querySelector("#search-results"); 66 | tbody.innerHTML = ""; 67 | 68 | if (fuse_inited) { 69 | pattern = document.getElementById("search-query").value; 70 | console.log(pattern); 71 | result = fuse.search(pattern); 72 | console.log(result); 73 | 74 | if (result.length > 0) { 75 | for (i = 0; i < result.length; i++) { 76 | display_result(result[i]); 77 | } 78 | } else { 79 | no_result("Sorry, no result found. Try again with different keywords."); 80 | } 81 | } 82 | else { 83 | no_result("Sorry, the fuse.js library did not load and research is not available. Try to reload the page."); 84 | } 85 | } 86 | 87 | function search_results_from_keyboard() { 88 | if(event.key === 'Enter') { 89 | search_results(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /themes/ansel/assets/js/search.min.js: -------------------------------------------------------------------------------- 1 | var fuse="",fuse_inited=!1;function create_fuse(db_json){fuseOptions={shouldSort:!0,includeScore:!0,minMatchCharLength:4,threshold:0,ignoreLocation:!0,keys:[{name:"title",weight:.8},{name:"summary",weight:.6},{name:"contents",weight:.5},{name:"permalink",weight:.8},{name:"keywords",weight:.8}]},fuse=new Fuse(db_json,fuseOptions),fuse_inited=!0}function loadJSON(path){var xhr=new XMLHttpRequest;xhr.onreadystatechange=function(){4===xhr.readyState&&200===xhr.status&&create_fuse(JSON.parse(xhr.responseText))},xhr.open("GET",path,!0),xhr.send()}function truncate(str,n){return str.length>n?str.slice(0,n-1)+"…":str}function display_result(elem){const tbody=document.querySelector("#search-results"),template=document.querySelector("#search-result-template"),clone=template.content.cloneNode(!0);title=clone.querySelector("h6"),title.innerHTML=title.innerHTML.replace("(title)",elem.item.title),title.innerHTML=title.innerHTML.replace("(url)",elem.item.permalink),title.innerHTML=title.innerHTML.replace("(score)",(100*(1-elem.score)).toFixed(0)+" %"),summary=clone.querySelector("p"),summary.innerHTML=summary.innerHTML.replace("(summary)",truncate(elem.item.summary,140)),summary.innerHTML=summary.innerHTML.replace("(section)",elem.item.section),tbody.appendChild(clone)}function no_result(message){const tbody=document.querySelector("#search-results"),clone=document.createElement("div");clone.innerHTML="

"+message+"

",tbody.appendChild(clone)}function search_results(){if(tbody=document.querySelector("#search-results"),tbody.innerHTML="",fuse_inited)if(pattern=document.getElementById("search-query").value,console.log(pattern),result=fuse.search(pattern),console.log(result),result.length>0)for(i=0;iSetting : {{ .Page.Scratch.Get "columns" }}

2 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/_markup/render-blockquote.html: -------------------------------------------------------------------------------- 1 |
2 | {{ .Text }} 3 |
4 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/_markup/render-codeblock-mermaid.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{ .Inner | safeHTML }}
4 | 
5 |
6 | {{- .Page.Store.Set "hasMermaid" true -}} 7 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/_markup/render-codeblock.html: -------------------------------------------------------------------------------- 1 |
2 | {{ $result := transform.HighlightCodeBlock . }} 3 | {{ $result.Wrapped }} 4 |
5 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/_markup/render-heading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | {{ .Text | safeHTML}} 6 | {{ if eq .Level 2}}{{ end }} 7 | 8 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/_markup/render-image.html: -------------------------------------------------------------------------------- 1 | {{ partial "image.html" (dict "Page" .Page "Src" .Destination "Caption" .Title) }} 2 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/_markup/render-link.html: -------------------------------------------------------------------------------- 1 | {{- $link := strings.Replace .Destination "_index.md" "" -}} 2 | {{- $isRemote := strings.HasPrefix $link "http" -}} 3 | {{- $isAnchor := strings.HasPrefix $link "#" -}} 4 | {{- $isWikipedia := strings.Contains $link "wikipedia.org" -}} 5 | {{- $isNetwork := strings.Contains $link "ansel.photos" -}} 6 | {{- $isDownload := eq (lower .Title) "download" -}} 7 | {{- $title := .Title -}} 8 | {{- $page := .Page -}} 9 | 10 | {{- if and $isWikipedia (not $title) -}} 11 | {{- $title = "Wikipedia link" -}} 12 | {{- end -}} 13 | 14 | {{- if and $isRemote (and (not $isNetwork) (not $title)) -}} 15 | {{- $title = "External link" -}} 16 | {{- end -}} 17 | 18 | {{- if and (not $isRemote) (not $isAnchor) -}} 19 | {{/* 20 | For local links, we want writers to use relative links to (mostly .md) files, as much as possible. 21 | These links can be followed in modern text editors on the file system, without building the website. 22 | But Hugo needs links to be relative to the generated website structure, and the conversion is not straight-forward, 23 | especially with translations. 24 | */}} 25 | {{- $url := urls.Parse $link -}} 26 | {{- if $url.Path -}} 27 | {{- $fragment := printf "%s" $url.Fragment -}} 28 | {{- $link = $url.Path -}} 29 | 30 | {{- $output := "" -}} 31 | {{- if strings.HasSuffix $link ".xml" -}} 32 | {{- $output = "rss" -}} 33 | {{- $link = strings.Replace $link ".xml" "" -}} 34 | {{- else if strings.HasSuffix $link ".md" -}} 35 | {{- $output = "html" -}} 36 | {{- $link = strings.Replace $link ".md" "" -}} 37 | {{- end -}} 38 | 39 | {{- $got_it := false -}} 40 | 41 | {{/* This works as-is only for relative links to pages from the same section/branch bundle */}} 42 | {{- with $page.GetPage $link -}} 43 | {{- $link = .RelPermalink -}} 44 | {{- $got_it = true -}} 45 | {{- end }} 46 | 47 | {{- with site.GetPage $link -}} 48 | {{- $link = .RelPermalink -}} 49 | {{- $got_it = true -}} 50 | {{- end }} 51 | 52 | {{/* This works only for relative links pointing to pages outside the current section/branch bundle 53 | and if the current page is NOT IN a page boundle. 54 | see https://gohugo.io/content-management/page-bundles/ 55 | */}} 56 | {{- if not $got_it -}} 57 | {{- $opts := dict "path" $link "lang" .Page.Lang "outputFormat" $output }} 58 | {{- with try (ref .Page $opts) -}} 59 | {{ with $page.GetPage .Value }} 60 | {{- $link = .RelPermalink -}} 61 | {{- $got_it = true -}} 62 | {{ end }} 63 | {{- end }} 64 | {{- end -}} 65 | 66 | {{/* This works only for relative links pointing to pages outside the current section/branch bundle 67 | and if the current page is IN a page boundle. 68 | see https://gohugo.io/content-management/page-bundles/ 69 | */}} 70 | {{- if not $got_it -}} 71 | {{- $opts := dict "path" (strings.TrimPrefix "../" $link) "lang" .Page.Lang "outputFormat" $output }} 72 | {{- with try (ref .Page $opts) -}} 73 | {{ with $page.GetPage .Value }} 74 | {{- $link = .RelPermalink -}} 75 | {{- $got_it = true -}} 76 | {{ end }} 77 | {{- end }} 78 | {{- end -}} 79 | 80 | {{- if not $got_it -}} 81 | {{- errorf "Internal link %q (%q) NOT FOUND from page %q." $link .Destination .Page -}} 82 | {{- end -}} 83 | 84 | {{- if $fragment -}} 85 | {{- $link = printf "%s#%s" $link $fragment -}} 86 | {{- end -}} 87 | {{- end -}} 88 | {{- end -}} 89 | 90 | {{ .Text | safeHTML }} 91 | {{- if $isDownload -}} 92 |   93 | {{- else if $isRemote -}} 94 | {{- if $isWikipedia -}} 95 |   96 | {{- else if not $isNetwork -}} 97 |   98 | {{- end }} 99 | {{- end -}} 100 | 101 | {{- "" -}} 102 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{- partial "head.html" . -}} 4 | 9 | {{- partial "header.html" . -}} 10 |
11 | {{- block "main" . }}{{- end }} 12 |
13 | {{- partial "footer.html" . -}} 14 | {{- partial "script.html" . -}} 15 | {{- partial "search.html" . -}} 16 | 17 | 18 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/index.json: -------------------------------------------------------------------------------- 1 | {{- $.Scratch.Add "index" slice -}} 2 | {{- range .Site.Pages -}} 3 | {{ $section_heading := .Site.GetPage "section" .Section }} 4 | {{ $section_title := .Section }} 5 | {{with $section_heading}} 6 | {{ $section_title = .Title }} 7 | {{end}} 8 | {{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "keywords" .Keywords "categories" .Params.categories "contents" .Plain "summary" .Summary "section" $section_title "permalink" .Permalink) -}} 9 | {{- end -}} 10 | {{- $.Scratch.Get "index" | jsonify -}} 11 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/index.md: -------------------------------------------------------------------------------- 1 | {{- range .Site.Pages -}} 2 | 3 | --- 4 | 5 | {{ printf "# %s : %s" .Title .Permalink }} 6 | {{ .RawContent }} 7 | {{- end -}} 8 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ $has_toc := (ne .TableOfContents "") }} 3 | {{ $content := .Content }} 4 | 5 |
6 |
7 | 12 | 13 |
14 |
15 | {{ partial "breadcrumb.html" . }} 16 |
17 | 18 | {{ if $content }} 19 |
20 |
21 |

{{ .Title | strings.FirstUpper | safeHTML }}

22 |
23 |
24 | {{ partial "metadata.html" . }} 25 |
26 |
27 |
28 | {{ $content }} 29 |
30 |
31 |
32 | 33 | {{ partial "social.html" . }} 34 | {{ partial "prev-next.html" . }} 35 | {{ end }} 36 | 37 | {{ if not $content }} 38 |

{{ .Title }} {{ partial "rss.html" . }}

39 | {{ else }} 40 |

Section content {{ partial "rss.html" . }}

41 | {{ end }} 42 | 43 |
44 | {{ $pages := .Pages.ByPublishDate.Reverse }} 45 | {{ range .Translations }} 46 | {{ $pages = $pages | lang.Merge .Pages }} 47 | {{ end }} 48 | {{ range $pages }} 49 | 79 | {{ end }} 80 |
81 |
82 | 83 | 90 |
91 |
92 | {{ end }} 93 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/rss.xml: -------------------------------------------------------------------------------- 1 | {{- $pctx := . -}} 2 | {{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}} 3 | {{- if .IsSection -}}{{ $pctx = .FirstSection }}{{- end -}} 4 | {{- $pages := slice -}} 5 | {{- if or $.IsHome -}} 6 | {{- $pages = $pctx.RegularPages -}} 7 | {{- else -}} 8 | {{- $pages = $pctx.Pages -}} 9 | {{- end -}} 10 | {{- $limit := .Site.Config.Services.RSS.Limit -}} 11 | {{- if ge $limit 1 -}} 12 | {{- $pages = $pages | first $limit -}} 13 | {{- end -}} 14 | {{- printf "" | safeHTML }} 15 | 16 | 17 | {{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }} 18 | {{ .Permalink }} 19 | Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }} 20 | Hugo -- gohugo.io{{ with .Site.LanguageCode }} 21 | {{.}}{{end}}{{ with .Site.Params.Author.email }} 22 | {{.}}{{ with $.Site.Params.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Params.Author.email }} 23 | {{.}}{{ with $.Site.Params.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Copyright }} 24 | {{.}}{{end}}{{ if not .Date.IsZero }} 25 | {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}{{ end }} 26 | {{- with .OutputFormats.Get "RSS" -}} 27 | {{ printf "" .Permalink .MediaType | safeHTML }} 28 | {{- end -}} 29 | {{ range $pages }} 30 | {{ template "section" . }} 31 | {{ end }} 32 | 33 | 34 | 35 | {{- define "section" -}} 36 | {{ if .IsSection }} 37 | {{ template "item" . }} 38 | {{ range .Pages }} 39 | {{ template "section" . }} 40 | {{ end }} 41 | {{ else }} 42 | {{ template "item" . }} 43 | {{ end }} 44 | 45 | {{- end -}} 46 | 47 | {{- define "item" -}} 48 | 49 | {{ .Title }} 50 | {{ .Permalink | safeHTML }} 51 | {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} 52 | {{ .Lastmod.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} 53 | {{ with .Site.Params.Author.email }}{{.}}{{ with $.Site.Params.Author.name }} ({{.}}){{end}}{{end}} 54 | {{ sha256 (print .Permalink (.Lastmod.Format "Mon, 02 Jan 2006 15:04:05 -0700") ) }} 55 | {{ .Summary | html }} 56 | 57 | {{- end -}} 58 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ $has_toc := (ne .TableOfContents "") }} 3 | 4 | {{ partial "header_thumb.html" . }} 5 | 6 |
7 | 8 |
9 | 14 | 15 | {{ if eq .Params.type "large" }} 16 |
17 | {{ else }} 18 |
19 | {{ end }} 20 |
21 | {{ partial "breadcrumb.html" . }} 22 |
23 |
24 |
25 |

{{ .Title | strings.FirstUpper | safeHTML }}

26 |
27 |
28 | {{ partial "metadata.html" . }} 29 |
30 |
31 |
32 | {{ .Content }} 33 |
34 |
35 |
36 | 37 | {{ partial "social.html" . }} 38 | {{ partial "prev-next.html" . }} 39 | 40 | {{- if not .Params.noauthor }} 41 | 42 | {{ partial "authors.html" . }} 43 | 44 | {{- /* partial "related_posts.html" . */ -}} 45 | 46 | {{ partial "comments.html" . }} 47 | {{- end -}} 48 |
49 | 50 | 57 |
58 |
59 | 60 | {{ end }} 61 | -------------------------------------------------------------------------------- /themes/ansel/layouts/_default/summary.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ .Title }}

4 | 5 |
6 | {{ .Summary | safeHTML }} 7 | 10 |
11 | -------------------------------------------------------------------------------- /themes/ansel/layouts/index.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 | {{ .Content }} 4 |
5 | {{ end }} 6 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/authors.html: -------------------------------------------------------------------------------- 1 | 2 | {{ if .Param "authors" }} 3 |
4 |

{{ i18n "author" (len (.Param "authors")) }}

5 | {{ range .Param "authors" }} 6 | {{ $name := . }} 7 | {{ $path := printf "/%s/%s" "authors" ($name | urlize) }} 8 | {{ with $.Site.GetPage $path }} 9 |
10 | 11 |
{{ .Params.name }}
12 |

{{ .Params.bio }} Website

13 |
14 | {{ end }} 15 | {{ end }} 16 |
17 | {{ end }} 18 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/breadcrumb.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/comments.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ i18n "comments" }} ?

3 | 41 |
42 | 43 |
44 |

{{ i18n "donations" }}

45 | 62 |
63 | 64 | {{ $params := print .Site.Title " " .Title }} 65 | 66 |
67 |

{{ i18n "related" }}

68 | 86 |
87 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/footer.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

{{ .Site.Copyright }}

6 |
    7 |
  • 8 |
  • 9 |
  • 10 |
11 |
12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/get_resource.html: -------------------------------------------------------------------------------- 1 | {{- $src := index (split .src "#") 0 -}} 2 | {{- $page := .Page }} 3 | 4 | {{- $image := "" -}} 5 | {{- $path := "" -}} 6 | {{- $rel_path := "" -}} 7 | {{- $abs_path := "" -}} 8 | 9 | {{- if strings.HasPrefix $src "http" -}} 10 | {{- $image = resources.GetRemote $src -}} 11 | {{- else -}} 12 | {{- $path = strings.TrimLeft "./" (strings.TrimPrefix (print "./" .Page.File "/") $src ) -}} 13 | {{- $abs_path = path.Join .Page.File.Dir (strings.TrimLeft "./" $src ) -}} 14 | {{- $rel_path = print "./" $path -}} 15 | 16 | {{- if not $image -}} 17 | {{- $image = resources.Get $src -}} 18 | {{- end }} 19 | {{- if not $image -}} 20 | {{- $image = resources.Get $path -}} 21 | {{- end }} 22 | {{- if not $image -}} 23 | {{- $image = resources.Get $rel_path -}} 24 | {{- end -}} 25 | {{- if not $image -}} 26 | {{- $image = resources.Get $abs_path -}} 27 | {{- end -}} 28 | 29 | {{- if not $image -}} 30 | {{- $image = .Resources.Get $src -}} 31 | {{- end }} 32 | {{- if not $image -}} 33 | {{- $image = .Resources.Get $path -}} 34 | {{- end }} 35 | {{- if not $image -}} 36 | {{- $image = .Resources.Get $abs_path -}} 37 | {{- end }} 38 | {{- if not $image -}} 39 | {{- $image = .Resources.Get $rel_path -}} 40 | {{- end -}} 41 | 42 | {{- if not $image -}} 43 | {{- $image = .Page.Resources.Get $src -}} 44 | {{- end -}} 45 | {{- if not $image -}} 46 | {{- $image = .Page.Resources.Get $path -}} 47 | {{- end -}} 48 | {{- if not $image -}} 49 | {{- $image = .Page.Resources.Get $rel_path -}} 50 | {{- end }} 51 | {{- if not $image -}} 52 | {{- $image = .Page.Resources.Get $abs_path -}} 53 | {{- end -}} 54 | {{- end -}} 55 | 56 | {{- if not $image }} 57 | {{- warnf "Resource:\n%q\n%q\n%q\n%q\nnot found from page %q." $src $path $rel_path $abs_path $page.File.Path -}} 58 | {{- else -}} 59 | {{- return $image -}} 60 | {{- end -}}} 61 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/get_sizes.html: -------------------------------------------------------------------------------- 1 | {{ $cols := int (.Page.Scratch.Get "columns" | default 0) }} 2 | {{ $sizes := "" }} 3 | 4 | {{ if eq $cols 0 }} 5 | 6 | {{ if eq .Class "narrow-width" }} 7 | {{ $sizes = "(max-width: 36rem) 100vw, 36rem" }} 8 | {{ else }} 9 | {{ $sizes = site.Params.Images.sizes }} 10 | {{ end }} 11 | 12 | 13 | {{ else if eq $cols 1 }} 14 | {{ $sizes = "(max-width: 992px) 100vw, (max-width: 1200px) 66.67vw, 50vw" }} 15 | 16 | 17 | {{ else if eq $cols 2 }} 18 | {{ $sizes = "(max-width: 140px) 100vw, (max-width: 992px) 50vw, (max-width: 1200px) 33.33vw, 25vw" }} 19 | {{ else if eq $cols 3 }} 20 | {{ $sizes = "(max-width: 140px) 100vw, (max-width: 992px) 33.33vw, (max-width: 1200px) 22vw, 16.67vw" }} 21 | {{ else if eq $cols 4 }} 22 | {{ $sizes = "(max-width: 140px) 100vw, (max-width: 992px) 25vw, (max-width: 1200px) 16.67vw, 12.5vw" }} 23 | {{ end }} 24 | 25 | {{- return $sizes -}} 26 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/get_srcset.html: -------------------------------------------------------------------------------- 1 | {{ $srcset := "" }} 2 | {{ $image := . }} 3 | {{ if $image }} 4 | {{ if not ( eq $image.MediaType.SubType "svg" ) }} 5 | {{ print "is not SVG" }} 6 | {{ $iw := $image.Width }} 7 | {{ $ih := $image.Height }} 8 | {{ $set := slice }} 9 | {{ range slice 140 264 331 400 496 576 600 720 800 992 1200 1320 1440 1600 1920 2048 }} 10 | {{ if lt . $iw }} 11 | {{ $size := print . "x" .}} 12 | {{ $thumb := $image.Fit $size }} 13 | {{ $set = $set | append (printf ("%s %dw") $thumb.RelPermalink $thumb.Width ) }} 14 | {{ end }} 15 | {{ end }} 16 | {{ if gt (len $set) 0 }} 17 | {{ $srcset = delimit $set ", "}} 18 | {{ end }} 19 | {{ end }} 20 | {{ end }} 21 | {{- return $srcset -}} 22 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{ $title := "" }} 10 | {{ if .IsHome }} 11 | {{ $title = .Site.Title }} 12 | {{ else }} 13 | {{ $title = print .Site.Title " | " .Title }} 14 | {{ end }} 15 | {{ $title }} 16 | 17 | {{- $bs_1 := resources.Get "css/bootstrap.css" -}} 18 | {{- $style := resources.Get "css/style.css" -}} 19 | {{- $faa := resources.Get "css/all.css" -}} 20 | {{- $fas := resources.Get "css/solid.css" -}} 21 | {{- $fab := resources.Get "css/brands.css" -}} 22 | {{- $far := resources.Get "css/regular.css" -}} 23 | {{- $ff_css := resources.Get "/css/fifty-fifty.css" -}} 24 | {{- $figures := resources.Get "/css/figures.css" -}} 25 | 26 | {{- $css := slice $bs_1 $faa $fas $far $fab $ff_css $figures $style | resources.Concat "css/bundle.css" | minify | fingerprint -}} 27 | 28 | 29 | 30 | 31 | 32 | {{ $description := "" }} 33 | {{ if .Params.description }} 34 | {{ $description = .Params.description | safeHTML }} 35 | {{ else if .Summary }} 36 | {{ $description = .Summary| safeHTML }} 37 | {{ else }} 38 | {{ $description = .Title | safeHTML }} 39 | {{ end }} 40 | 41 | 42 | 43 | 44 | 45 | {{ if .Params.tags }} 46 | 47 | {{ end }} 48 | 49 | {{- if .IsTranslated -}} 50 | {{ range .AllTranslations }} 51 | 52 | {{ end }} 53 | {{ else }} 54 | {{ if in .Language "fr" }} 55 | 56 | {{ else }} 57 | 58 | {{ end }} 59 | {{- end -}} 60 | 61 | {{ $href := .Permalink | absLangURL }} 62 | 63 | {{ if .IsPage }} 64 | 65 | {{ end }} 66 | 67 | 68 | 69 | 70 | 71 | {{ if .Params.thumbnail }} 72 | 73 | {{ else }} 74 | 75 | {{ end }} 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | {{ if .Lastmod }} 84 | 85 | {{ end }} 86 | 87 | {{ range .Params.tags }} 88 | 89 | {{ end }} 90 | 91 | 92 | 93 | {{ range .AlternativeOutputFormats -}} 94 | {{ printf `` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }} 95 | {{ end -}} 96 | 97 | 98 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/header.html: -------------------------------------------------------------------------------- 1 | 74 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/header_thumb.html: -------------------------------------------------------------------------------- 1 | {{ if .Params.thumbnail }} 2 | {{ $thumb := partial "get_resource.html" (dict "src" .Params.thumbnail "Page" .Page ) }} 3 |
4 | {{ if strings.HasSuffix .Params.thumbnail ".svg" }} 5 | 6 | {{ else }} 7 | {{ $srcset := partial "get_srcset.html" $thumb }} 8 | 11 | {{ end }} 12 |
13 | {{ end }} 14 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/i18nlist.html: -------------------------------------------------------------------------------- 1 | {{ if .IsTranslated }} 2 | — 3 |
4 | 7 | 15 |
16 | {{ end }} 17 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/image.html: -------------------------------------------------------------------------------- 1 | {{ $src := .Src | safeURL }} 2 | {{ $p := .Page }} 3 | 4 | 5 | {{ $sizes := partial "get_sizes.html" (dict "class" .Class "Page" .Page) }} 6 | {{ $image := partial "get_resource.html" (dict "src" $src "Page" .Page ) }} 7 | 8 | {{ if $image }} 9 | {{ $fig_id := $image.RelPermalink | anchorize | safeCSS }} 10 | {{ $srcset := partial "get_srcset.html" $image }} 11 | {{ $isSVG := eq $image.MediaType.SubType "svg" }} 12 | {{ $isShit := eq $image.MediaType.SubType "webp" }} 13 | {{ $isDistant := strings.HasPrefix $src "http" }} 14 | 15 | 16 |
17 | 20 | 23 |
24 | image 30 |
31 | {{ with .Caption }} 32 |
33 | {{ . }} 34 |
35 | {{ end }} 36 |
37 | {{ end }} 38 | {{- "" -}} 39 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/metadata.html: -------------------------------------------------------------------------------- 1 |
2 | {{ partial "metadata_common.html" . }} 3 | {{ partial "i18nlist.html" . }} 4 | 5 | {{ if .IsPage }} 6 | {{ with .GetPage .Section }} 7 | — {{ partial "rss.html" . }} 8 | {{ end }} 9 | {{ else }} 10 | {{ with .FirstSection }} 11 | — {{ partial "rss.html" . }} 12 | {{ end }} 13 | {{ end }} 14 |
15 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/metadata_common.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ if .Lastmod }} 5 | — 6 | 7 | {{ end }} 8 | 9 | {{ if .Params.tags }} 10 | — 11 | {{ range (.GetTerms "tags") }} 12 | {{ .Title }} 13 | {{ end }} 14 | {{ end }} 15 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/metadata_list.html: -------------------------------------------------------------------------------- 1 |
2 | {{ partial "metadata_common.html" . }} 3 |
4 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/navigation.html: -------------------------------------------------------------------------------- 1 | {{ if .includeTop }} 2 |
    3 | {{ $active := eq .top .current }} 4 | 13 |
14 | {{ else }} 15 | {{- template "nav-children" (dict "Section" .top "CurrentPage" .current "isDropdown" false "recurseLevel" 0) -}} 16 | {{ end }} 17 | 18 | {{- define "nav-children" -}}{{- /* (dict "Section" .Section "CurrentPage" .CurrentPage) */ -}} 19 | {{ $CurrentSection := .Section }} 20 | {{ $CurrentPage := .CurrentPage }} 21 | {{ $current := or (.CurrentPage.IsDescendant .Section) (.CurrentPage.InSection .Section) }} 22 | 23 |
    34 | {{- range .Section.Pages -}} 35 | {{ $is_sibling := or (.IsAncestor $CurrentPage) ($CurrentSection.IsAncestor $CurrentPage) }} 36 | {{ $random := delimit (shuffle (split (md5 "foo") "" )) "" }} 37 | {{ $open_by_default := ($CurrentPage.IsDescendant .) }} 38 | {{ if not .Params.hidden }} 39 | 49 | {{ end }} 50 | {{- end -}} 51 |
52 | {{- end -}} 53 | 54 | {{ define "nav-link" }}{{/* (dict "Page" .Page "CurrentPage" .CurrentPage "parent" .isParent "isParent" .isSibling .isCurrent) */}} 55 | {{ $current := eq .CurrentPage .Page }} 56 | {{ if .isParent }} 57 | 65 | 67 | 68 | 69 | {{ else }} 70 | 73 | {{ .Page.Title | strings.FirstUpper | safeHTML }} 74 | 75 | {{ end }} 76 | {{ end }} 77 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/offcanvas-nav.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{ print .top.Title }}
4 | 5 |
6 |
7 | {{ partial "navigation.html" . }} 8 |
9 |
10 | 11 | 12 | 13 | {{- .Page.Store.Set "hasSectionNav" true -}} 14 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/prev-next.html: -------------------------------------------------------------------------------- 1 | {{ if or .PrevInSection .NextInSection }} 2 |
3 | 10 | 11 | 18 |
19 | {{ end }} 20 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/related_posts.html: -------------------------------------------------------------------------------- 1 | {{ $related := .Site.RegularPages.Related . | first 4 }} 2 | {{ with $related }} 3 | 14 | {{ end }} 15 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/rss.html: -------------------------------------------------------------------------------- 1 | {{ with .OutputFormats.Get "rss" -}} 2 | 3 | 4 | 5 | {{ end }} 6 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/script.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | {{ $ff_js := resources.Get "js/fifty-fifty.js" }} 10 | {{ $bt_js := resources.Get "js/bootstrap.bundle.js" }} 11 | {{ $script := resources.Get "js/scripts.js" }} 12 | {{ $fuse := resources.Get "js/fuse.js" }} 13 | {{ $srch := resources.Get "js/search.js" }} 14 | {{ $js := slice $ff_js $bt_js $script $fuse $srch | resources.Concat "js/bundle.js" | minify | fingerprint }} 15 | 16 | 17 | 18 | {{ if .Page.Store.Get "hasMermaid" }} 19 | {{- /* $mermaid := resources.Get "js/mermaid.min.js" }} 20 | 21 | 26 | {{ */ -}} 27 | 34 | {{ end }} 35 | 36 | {{ if .Params.latex}} 37 | 75 | 76 | 77 | 79 | {{ end }} 80 | 81 | 82 | 88 | 93 | 94 | 95 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/search.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Search
4 | 5 |
6 |
7 |
8 | 9 | 12 |
13 |

You can also ask Chantal, the AI search engine.

14 |
15 |
16 |
17 | 18 | 28 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/sidebar-nav.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/social.html: -------------------------------------------------------------------------------- 1 | 62 | -------------------------------------------------------------------------------- /themes/ansel/layouts/partials/toc.html: -------------------------------------------------------------------------------- 1 | {{ if (ne .TableOfContents "") }} 2 |
3 |
{{ i18n "onthispage" }}
4 | {{ .TableOfContents }} 5 |
6 | {{ end }} 7 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/advice.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/button.html: -------------------------------------------------------------------------------- 1 | {{ $icon := .Get "icon" }} 2 | {{ $url := .Get "url" }} 3 | {{ $data := .Get "data" }} 4 | {{ if $icon }} 5 | {{ if $url }} 6 | {{ .Get "label" }} 7 | {{ else }} 8 | 9 | {{ end }} 10 | {{ else }} 11 | {{ .Get "label" }} 12 | {{ end }} 13 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/calcom.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ $code := printf ` 4 | Cal("init", "%s", {origin:"https://cal.com"}); 5 | Cal.ns["%s"]("inline", { 6 | elementOrSelector:"#%s", 7 | config: {"layout":"month_view"}, 8 | calLink: "%s/%s", 9 | }); 10 | Cal.ns["%s"]("ui", {"hideEventTypeDetails":false,"layout":"month_view","theme":"light"}); 11 | ` (.Get 1) (.Get 1) (.Get 1) (.Get 0) (.Get 1) (.Get 1) 12 | }} 13 | 14 | {{ .Page.Scratch.Set "calcom" $code }} 15 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/card.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 |
{{ .Get "title" }}
8 |
{{ .Inner }}
9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/column.html: -------------------------------------------------------------------------------- 1 | {{ $p := .Page }} 2 | {{ .Page.Scratch.Set "columns" (.Get "cols" | default 2 ) }} 3 |
4 | {{ .Inner | $p.RenderString }} 5 |
6 | {{ .Page.Scratch.Delete "columns" }} 7 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/compare.html: -------------------------------------------------------------------------------- 1 | {{ $p := .Page }} 2 | {{ .Page.Scratch.Set "columns" (.Get "cols" | default 0 ) }} 3 | 4 | {{ if .IsNamedParams }} 5 | {{ $random := delimit (shuffle (split (md5 (.Get "after") ) "" )) "" }} 6 | 7 | {{ $after := partial "get_resource.html" (dict "src" (.Get "after") "Page" .Page ) }} 8 | {{ $before := partial "get_resource.html" (dict "src" (.Get "before") "Page" .Page ) }} 9 | {{ $sizes := partial "get_sizes.html" (dict "class" (.Get "class") "Page" .Page ) }} 10 | 11 |
12 | 15 |
16 |
17 | {{ i18n "after" }} 18 | {{ i18n 19 |
20 |
21 | {{ i18n "before" }} 22 | {{ i18n 23 |
24 |
25 | 26 | {{ with .Inner }} 27 |
28 | {{ . | $p.RenderString }} 29 |
30 | {{ end}} 31 | 32 |
33 | {{ end }} 34 | 35 | {{ .Page.Scratch.Delete "columns" }} 36 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/container.html: -------------------------------------------------------------------------------- 1 |
2 | {{ .Inner | markdownify }} 3 |
4 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/danger.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/divider.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/figure.html: -------------------------------------------------------------------------------- 1 | {{ $caption := "" }} 2 | {{ if not $caption }} 3 | {{ $caption = .Get "caption" }} 4 | {{ end }} 5 | {{ if not $caption }} 6 | {{ with .Inner }} 7 | {{ $caption = . }} 8 | {{ end }} 9 | {{ end }} 10 | {{ partial "image.html" (dict "Page" .Page "Src" (.Get "src") "Caption" $caption "Width" (.Get "width") "Height" (.Get "height") "Class" (.Get "class") "Style" (.Get "style") ) }} 11 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/gallery.html: -------------------------------------------------------------------------------- 1 | {{ $has_caption := false }} 2 | {{ with .Get "caption" }} 3 | {{ $has_caption = true }} 4 | {{ end }} 5 | {{ $p := .Page }} 6 | {{ $cols := int (.Get "cols") }} 7 | {{ .Page.Scratch.Set "columns" $cols }} 8 | 12 | {{ .Page.Scratch.Delete "columns" }} 13 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/note.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/quote.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{ .Inner | markdownify }} 4 | {{ with .Get "author" }}— {{ . | markdownify }}{{ end }} 5 |
6 |
7 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/row.html: -------------------------------------------------------------------------------- 1 | {{ $p := .Page }} 2 |
3 | {{ .Inner | $p.RenderString }} 4 |
5 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/slideshow.html: -------------------------------------------------------------------------------- 1 | 26 | 27 |
28 | {{ $p := .Page }} 29 | {{ $i := 0 }} 30 | {{ range split (.Get "images") "," }} 31 | {{ $i = add $i 1 }} 32 | {{ $image := partial "get_resource.html" (dict "src" . "Page" $p ) }} 33 | {{ $srcset := partial "get_srcset.html" $image }} 34 |
35 | image 40 |
41 | 44 | {{ end }} 45 | 50 | 55 |
56 | 57 | 60 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/table.html: -------------------------------------------------------------------------------- 1 | {{ $htmlTable := .Inner | markdownify }} 2 | {{ $old := "" }} 3 | {{ $new := "
" }} 4 | {{ $htmlTable := replace $htmlTable $old $new }} 5 | 6 | {{ $old := "" }} 7 | {{ $new := "" }} 8 | {{ $htmlTable := replace $htmlTable $old $new }} 9 | 10 |
11 | {{ $htmlTable | safeHTML }} 12 |
13 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/testimonial.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 |
{{ .Get "name" }}
7 | {{ .Get "location" }} 8 | {{ if .Get "url" }} 9 | — {{ trim (.Get "url") "https://" }} 10 | {{ end }} 11 |
12 |
13 |
14 |
15 | {{ .Inner }} 16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/translators.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Translated from English by : 4 | {{ .Inner | replaceRE `[, ]*?(?:$|\n)` "" }}. 5 | In case of conflict, inconsistency or error, the English version shall prevail. 6 |
7 | -------------------------------------------------------------------------------- /themes/ansel/layouts/shortcodes/warning.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /themes/ansel/static/.htmltest.yml: -------------------------------------------------------------------------------- 1 | DirectoryPath: "./public/artifact" 2 | IgnoreURLs: 3 | # Ignore HTML template for search - (url) is replaced client-side by JS 4 | - "(url)" 5 | # Don't check social networks 6 | - "https://www.instagram.com/photo.aurelienpierre/" 7 | # My cloud forbids bots 8 | - "https://cloud.apmlt.net/s/YAdfYajPkE5nLyW" 9 | # Science-y portal refuses bots 10 | - "https://doi.org/10.1002/col.20128" 11 | - "https://doi.org/10.1364/OE.25.015131" 12 | -------------------------------------------------------------------------------- /themes/ansel/static/book-solid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /themes/ansel/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/favicon.png -------------------------------------------------------------------------------- /themes/ansel/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/logo.png -------------------------------------------------------------------------------- /themes/ansel/static/logo_128x128.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/logo_128x128.ico -------------------------------------------------------------------------------- /themes/ansel/static/logo_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/logo_128x128.png -------------------------------------------------------------------------------- /themes/ansel/static/logo_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/logo_text.png -------------------------------------------------------------------------------- /themes/ansel/static/paint-roller-solid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /themes/ansel/static/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aurelienpierreeng/ansel-website/5167f3330288a9bde01e45ea711ac7af3feb7eb6/themes/ansel/static/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /themes/ansel/theme.toml: -------------------------------------------------------------------------------- 1 | # theme.toml template for a Hugo theme 2 | # See https://github.com/gohugoio/hugoThemes#themetoml for an example 3 | 4 | name = "ansel" 5 | license = "Copyright" 6 | description = "" 7 | homepage = "https://ansel.photos" 8 | tags = [] 9 | features = [] 10 | min_version = "0.98.0" 11 | 12 | [author] 13 | name = "Aurélien Pierre" 14 | homepage = "https://aurelienpierre.com" 15 | -------------------------------------------------------------------------------- /tools/auto-translate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Update translations from .md file, translate through ChatGPT, validate translations and build .md files, all in one. 4 | # Call with LANG code, like `sh tools/auto-translate.sh de` from repository folder 5 | 6 | # Refresh .pot and .po from English .md 7 | ./tools/update-translations.sh 8 | 9 | # Auto-translate .po 10 | python ./tools/chatgpt-translate.py $1 11 | 12 | # Validate auto-translated .po 13 | ./tools/update-translations.sh 14 | 15 | # Build the translated .md 16 | ./tools/build-translations.sh --add 17 | 18 | # Check that hugo has proper syntax in translated .md 19 | hugo 20 | -------------------------------------------------------------------------------- /tools/build-translations.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Requires po4a version 0.58 or higher. 3 | 4 | # go to project root 5 | PROJECT_ROOT="$(cd `dirname $0`/..; pwd -P)" 6 | cd "$PROJECT_ROOT" 7 | 8 | set -e 9 | 10 | # Is po4a installed? 11 | if ! which po4a; then 12 | echo "ERROR: Install po4a from your package manager." 13 | exit 1 14 | fi 15 | 16 | # Get the config file 17 | po4a_conf="po/po4a.conf" 18 | if ! test -f $po4a_conf || [ ! -s $po4a_conf ]; then 19 | echo "The file $po4a_conf is empty or don't exist. Run `./tools/update-translations.sh` first" 20 | exit 1 21 | fi 22 | 23 | # Get the mode 24 | mode="undef" 25 | 26 | if [ "$1" = "--add" ]; then 27 | mode="add" 28 | elif [ "$1" = "--remove" ]; then 29 | mode="remove" 30 | else 31 | echo "This script needs to be called with either --add or --remove arguments" 32 | exit 1 33 | fi 34 | 35 | # Always remove all languages translations in case the set of disabled languages has changed 36 | echo "Removing translations for all languages" 37 | po4a --rm-translations --no-update --no-translations --verbose "$po4a_conf" 38 | 39 | # get list of target languages minus disabled ones 40 | disabled_languages=$(cat "po/disable-languages") 41 | for lang in `find po -name '*.po' | cut -d . -f 2 | sort -u`; do 42 | if [[ ! $disabled_languages == *$lang* ]]; then 43 | languages="$languages $lang" 44 | fi 45 | done 46 | 47 | # Update the languages line in config to only contain supported languages 48 | sed -i "/\[po4a_langs\].*/c\[po4a_langs] $languages" $po4a_conf 49 | 50 | # Generate only the target languages 51 | if [ "$mode" = "add" ]; then 52 | echo "Generating translations for $languages" 53 | po4a --keep 0 --no-update --verbose "$po4a_conf" 54 | fi 55 | -------------------------------------------------------------------------------- /tools/build_page_contributors.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # build_page_contributors.sh 3 | # 4 | # Example: 5 | # ./build_page_contributors.sh docs/about.adoc footers/about.add po/fr.po po/es.po po/de.po 6 | # 7 | # For the *same* source page (about.adoc in this example) you typically have one 8 | # PO file per language. This helper gathers every 9 | # "# TRANSLATOR Name " 10 | # comment across all those POs, deduplicates the names and writes a single 11 | # addendum that po4a can splice into **every** translated output. 12 | # 13 | # ──────────────────────────────────────────────────────────────────────────── 14 | # Usage in a Makefile (sketch): 15 | # 16 | # PAGE := about.adoc 17 | # ADDEND := footers/$(basename $(PAGE)).add 18 | # POFILES:= $(wildcard po/*/$(basename $(PAGE)).po) 19 | # 20 | # $(ADDEND): $(POFILES) build_page_contributors.sh 21 | # ./build_page_contributors.sh $(PAGE) $@ $(POFILES) 22 | # 23 | # [type: asciidoc] 24 | # docs/$(PAGE) $lang:build/$(PAGE:%.adoc=%).$lang.adoc add_$lang:?@$(ADDEND) 25 | # --------------------------------------------------------------------------- 26 | 27 | # go to project root 28 | PROJECT_ROOT="$(cd `dirname $0`/..; pwd -P)" 29 | cd "$PROJECT_ROOT" 30 | 31 | set -euo pipefail 32 | 33 | master_doc=$1 # shown in the comment of the footer 34 | addendum=$2 35 | shift 2 || { echo "Usage: $0 " >&2; exit 1; } 36 | po_files=("$@") 37 | 38 | if [ ${#po_files[@]} -eq 0 ]; then 39 | echo "No .po files supplied" >&2 40 | exit 1 41 | fi 42 | 43 | # Ensure the directory for the addendum exists 44 | mkdir -p "$(dirname "$addendum")" 45 | 46 | # ──────────────────────────────────────────────────────────────────────────── 47 | # 1. Try explicit `# TRANSLATOR …` tags 48 | readarray -t contributors < <( 49 | grep -Eho '^# TRANSLATOR .*$' "${po_files[@]}" \ 50 | | sed 's/^# TRANSLATOR[[:space:]]*//' \ 51 | | sort -u) 52 | 53 | # 2. Fallback → Last‑Translator header (name only) 54 | if [ ${#contributors[@]} -eq 0 ]; then 55 | mapfile -t contributors < <( 56 | grep -Eho '^"Last-Translator:[^"\\]+' "${po_files[@]}" | 57 | sed -E 's/^"Last-Translator:[[:space:]]*//' | 58 | sed -E 's/[[:space:]]*<[^>]*>//' | 59 | sed -E 's/\\n$//' | 60 | sed -E 's/[[:space:]]+$//' | 61 | sort -u 62 | ) 63 | fi 64 | 65 | # 3. Nothing → write header-only addendum so po4a 0.69 is happy. 66 | if [ ${#contributors[@]} -eq 0 ]; then 67 | { 68 | echo 'PO4A-HEADER: mode=eof' 69 | echo '' 70 | } > "$addendum" 71 | exit 0 72 | fi 73 | 74 | # Join contributors with , 75 | joined=$(printf '%s, ' "${contributors[@]}") 76 | # Remove the trailing , 77 | joined=${joined%, } 78 | 79 | # ──────────────────────────────────────────────────────────────────────────── 80 | # Write the footer. Each translator ends up on its own line (
) so the 81 | # list keeps formatting in HTML, AsciiDoc, Markdown, POD (etc.). 82 | { 83 | echo "PO4A-HEADER: mode=eof" 84 | printf '\n\n' 85 | printf '\n' "$master_doc" 86 | printf '{{< translators >}}\n' 87 | printf '%s' "$joined" 88 | printf '\n{{}}\n' 89 | } > "$addendum" 90 | -------------------------------------------------------------------------------- /tools/clean-translations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Clean-up translations generated by ChatGPT or other AI translators, namely: 3 | 4 | - ensure double quotes delimiting Gettext strings are not escaped, 5 | - ensure double quotes within Gettext strings are escaped, 6 | - ensure newline characters match between msgid and msgstr. 7 | 8 | This deals with the fact that AI translators are wonky when it comes to properly 9 | handle formatting. 10 | 11 | Usage: 12 | `python tools/clean-translations.py po/content.LANG.po`. 13 | 14 | Notes: 15 | - creates a backup of the original file, 16 | - doesn't deal with all corner cases but significantly reduces manual corrections. 17 | 18 | Copyright © Aurélien Pierre - 2025. 19 | 20 | """ 21 | 22 | import sys 23 | import regex as re 24 | 25 | FILE = sys.argv[1] 26 | 27 | content = "" 28 | 29 | # Select single- or multiple-line Gettext strings, discarding comments 30 | dq_line = re.compile( 31 | r'^(?:msgid|msgstr) (.*)$' 32 | r'|^(?!#)(.+)$', re.MULTILINE, 33 | ) 34 | 35 | lines = re.compile(r'"(.+)"') 36 | 37 | def cleanup_quotes(line: str) -> str: 38 | # Brutally remove all enclosing (final/terminal) quotes, whether escaped or not 39 | new_line = line.strip('\"\\"') 40 | 41 | # In case we have a mix of escaped and unescaped double quotes, in the line inner content, 42 | # brutally unescape all of them, and then re-escape them all. 43 | # This prevents double escaping or special/contextual handling preventing it. 44 | new_line = new_line.replace('\\"', '"').replace('"', '\\"') 45 | 46 | # Enclose the final result within non-espaced double quotes 47 | return f'"{new_line}"' 48 | 49 | 50 | with open(FILE, "r") as f: 51 | content = f.read() 52 | 53 | with open(FILE + ".bck", "w") as f: 54 | f.write(content) 55 | 56 | # Ensure initial and terminal double quote are unescaped, but internal double quotes are 57 | for item in content.split("\n\n"): 58 | for line in [line[0] or line[1] for line in dq_line.findall(item)]: 59 | if content.find(line) > -1: 60 | content = content.replace(line, cleanup_quotes(line)) 61 | else: 62 | print("not found:", line) 63 | 64 | # Ensure each translated line ends with \n if original ends with one, 65 | # and the other way around. 66 | for item in content.split("\n\n"): 67 | # Split original and translation lines 68 | groups = re.split(r'(?:msgid|msgstr)', item) 69 | 70 | # groups[0] = .po comments 71 | original = lines.findall(groups[1]) 72 | translation = lines.findall(groups[2]) 73 | 74 | # Replace line by line 75 | for o, t in zip(original, translation): 76 | if o.endswith("\\n") and not t.endswith("\\n"): 77 | print("replacing", t) 78 | content = content.replace(t, t + "\\n") 79 | elif not o.endswith("\\n") and t.endswith("\\n"): 80 | print("replacing", t) 81 | content = content.replace(t, t.strip("\\n")) 82 | 83 | 84 | with open(FILE, "w") as f: 85 | f.write(content + "\n") 86 | -------------------------------------------------------------------------------- /tools/merge-translations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Read source code translations and init the documentation translations 3 | where we find exact matches for `msgid` fields. 4 | 5 | Call with `python tools/merge-translations.py path/to/sourcecode path/to/doc`. 6 | We assume both directories contain an immediate `po/` subdirectory. 7 | 8 | Copyright (c) Aurélien Pierre - 2025 9 | """ 10 | 11 | import regex as re 12 | import glob 13 | import sys 14 | import os 15 | 16 | SOURCE = os.path.join(sys.argv[1], "po") 17 | LANG = sys.argv[2] 18 | 19 | entry_pattern = re.compile(r"((?:#: \S+?\n)+)#, no-wrap\n(?:#~ )?msgid ((?:\"[\s\S]*?\"\n)+)(?:#~ )?msgstr ((?:\"[\s\S]*?\"\n)+)") 20 | file_pattern = re.compile(rf"(?:#: (\S+?)(\.{LANG})?\.md:(\d+)\n)") 21 | 22 | 23 | sourcecode: dict 24 | content : str 25 | with open(os.path.join(SOURCE, f'content.{LANG}.po'), "r") as f: 26 | content = f.read() 27 | sourcecode = { line: [match[1], match[2]] 28 | for match in entry_pattern.findall(content) 29 | for line in file_pattern.findall(match[0]) } 30 | 31 | for key, value in sourcecode.items(): 32 | # If translated string is empty for non-default language 33 | if key[1] == "" and len(sourcecode[key][1]) < 4: 34 | found = False 35 | 36 | # First sweep: look for exact matches 37 | for i in range(-30, 30): 38 | new_key = (key[0], f".{LANG}", str(int(key[2]) + i)) 39 | 40 | # Found the n-th closest line in non-translated file 41 | # from the current translated file line and its translation is empty 42 | if new_key in sourcecode: 43 | # Found exact match: no brainer 44 | if(sourcecode[key] == sourcecode[new_key]): 45 | template_source = "msgid " + sourcecode[key][0] + "msgstr " + sourcecode[key][1] 46 | template_destin = "msgid " + sourcecode[key][0] + "msgstr " + sourcecode[key][0] 47 | if(content.find(template_source) > 1): 48 | content = content.replace(template_source, template_destin) 49 | print("replaced:") 50 | print(template_destin) 51 | print("") 52 | else: 53 | # Should not happen 54 | print("problem on", template_source) 55 | 56 | found = True 57 | break 58 | 59 | # Move on to next translation ? 60 | if found: 61 | continue 62 | 63 | # Second sweep: no exact matches, look increasingly further and ask user 64 | i = 0 65 | ping = True 66 | while not found and abs(i) < 30: 67 | print(i) 68 | new_key = (key[0], f".{LANG}", str(int(key[2]) + i)) 69 | 70 | if ping: 71 | sign = -1 if i < 0 else 1 72 | i = (abs(i) + 1) * sign 73 | ping = False 74 | else: 75 | i = i * (-1) 76 | ping = True 77 | 78 | # Found the n-th closest line in non-translated file 79 | # from the current translated file line and its translation is empty 80 | if new_key in sourcecode: 81 | os.system('clear') 82 | print("IS", key) 83 | print("") 84 | print(sourcecode[key][0]) 85 | print("TRANSLATED BY:", new_key) 86 | print("") 87 | print(sourcecode[new_key][0]) 88 | 89 | response = input("Y(es) / N(o) / A(bort) / C(opy) / Q(uit) ?").lower() 90 | 91 | if response == "y": 92 | template_source = "msgid " + sourcecode[key][0] + "msgstr " + sourcecode[key][1] 93 | template_destin = "msgid " + sourcecode[key][0] + "msgstr " + sourcecode[new_key][0] 94 | if(content.find(template_source) > 1): 95 | content = content.replace(template_source, template_destin) 96 | print("replaced:") 97 | print(template_destin) 98 | print("") 99 | else: 100 | # Should not happen 101 | print("problem on", template_source) 102 | 103 | found = True 104 | 105 | elif response == "c": 106 | # Copy original, untranslated content, for example if it's code or markup 107 | template_source = "msgid " + sourcecode[key][0] + "msgstr " + sourcecode[key][1] 108 | template_destin = "msgid " + sourcecode[key][0] + "msgstr " + sourcecode[key][0] 109 | if(content.find(template_source) > 1): 110 | content = content.replace(template_source, template_destin) 111 | print("replaced:") 112 | print(template_destin) 113 | print("") 114 | else: 115 | # Should not happen 116 | print("problem on", template_source) 117 | 118 | found = True 119 | 120 | elif response == "a": 121 | break 122 | elif response == "n": 123 | continue 124 | elif response == "q": 125 | with open(os.path.join(SOURCE, f'content.{LANG}.po'), "w") as f: 126 | f.write(content) 127 | exit(0) 128 | else: 129 | exit(1) 130 | 131 | 132 | with open(os.path.join(SOURCE, f'content.{LANG}.po'), "w") as f: 133 | f.write(content) 134 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | deep-translator 2 | deep-translator[ai] 3 | regex 4 | -------------------------------------------------------------------------------- /tools/update-translations.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Requires po4a version 0.58 or higher. 3 | 4 | # go to project root 5 | PROJECT_ROOT="$(cd `dirname $0`/..; pwd -P)" 6 | cd "$PROJECT_ROOT" 7 | 8 | set -e 9 | 10 | # Is po4a installed? 11 | if ! which po4a; then 12 | echo "ERROR: Install po4a from your package manager." 13 | exit 1 14 | fi 15 | 16 | # Aggregate available .po files 17 | for lang in `find po -name '*.po' | cut -d . -f 2 | sort -u`; do 18 | languages="$languages $lang" 19 | done 20 | 21 | # Create a blank conf file 22 | po4a_conf="po/po4a.conf" 23 | touch $po4a_conf 24 | > $po4a_conf 25 | 26 | # Populate languages with what we found in po/ folder 27 | echo "[po4a_langs] $languages" >> $po4a_conf 28 | echo "[po4a_paths] po/content.pot \$lang:po/content.\$lang.po" >> $po4a_conf 29 | 30 | # Parsing options 31 | # opt:"--option neverwrap" and opt:"--option nobullets" ensure Markdown bullet lists don't get separated by an extra newline that would break them 32 | cat >> $po4a_conf <> $po4a_conf 78 | fi 79 | fi 80 | 81 | done 82 | 83 | # Update .pot and .po content with fresh .md files 84 | po4a --verbose --previous --no-translations --rm-translations "$po4a_conf" 85 | --------------------------------------------------------------------------------