mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-31 07:38:16 +00:00
Merge pull request #8 from XusBadia/dmg-background
macOS DMG: branded window background and icon layout
This commit is contained in:
7 files changed
+241
-1
No files matched your search
@@ -18,6 +18,8 @@ deck and UI icons are original work of the DeckCraft contributors (drawn or gene
|
||||
| `docs/brand/artcraft-mark-black.svg`, `docs/brand/artcraft-mark-black.png` | ArtCraft Team | ArtCraft brand kit | ArtCraft trademark, `docs/brand/LICENSE-brand.txt` | Mark for light backgrounds |
|
||||
| `docs/brand/LICENSE-brand.txt` | ArtCraft Team | craftrules `standards/license-files` | — (licence text) | Terms for the ArtCraft marks |
|
||||
| `assets/app-icon/deckcraft-1024.png`, `assets/app-icon/hicolor/*/apps/ai.storyteller.deckcraft.png` | DeckCraft contributors | rendered by DeckCraft from `assets/app-icon/icon-source.deckcraft` (shapes only) | MIT OR Apache-2.0 | Placeholder app icon (presentation board) until the mascot icon is drawn |
|
||||
| `packaging/macos/dmg/background.svg` | @XusBadia | DeckCraft macOS DMG window background, original work for this repository (2026-10-08), derived from the DeckCraft app icon `assets/app-icon/deckcraft-1024.png` (referenced via `<image>`, not copied); text is outlined Inter / JetBrains Mono glyph paths | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`) | Finder window of the macOS DMG; `packaging/macos/dmg/generate.py` renders it to `background.tiff` |
|
||||
| `packaging/macos/dmg/background.tiff` | @XusBadia | Rendered from `packaging/macos/dmg/background.svg` by `packaging/macos/dmg/generate.py` | MIT OR Apache-2.0 (`LICENSE-MIT`, `LICENSE-APACHE`) | 1x + 2x HiDPI TIFF for the macOS DMG window; includes the app icon (see its row) and LittleCMS's built-in sRGB profile ("No copyright, use freely") |
|
||||
| `assets/app-icon/deckcraft.icns`, `assets/app-icon/deckcraft.ico` | DeckCraft contributors | generated from the PNGs above by `packaging/icons.sh` (sips/iconutil, `cargo xtask ico`) | MIT OR Apache-2.0 | macOS and Windows app icons |
|
||||
| `assets/app-icon/icon-source.deckcraft` | DeckCraft contributors | made with `deckcraft-cli run` (see git history) | MIT OR Apache-2.0 | Source of the placeholder icon |
|
||||
| `docs/images/editor.png`, `docs/images/shape-format.png`, `docs/images/format-pane.png`, `docs/images/slide-sorter.png`, `docs/images/dark-mode.png`, `docs/images/sample-deck.png` | DeckCraft contributors | Screenshots of DeckCraft and slides rendered by `deckcraft-cli` from the built-in sample deck (original content; Inter font, OFL-1.1) | MIT OR Apache-2.0 | README 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/deckcraft-1024.png`, linked, not copied) cropped as a cover on the DeckCraft colour field (`#f26b1d`), Ink and Paper. Its text (Inter, JetBrains Mono) is outlined, so rendering it needs no fonts. No paper grain: noise doesn't compress, and this keeps `background.tiff` small. |
|
||||
| `background.tiff` | The background at 1x (660 × 400 px, 72 dpi) and 2x (1320 × 800 px, 144 dpi) in one HiDPI TIFF (16-colour palette, Deflate, sRGB). Goes to `.background/background.tiff`. |
|
||||
| `dmg-layout.DS_Store` | Finder's view settings for the volume: window size, icon size 128, DeckCraft.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 `DeckCraft`, not `DeckCraft <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 (`deckcraft-<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"/>
|
||||
<g clip-path="url(#panel)"><rect width="232" height="400" fill="#f26b1d"/><g transform="translate(-63.2,20.8) scale(0.7)"><image href="../../../assets/app-icon/deckcraft-1024.png" 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="#f26b1d"/>
|
||||
|
||||
<rect x="408" y="199.4" width="20" height="11.2" rx="1.5" fill="#efe9dc" stroke="#0b0b0c" stroke-width="1.2" stroke-opacity="0.4"/><rect x="434" y="198.2" width="24" height="13.5" rx="1.5" fill="#efe9dc" stroke="#0b0b0c" stroke-width="1.2" stroke-opacity="0.65"/><rect x="462" y="196.0" width="32" height="18.0" rx="1.5" fill="#efe9dc" stroke="#f26b1d" stroke-width="2" stroke-opacity="1"/>
|
||||
<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 275.58008 72 L 268.19727 72 L 268.19727 50.17383 L 275.72656 50.17383 Q 278.97852 50.17383 281.31494 51.484863 Q 283.65137 52.7959 284.89648 55.234863 Q 286.1416 57.673832 286.1416 61.057617 Q 286.1416 64.4707 284.88916 66.92432 Q 283.63672 69.37793 281.271 70.688965 Q 278.90527 72 275.58008 72 Z M 272.1084 68.61621 L 275.38965 68.61621 Q 282.28906 68.61621 282.28906 61.057617 Q 282.28906 53.557617 275.4922 53.557617 L 272.1084 53.557617 Z M 296.42285 72.336914 Q 293.94727 72.336914 292.16748 71.296875 Q 290.3877 70.256836 289.42822 68.36719 Q 288.46875 66.47754 288.46875 63.914063 Q 288.46875 61.394527 289.41357 59.48291 Q 290.3584 57.571285 292.09424 56.49463 Q 293.83008 55.41797 296.17383 55.41797 Q 298.16602 55.41797 299.87256 56.28955 Q 301.5791 57.161133 302.61914 58.984863 Q 303.65918 60.80859 303.65918 63.679688 L 303.65918 64.88086 L 292.2627 64.88086 Q 292.33594 67.06348 293.48584 68.206055 Q 294.63574 69.34863 296.4668 69.34863 Q 297.72656 69.34863 298.62744 68.80664 Q 299.52832 68.26465 299.90918 67.22461 L 303.41016 67.94238 Q 302.82422 69.91992 300.98584 71.12842 Q 299.14746 72.336914 296.42285 72.336914 Z M 292.27734 62.288086 L 299.95313 62.288086 Q 299.77734 60.530273 298.83252 59.46826 Q 297.8877 58.40625 296.18848 58.40625 Q 294.4453 58.40625 293.42725 59.526855 Q 292.40918 60.64746 292.27734 62.288086 Z M 313.53027 72.336914 Q 311.14258 72.336914 309.38477 71.2749 Q 307.62695 70.21289 306.66748 68.31592 Q 305.708 66.418945 305.708 63.899414 Q 305.708 61.350586 306.66748 59.438965 Q 307.62695 57.527344 309.38477 56.472656 Q 311.14258 55.41797 313.53027 55.41797 Q 316.26953 55.41797 318.1665 56.787598 Q 320.06348 58.157227 320.59082 60.55957 L 317.03125 61.30664 Q 316.72363 60.032227 315.83008 59.270508 Q 314.93652 58.50879 313.55957 58.50879 Q 311.56738 58.50879 310.5786 60.046875 Q 309.58984 61.58496 309.58984 63.884766 Q 309.58984 65.393555 310.0293 66.609375 Q 310.46875 67.825195 311.34766 68.535645 Q 312.22656 69.24609 313.55957 69.24609 Q 314.96582 69.24609 315.8667 68.447754 Q 316.76758 67.649414 317.0752 66.331055 L 320.63477 67.078125 Q 320.10742 69.524414 318.20313 70.930664 Q 316.29883 72.336914 313.53027 72.336914 Z M 323.40137 72 L 323.40137 50.17383 L 327.20996 50.17383 L 327.20996 62.229492 L 327.48828 62.229492 L 333.3916 55.623047 L 337.85938 55.623047 L 331.5166 62.69824 L 338.24023 72 L 333.66992 72 L 328.6162 64.9834 L 327.20996 66.49219 L 327.20996 72 Z M 349.45895 72.29297 Q 346.58786 72.29297 344.33203 70.95996 Q 342.07617 69.62695 340.77246 67.12207 Q 339.46875 64.61719 339.46875 61.101563 Q 339.46875 57.571285 340.7798 55.059082 Q 342.09082 52.54688 344.34668 51.213863 Q 346.60254 49.88086 349.45895 49.88086 Q 351.84668 49.88086 353.80225 50.774414 Q 355.75778 51.66797 357.03223 53.359863 Q 358.30664 55.051754 358.6582 57.439453 L 354.71777 57.439453 Q 354.35156 55.50586 352.91602 54.443848 Q 351.48047 53.381836 349.51758 53.381836 Q 346.8369 53.381836 345.11572 55.381344 Q 343.39453 57.38086 343.39453 61.101563 Q 343.39453 64.86621 345.12305 66.8291 Q 346.85156 68.79199 349.50293 68.79199 Q 351.46585 68.79199 352.9087 67.72998 Q 354.35156 66.66797 354.71777 64.734375 L 358.67282 64.734375 Q 358.36523 66.8291 357.16406 68.54297 Q 355.9629 70.256836 354 71.2749 Q 352.0371 72.29297 349.45895 72.29297 Z M 361.58594 72 L 361.58594 55.623047 L 365.27734 55.623047 L 365.27734 58.362305 L 365.4531 58.362305 Q 365.89258 56.941402 366.9912 56.172363 Q 368.0898 55.40332 369.4961 55.40332 Q 370.22852 55.40332 370.88766 55.50586 L 370.88766 59.006836 Q 370.65332 58.948246 370.12598 58.882324 Q 369.59863 58.816406 369.08594 58.816406 Q 367.48926 58.816406 366.4419 59.805172 Q 365.39453 60.79394 365.39453 62.36133 L 365.39453 72 Z M 377.2871 72.336914 Q 375.7344 72.336914 374.48926 71.77295 Q 373.24414 71.208984 372.52637 70.11035 Q 371.8086 69.01172 371.8086 67.40039 Q 371.8086 65.55469 372.70947 64.53662 Q 373.61032 63.518555 375.03857 63.057125 Q 376.4668 62.595703 378.04883 62.43457 Q 380.18747 62.200195 381.13965 62.00244 Q 382.0918 61.804688 382.0918 60.95508 L 382.0918 60.88184 Q 382.0918 59.680664 381.3594 59.01416 Q 380.62695 58.34766 379.23538 58.34766 Q 377.7998 58.34766 376.9502 58.977543 Q 376.1006 59.607426 375.80762 60.413086 L 372.27734 59.695313 Q 372.99512 57.527344 374.87744 56.472656 Q 376.75974 55.41797 379.2207 55.41797 Q 380.37796 55.41797 381.55716 55.688965 Q 382.73633 55.95996 383.71777 56.597168 Q 384.69922 57.234375 385.29984 58.325684 Q 385.9004 59.416992 385.9004 61.057617 L 385.9004 72 L 382.25293 72 L 382.25293 69.74414 L 382.10645 69.74414 Q 381.56442 70.79883 380.37796 71.56787 Q 379.1914 72.336914 377.2871 72.336914 Z M 378.26855 69.509766 Q 380.02634 69.509766 381.07373 68.49902 Q 382.1211 67.48828 382.1211 66.12598 L 382.1211 64.19238 Q 381.85742 64.39746 381.1836 64.55127 Q 380.50977 64.70508 379.75537 64.81494 Q 379.001 64.924805 378.50293 64.99805 Q 377.21387 65.17383 376.35693 65.70117 Q 37Line truncated
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#0b0b0c" fill-opacity="0.7" stroke="none" d="M 269.736 112.09 Q 268.782 112.09 268.215 111.586 Q 267.648 111.082 267.648 110.19999 L 268.458 110.19999 Q 268.458 110.749 268.809 111.059494 Q 269.16 111.37 269.736 111.37 Q 270.294 111.37 270.627 111.046 Q 270.96 110.722 270.96 110.19999 Q 270.96 109.804 270.7485 109.5115 Q 270.537 109.219 270.141 109.111 L 269.142 108.832 Q 268.521 108.652 268.1655 108.1885 Q 267.81 107.72499 267.81 107.095 Q 267.81 106.573 268.044 106.177 Q 268.278 105.781006 268.701 105.5605 Q 269.124 105.34 269.673 105.34 Q 270.231 105.34 270.6585 105.5605 Q 271.086 105.781006 271.329 106.1725 Q 271.572 106.564 271.572 107.07701 L 270.762 107.07701 Q 270.762 106.627 270.456 106.3435 Q 270.15 106.06 269.673 106.06 Q 269.196 106.06 268.899 106.3435 Q 268.602 106.627 268.602 107.07701 Q 268.602 107.437 268.7955 107.6935 Q 268.989 107.95 269.34 108.04901 L 270.366 108.337 Q 271.023 108.517 271.3875 109.0165 Q 271.752 109.516 271.752 110.19999 Q 271.752 111.064 271.203 111.577 Q 270.654 112.09 269.736 112.09 Z M 275.82 112 Q 275.163 112 274.77148 111.61751 Q 274.38 111.235 274.38 110.605 L 274.38 106.168 L 272.66998 106.168 L 272.66998 105.42999 L 275.19 105.42999 L 275.19 110.605 Q 275.19 110.911 275.361 111.0865 Q 275.53198 111.262 275.82 111.262 L 277.35 111.262 L 277.35 112 Z M 278.565 112 L 278.565 111.262 L 280.31998 111.262 L 280.31998 107.788 L 278.745 107.788 L 278.745 107.05 L 281.12997 107.05 L 281.12997 111.262 L 282.79498 111.262 L 282.79498 112 Z M 280.63498 106.159004 Q 280.33798 106.159004 280.167 106.006 Q 279.996 105.853 279.996 105.592 Q 279.996 105.32199 280.167 105.16449 Q 280.33798 105.007 280.63498 105.007 Q 280.93198 105.007 281.103 105.16449 Q 281.274 105.32199 281.274 105.592 Q 281.274 105.853 281.103 106.006 Q 280.93198 106.159004 280.63498 106.159004 Z M 285.612 112.09 Q 284.87402 112.09 284.4285 111.595 Q 283.983 111.1 283.983 110.254 L 283.983 108.805 Q 283.983 107.95 284.424 107.45501 Q 284.86502 106.95999 285.612 106.95999 Q 286.17 106.95999 286.53452 107.23899 Q 286.89902 107.51799 286.971 107.995 L 286.98 107.995 L 286.962 106.87 L 286.962 105.42999 L 287.772 105.42999 L 287.772 112 L 286.962 112 L 286.962 111.055 L 286.953 111.055 Q 286.89 111.541 286.53 111.8155 Q 286.17 112.09 285.612 112.09 Z M 285.88202 111.38799 Q 286.38602 111.38799 286.674 111.07299 Q 286.962 110.758 286.962 110.19999 L 286.962 108.85 Q 286.962 108.29201 286.674 107.977 Q 286.38602 107.661995 285.88202 107.661995 Q 285.36902 107.661995 285.08102 107.9275 Q 284.793 108.193 284.793 108.805 L 284.793 110.24501 Q 284.793 110.848 285.08102 111.118 Q 285.36902 111.38799 285.88202 111.38799 Z M 291.30002 112.09 Q 290.427 112.09 289.8915 111.5635 Q 289.35602 111.037 289.35602 110.11 L 289.35602 108.94 Q 289.35602 108.01301 289.8915 107.4865 Q 290.427 106.95999 291.30002 106.95999 Q 291.885 106.95999 292.3215 107.194 Q 292.758 107.428 293.001 107.851 Q 293.24402 108.274 293.24402 108.85 L 293.24402 109.732 L 290.148 109.732 L 290.148 110.19999 Q 290.148 110.749 290.463 111.0685 Q 290.778 111.38799 291.30002 111.38799 Q 291.75 111.38799 292.0425 111.2125 Q 292.335 111.037 292.398 110.74 L 293.208 110.74 Q 293.127 111.361 292.605 111.72551 Q 292.083 112.09 291.30002 112.09 Z M 290.148 109.102 L 292.452 109.102 L 292.452 108.85 Q 292.452 108.265 292.1505 107.9455 Q 291.849 107.62601 291.30002 107.62601 Q 290.751 107.62601 290.4495 107.9455 Q 290.148 108.265 290.148 108.85 Z M 300.21 112 L 300.21 111.262 L 301.992 111.262 L 301.992 106.131996 L 300.21 107.464 L 300.21 106.537 L 301.695 105.42999 L 302.802 105.42999 L 302.802 111.262 L 304.25998 111.262 L 304.25998 112 Z M 312.90002 112.072 Q 312.009 112.072 311.4825 111.55 Q 310.95602 111.028 310.95602 110.092 L 310.95602 108.958 Q 310.95602 108.01301 311.47803 107.4955 Q 312 106.978 312.90002 106.978 Q 313.80002 106.978 314.32202 107.4955 Q 314.84402 108.01301 314.84402 108.958 L 314.84402 110.092 Q 314.84402 111.028 314.3175 111.55 Q 313.79102 112.072 312.90002 112.072 Z M 312.90002 111.35199 Q 313.431 111.35199 313.7325 111.055 Q 314.03403 110.758 314.03403 110.182 L 314.03403 108.868 Q 314.03403 108.29201 313.7325 107.995 Q 313.431 107.698006 312.90002 107.698006 Q 312.37802 107.698006 312.07202 107.995 Q 311.76602 108.29201 311.76602 108.868 L 311.76602 110.182 Q 311.76602 110.758 312.07202 111.055 Q 312.37802 111.35199 312.90002 111.35199 Z M 317.535 112 L 317.535 108.463005 L 316.095 108.463005 L 316.095 107.72499 L 317.535 107.72499 L 317.535 106.69001 Q 317.535 106.105 317.904 105.76751 Q 318.273 105.42999 318.92102 105.42999 L 320.37 105.42999 L 320.37 106.168 L 318.92102 106.168 Q 318.345 106.168 318.345 106.69001 L 318.345 107.72499 L 320.37 107.72499 L 320.37 108.463005 L 318.345 108.463005 L 318.345 112 Z M 329.001 112.09 Q 328.09198 112.09 327.561 111.581505 Q 327.03 111.07299 327.03 110.19999 L 327.84 110.19999 Q 327.84 110.74 328.155 111.055 Q 328.47 111.37 329.00998 111.37 Q 329.55 111.37 329.865 111.055 Q 330.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: 31 KiB |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,158 @@
|
||||
#!/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 = "DeckCraft"
|
||||
WIDTH, HEIGHT = 660, 400 # window content, pt; the background's 1x size
|
||||
TITLE_BAR = 32
|
||||
ICON_SIZE = 128
|
||||
PALETTE = 16 # colours in background.tiff
|
||||
ICONS = {"DeckCraft.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 quantize(im):
|
||||
# No dithering: dither noise compresses badly and the artwork has flat fills.
|
||||
return im.quantize(PALETTE, method=Image.Quantize.FASTOCTREE, dither=Image.Dither.NONE)
|
||||
|
||||
|
||||
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 = (
|
||||
quantize(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 16-colour palette, Deflate: the artwork is three inks plus antialiasing, and a palette
|
||||
# keeps the file under ~100 KB (repository assets must stay small). As PhotoCraft's.
|
||||
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()
|
||||
@@ -131,10 +131,15 @@ STAGE="$WORK/dmg"
|
||||
mkdir -p "$STAGE"
|
||||
ditto "$APP" "$STAGE/DeckCraft.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 "DeckCraft $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 "DeckCraft" -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