@pixerate/editor 0.101.0 → 0.102.0

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.
@@ -197,6 +197,7 @@ GridCraft. Apache POI is © The Apache Software Foundation, licensed under the A
197
197
  - `crates/algo/src/transform.rs` (Free Transform: `Homography::square_to_quad`, `rect_to_quad`, `inverse`, `mul`, `local_scale`, `front_side`; `warp_output_bounds`, `convex_quad`; Photoshop's Bicubic as the Keys cubic at a = −0.75; the inverse-mapped warp per destination tile with premultiplied nearest / bilinear / bicubic sampling, the source footprint of each tile clipped against the horizon (Sutherland–Hodgman on the inverse w) and the front side of a source straddling it, grid snapping so an identity is exact, and a pre-reduction for bicubic shrinking) and `crates/algo/src/warp.rs` (`warp_mesh_surface` / `warp_triangles`: a forward-mapped grid of 4 px cells rasterized as triangles with barycentric source positions, binned per destination tile, with bilinear subsamples over each pixel's source footprint where the warp shrinks) → `transformSurface` and `warpSurface` in `packages/core/src/raster/transform.ts` and the homography helpers in `packages/core/src/geom/homography.ts`; single-threaded, on 8-bit tiles, with masks warped as value + inside flattened onto their default, a box pre-reduction by whole factors plus a widened cubic instead of photocraft's Image Size resize, and block-sampled previews of our own; test cases re-expressed (the 200 % step edge measured on Photoshop, the steep distort, the distort past the horizon, the prefiltered checkerboard) → `packages/core/tests/raster-transform.test.ts`
198
198
  - `crates/engine/src/transform_cmds.rs` (`split_selected` and `split_gray_selected`: lifting the selected pixels and the same part of a mask as grey + coverage, composited back over the rest; linked masks moving with their pixels and an unlinked mask transformed alone; position locks refusing a transform) and `crates/io/src/psd_import.rs` / `psd_export.rs` (mask flag bit 0 as an unlinked mask) → `packages/core/src/image-editor/free-transform.ts` and `packages/core/src/image-editor/psd/`; test cases re-expressed → `packages/core/tests/image-free-transform.test.ts`
199
199
  - `crates/io/src/effects_map.rs` (`parse_lfx2` / `write_lfx2`: the per-kind descriptor keys, the single and `…Multi` instance keys, `present` / `enab`, blend ids as four-character codes or long string ids, contours with corner points, `parse_lrfx` for legacy effects), `crates/io/src/blocks.rs` (`color_from_desc` / `color_to_desc`, `gradient_style`, the `Grdn` colour and transparency stops, `pattern_ref`, `pattern_placement`), `crates/io/src/psd_import.rs` / `psd_export.rs` (`lmfx` over `lfx2` / `lfxs`, the block kept and written back while the effects are unchanged, odd-length blocks padded) and `crates/psd/src/patterns.rs` (`Patt` / `Pat2` / `Pat3` blocks: patterns, virtual memory array lists, written channels, padded channel rectangles) → `packages/core/src/image-editor/psd/effects.ts` and `patterns.ts`; gradient midpoints become extra stops and smoothness is drawn linearly (photocraft bakes Photoshop's interpolation), and patterns are written as 8-bit RGB; test cases re-expressed → `packages/core/tests/image-psd-effects.test.ts`
200
+ - `crates/doc/src/lib.rs` (`SmartObject`: contents shared by an identity that ordinary duplicates keep and New Smart Object via Copy renews, the embedded or linked `SmartSource`, the placement transform with a warp applied first in source pixels and a projective override, the ordered `smart_filters` with blend, opacity and visibility, the stack-wide `filters_enabled` switch and the one `filter_mask`, the rendered `cache`) → `SmartContents`, `SmartPlacement`, `SmartFilterStack` and `SmartObjectLayer` in `packages/core/src/image-editor/layers/model.ts` and the operations in `layers/smart.ts`; the placement is our Free Transform geometry (corners plus a Bézier mesh), the smart filters are our `develop` / `blur` layer filters, and rendering, caching and Edit Contents as a nested document are our own; test cases re-expressed → `packages/core/tests/image-smart-objects.test.ts`
200
201
 
201
202
  ## soundcraft
202
203
 
@@ -2170,7 +2170,6 @@ function lerpTile(dst, before, alpha, coverage) {
2170
2170
  }
2171
2171
  var ZERO_TILE = new Uint8ClampedArray(TILE_BYTES);
2172
2172
  var isGroup = (l) => l.type === "group";
2173
- var isPixel = (l) => l.type === "pixel";
2174
2173
  var RasterCompositor = class {
2175
2174
  constructor(profile = {}, options = {}) {
2176
2175
  this.profile = profile;
@@ -2285,6 +2284,10 @@ var RasterCompositor = class {
2285
2284
  return this.maskTile(layer, r);
2286
2285
  }
2287
2286
  // --- Steps -------------------------------------------------------------------
2287
+ /** Pixel layers, and the layer kinds the profile composites like them. */
2288
+ isPixel(l) {
2289
+ return l.type === "pixel" || (this.profile.isPixelLike?.(l) ?? false);
2290
+ }
2288
2291
  isFilter(l) {
2289
2292
  return this.profile.isFilterLayer?.(l) ?? false;
2290
2293
  }
@@ -2325,7 +2328,7 @@ var RasterCompositor = class {
2325
2328
  if (key !== void 0) return key;
2326
2329
  const mask = layer.mask ? [layer.mask.enabled !== false, layer.mask.density ?? 1, layer.mask.feather ?? 0, layer.mask.defaultValue, layer.mask.source ?? null] : null;
2327
2330
  const base = [layer.type, layer.id, layer.visible, layer.opacity, layer.blend, Boolean(layer.clipped), mask];
2328
- if (isPixel(layer)) base.push(layer.offset?.x ?? 0, layer.offset?.y ?? 0, layer.fillOpacity ?? 1);
2331
+ if (this.isPixel(layer)) base.push(layer.offset?.x ?? 0, layer.offset?.y ?? 0, layer.fillOpacity ?? 1);
2329
2332
  if (this.hasEffects(layer)) base.push(effectsFingerprint(layer.effects));
2330
2333
  const extra = this.profile.layerKey?.(layer);
2331
2334
  if (extra !== void 0) base.push(extra);
@@ -2489,7 +2492,7 @@ var RasterCompositor = class {
2489
2492
  plainContentSig(layer, tx, ty) {
2490
2493
  const key = "C" + this.propsKey(layer);
2491
2494
  if (!layer.visible) return { key, refs: [] };
2492
- if (!isPixel(layer)) return { key, refs: this.maskRefs(layer, tx, ty, 0, 0) };
2495
+ if (!this.isPixel(layer)) return { key, refs: this.maskRefs(layer, tx, ty, 0, 0) };
2493
2496
  const { surface, dx, dy } = this.layerPixels(layer);
2494
2497
  const refs = [surface.defaultValue];
2495
2498
  const r = { x: tx * TILE - dx, y: ty * TILE - dy, width: TILE, height: TILE };
@@ -2543,7 +2546,7 @@ var RasterCompositor = class {
2543
2546
  effectRegion(layer) {
2544
2547
  const m = effectsMargin(layer.effects);
2545
2548
  const canvas = { x: -m, y: -m, width: this.sources.width + 2 * m, height: this.sources.height + 2 * m };
2546
- if (!isPixel(layer)) return canvas;
2549
+ if (!this.isPixel(layer)) return canvas;
2547
2550
  const { surface, dx, dy } = this.layerPixels(layer);
2548
2551
  if (surface.defaultValue !== 0) return canvas;
2549
2552
  const b = surface.bounds;
@@ -2652,7 +2655,7 @@ var RasterCompositor = class {
2652
2655
  * without filters or a feathered or parametric mask (those spread a change beyond it).
2653
2656
  */
2654
2657
  dirtyCoversShape(layer) {
2655
- if (!isPixel(layer) || this.profile.pixelFilters?.(layer)) return false;
2658
+ if (!this.isPixel(layer) || this.profile.pixelFilters?.(layer)) return false;
2656
2659
  const mask = layer.mask;
2657
2660
  return !mask || mask.enabled === false || !mask.source && !((mask.feather ?? 0) > 0);
2658
2661
  }
@@ -2711,7 +2714,7 @@ var RasterCompositor = class {
2711
2714
  maps,
2712
2715
  blend: blend2,
2713
2716
  opacity: layer.opacity,
2714
- fillOpacity: isPixel(layer) ? layer.fillOpacity ?? 1 : 1,
2717
+ fillOpacity: this.isPixel(layer) ? layer.fillOpacity ?? 1 : 1,
2715
2718
  canvas: { x: 0, y: 0, width: this.sources.width, height: this.sources.height },
2716
2719
  ctx: this.effectContext()
2717
2720
  });
@@ -2760,7 +2763,7 @@ var RasterCompositor = class {
2760
2763
  }
2761
2764
  /** RGBA of a content layer over `r` (document space, inside one tile), or `null` when it has nothing there. */
2762
2765
  contentTile(layer, r) {
2763
- if (!isPixel(layer)) return this.profile.contentTile?.(layer, r, this.sources) ?? null;
2766
+ if (!this.isPixel(layer)) return this.profile.contentTile?.(layer, r, this.sources) ?? null;
2764
2767
  const { surface, dx, dy, perPixel } = this.layerPixels(layer);
2765
2768
  const src = { x: r.x - dx, y: r.y - dy, width: r.width, height: r.height };
2766
2769
  const covered = tilesInRect(src).map((t) => surface.getTile(t.tx, t.ty));
@@ -2832,8 +2835,8 @@ var RasterCompositor = class {
2832
2835
  maskTile(layer, r) {
2833
2836
  const mask = layer.mask;
2834
2837
  if (!mask || mask.enabled === false) return null;
2835
- const ox = isPixel(layer) ? layer.offset?.x ?? 0 : 0;
2836
- const oy = isPixel(layer) ? layer.offset?.y ?? 0 : 0;
2838
+ const ox = this.isPixel(layer) ? layer.offset?.x ?? 0 : 0;
2839
+ const oy = this.isPixel(layer) ? layer.offset?.y ?? 0 : 0;
2837
2840
  const n = r.width * r.height;
2838
2841
  const out = new Float32Array(n);
2839
2842
  const density = mask.density ?? 1;
@@ -2894,7 +2897,7 @@ var RasterCompositor = class {
2894
2897
  }
2895
2898
  const content = this.contentTile(step.layer, r);
2896
2899
  if (!content) return empty;
2897
- const fill2 = isPixel(step.layer) ? step.layer.fillOpacity ?? 1 : 1;
2900
+ const fill2 = this.isPixel(step.layer) ? step.layer.fillOpacity ?? 1 : 1;
2898
2901
  const blend2 = this.contentBlend(step.layer);
2899
2902
  if (!clipped.length) return this.blendOnto(acc, content, empty, blend2, layer.opacity * fill2, coverage);
2900
2903
  const buf = new Uint8ClampedArray(acc.length);
@@ -2944,7 +2947,7 @@ var RasterCompositor = class {
2944
2947
  }
2945
2948
  const content = this.contentTile(c, r);
2946
2949
  if (!content) continue;
2947
- const fill2 = isPixel(c) ? c.fillOpacity ?? 1 : 1;
2950
+ const fill2 = this.isPixel(c) ? c.fillOpacity ?? 1 : 1;
2948
2951
  blendAtop(buf, content, this.contentBlend(c), c.opacity * fill2, coverage);
2949
2952
  }
2950
2953
  flush();
@@ -4649,4 +4652,4 @@ export {
4649
4652
  parseDataUrl,
4650
4653
  pngDataUrl
4651
4654
  };
4652
- //# sourceMappingURL=chunk-WIR377F6.js.map
4655
+ //# sourceMappingURL=chunk-67FRIOPZ.js.map