mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-22 18:22:26 +00:00
Merge PR #297
This commit is contained in:
7 files changed
+231
-1
No files matched your search
@@ -11,6 +11,7 @@ covers a whole directory), or if a licence file referenced in the Licence column
|
||||
| `assets/fonts/Inter-*.ttf` (Regular, Medium, SemiBold) | Inter | Rasmus Andersson | https://github.com/rsms/inter | SIL Open Font License 1.1 (`assets/fonts/OFL-Inter.txt`) | 2026-09-30 | none |
|
||||
| `assets/app-icon/` (`lightcraft.svg` and the PNG/ICNS/ICO/SVG files derived from it) | LightCraft app icon (lynx) | LightCraft project owner (drawn in ArtCraft) | original work (vectorised from the owner's drawing; see `assets/app-icon/README.md`) | MIT OR Apache-2.0 (`assets/app-icon/LICENSE.txt`) | 2026-10-02 | vectorised to SVG; rendered to PNG/ICNS/ICO by `packaging/icons.sh` |
|
||||
| `assets/camera-profiles/*.json` | Camera colour profiles (matrix + hue/saturation/value table), built into LightCraft | ILCE-7M4: Harald Hoyer | original work: fitted by `lightcraft-cli calibrate` to the contributor's own raw photos and their in-camera JPEGs (597 ILCE-7M4 photos, 2026); aggregate colour statistics only, no image content; no Adobe or third-party profile data | MIT OR Apache-2.0 | 2026-10-07 | none |
|
||||
| `packaging/macos/dmg/` (`background.svg`, the `background.tiff` rendered from it by `generate.py`, and the `dmg-layout.DS_Store` layout file) | LightCraft macOS DMG window background | @XusBadia | original work for this repository, derived from the LightCraft app icon (`assets/app-icon/lightcraft.svg`, referenced via `<image>`, not copied); text is outlined Inter / JetBrains Mono glyph paths | MIT OR Apache-2.0 | 2026-10-08 | none (original); used for the Finder window of the macOS DMG, `packaging/macos/dmg/generate.py` renders it to `background.tiff` |
|
||||
| `crates/scenes/` (generated images) | Procedural demo photographs | LightCraft contributors | original work (generated at runtime, no source imagery) | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
||||
| `crates/ui-egui/src/icons.rs` | UI icons drawn as vector paths in code | LightCraft contributors | original work | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
||||
| `docs/images/*-tetons.jpg`, `docs/images/grid-pd.jpg` (screenshots containing it) | "The Tetons and the Snake River" | Ansel Adams (1942), U.S. National Archives | https://commons.wikimedia.org/wiki/File:Adams_The_Tetons_and_the_Snake_River.jpg | Public domain (U.S. federal government work) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# macOS DMG window
|
||||
|
||||
What Finder shows when the DMG opens: a 660 × 400 pt background with the app icon and the
|
||||
`Applications` link side by side. `package.sh` copies these files into the image; nothing here is
|
||||
generated at build time, so the DMG still builds with `hdiutil makehybrid` (no mounted device, no
|
||||
Finder scripting on CI, nothing extra installed in the signing job).
|
||||
|
||||
| File | What |
|
||||
|---|---|
|
||||
| `background.svg` | Source of the background: the app icon (`assets/app-icon/lightcraft.svg`, linked, not copied) cropped as a cover on the LightCraft colour field (`#f2a516`), Ink and Paper. Its text (Inter, JetBrains Mono) is outlined, so rendering it needs no fonts. |
|
||||
| `background.tiff` | The background at 1x (660 × 400 px, 72 dpi) and 2x (1320 × 800 px, 144 dpi) in one HiDPI TIFF (Deflate, sRGB). Goes to `.background/background.tiff`. |
|
||||
| `dmg-layout.DS_Store` | Finder's view settings for the volume: window size, icon size 128, LightCraft.app at (326, 205), `Applications` at (574, 205), and the background. Goes to `.DS_Store` in the image; named so it isn't mistaken for (or ignored like) a Finder-generated `.DS_Store`. |
|
||||
| `generate.py` | Writes `background.tiff` and `dmg-layout.DS_Store` from the SVG and the layout above. |
|
||||
|
||||
## The volume name has no version
|
||||
|
||||
The mounted volume is called `LightCraft`, not `LightCraft <version>`. The layout points at the background
|
||||
through an alias that includes the volume name, and Finder resolves it by that name: with a
|
||||
versioned name the window keeps its size and icon positions but shows no background (tested).
|
||||
The DMG file name (`lightcraft-<version>-macos-<arch>.dmg`) still carries the version.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Finder draws the icon labels in black in light and dark mode** when a window has a background,
|
||||
so the area under both icons stays light (Paper).
|
||||
- **Nothing goes inside the icon boxes:** artwork keeps 10 pt clear of each 128 pt icon box and of
|
||||
the label strip under it.
|
||||
|
||||
## Regenerate
|
||||
|
||||
Edit `background.svg` (or the layout constants in `generate.py`), then run, on any OS:
|
||||
|
||||
```sh
|
||||
pip install 'pillow>=12' ds_store==1.3.3 mac_alias==2.2.3
|
||||
python3 packaging/macos/dmg/generate.py # needs resvg on PATH
|
||||
```
|
||||
|
||||
Both outputs are byte-for-byte reproducible and carry nothing from the machine that ran it: the
|
||||
SVG renders without any fonts, and `dmg-layout.DS_Store` is written from scratch, its background
|
||||
alias holding only the volume name and `/.background/background.tiff`. If you add text to the SVG,
|
||||
outline it (`usvg` from resvg converts text to paths). The window is 660 × 432 with Finder's 32 pt
|
||||
title bar; the content area is 660 × 400.
|
||||
|
||||
This follows VectorCraft's `packaging/macos/dmg/` (storytold/vectorcraft#493).
|
||||
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="660" height="400" viewBox="0 0 660 400">
|
||||
<defs><clipPath id="panel"><rect width="232" height="400"/></clipPath><pattern id="hatch" width="2.6" height="2.6" patternUnits="userSpaceOnUse" patternTransform="rotate(-38)">
|
||||
<rect width="2.6" height="1.05" fill="#0b0b0c"/></pattern><filter id="grain" x="0" y="0" width="100%" height="100%">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" seed="7"/>
|
||||
<feColorMatrix values="0 0 0 0 0.04 0 0 0 0 0.04 0 0 0 0 0.05 0.5 0 0 0 -0.225"/>
|
||||
</filter></defs>
|
||||
|
||||
<rect width="660" height="400" fill="#efe9dc"/><rect width="660" height="400" filter="url(#grain)"/>
|
||||
<g clip-path="url(#panel)"><rect width="232" height="400" fill="#f2a516"/><g transform="translate(-134.0,-40.0) scale(1.0)"><image href="../../../assets/app-icon/lightcraft.svg" width="512" height="512"/></g></g>
|
||||
<line x1="232.5" y1="0" x2="232.5" y2="400" stroke="#0b0b0c" stroke-width="1.2"/>
|
||||
<line x1="236.5" y1="0" x2="236.5" y2="400" stroke="#0b0b0c" stroke-width="0.5"/>
|
||||
|
||||
<line x1="267" y1="88.5" x2="624" y2="88.5" stroke="#0b0b0c" stroke-width="0.6"/>
|
||||
<path d="M271.5,81.5 L276,88.5 L271.5,95.5 L267,88.5 Z" fill="#f2a516"/>
|
||||
|
||||
<line x1="408" y1="205" x2="478" y2="205" stroke="#0b0b0c" stroke-opacity="0.35" stroke-width="3" stroke-linecap="round"/><line x1="408" y1="205" x2="474" y2="205" stroke="#f2a516" stroke-width="3" stroke-linecap="round"/><line x1="408" y1="214" x2="408" y2="218" stroke="#0b0b0c" stroke-width="0.7"/><line x1="419" y1="214" x2="419" y2="218" stroke="#0b0b0c" stroke-width="0.7"/><line x1="430" y1="214" x2="430" y2="218" stroke="#0b0b0c" stroke-width="0.7"/><line x1="441" y1="214" x2="441" y2="218" stroke="#0b0b0c" stroke-width="0.7"/><line x1="452" y1="214" x2="452" y2="218" stroke="#0b0b0c" stroke-width="0.7"/><line x1="463" y1="214" x2="463" y2="218" stroke="#0b0b0c" stroke-width="0.7"/><line x1="474" y1="214" x2="474" y2="218" stroke="#0b0b0c" stroke-width="0.7"/><circle cx="474" cy="205" r="7" fill="#efe9dc" stroke="#0b0b0c" stroke-width="1.6"/><path d="M484,199 L492,205 L484,211" fill="none" stroke="#0b0b0c" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<line x1="267" y1="335.5" x2="624" y2="335.5" stroke="#0b0b0c" stroke-width="0.6"/>
|
||||
|
||||
|
||||
<g id="text">
|
||||
<g>
|
||||
<path fill="#0b0b0c" stroke="none" d="M 268.19727 72 L 268.19727 50.17383 L 272.1084 50.17383 L 272.1084 68.7041 L 281.74707 68.7041 L 281.74707 72 Z M 284.48438 72 L 284.48438 55.623047 L 288.29297 55.623047 L 288.29297 72 Z M 286.38867 53.308594 Q 285.48047 53.308594 284.8286 52.700684 Q 284.17676 52.092773 284.17676 51.213863 Q 284.17676 50.34961 284.8286 49.7417 Q 285.48047 49.13379 286.38867 49.13379 Q 287.31152 49.13379 287.96338 49.7417 Q 288.61523 50.34961 288.61523 51.213863 Q 288.61523 52.092773 287.96338 52.700684 Q 287.31152 53.308594 286.38867 53.308594 Z M 298.89648 78.47461 Q 295.9375 78.47461 294.1504 77.390625 Q 292.36328 76.30664 291.74805 74.680664 L 294.9707 73.52344 Q 295.35156 74.22656 296.22314 74.90039 Q 297.09473 75.57422 298.88184 75.57422 Q 300.6543 75.57422 301.72363 74.74658 Q 302.79297 73.918945 302.79297 72.16113 L 302.79297 69.07031 L 302.4707 69.07031 Q 302.17773 69.65625 301.63574 70.28613 Q 301.09375 70.916016 300.18555 71.333496 Q 299.27734 71.75098 297.85645 71.75098 Q 295.98145 71.75098 294.45068 70.864746 Q 292.91992 69.978516 292.01904 68.206055 Q 291.11816 66.43359 291.11816 63.76758 Q 291.11816 61.086914 292.01904 59.219234 Q 292.91992 57.351563 294.458 56.38477 Q 295.9961 55.41797 297.88574 55.41797 Q 299.33594 55.41797 300.27344 55.901367 Q 301.21094 56.38477 301.76758 57.065918 Q 302.32422 57.74707 302.6172 58.33301 L 302.82227 58.33301 L 302.82227 55.623047 L 306.55762 55.623047 L 306.55762 72.043945 Q 306.55762 74.24121 305.56152 75.66211 Q 304.56543 77.08301 302.8369 77.77881 Q 301.1084 78.47461 298.89648 78.47461 Z M 298.92578 68.74805 Q 300.78613 68.74805 301.79688 67.41504 Q 302.80762 66.08203 302.80762 63.73828 Q 302.80762 61.409176 301.81152 59.980957 Q 300.81543 58.552734 298.92578 58.552734 Q 296.9922 58.552734 296.00342 60.032227 Q 295.01465 61.511723 295.01465 63.73828 Q 295.01465 66.00879 296.01074 67.37842 Q 297.00684 68.74805 298.92578 68.74805 Z M 313.90918 62.405273 L 313.90918 72 L 310.1006 72 L 310.1006 50.17383 L 313.8506 50.17383 L 313.8506 58.655273 Q 315.34473 55.41797 318.8164 55.41797 Q 321.3506 55.41797 322.88867 57.0293 Q 324.42676 58.640625 324.42676 61.58496 L 324.42676 72 L 320.60352 72 L 320.60352 62.170902 Q 320.60352 60.530273 319.7539 59.592777 Q 318.9043 58.655273 317.41016 58.655273 Q 315.88672 58.655273 314.89795 59.63672 Q 313.90918 60.618164 313.90918 62.405273 Z M 335.54297 55.623047 L 335.54297 58.61133 L 332.3789 58.61133 L 332.3789 67.38574 Q 332.3789 68.2793 332.75244 68.69678 Q 333.12598 69.11426 334.00488 69.11426 Q 334.26855 69.11426 334.69336 69.04834 Q 335.11816 68.98242 335.39648 68.92383 L 335.99707 71.868164 Q 335.3672 72.05859 334.708 72.13916 Q 334.04883 72.21973 333.44824 72.21973 Q 331.08984 72.21973 329.83008 71.04785 Q 328.5703 69.87598 328.5703 67.70801 L 328.5703 58.61133 L 326.2412 58.61133 L 326.2412 55.623047 L 328.5703 55.623047 L 328.5703 51.726563 L 332.3789 51.726563 L 332.3789 55.623047 Z M 347.53812 72.29297 Q 344.66696 72.29297 342.41113 70.95996 Q 340.15527 69.62695 338.85156 67.12207 Q 337.54785 64.61719 337.54785 61.101563 Q 337.54785 57.571285 338.8589 55.059082 Q 340.16992 52.54688 342.42578 51.213863 Q 344.68164 49.88086 347.53812 49.88086 Q 349.92578 49.88086 351.88135 50.774414 Q 353.83694 51.66797 355.11133 53.359863 Q 356.38574 55.051754 356.7373 57.439453 L 352.79688 57.439453 Q 352.43066 55.50586 350.99512 54.443848 Q 349.55957 53.381836 347.59668 53.381836 Q 344.91602 53.381836 343.19482 55.381344 Q 341.47363 57.38086 341.47363 61.101563 Q 341.47363 64.86621 343.20215 66.8291 Q 344.93066 68.79199 347.582 68.79199 Q 349.54495 68.79199 350.9878 67.72998 Q 352.43066 66.66797 352.79688 64.734375 L 356.75192 64.734375 Q 356.44434 66.8291 355.24316 68.54297 Q 354.042 70.256836 352.0791 71.2749 Q 350.1162 72.29297 347.53812 72.29297 Z M 359.66504 72 L 359.66504 55.623047 L 363.35645 55.623047 L 363.35645 58.362305 L 363.53226 58.362305 Q 363.97168 56.941402 365.07028 56.172363 Q 366.16898 55.40332 367.5752 55.40332 Q 368.30762 55.40332 368.96677 55.50586 L 368.96677 59.006836 Q 368.7324 58.948246 368.20508 58.882324 Q 367.67773 58.816406 367.16504 58.816406 Q 365.56836 58.816406 364.52097 59.805172 Q 363.47363 60.79394 363.47363 62.36133 L 363.47363 72 Z M 375.3662 72.336914 Q 373.8135 72.336914 372.56836 71.77295 Q 371.32324 71.208984 370.60547 70.11035 Q 369.8877 69.01172 369.8877 67.40039 Q 369.8877 65.55469 370.78854 64.53662 Q 371.68948 63.518555 373.11768 63.057125 Q 374.5459 62.595703 376.12793 62.43457 Q 378.26657 62.200195 379.21875 62.00244 Q 380.1709 61.804688 380.1709 60.95508 L 380.1709 60.88184 Q 380.1709 59.680664 379.43848 59.01416 Q 378.70605 58.34766 377.31445 58.34766 Q 375.8789 58.34766 375.0293 58.977543 Q 374.1797 59.607426 373.88672 60.413086 L 370.3564 59.695313 Q 371.07422 57.527344 372.95654 56.472656 Q 374.8389 55.41797 377.2998 55.41797 Q 378.45706 55.41797 379.63623 55.688965 Q 380.81543 55.95996 381.79688 56.597168 Q 382.77832 57.234375 383.37894 58.Line truncated
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#0b0b0c" fill-opacity="0.7" stroke="none" d="M 267.9 112 L 267.9 105.42999 L 271.68 105.42999 L 271.68 106.168 L 268.701 106.168 L 268.701 108.202 L 271.365 108.202 L 271.365 108.922 L 268.701 108.922 L 268.701 111.262 L 271.68 111.262 L 271.68 112 Z M 272.85 112 L 274.60498 109.453 L 272.958 107.05 L 273.912 107.05 L 274.893 108.58 Q 274.956 108.679 275.0145 108.796 Q 275.073 108.913 275.109 108.98499 Q 275.136 108.913 275.1945 108.796 Q 275.253 108.679 275.31598 108.58 L 276.297 107.05 L 277.251 107.05 L 275.604 109.462 L 277.35 112 L 276.396 112 L 275.33398 110.380005 Q 275.271 110.281 275.2125 110.150505 Q 275.154 110.02 275.109 109.939 Q 275.073 110.02 275.0055 110.150505 Q 274.938 110.281 274.866 110.380005 L 273.804 112 Z M 278.628 113.619995 L 278.628 107.05 L 279.438 107.05 L 279.438 107.995 L 279.447 107.995 Q 279.50998 107.509 279.87 107.2345 Q 280.22998 106.95999 280.788 106.95999 Q 281.53497 106.95999 281.97598 107.4505 Q 282.417 107.940994 282.417 108.796 L 282.417 110.24501 Q 282.417 111.1 281.97598 111.595 Q 281.53497 112.09 280.788 112.09 Q 280.22998 112.09 279.87 111.811 Q 279.50998 111.532 279.447 111.055 L 279.41998 111.055 L 279.438 112.18 L 279.438 113.619995 Z M 280.51797 111.38799 Q 281.03098 111.38799 281.319 111.118 Q 281.607 110.848 281.607 110.24501 L 281.607 108.805 Q 281.607 108.193 281.319 107.9275 Q 281.03098 107.661995 280.51797 107.661995 Q 280.02298 107.661995 279.7305 107.977 Q 279.438 108.29201 279.438 108.85 L 279.438 110.19999 Q 279.438 110.758 279.7305 111.07299 Q 280.02298 111.38799 280.51797 111.38799 Z M 285.90002 112.072 Q 285.009 112.072 284.4825 111.55 Q 283.95602 111.028 283.95602 110.092 L 283.95602 108.958 Q 283.95602 108.01301 284.47803 107.4955 Q 285 106.978 285.90002 106.978 Q 286.80002 106.978 287.32202 107.4955 Q 287.84402 108.01301 287.84402 108.958 L 287.84402 110.092 Q 287.84402 111.028 287.3175 111.55 Q 286.79102 112.072 285.90002 112.072 Z M 285.90002 111.35199 Q 286.431 111.35199 286.7325 111.055 Q 287.03403 110.758 287.03403 110.182 L 287.03403 108.868 Q 287.03403 108.29201 286.7325 107.995 Q 286.431 107.698006 285.90002 107.698006 Q 285.37802 107.698006 285.07202 107.995 Q 284.76602 108.29201 284.76602 108.868 L 284.76602 110.182 Q 284.76602 110.758 285.07202 111.055 Q 285.37802 111.35199 285.90002 111.35199 Z M 291.10202 112.072 Q 290.27402 112.072 289.81952 111.6985 Q 289.36502 111.325 289.36502 110.641 L 290.17502 110.641 Q 290.17502 110.983 290.418 111.1765 Q 290.661 111.37 291.10202 111.37 L 291.49802 111.37 Q 291.948 111.37 292.1955 111.172 Q 292.443 110.97401 292.443 110.614 Q 292.443 109.975 291.858 109.894 L 290.49002 109.696 Q 289.986 109.624 289.707 109.277504 Q 289.428 108.931 289.428 108.364 Q 289.428 107.716 289.8735 107.34699 Q 290.319 106.978 291.10202 106.978 L 291.49802 106.978 Q 292.21802 106.978 292.67252 107.333496 Q 293.127 107.689 293.163 108.265 L 292.344 108.265 Q 292.32602 108.00399 292.0965 107.83299 Q 291.867 107.661995 291.49802 107.661995 L 291.10202 107.661995 Q 290.68802 107.661995 290.454 107.851 Q 290.22 108.04 290.22 108.364 Q 290.22 108.88601 290.697 108.958 L 291.975 109.138 Q 293.23502 109.318 293.23502 110.614 Q 293.23502 111.307 292.78052 111.68951 Q 292.32602 112.072 291.49802 112.072 Z M 296.691 112.09 Q 295.836 112.09 295.323 111.581505 Q 294.81 111.07299 294.81 110.19999 L 294.81 107.05 L 295.62 107.05 L 295.62 110.19999 Q 295.62 110.74 295.908 111.059494 Q 296.196 111.379 296.691 111.379 Q 297.195 111.379 297.4875 111.059494 Q 297.78 110.74 297.78 110.19999 L 297.78 107.05 L 298.59 107.05 L 298.59 110.19999 Q 298.59 111.07299 298.068 111.581505 Q 297.546 112.09 296.691 112.09 Z M 300.408 112 L 300.408 107.05 L 301.218 107.05 L 301.218 107.995 L 301.236 107.995 Q 301.29898 107.51799 301.641 107.23899 Q 301.983 106.95999 302.559 106.95999 Q 303.333 106.95999 303.7515 107.4235 Q 304.16998 107.887 304.16998 108.742004 L 304.16998 109.16501 L 303.36 109.16501 L 303.36 108.742004 Q 303.36 107.661995 302.307 107.661995 Q 301.776 107.661995 301.49698 107.968 Q 301.218 108.274 301.218 108.85 L 301.218 112 Z M 307.5 112.09 Q 306.62698 112.09 306.0915 111.5635 Q 305.556 111.037 305.556 110.11 L 305.556 108.94 Q 305.556 108.01301 306.0915 107.4865 Q 306.62698 106.95999 307.5 106.95999 Q 308.085 106.95999 308.52148 107.194 Q 308.95798 107.428 309.201 107.851 Q 309.444 108.274 309.444 108.85 L 309.444 109.732 L 306.348 109.732 L 306.348 110.19999 Q 306.348 110.749 306.663 111.0685 Q 306.978 111.38799 307.5 111.38799 Q 307.94998 111.38799 308.2425 111.2125 Q 308.53497 111.037 308.598 110.74 L 309.408 110.74 Q 309.327 111.361 308.805 111.72551 Q 308.283 112.09 307.5 112.09 Z M 306.348 109.102 L 308.65198 109.102 L 308.65198 108.85 Q 308.65198 108.265 308.3505 107.9455 Q 308.04898 107.62601 307.5 107.62601 Q 306.951 107.62601 306.64948 107.9455 Q 306.348 108.265 306.348 108.85 Z M 317.904 111.145004 L 317.904 109.39 L 316.185 109.39 L 316.185 108.670006 L 317.904 108.670006 L 317.904 106.915 L 318.Line truncated
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#0b0b0c" fill-opacity="0.65" stroke="none" d="M 270.4912 358 L 267.88623 358 L 267.88623 349.99707 L 270.5664 349.99707 Q 271.74805 349.99707 272.5913 350.4778 Q 273.43457 350.9585 273.88574 351.8501 Q 274.3369 352.7417 274.3369 353.9878 Q 274.3369 355.23923 273.88306 356.13623 Q 273.4292 357.0332 272.56714 357.5166 Q 271.70508 358 270.4912 358 Z M 269.11084 356.92578 L 270.4214 356.92578 Q 271.78027 356.92578 272.45703 356.16574 Q 273.1338 355.40573 273.1338 353.9878 Q 273.1338 352.5752 272.4651 351.82327 Q 271.7964 351.07126 270.48584 351.07126 L 269.11084 351.07126 Z M 277.3247 358 L 277.3247 349.99707 L 280.19287 349.99707 Q 281.1167 349.99707 281.73438 350.31934 Q 282.35205 350.6416 282.6582 351.20825 Q 282.96436 351.77487 282.96436 352.51074 Q 282.96436 353.3164 282.59912 353.90457 Q 282.2339 354.49268 281.50342 354.7666 L 283.26514 358 L 281.87402 358 L 280.25195 354.97607 Q 280.21973 354.97607 280.18213 354.97607 L 278.54932 354.97607 L 278.54932 358 Z M 278.54932 353.9287 L 280.06396 353.9287 Q 280.94482 353.9287 281.33423 353.55542 Q 281.72363 353.18216 281.72363 352.51074 Q 281.72363 351.83398 281.33154 351.4392 Q 280.93945 351.04443 280.05322 351.04443 L 278.54932 351.04443 Z M 285.33984 358 L 288.18652 349.99707 L 289.69043 349.99707 L 292.59082 358 L 291.26416 358 L 290.52832 355.88916 L 287.38086 355.88916 L 286.6665 358 Z M 287.72998 354.86862 L 290.16846 354.86862 L 289.70654 353.54733 Q 289.5454 353.06934 289.35742 352.43823 Q 289.16943 351.80713 288.9331 350.9585 Q 288.69678 351.81784 288.51147 352.4543 Q 288.32617 353.09082 288.17578 353.54733 Z M 298.21045 358.10742 Q 297.1255 358.10742 296.3037 357.6079 Q 295.48193 357.1084 295.0254 356.1899 Q 294.56885 355.27148 294.56885 354.00388 Q 294.56885 352.72562 295.03345 351.80444 Q 295.49805 350.8833 296.30908 350.38647 Q 297.12012 349.88965 298.15674 349.88965 Q 299.02148 349.88965 299.7251 350.2253 Q 300.4287 350.56104 300.88794 351.15454 Q 301.34717 351.74805 301.48145 352.52686 L 300.2246 352.52686 Q 300.0044 351.82327 299.4807 351.41504 Q 298.95703 351.00684 298.16748 351.00684 Q 297.49072 351.00684 296.95093 351.3506 Q 296.41113 351.6943 296.09692 352.36304 Q 295.7827 353.03174 295.7827 353.99854 Q 295.7827 354.96533 296.09692 355.63135 Q 296.41113 356.29736 296.95898 356.6438 Q 297.50684 356.99023 298.21582 356.99023 Q 299.1665 356.99023 299.74927 356.42896 Q 300.33203 355.86768 300.35352 354.90625 L 298.39307 354.90625 L 298.39307 353.89648 L 301.55127 353.89648 L 301.55127 354.81494 Q 301.55127 355.8247 301.1189 356.56323 Q 300.68652 357.30173 299.93457 357.7046 Q 299.18262 358.10742 298.21045 358.10742 Z M 312.33936 358.10742 Q 311.30273 358.10742 310.48364 357.61328 Q 309.66455 357.11914 309.19458 356.20068 Q 308.7246 355.2822 308.7246 354.00388 Q 308.7246 352.7202 309.19458 351.7991 Q 309.66455 350.87793 310.48364 350.3838 Q 311.30273 349.88965 312.33936 349.88965 Q 313.37598 349.88965 314.1897 350.3838 Q 315.00342 350.87793 315.4734 351.7991 Q 315.94336 352.7202 315.94336 354.00388 Q 315.94336 355.2822 315.4734 356.20337 Q 315.00342 357.1245 314.1897 357.616 Q 313.37598 358.10742 312.33936 358.10742 Z M 312.33936 356.99023 Q 313.02148 356.99023 313.56128 356.6465 Q 314.10107 356.30273 314.41528 355.63672 Q 314.7295 354.9707 314.7295 354.00388 Q 314.7295 353.03174 314.41528 352.36304 Q 314.10107 351.6943 313.56128 351.3506 Q 313.02148 351.00684 312.33936 351.00684 Q 311.65186 351.00684 311.10938 351.3506 Q 310.5669 351.6943 310.2527 352.36304 Q 309.93848 353.03174 309.93848 354.00388 Q 309.93848 354.9707 310.2527 355.63672 Q 310.5669 356.30273 311.10938 356.6465 Q 311.65186 356.99023 312.33936 356.99023 Z M 318.93652 358 L 318.93652 349.99707 L 320.34912 349.99707 L 323.3623 354.76123 Q 323.5503 355.062 323.80273 355.51053 Q 324.05518 355.95898 324.32373 356.5337 Q 324.28076 355.9536 324.26196 355.42453 Q 324.24316 354.8955 324.24316 354.55176 L 324.24316 349.99707 L 325.4839 349.99707 L 325.4839 358 L 324.06592 358 L 321.36426 353.74072 Q 321.16553 353.4238 320.9856 353.1123 Q 320.80566 352.80078 320.59082 352.41135 Q 320.37598 352.02194 320.08594 351.48483 Q 320.12354 352.23682 320.1504 352.82764 Q 320.17725 353.41846 320.17725 353.72998 L 320.17725 358 Z M 328.35352 351.0498 L 328.35352 349.99707 L 334.56787 349.99707 L 334.56787 351.0498 L 332.08105 351.0498 L 332.08105 358 L 330.85107 358 L 330.85107 351.0498 Z M 340.43994 358.10742 Q 339.40332 358.10742 338.58423 357.61328 Q 337.76514 357.11914 337.29517 356.20068 Q 336.8252 355.2822 336.8252 354.00388 Q 336.8252 352.7202 337.29517 351.7991 Q 337.76514 350.87793 338.58423 350.3838 Q 339.40332 349.88965 340.43994 349.88965 Q 341.47656 349.88965 342.29028 350.3838 Q 343.104 350.87793 343.57397 351.7991 Q 344.0439 352.7202 344.0439 354.00388 Q 344.0439 355.2822 343.57397 356.20337 Q 343.104 357.1245 342.29028 357.616 Q 341.47656 358.10742 340.43994 358.10742 Z M 340.43994 356.99023 Q 341.12207 356.99023 341.66187 356.6465 Q 342.20166 356.30273 342.51587 35Line truncated
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regenerate background.tiff and dmg-layout.DS_Store for the macOS DMG window (see README.md here).
|
||||
|
||||
Needs resvg on PATH and:
|
||||
pip install 'pillow>=12' ds_store==1.3.3 mac_alias==2.2.3
|
||||
|
||||
Runs on any OS, no Mac needed. Both outputs come from this script alone, so they carry nothing
|
||||
from the machine that made them: no local paths, user or disk names, dates or volume UUIDs.
|
||||
|
||||
python3 packaging/macos/dmg/generate.py
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from ds_store import DSStore
|
||||
from mac_alias import Alias, TargetInfo, VolumeInfo
|
||||
from PIL import Image, ImageCms
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Keep in sync with package.sh (volume name) and README.md (layout).
|
||||
VOLUME = "LightCraft"
|
||||
WIDTH, HEIGHT = 660, 400 # window content, pt; the background's 1x size
|
||||
TITLE_BAR = 32
|
||||
ICON_SIZE = 128
|
||||
ICONS = {"LightCraft.app": (326, 205), "Applications": (574, 205)}
|
||||
# A fixed date for the alias and the colour profile. Finder never matches it against the image
|
||||
# (each build is a new volume): it finds the background by volume name and path.
|
||||
FIXED_DATE = datetime.datetime(2026, 10, 8, tzinfo=datetime.timezone.utc)
|
||||
|
||||
|
||||
def render(svg, width, out):
|
||||
# The SVG's text is already outlined and no fonts are loaded, so every machine draws the
|
||||
# same pixels.
|
||||
subprocess.run(
|
||||
["resvg", "--skip-system-fonts", "-w", str(width), svg, out],
|
||||
check=True,
|
||||
)
|
||||
with Image.open(out) as im:
|
||||
return im.convert("RGB")
|
||||
|
||||
|
||||
def srgb_profile():
|
||||
# LittleCMS's built-in sRGB ("No copyright, use freely"), with its creation date fixed.
|
||||
icc = bytearray(ImageCms.ImageCmsProfile(ImageCms.createProfile("sRGB")).tobytes())
|
||||
d = FIXED_DATE
|
||||
icc[24:36] = b"".join(v.to_bytes(2, "big") for v in (d.year, d.month, d.day, 0, 0, 0))
|
||||
if icc[84:100] != bytes(16):
|
||||
sys.exit("error: the sRGB profile has an ID; recompute it after fixing the date")
|
||||
return bytes(icc)
|
||||
|
||||
|
||||
def write_tiff(svg, out):
|
||||
"""1x (72 dpi) and 2x (144 dpi) in one TIFF, as `tiffutil -cathidpicheck` writes them."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
one, two = (render(svg, WIDTH * s, os.path.join(tmp, f"{s}x.png")) for s in (1, 2))
|
||||
two.encoderinfo = {"dpi": (144, 144)} # the rest as the first page
|
||||
# Opaque RGB, Deflate without a predictor: the paper grain is noise, which a predictor inflates.
|
||||
one.save(
|
||||
out,
|
||||
"TIFF",
|
||||
save_all=True,
|
||||
append_images=[two],
|
||||
compression="tiff_adobe_deflate", # brand-ok: Pillow's name for TIFF compression 8 (Deflate)
|
||||
dpi=(72, 72),
|
||||
icc_profile=srgb_profile(),
|
||||
)
|
||||
with Image.open(out) as im:
|
||||
im.seek(1)
|
||||
if im.info.get("dpi") != (144, 144):
|
||||
sys.exit("error: the 2x page isn't 144 dpi (needs Pillow 12 or later)")
|
||||
strips = []
|
||||
for page in (0, 1):
|
||||
im.seek(page)
|
||||
strips += zip(im.tag_v2[273], im.tag_v2[279]) # StripOffsets, StripByteCounts
|
||||
# TIFF keeps directories and tag data on even offsets. When a strip ends on an odd one, libtiff
|
||||
# leaves the padding byte after it uninitialised, so the file changed from run to run with
|
||||
# identical pixels. Zero it: nothing refers to that byte.
|
||||
starts = {o for o, _ in strips}
|
||||
with open(out, "r+b") as f:
|
||||
for o, n in strips:
|
||||
if (o + n) % 2 and o + n not in starts:
|
||||
f.seek(o + n)
|
||||
f.write(bytes(1))
|
||||
|
||||
|
||||
def background_alias():
|
||||
# What Finder stores for /.background/background.tiff on the volume, minus anything about the
|
||||
# machine (dmgbuild writes the same kind of alias from a mounted image). Disk type 5 (ejectable),
|
||||
# the volume flags and the folder/file ids (25, 26) are what Finder wrote on a test image; the ids
|
||||
# are only hints, as the volume's creation date.
|
||||
volume = VolumeInfo(VOLUME, FIXED_DATE, b"H+", 5, 0x0D02, b"\0\0")
|
||||
volume.posix_path = f"/Volumes/{VOLUME}"
|
||||
target = TargetInfo(0, "background.tiff", 25, 26, FIXED_DATE, b"\0\0\0\0", b"\0\0\0\0")
|
||||
target.folder_name = ".background"
|
||||
target.cnid_path = [25]
|
||||
target.carbon_path = f"{VOLUME}:.background:\0background.tiff"
|
||||
target.posix_path = "/.background/background.tiff"
|
||||
return Alias(volume=volume, target=target).to_bytes()
|
||||
|
||||
|
||||
def write_ds_store(out):
|
||||
if os.path.exists(out):
|
||||
os.remove(out)
|
||||
with DSStore.open(out, "w+") as d:
|
||||
d["."]["bwsp"] = {
|
||||
"ShowStatusBar": False,
|
||||
"ShowToolbar": False,
|
||||
"ShowTabView": False,
|
||||
"ContainerShowSidebar": False,
|
||||
"ShowSidebar": False,
|
||||
"WindowBounds": f"{{{{200, 528}}, {{{WIDTH}, {HEIGHT + TITLE_BAR}}}}}",
|
||||
}
|
||||
d["."]["icvp"] = {
|
||||
"viewOptionsVersion": 1,
|
||||
"backgroundType": 2,
|
||||
"backgroundImageAlias": background_alias(),
|
||||
"backgroundColorRed": 1.0,
|
||||
"backgroundColorGreen": 1.0,
|
||||
"backgroundColorBlue": 1.0,
|
||||
"gridOffsetX": 0.0,
|
||||
"gridOffsetY": 0.0,
|
||||
"gridSpacing": 100.0,
|
||||
"arrangeBy": "none",
|
||||
"showIconPreview": True,
|
||||
"showItemInfo": False,
|
||||
"labelOnBottom": True,
|
||||
"textSize": 16.0,
|
||||
"iconSize": float(ICON_SIZE),
|
||||
}
|
||||
d["."]["vSrn"] = ("long", 1)
|
||||
for name, pos in ICONS.items():
|
||||
d[name]["Iloc"] = pos
|
||||
|
||||
|
||||
def main():
|
||||
if not shutil.which("resvg"):
|
||||
sys.exit("error: resvg not found (brew install resvg / cargo install resvg --locked)")
|
||||
write_tiff(os.path.join(HERE, "background.svg"), os.path.join(HERE, "background.tiff"))
|
||||
write_ds_store(os.path.join(HERE, "dmg-layout.DS_Store"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -132,10 +132,15 @@ STAGE="$WORK/dmg"
|
||||
mkdir -p "$STAGE"
|
||||
ditto "$APP" "$STAGE/LightCraft.app"
|
||||
ln -s /Applications "$STAGE/Applications"
|
||||
# Finder window layout: background, icon size and positions (packaging/macos/dmg/README.md).
|
||||
mkdir -p "$STAGE/.background"
|
||||
cp "$HERE/dmg/background.tiff" "$STAGE/.background/background.tiff"
|
||||
cp "$HERE/dmg/dmg-layout.DS_Store" "$STAGE/.DS_Store"
|
||||
rm -f "$DMG" "$WORK/raw.dmg"
|
||||
# makehybrid + convert builds the image without attaching a device, unlike `create -srcfolder`,
|
||||
# which is flaky on CI runners ("Resource busy") and hangs in sandboxed sessions.
|
||||
hdiutil makehybrid -hfs -hfs-volume-name "LightCraft $VERSION" -hfs-openfolder "$STAGE" -o "$WORK/raw.dmg" "$STAGE"
|
||||
# The volume name has no version: .DS_Store finds the background through an alias that includes it.
|
||||
hdiutil makehybrid -hfs -hfs-volume-name "LightCraft" -hfs-openfolder "$STAGE" -o "$WORK/raw.dmg" "$STAGE"
|
||||
hdiutil convert "$WORK/raw.dmg" -format UDZO -imagekey zlib-level=9 -o "$DMG"
|
||||
rm -f "$WORK/raw.dmg"
|
||||
sign "$DMG"
|
||||
|
||||
Reference in new issue
Block a user