@kirigami/php-prepros 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1521,11 +1521,12 @@ $img->height // int
1521
1521
  // Instance methods (resize/save are chainable)
1522
1522
  $img->resize(int $width, int $height = 0, bool $cover = false): self
1523
1523
  $img->save(string $dest, ?int $quality = null): self // quality 0-100 for jpg/webp/avif; null = per-format default (82)
1524
- $img->getRepresentativeColors(int $count = 5): string[] // ['#rrggbb', …]
1524
+ $img->getRepresentativeColors(int $count = 5): string[] // ['#rrggbb', …], median-cut + Lab merge
1525
+ $img->getAuraColors(int $count = 5): string[] // ['#rrggbb', …], up to 6, via the Aura extension
1525
1526
 
1526
1527
  // Static helpers
1527
1528
  IMG::asset(string $path, int $width = 0, int $height = 0, bool $cover = false): string // same feature as the <img asset> tag and the img-asset() Sass function
1528
- IMG::palette(string $path, int $colors = 5): string[]
1529
+ IMG::palette(string $path, int $colors = 5): string[] // Aura-backed: at most 6 colours
1529
1530
  ```
1530
1531
 
1531
1532
  `resize()` operates in *contain* mode by default (scales to fit within the target box while preserving aspect ratio). Pass `$cover = true` to crop and fill the exact target dimensions.
@@ -1543,7 +1544,10 @@ IMG::palette(string $path, int $colors = 5): string[]
1543
1544
  and `colors()` Sass functions: they resolve `$path` against `image.source` from
1544
1545
  `kirigami.yaml`, generate a resized/re-encoded file under `image.dest` (only
1545
1546
  when missing or stale), or return a `CACHE`-backed list of representative
1546
- colours. Both are equally usable from your own PHP.
1547
+ colours. `IMG::palette()` extracts them with the Aura extension (vibrant and
1548
+ muted swatches, each in a dark and a light variant), so it returns at most six
1549
+ colours, most populated first; asking for more returns what Aura found. Both
1550
+ are equally usable from your own PHP.
1547
1551
 
1548
1552
  `IMG::asset()` is the single implementation behind the [`<img asset>` tag](#built-in-tags)
1549
1553
  too — the tag is just a thin wrapper. Generated files are named after the source
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kirigami/php-prepros",
3
- "version": "3.0.1",
3
+ "version": "3.1.1",
4
4
  "description": "PHP preprocessor for the Kirigami static site generator. Compile PHP page templates to clean, deployable HTML — with zero server dependency.",
5
5
  "keywords": [
6
6
  "kirigami",
@@ -44,7 +44,7 @@
44
44
  "test": "node --test --test-concurrency=1 \"test/*.test.js\""
45
45
  },
46
46
  "dependencies": {
47
- "@kirigami/php-wasm": "8.5.11",
47
+ "@kirigami/php-wasm": "8.5.11-1",
48
48
  "@kirigami/struct-walker": "1.0.6",
49
49
  "picomatch": "^4.0.7"
50
50
  },
@@ -332,6 +332,62 @@ class IMG
332
332
  }
333
333
 
334
334
 
335
+ /**
336
+ * Extracts a color palette with Aura (the static `aura` extension), which
337
+ * picks up to six named swatches (vibrant, muted, each in a dark and a
338
+ * light variant) instead of clustering N arbitrary colors.
339
+ *
340
+ * Swatches Aura had to fake (`was_ineligible`) are dropped, then colors
341
+ * are ordered by descending population and deduplicated.
342
+ *
343
+ * @param int $numColors Number of colors to return (at most 6).
344
+ * @return string[] Colors as "#rrggbb".
345
+ */
346
+ public function getAuraColors(int $numColors = 5): array
347
+ {
348
+ if (!class_exists('Aura\Palette')) throw new Exception("The aura extension is not available.");
349
+
350
+ // Aura reads raw RGBA bytes. A small sample is plenty to find the
351
+ // dominant colors, and keeps the PHP pixel loop cheap.
352
+ $srcW = $this->width;
353
+ $srcH = $this->height;
354
+ $scale = min(1, 150 / max($srcW, $srcH));
355
+ $w = max(1, (int) round($srcW * $scale));
356
+ $h = max(1, (int) round($srcH * $scale));
357
+
358
+ $sample = imagecreatetruecolor($w, $h);
359
+ imagealphablending($sample, false);
360
+ imagesavealpha($sample, true);
361
+ imagefill($sample, 0, 0, imagecolorallocatealpha($sample, 0, 0, 0, 127));
362
+ imagecopyresampled($sample, $this->im, 0, 0, 0, 0, $w, $h, $srcW, $srcH);
363
+
364
+ $rgba = '';
365
+ for ($y = 0; $y < $h; $y++) {
366
+ for ($x = 0; $x < $w; $x++) {
367
+ $c = imagecolorat($sample, $x, $y);
368
+ $alpha = 255 - (($c >> 24) & 127) * 2; // GD alpha is 0 (opaque) to 127
369
+ $rgba .= chr(($c >> 16) & 255) . chr(($c >> 8) & 255) . chr($c & 255) . chr(min(255, $alpha));
370
+ }
371
+ }
372
+
373
+ $palette = \Aura\Palette::generate($rgba);
374
+
375
+ $swatches = [];
376
+ foreach (['vibrant', 'vibrant_dark', 'vibrant_light', 'muted', 'muted_dark', 'muted_light'] as $name) {
377
+ $swatch = $palette->$name;
378
+ if ($swatch && !$swatch->was_ineligible) $swatches[] = $swatch;
379
+ }
380
+ usort($swatches, fn($a, $b) => $b->population <=> $a->population);
381
+
382
+ $colors = [];
383
+ foreach ($swatches as $swatch) {
384
+ $colors[] = sprintf('#%02x%02x%02x', $swatch->color->r, $swatch->color->g, $swatch->color->b);
385
+ }
386
+
387
+ return array_slice(array_values(array_unique($colors)), 0, $numColors);
388
+ }
389
+
390
+
335
391
  /**
336
392
  * The AVIF encoder (libavif/aom) used by imageavif() can fail with
337
393
  * "Encoding of color planes failed" in two common cases:
@@ -463,10 +519,10 @@ class IMG
463
519
  {
464
520
  $srcfile = FS::pathJoin(PREPROS::$config->image->source, $path);
465
521
  if(!$srcinfo = PREPROS::fstat($srcfile)) throw new Exception("Invalid image file.");
466
- $key = 'palette_' . STR::shorthash("{$srcfile}:{$srcinfo->modifiedAt}:{$colors}");
522
+ $key = 'aura_palette_' . STR::shorthash("{$srcfile}:{$srcinfo->modifiedAt}:{$colors}");
467
523
  if($palette = CACHE::get($key)) return $palette;
468
524
  if(!$localfile = current(PREPROS::mount($srcfile))) throw new Exception("Can't mount image.");
469
- if(!$palette = (new self($localfile))->getRepresentativeColors($colors)) throw new Exception("Can't extract palette from image \"{$path}\".");
525
+ if(!$palette = (new self($localfile))->getAuraColors($colors)) throw new Exception("Can't extract palette from image \"{$path}\".");
470
526
  CACHE::set($key, $palette);
471
527
  return $palette;
472
528
  }