Skip to main content

ag_psd/
psd.rs

1/*
2File: crates/ag-psd/src/psd.rs
3
4Purpose:
5главные типы документа Psd (общая модель данных), опции чтения/записи.
6Это центральная shared-модель, на которую ссылаются все остальные модули порта.
7
8Source compatibility:
9- порт upstream-файла `test/ag-psd/src/psd.ts` (разбиение 1:1).
10- портированы ТОЛЬКО объявления модели данных (interface/type/enum/union).
11  Функции `readPsd`/`writePsd` и любая оркестрация чтения/записи здесь НЕ
12  портированы — их портирует отдельная задача в этот же файл.
13
14Соглашения порта (становятся конвенциями проекта):
15- TS optional `field?: T`  -> `field: Option<T>`.
16- TS string-union (BlendMode = 'normal' | ...) -> Rust `enum`
17  с `#[derive(Debug, Clone, Copy, PartialEq, Eq)]`; точные строковые значения
18  сохранены в doc-комментариях для будущего слоя (де)сериализации.
19- TS numeric enum -> Rust enum с явными дискриминантами, совпадающими с TS.
20- camelCase -> snake_case. Для 4-char PSD-ключей и неочевидных имён в
21  doc-комментарии указано оригинальное TS-имя.
22- структуры derive `Debug, Clone` (+ `Default`, где есть осмысленный default).
23- массивы -> `Vec<T>`; `Option<Box<T>>` только для разрыва рекурсии.
24
25Маппинг canvas / imageData:
26- В TS поля `canvas: HTMLCanvasElement` и `imageData: PixelData` (где PixelData
27  оборачивает типизированный массив). Здесь и то, и другое моделируется одним
28  типом `PixelData { width, height, data: Vec<u8> /* RGBA8 */ }`. Поля,
29  бывшие `canvas?: HTMLCanvasElement`, становятся `canvas: Option<PixelData>`,
30  чтобы сохранить раздельность полей оригинала. Крейт `image` не подключаем.
31- TS `Uint8Array` / `PixelArray` -> `Vec<u8>` (для PixelArray теряем сведения о
32  битности, как и просили — буфер сырых байт).
33
34Размещение типов:
35- Все типы документа определены здесь (это общая модель). Типы, которые в TS
36  жили бы в других модулях, но являются частью публичной формы документа,
37  тоже определены здесь. Никакие ещё-stub-модули не трогаются.
38*/
39
40// PORT STATUS: types ported; read/write orchestration pending
41
42// ===========================================================================
43// Canvas / pixel data mapping
44// ===========================================================================
45
46/// Замена для TS `HTMLCanvasElement` и `PixelData`.
47/// `data` — сырые пиксели RGBA8 (4 байта на пиксель), длина = width*height*4.
48/// (В оригинале тип массива зависит от битности документа — здесь храним байты.)
49#[derive(Debug, Clone, Default)]
50pub struct PixelData {
51    pub width: u32,
52    pub height: u32,
53    /// RGBA8, либо сырые байты канала(ов).
54    pub data: Vec<u8>,
55}
56
57// ===========================================================================
58// Blend mode (string union)
59// ===========================================================================
60
61/// TS `BlendMode` string-union. Строковые значения см. в doc-комментариях.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum BlendMode {
64    /// "pass through"
65    PassThrough,
66    /// "normal"
67    Normal,
68    /// "dissolve"
69    Dissolve,
70    /// "darken"
71    Darken,
72    /// "multiply"
73    Multiply,
74    /// "color burn"
75    ColorBurn,
76    /// "linear burn"
77    LinearBurn,
78    /// "darker color"
79    DarkerColor,
80    /// "lighten"
81    Lighten,
82    /// "screen"
83    Screen,
84    /// "color dodge"
85    ColorDodge,
86    /// "linear dodge"
87    LinearDodge,
88    /// "lighter color"
89    LighterColor,
90    /// "overlay"
91    Overlay,
92    /// "soft light"
93    SoftLight,
94    /// "hard light"
95    HardLight,
96    /// "vivid light"
97    VividLight,
98    /// "linear light"
99    LinearLight,
100    /// "pin light"
101    PinLight,
102    /// "hard mix"
103    HardMix,
104    /// "difference"
105    Difference,
106    /// "exclusion"
107    Exclusion,
108    /// "subtract"
109    Subtract,
110    /// "divide"
111    Divide,
112    /// "hue"
113    Hue,
114    /// "saturation"
115    Saturation,
116    /// "color"
117    Color,
118    /// "luminosity"
119    Luminosity,
120}
121
122// ===========================================================================
123// Numeric enums
124// ===========================================================================
125
126/// TS `const enum ColorMode`.
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub enum ColorMode {
129    Bitmap = 0,
130    Grayscale = 1,
131    Indexed = 2,
132    Rgb = 3,
133    Cmyk = 4,
134    Multichannel = 7,
135    Duotone = 8,
136    Lab = 9,
137}
138
139/// TS `const enum SectionDividerType`.
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
141pub enum SectionDividerType {
142    Other = 0,
143    OpenFolder = 1,
144    ClosedFolder = 2,
145    BoundingSectionDivider = 3,
146}
147
148/// TS `enum LayerCompCapturedInfo`.
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub enum LayerCompCapturedInfo {
151    None = 0,
152    Visibility = 1,
153    Position = 2,
154    Appearance = 4,
155}
156
157/// TS `const enum ChannelID`.
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub enum ChannelId {
160    /// red (rgb) / cyan (cmyk)
161    Color0 = 0,
162    /// green (rgb) / magenta (cmyk)
163    Color1 = 1,
164    /// blue (rgb) / yellow (cmyk)
165    Color2 = 2,
166    /// - (rgb) / black (cmyk)
167    Color3 = 3,
168    Transparency = -1,
169    UserMask = -2,
170    RealUserMask = -3,
171}
172
173/// TS `const enum Compression`.
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175pub enum Compression {
176    RawData = 0,
177    RleCompressed = 1,
178    ZipWithoutPrediction = 2,
179    ZipWithPrediction = 3,
180}
181
182// ===========================================================================
183// Color variants
184// ===========================================================================
185
186/// TS `RGBA` — values from 0 to 255.
187#[derive(Debug, Clone, Copy, Default, PartialEq)]
188pub struct Rgba {
189    pub r: f64,
190    pub g: f64,
191    pub b: f64,
192    pub a: f64,
193}
194
195/// TS `RGB` — values from 0 to 255.
196#[derive(Debug, Clone, Copy, Default, PartialEq)]
197pub struct Rgb {
198    pub r: f64,
199    pub g: f64,
200    pub b: f64,
201}
202
203/// TS `FRGB` — values from 0 to 1 (can be above 1, can be negative).
204#[derive(Debug, Clone, Copy, Default, PartialEq)]
205pub struct Frgb {
206    pub fr: f64,
207    pub fg: f64,
208    pub fb: f64,
209}
210
211/// TS `HSB` — values from 0 to 1.
212#[derive(Debug, Clone, Copy, Default, PartialEq)]
213pub struct Hsb {
214    pub h: f64,
215    pub s: f64,
216    pub b: f64,
217}
218
219/// TS `CMYK` — values from 0 to 255.
220#[derive(Debug, Clone, Copy, Default, PartialEq)]
221pub struct Cmyk {
222    pub c: f64,
223    pub m: f64,
224    pub y: f64,
225    pub k: f64,
226}
227
228/// TS `LAB` — `l` from 0 to 1; `a` and `b` from -1 to 1.
229#[derive(Debug, Clone, Copy, Default, PartialEq)]
230pub struct Lab {
231    pub l: f64,
232    pub a: f64,
233    pub b: f64,
234}
235
236/// TS `Grayscale` — values from 0 to 255.
237#[derive(Debug, Clone, Copy, Default, PartialEq)]
238pub struct Grayscale {
239    pub k: f64,
240}
241
242/// TS `Color = RGBA | RGB | FRGB | HSB | CMYK | LAB | Grayscale`.
243#[derive(Debug, Clone, Copy, PartialEq)]
244pub enum Color {
245    Rgba(Rgba),
246    Rgb(Rgb),
247    Frgb(Frgb),
248    Hsb(Hsb),
249    Cmyk(Cmyk),
250    Lab(Lab),
251    Grayscale(Grayscale),
252}
253
254// ===========================================================================
255// Units / generic small shapes
256// ===========================================================================
257
258/// TS `Units` string-union.
259#[derive(Debug, Clone, Copy, PartialEq, Eq)]
260pub enum Units {
261    /// "Pixels"
262    Pixels,
263    /// "Points"
264    Points,
265    /// "Picas"
266    Picas,
267    /// "Millimeters"
268    Millimeters,
269    /// "Centimeters"
270    Centimeters,
271    /// "Inches"
272    Inches,
273    /// "None"
274    None,
275    /// "Density"
276    Density,
277}
278
279/// TS `UnitsValue`.
280#[derive(Debug, Clone, Copy)]
281pub struct UnitsValue {
282    pub units: Units,
283    pub value: f64,
284}
285
286/// TS `UnitsBounds`.
287#[derive(Debug, Clone, Copy)]
288pub struct UnitsBounds {
289    pub top: UnitsValue,
290    pub left: UnitsValue,
291    pub right: UnitsValue,
292    pub bottom: UnitsValue,
293}
294
295/// Generic `{ x: number; y: number; }` point.
296#[derive(Debug, Clone, Copy, Default, PartialEq)]
297pub struct PointF {
298    pub x: f64,
299    pub y: f64,
300}
301
302/// Generic `{ x: UnitsValue; y: UnitsValue; }`.
303#[derive(Debug, Clone, Copy)]
304pub struct UnitsPoint {
305    pub x: UnitsValue,
306    pub y: UnitsValue,
307}
308
309/// Generic `{ horizontal: number; vertical: number; }`.
310#[derive(Debug, Clone, Copy, Default)]
311pub struct HorizontalVertical {
312    pub horizontal: f64,
313    pub vertical: f64,
314}
315
316/// Generic integer rect `{ top; left; bottom; right; }`.
317#[derive(Debug, Clone, Copy, Default)]
318pub struct Bounds {
319    pub top: f64,
320    pub left: f64,
321    pub bottom: f64,
322    pub right: f64,
323}
324
325/// Generic `{ left; top; right; bottom; }` (order as it appears in slices).
326#[derive(Debug, Clone, Copy, Default)]
327pub struct LtrbBounds {
328    pub left: f64,
329    pub top: f64,
330    pub right: f64,
331    pub bottom: f64,
332}
333
334/// TS `Fraction`.
335#[derive(Debug, Clone, Copy, Default)]
336pub struct Fraction {
337    pub numerator: f64,
338    pub denominator: f64,
339}
340
341// ===========================================================================
342// String-union helper enums
343// ===========================================================================
344
345/// TS `TextGridding = 'none' | 'round'`.
346#[derive(Debug, Clone, Copy, PartialEq, Eq)]
347pub enum TextGridding {
348    /// "none"
349    None,
350    /// "round"
351    Round,
352}
353
354/// TS `Orientation = 'horizontal' | 'vertical'`.
355#[derive(Debug, Clone, Copy, PartialEq, Eq)]
356pub enum Orientation {
357    /// "horizontal"
358    Horizontal,
359    /// "vertical"
360    Vertical,
361}
362
363/// TS `AntiAlias`.
364#[derive(Debug, Clone, Copy, PartialEq, Eq)]
365pub enum AntiAlias {
366    /// "none"
367    None,
368    /// "sharp"
369    Sharp,
370    /// "crisp"
371    Crisp,
372    /// "strong"
373    Strong,
374    /// "smooth"
375    Smooth,
376    /// "platform"
377    Platform,
378    /// "platformLCD"
379    PlatformLcd,
380}
381
382/// TS `WarpStyle`.
383#[derive(Debug, Clone, Copy, PartialEq, Eq)]
384pub enum WarpStyle {
385    /// "none"
386    None,
387    /// "arc"
388    Arc,
389    /// "arcLower"
390    ArcLower,
391    /// "arcUpper"
392    ArcUpper,
393    /// "arch"
394    Arch,
395    /// "bulge"
396    Bulge,
397    /// "shellLower"
398    ShellLower,
399    /// "shellUpper"
400    ShellUpper,
401    /// "flag"
402    Flag,
403    /// "wave"
404    Wave,
405    /// "fish"
406    Fish,
407    /// "rise"
408    Rise,
409    /// "fisheye"
410    Fisheye,
411    /// "inflate"
412    Inflate,
413    /// "squeeze"
414    Squeeze,
415    /// "twist"
416    Twist,
417    /// "custom"
418    Custom,
419    /// "cylinder"
420    Cylinder,
421}
422
423/// TS `BevelStyle`.
424#[derive(Debug, Clone, Copy, PartialEq, Eq)]
425pub enum BevelStyle {
426    /// "outer bevel"
427    OuterBevel,
428    /// "inner bevel"
429    InnerBevel,
430    /// "emboss"
431    Emboss,
432    /// "pillow emboss"
433    PillowEmboss,
434    /// "stroke emboss"
435    StrokeEmboss,
436}
437
438/// TS `BevelTechnique`.
439#[derive(Debug, Clone, Copy, PartialEq, Eq)]
440pub enum BevelTechnique {
441    /// "smooth"
442    Smooth,
443    /// "chisel hard"
444    ChiselHard,
445    /// "chisel soft"
446    ChiselSoft,
447}
448
449/// TS `BevelDirection`.
450#[derive(Debug, Clone, Copy, PartialEq, Eq)]
451pub enum BevelDirection {
452    /// "up"
453    Up,
454    /// "down"
455    Down,
456}
457
458/// TS `GlowTechnique`.
459#[derive(Debug, Clone, Copy, PartialEq, Eq)]
460pub enum GlowTechnique {
461    /// "softer"
462    Softer,
463    /// "precise"
464    Precise,
465}
466
467/// TS `GlowSource`.
468#[derive(Debug, Clone, Copy, PartialEq, Eq)]
469pub enum GlowSource {
470    /// "edge"
471    Edge,
472    /// "center"
473    Center,
474}
475
476/// TS `GradientStyle`.
477#[derive(Debug, Clone, Copy, PartialEq, Eq)]
478pub enum GradientStyle {
479    /// "linear"
480    Linear,
481    /// "radial"
482    Radial,
483    /// "angle"
484    Angle,
485    /// "reflected"
486    Reflected,
487    /// "diamond"
488    Diamond,
489}
490
491/// TS `Justification`.
492#[derive(Debug, Clone, Copy, PartialEq, Eq)]
493pub enum Justification {
494    /// "left"
495    Left,
496    /// "right"
497    Right,
498    /// "center"
499    Center,
500    /// "justify-left"
501    JustifyLeft,
502    /// "justify-right"
503    JustifyRight,
504    /// "justify-center"
505    JustifyCenter,
506    /// "justify-all"
507    JustifyAll,
508}
509
510/// TS `LineCapType`.
511#[derive(Debug, Clone, Copy, PartialEq, Eq)]
512pub enum LineCapType {
513    /// "butt"
514    Butt,
515    /// "round"
516    Round,
517    /// "square"
518    Square,
519}
520
521/// TS `LineJoinType`.
522#[derive(Debug, Clone, Copy, PartialEq, Eq)]
523pub enum LineJoinType {
524    /// "miter"
525    Miter,
526    /// "round"
527    Round,
528    /// "bevel"
529    Bevel,
530}
531
532/// TS `LineAlignment`.
533#[derive(Debug, Clone, Copy, PartialEq, Eq)]
534pub enum LineAlignment {
535    /// "inside"
536    Inside,
537    /// "center"
538    Center,
539    /// "outside"
540    Outside,
541}
542
543/// TS `InterpolationMethod`.
544#[derive(Debug, Clone, Copy, PartialEq, Eq)]
545pub enum InterpolationMethod {
546    /// "classic"
547    Classic,
548    /// "perceptual"
549    Perceptual,
550    /// "linear"
551    Linear,
552    /// "smooth"
553    Smooth,
554}
555
556/// TS `RenderingIntent`.
557#[derive(Debug, Clone, Copy, PartialEq, Eq)]
558pub enum RenderingIntent {
559    /// "perceptual"
560    Perceptual,
561    /// "saturation"
562    Saturation,
563    /// "relative colorimetric"
564    RelativeColorimetric,
565    /// "absolute colorimetric"
566    AbsoluteColorimetric,
567}
568
569/// TS `BooleanOperation`.
570#[derive(Debug, Clone, Copy, PartialEq, Eq)]
571pub enum BooleanOperation {
572    /// "exclude"
573    Exclude,
574    /// "combine"
575    Combine,
576    /// "subtract"
577    Subtract,
578    /// "intersect"
579    Intersect,
580}
581
582/// TS `LayerColor`.
583#[derive(Debug, Clone, Copy, PartialEq, Eq)]
584pub enum LayerColor {
585    /// "none"
586    None,
587    /// "red"
588    Red,
589    /// "orange"
590    Orange,
591    /// "yellow"
592    Yellow,
593    /// "green"
594    Green,
595    /// "blue"
596    Blue,
597    /// "violet"
598    Violet,
599    /// "gray"
600    Gray,
601}
602
603/// TS `PlacedLayerType`.
604#[derive(Debug, Clone, Copy, PartialEq, Eq)]
605pub enum PlacedLayerType {
606    /// "unknown"
607    Unknown,
608    /// "vector"
609    Vector,
610    /// "raster"
611    Raster,
612    /// "image stack"
613    ImageStack,
614}
615
616/// TS `TimelineKeyInterpolation`.
617#[derive(Debug, Clone, Copy, PartialEq, Eq)]
618pub enum TimelineKeyInterpolation {
619    /// "linear"
620    Linear,
621    /// "hold"
622    Hold,
623}
624
625/// TS `TimelineTrackType`.
626#[derive(Debug, Clone, Copy, PartialEq, Eq)]
627pub enum TimelineTrackType {
628    /// "opacity"
629    Opacity,
630    /// "style"
631    Style,
632    /// "sheetTransform"
633    SheetTransform,
634    /// "sheetPosition"
635    SheetPosition,
636    /// "globalLighting"
637    GlobalLighting,
638}
639
640/// TS `LayerEffectStroke.position`.
641#[derive(Debug, Clone, Copy, PartialEq, Eq)]
642pub enum StrokePosition {
643    /// "inside"
644    Inside,
645    /// "center"
646    Center,
647    /// "outside"
648    Outside,
649}
650
651/// TS `LayerEffectStroke.fillType`.
652#[derive(Debug, Clone, Copy, PartialEq, Eq)]
653pub enum StrokeFillType {
654    /// "color"
655    Color,
656    /// "gradient"
657    Gradient,
658    /// "pattern"
659    Pattern,
660}
661
662/// TS `EffectNoiseGradient.colorModel` and similar `'rgb' | 'hsb' | 'lab'`.
663#[derive(Debug, Clone, Copy, PartialEq, Eq)]
664pub enum GradientColorModel {
665    /// "rgb"
666    Rgb,
667    /// "hsb"
668    Hsb,
669    /// "lab"
670    Lab,
671}
672
673/// TS `BezierPath.fillRule = 'even-odd' | 'non-zero'`.
674#[derive(Debug, Clone, Copy, PartialEq, Eq)]
675pub enum FillRule {
676    /// "even-odd"
677    EvenOdd,
678    /// "non-zero"
679    NonZero,
680}
681
682// ===========================================================================
683// Effects
684// ===========================================================================
685
686/// TS `EffectContour`.
687#[derive(Debug, Clone, Default)]
688pub struct EffectContour {
689    pub name: String,
690    /// curve points `{ x; y; }[]`
691    pub curve: Vec<PointF>,
692}
693
694/// TS `EffectPattern` (TODO: add fields upstream).
695#[derive(Debug, Clone, Default)]
696pub struct EffectPattern {
697    pub name: String,
698    pub id: String,
699}
700
701/// TS `ColorStop`.
702#[derive(Debug, Clone)]
703pub struct ColorStop {
704    pub color: Color,
705    pub location: f64,
706    pub midpoint: f64,
707}
708
709/// TS `OpacityStop`.
710#[derive(Debug, Clone, Default)]
711pub struct OpacityStop {
712    pub opacity: f64,
713    pub location: f64,
714    pub midpoint: f64,
715}
716
717/// TS `EffectSolidGradient` (`type: 'solid'`).
718#[derive(Debug, Clone, Default)]
719pub struct EffectSolidGradient {
720    pub name: String,
721    pub smoothness: Option<f64>,
722    pub color_stops: Vec<ColorStop>,
723    pub opacity_stops: Vec<OpacityStop>,
724}
725
726/// TS `EffectNoiseGradient` (`type: 'noise'`).
727#[derive(Debug, Clone, Default)]
728pub struct EffectNoiseGradient {
729    pub name: String,
730    pub roughness: Option<f64>,
731    pub color_model: Option<GradientColorModel>,
732    pub random_seed: Option<f64>,
733    pub restrict_colors: Option<bool>,
734    pub add_transparency: Option<bool>,
735    pub min: Vec<f64>,
736    pub max: Vec<f64>,
737}
738
739/// TS union `EffectSolidGradient | EffectNoiseGradient`.
740#[derive(Debug, Clone)]
741pub enum EffectGradient {
742    Solid(EffectSolidGradient),
743    Noise(EffectNoiseGradient),
744}
745
746/// TS `ExtraGradientInfo` (intersected with gradient unions in several places).
747#[derive(Debug, Clone, Default)]
748pub struct ExtraGradientInfo {
749    pub style: Option<GradientStyle>,
750    pub scale: Option<f64>,
751    pub angle: Option<f64>,
752    pub dither: Option<bool>,
753    pub interpolation_method: Option<InterpolationMethod>,
754    pub reverse: Option<bool>,
755    pub align: Option<bool>,
756    pub offset: Option<PointF>,
757}
758
759/// TS `ExtraPatternInfo`.
760#[derive(Debug, Clone, Default)]
761pub struct ExtraPatternInfo {
762    pub linked: Option<bool>,
763    pub phase: Option<PointF>,
764}
765
766/// TS `(EffectSolidGradient | EffectNoiseGradient) & ExtraGradientInfo`.
767#[derive(Debug, Clone)]
768pub struct GradientWithExtra {
769    pub gradient: EffectGradient,
770    pub extra: ExtraGradientInfo,
771}
772
773/// TS `LayerEffectShadow` (drop & inner shadow).
774#[derive(Debug, Clone, Default)]
775pub struct LayerEffectShadow {
776    pub present: Option<bool>,
777    pub show_in_dialog: Option<bool>,
778    pub enabled: Option<bool>,
779    pub size: Option<UnitsValue>,
780    pub angle: Option<f64>,
781    pub distance: Option<UnitsValue>,
782    pub color: Option<Color>,
783    pub blend_mode: Option<BlendMode>,
784    pub opacity: Option<f64>,
785    pub use_global_light: Option<bool>,
786    pub antialiased: Option<bool>,
787    pub contour: Option<EffectContour>,
788    /// spread
789    pub choke: Option<UnitsValue>,
790    /// only drop shadow
791    pub layer_conceals: Option<bool>,
792}
793
794/// TS `LayerEffectsOuterGlow`.
795#[derive(Debug, Clone, Default)]
796pub struct LayerEffectsOuterGlow {
797    pub present: Option<bool>,
798    pub show_in_dialog: Option<bool>,
799    pub enabled: Option<bool>,
800    pub size: Option<UnitsValue>,
801    pub color: Option<Color>,
802    pub blend_mode: Option<BlendMode>,
803    pub opacity: Option<f64>,
804    pub source: Option<GlowSource>,
805    pub antialiased: Option<bool>,
806    pub noise: Option<f64>,
807    pub range: Option<f64>,
808    pub choke: Option<UnitsValue>,
809    pub jitter: Option<f64>,
810    pub contour: Option<EffectContour>,
811}
812
813/// TS `LayerEffectInnerGlow`.
814#[derive(Debug, Clone, Default)]
815pub struct LayerEffectInnerGlow {
816    pub present: Option<bool>,
817    pub show_in_dialog: Option<bool>,
818    pub enabled: Option<bool>,
819    pub size: Option<UnitsValue>,
820    pub color: Option<Color>,
821    pub blend_mode: Option<BlendMode>,
822    pub opacity: Option<f64>,
823    pub source: Option<GlowSource>,
824    pub technique: Option<GlowTechnique>,
825    pub antialiased: Option<bool>,
826    pub noise: Option<f64>,
827    pub range: Option<f64>,
828    /// spread
829    pub choke: Option<UnitsValue>,
830    pub jitter: Option<f64>,
831    pub contour: Option<EffectContour>,
832}
833
834/// TS `LayerEffectBevel`.
835#[derive(Debug, Clone, Default)]
836pub struct LayerEffectBevel {
837    pub present: Option<bool>,
838    pub show_in_dialog: Option<bool>,
839    pub enabled: Option<bool>,
840    pub size: Option<UnitsValue>,
841    pub angle: Option<f64>,
842    /// depth
843    pub strength: Option<f64>,
844    pub highlight_blend_mode: Option<BlendMode>,
845    pub shadow_blend_mode: Option<BlendMode>,
846    pub highlight_color: Option<Color>,
847    pub shadow_color: Option<Color>,
848    pub style: Option<BevelStyle>,
849    pub highlight_opacity: Option<f64>,
850    pub shadow_opacity: Option<f64>,
851    pub soften: Option<UnitsValue>,
852    pub use_global_light: Option<bool>,
853    pub altitude: Option<f64>,
854    pub technique: Option<BevelTechnique>,
855    pub direction: Option<BevelDirection>,
856    pub use_texture: Option<bool>,
857    pub use_shape: Option<bool>,
858    pub antialias_gloss: Option<bool>,
859    pub contour: Option<EffectContour>,
860}
861
862/// TS `LayerEffectSolidFill`.
863#[derive(Debug, Clone, Default)]
864pub struct LayerEffectSolidFill {
865    pub present: Option<bool>,
866    pub show_in_dialog: Option<bool>,
867    pub enabled: Option<bool>,
868    pub blend_mode: Option<BlendMode>,
869    pub color: Option<Color>,
870    pub opacity: Option<f64>,
871}
872
873/// TS `LayerEffectStroke`.
874#[derive(Debug, Clone, Default)]
875pub struct LayerEffectStroke {
876    pub present: Option<bool>,
877    pub show_in_dialog: Option<bool>,
878    pub enabled: Option<bool>,
879    pub overprint: Option<bool>,
880    pub size: Option<UnitsValue>,
881    pub position: Option<StrokePosition>,
882    pub fill_type: Option<StrokeFillType>,
883    pub blend_mode: Option<BlendMode>,
884    pub opacity: Option<f64>,
885    pub color: Option<Color>,
886    /// `(EffectSolidGradient | EffectNoiseGradient) & ExtraGradientInfo`
887    pub gradient: Option<GradientWithExtra>,
888    /// `EffectPattern & {}` (TODO: additional pattern info upstream)
889    pub pattern: Option<EffectPattern>,
890}
891
892/// TS `LayerEffectSatin`.
893#[derive(Debug, Clone, Default)]
894pub struct LayerEffectSatin {
895    pub present: Option<bool>,
896    pub show_in_dialog: Option<bool>,
897    pub enabled: Option<bool>,
898    pub size: Option<UnitsValue>,
899    pub blend_mode: Option<BlendMode>,
900    pub color: Option<Color>,
901    pub antialiased: Option<bool>,
902    pub opacity: Option<f64>,
903    pub distance: Option<UnitsValue>,
904    pub invert: Option<bool>,
905    pub angle: Option<f64>,
906    pub contour: Option<EffectContour>,
907}
908
909/// TS `LayerEffectPatternOverlay` (not supported yet upstream — `Patt` section).
910#[derive(Debug, Clone, Default)]
911pub struct LayerEffectPatternOverlay {
912    pub present: Option<bool>,
913    pub show_in_dialog: Option<bool>,
914    pub enabled: Option<bool>,
915    pub blend_mode: Option<BlendMode>,
916    pub opacity: Option<f64>,
917    pub scale: Option<f64>,
918    pub pattern: Option<EffectPattern>,
919    pub phase: Option<PointF>,
920    pub align: Option<bool>,
921}
922
923/// TS `LayerEffectGradientOverlay`.
924#[derive(Debug, Clone, Default)]
925pub struct LayerEffectGradientOverlay {
926    /// NOTE: in TS this is `string`, not `BlendMode`.
927    pub blend_mode: Option<String>,
928    pub present: Option<bool>,
929    pub show_in_dialog: Option<bool>,
930    pub enabled: Option<bool>,
931    pub opacity: Option<f64>,
932    pub align: Option<bool>,
933    pub scale: Option<f64>,
934    pub dither: Option<bool>,
935    pub reverse: Option<bool>,
936    /// TS field `type`
937    pub gradient_type: Option<GradientStyle>,
938    pub offset: Option<PointF>,
939    pub gradient: Option<EffectGradient>,
940    pub interpolation_method: Option<InterpolationMethod>,
941    /// degrees
942    pub angle: Option<f64>,
943}
944
945/// TS `LayerEffectsInfo`.
946#[derive(Debug, Clone, Default)]
947pub struct LayerEffectsInfo {
948    pub disabled: Option<bool>,
949    pub scale: Option<f64>,
950    pub drop_shadow: Option<Vec<LayerEffectShadow>>,
951    pub inner_shadow: Option<Vec<LayerEffectShadow>>,
952    pub outer_glow: Option<LayerEffectsOuterGlow>,
953    pub inner_glow: Option<LayerEffectInnerGlow>,
954    pub bevel: Option<LayerEffectBevel>,
955    pub solid_fill: Option<Vec<LayerEffectSolidFill>>,
956    pub satin: Option<LayerEffectSatin>,
957    pub stroke: Option<Vec<LayerEffectStroke>>,
958    pub gradient_overlay: Option<Vec<LayerEffectGradientOverlay>>,
959    /// not supported yet upstream because of `Patt` section
960    pub pattern_overlay: Option<LayerEffectPatternOverlay>,
961}
962
963// ===========================================================================
964// Mask data
965// ===========================================================================
966
967/// TS `LayerMaskData`.
968#[derive(Debug, Clone, Default)]
969pub struct LayerMaskData {
970    pub top: Option<f64>,
971    pub left: Option<f64>,
972    pub bottom: Option<f64>,
973    pub right: Option<f64>,
974    pub default_color: Option<f64>,
975    pub disabled: Option<bool>,
976    pub position_relative_to_layer: Option<bool>,
977    /// true if mask is generated from vector data, false if bitmap from user.
978    pub from_vector_data: Option<bool>,
979    pub user_mask_density: Option<f64>,
980    /// px
981    pub user_mask_feather: Option<f64>,
982    pub vector_mask_density: Option<f64>,
983    pub vector_mask_feather: Option<f64>,
984    /// TS `canvas?: HTMLCanvasElement` -> raw pixels.
985    pub canvas: Option<PixelData>,
986    pub image_data: Option<PixelData>,
987}
988
989// ===========================================================================
990// Warp / animations / fonts / text
991// ===========================================================================
992
993/// TS `Warp.customEnvelopeWarp`.
994#[derive(Debug, Clone, Default)]
995pub struct CustomEnvelopeWarp {
996    pub quilt_slice_x: Option<Vec<f64>>,
997    pub quilt_slice_y: Option<Vec<f64>>,
998    /// 16 points top-left to bottom-right, rows first, relative to first point.
999    pub mesh_points: Vec<PointF>,
1000}
1001
1002/// TS `Warp`.
1003#[derive(Debug, Clone, Default)]
1004pub struct Warp {
1005    pub style: Option<WarpStyle>,
1006    pub value: Option<f64>,
1007    pub values: Option<Vec<f64>>,
1008    pub perspective: Option<f64>,
1009    pub perspective_other: Option<f64>,
1010    pub rotate: Option<Orientation>,
1011    /// for custom warps
1012    pub bounds: Option<UnitsBounds>,
1013    pub u_order: Option<f64>,
1014    pub v_order: Option<f64>,
1015    pub deform_num_rows: Option<f64>,
1016    pub deform_num_cols: Option<f64>,
1017    pub custom_envelope_warp: Option<CustomEnvelopeWarp>,
1018}
1019
1020/// TS `Animations.frames[]` element.
1021#[derive(Debug, Clone, Default)]
1022pub struct AnimationFrameInfo {
1023    pub id: f64,
1024    pub delay: f64,
1025    /// 'auto' | 'none' | 'dispose'
1026    pub dispose: Option<AnimationDispose>,
1027}
1028
1029/// TS `Animations.frames[].dispose` string-union.
1030#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1031pub enum AnimationDispose {
1032    /// "auto"
1033    Auto,
1034    /// "none"
1035    None,
1036    /// "dispose"
1037    Dispose,
1038}
1039
1040/// TS `Animations.animations[]` element.
1041#[derive(Debug, Clone, Default)]
1042pub struct AnimationInfo {
1043    pub id: f64,
1044    pub frames: Vec<f64>,
1045    pub repeats: Option<f64>,
1046    pub active_frame: Option<f64>,
1047}
1048
1049/// TS `Animations`.
1050#[derive(Debug, Clone, Default)]
1051pub struct Animations {
1052    pub frames: Vec<AnimationFrameInfo>,
1053    pub animations: Vec<AnimationInfo>,
1054}
1055
1056/// TS `Font`.
1057#[derive(Debug, Clone, Default)]
1058pub struct Font {
1059    pub name: String,
1060    pub script: Option<f64>,
1061    /// TS field `type`
1062    pub font_type: Option<f64>,
1063    pub synthetic: Option<f64>,
1064}
1065
1066/// TS `ParagraphStyle`.
1067#[derive(Debug, Clone, Default)]
1068pub struct ParagraphStyle {
1069    pub justification: Option<Justification>,
1070    pub first_line_indent: Option<f64>,
1071    pub start_indent: Option<f64>,
1072    pub end_indent: Option<f64>,
1073    pub space_before: Option<f64>,
1074    pub space_after: Option<f64>,
1075    pub auto_hyphenate: Option<bool>,
1076    pub hyphenated_word_size: Option<f64>,
1077    pub pre_hyphen: Option<f64>,
1078    pub post_hyphen: Option<f64>,
1079    pub consecutive_hyphens: Option<f64>,
1080    pub zone: Option<f64>,
1081    pub word_spacing: Option<Vec<f64>>,
1082    pub letter_spacing: Option<Vec<f64>>,
1083    pub glyph_spacing: Option<Vec<f64>>,
1084    pub auto_leading: Option<f64>,
1085    pub leading_type: Option<f64>,
1086    pub hanging: Option<bool>,
1087    pub burasagari: Option<bool>,
1088    pub kinsoku_order: Option<f64>,
1089    pub every_line_composer: Option<bool>,
1090}
1091
1092/// TS `ParagraphStyleRun`.
1093#[derive(Debug, Clone, Default)]
1094pub struct ParagraphStyleRun {
1095    pub length: f64,
1096    pub style: ParagraphStyle,
1097}
1098
1099/// TS `TextStyle`.
1100#[derive(Debug, Clone, Default)]
1101pub struct TextStyle {
1102    pub font: Option<Font>,
1103    pub font_size: Option<f64>,
1104    pub faux_bold: Option<bool>,
1105    pub faux_italic: Option<bool>,
1106    pub auto_leading: Option<bool>,
1107    pub leading: Option<f64>,
1108    pub horizontal_scale: Option<f64>,
1109    pub vertical_scale: Option<f64>,
1110    pub tracking: Option<f64>,
1111    pub auto_kerning: Option<bool>,
1112    pub kerning: Option<f64>,
1113    pub baseline_shift: Option<f64>,
1114    /// 0 - none, 1 - small caps, 2 - all caps
1115    pub font_caps: Option<f64>,
1116    /// 0 - normal, 1 - superscript, 2 - subscript
1117    pub font_baseline: Option<f64>,
1118    pub underline: Option<bool>,
1119    pub strikethrough: Option<bool>,
1120    pub ligatures: Option<bool>,
1121    pub d_ligatures: Option<bool>,
1122    pub baseline_direction: Option<f64>,
1123    pub tsume: Option<f64>,
1124    pub style_run_alignment: Option<f64>,
1125    pub language: Option<f64>,
1126    pub no_break: Option<bool>,
1127    pub fill_color: Option<Color>,
1128    pub stroke_color: Option<Color>,
1129    pub fill_flag: Option<bool>,
1130    pub stroke_flag: Option<bool>,
1131    pub fill_first: Option<bool>,
1132    pub y_underline: Option<f64>,
1133    pub outline_width: Option<f64>,
1134    pub character_direction: Option<f64>,
1135    pub hindi_numbers: Option<bool>,
1136    pub kashida: Option<f64>,
1137    pub diacritic_pos: Option<f64>,
1138}
1139
1140/// TS `TextStyleRun`.
1141#[derive(Debug, Clone, Default)]
1142pub struct TextStyleRun {
1143    pub length: f64,
1144    pub style: TextStyle,
1145}
1146
1147/// TS `TextGridInfo`.
1148#[derive(Debug, Clone, Default)]
1149pub struct TextGridInfo {
1150    pub is_on: Option<bool>,
1151    pub show: Option<bool>,
1152    pub size: Option<f64>,
1153    pub leading: Option<f64>,
1154    pub color: Option<Color>,
1155    pub leading_fill_color: Option<Color>,
1156    pub align_line_height_to_grid_flags: Option<bool>,
1157}
1158
1159/// TS `TextPath.bezierCurve`.
1160#[derive(Debug, Clone, Default)]
1161pub struct TextPathBezierCurve {
1162    /// 8 values per bezier curve
1163    pub control_points: Vec<f64>,
1164}
1165
1166/// TS `TextPath.data.BaselineAlignment`.
1167#[derive(Debug, Clone, Default)]
1168pub struct TextPathBaselineAlignment {
1169    pub flag: Option<f64>,
1170    pub min: Option<f64>,
1171}
1172
1173/// TS `TextPath.data.pathData`.
1174#[derive(Debug, Clone, Default)]
1175pub struct TextPathPathData {
1176    pub reversed: Option<bool>,
1177    pub spacing: Option<f64>,
1178}
1179
1180/// TS `TextPath.data`.
1181#[derive(Debug, Clone, Default)]
1182pub struct TextPathData {
1183    /// TS field `type`
1184    pub path_type: Option<f64>,
1185    pub orientation: Option<f64>,
1186    pub frame_matrix: Vec<f64>,
1187    pub text_range: Vec<f64>,
1188    pub row_gutter: Option<f64>,
1189    pub column_gutter: Option<f64>,
1190    pub baseline_alignment: Option<TextPathBaselineAlignment>,
1191    pub path_data: TextPathPathData,
1192}
1193
1194/// TS `TextPath`.
1195#[derive(Debug, Clone, Default)]
1196pub struct TextPath {
1197    /// TODO: this is probably not a name (upstream note)
1198    pub name: Option<Vec<f64>>,
1199    pub bezier_curve: Option<TextPathBezierCurve>,
1200    pub data: TextPathData,
1201    pub uuid: Option<String>,
1202}
1203
1204/// TS `LayerTextData.shapeType`.
1205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1206pub enum TextShapeType {
1207    /// "point"
1208    Point,
1209    /// "box"
1210    Box,
1211}
1212
1213/// TS `LayerTextData`.
1214#[derive(Debug, Clone, Default)]
1215pub struct LayerTextData {
1216    pub text: String,
1217    /// 2d transform matrix [xx, xy, yx, yy, tx, ty]
1218    pub transform: Option<Vec<f64>>,
1219    pub anti_alias: Option<AntiAlias>,
1220    pub gridding: Option<TextGridding>,
1221    pub orientation: Option<Orientation>,
1222    /// index of Editor in extra editor data related to this layer
1223    pub index: Option<f64>,
1224    pub warp: Option<Warp>,
1225    pub top: Option<f64>,
1226    pub left: Option<f64>,
1227    pub bottom: Option<f64>,
1228    pub right: Option<f64>,
1229    pub grid_info: Option<TextGridInfo>,
1230    pub use_fractional_glyph_widths: Option<bool>,
1231    /// base style
1232    pub style: Option<TextStyle>,
1233    /// spans of different style
1234    pub style_runs: Option<Vec<TextStyleRun>>,
1235    /// base paragraph style
1236    pub paragraph_style: Option<ParagraphStyle>,
1237    /// style for each line
1238    pub paragraph_style_runs: Option<Vec<ParagraphStyleRun>>,
1239    pub superscript_size: Option<f64>,
1240    pub superscript_position: Option<f64>,
1241    pub subscript_size: Option<f64>,
1242    pub subscript_position: Option<f64>,
1243    pub small_cap_size: Option<f64>,
1244    pub shape_type: Option<TextShapeType>,
1245    pub point_base: Option<Vec<f64>>,
1246    pub box_bounds: Option<Vec<f64>>,
1247    pub bounds: Option<UnitsBounds>,
1248    pub bounding_box: Option<UnitsBounds>,
1249    /// This is a read-only field; any changes will not be saved.
1250    pub text_path: Option<TextPath>,
1251}
1252
1253// ===========================================================================
1254// Patterns / paths / vector content
1255// ===========================================================================
1256
1257/// TS `PatternInfo`.
1258#[derive(Debug, Clone, Default)]
1259pub struct PatternInfo {
1260    pub name: String,
1261    pub id: String,
1262    pub x: f64,
1263    pub y: f64,
1264    /// `{ x; y; w; h; }`
1265    pub bounds: PatternBounds,
1266    pub data: Vec<u8>,
1267}
1268
1269/// TS `PatternInfo.bounds` shape `{ x; y; w; h; }`.
1270#[derive(Debug, Clone, Copy, Default)]
1271pub struct PatternBounds {
1272    pub x: f64,
1273    pub y: f64,
1274    pub w: f64,
1275    pub h: f64,
1276}
1277
1278/// TS `BezierKnot`.
1279#[derive(Debug, Clone, Default)]
1280pub struct BezierKnot {
1281    pub linked: bool,
1282    /// x0, y0, x1, y1, x2, y2
1283    pub points: Vec<f64>,
1284}
1285
1286/// TS `BezierPath`.
1287#[derive(Debug, Clone)]
1288pub struct BezierPath {
1289    pub open: bool,
1290    pub operation: Option<BooleanOperation>,
1291    pub knots: Vec<BezierKnot>,
1292    pub fill_rule: FillRule,
1293}
1294
1295/// TS `VectorContent` union.
1296#[derive(Debug, Clone)]
1297pub enum VectorContent {
1298    /// `{ type: 'color'; color: Color; }`
1299    Color(Color),
1300    /// `EffectSolidGradient & ExtraGradientInfo`
1301    SolidGradient {
1302        gradient: EffectSolidGradient,
1303        extra: ExtraGradientInfo,
1304    },
1305    /// `EffectNoiseGradient & ExtraGradientInfo`
1306    NoiseGradient {
1307        gradient: EffectNoiseGradient,
1308        extra: ExtraGradientInfo,
1309    },
1310    /// `EffectPattern & { type: 'pattern'; } & ExtraPatternInfo`
1311    Pattern {
1312        pattern: EffectPattern,
1313        extra: ExtraPatternInfo,
1314    },
1315}
1316
1317// ===========================================================================
1318// Adjustments
1319// ===========================================================================
1320
1321/// TS `PresetInfo` (mixed into several adjustments).
1322#[derive(Debug, Clone, Default)]
1323pub struct PresetInfo {
1324    pub preset_kind: Option<f64>,
1325    pub preset_file_name: Option<String>,
1326}
1327
1328/// TS `BrightnessAdjustment` (`type: 'brightness/contrast'`).
1329#[derive(Debug, Clone, Default)]
1330pub struct BrightnessAdjustment {
1331    pub brightness: Option<f64>,
1332    pub contrast: Option<f64>,
1333    pub mean_value: Option<f64>,
1334    pub use_legacy: Option<bool>,
1335    pub lab_color_only: Option<bool>,
1336    pub auto: Option<bool>,
1337}
1338
1339/// TS `LevelsAdjustmentChannel`.
1340#[derive(Debug, Clone, Default)]
1341pub struct LevelsAdjustmentChannel {
1342    pub shadow_input: f64,
1343    pub highlight_input: f64,
1344    pub shadow_output: f64,
1345    pub highlight_output: f64,
1346    pub midtone_input: f64,
1347}
1348
1349/// TS `LevelsAdjustment extends PresetInfo` (`type: 'levels'`).
1350#[derive(Debug, Clone, Default)]
1351pub struct LevelsAdjustment {
1352    pub preset: PresetInfo,
1353    pub rgb: Option<LevelsAdjustmentChannel>,
1354    pub red: Option<LevelsAdjustmentChannel>,
1355    pub green: Option<LevelsAdjustmentChannel>,
1356    pub blue: Option<LevelsAdjustmentChannel>,
1357}
1358
1359/// TS `CurvesAdjustmentChannel = { input; output; }[]`.
1360pub type CurvesAdjustmentChannel = Vec<CurvesPoint>;
1361
1362/// Element of `CurvesAdjustmentChannel`.
1363#[derive(Debug, Clone, Copy, Default)]
1364pub struct CurvesPoint {
1365    pub input: f64,
1366    pub output: f64,
1367}
1368
1369/// TS `CurvesAdjustment extends PresetInfo` (`type: 'curves'`).
1370#[derive(Debug, Clone, Default)]
1371pub struct CurvesAdjustment {
1372    pub preset: PresetInfo,
1373    pub rgb: Option<CurvesAdjustmentChannel>,
1374    pub red: Option<CurvesAdjustmentChannel>,
1375    pub green: Option<CurvesAdjustmentChannel>,
1376    pub blue: Option<CurvesAdjustmentChannel>,
1377}
1378
1379/// TS `ExposureAdjustment extends PresetInfo` (`type: 'exposure'`).
1380#[derive(Debug, Clone, Default)]
1381pub struct ExposureAdjustment {
1382    pub preset: PresetInfo,
1383    pub exposure: Option<f64>,
1384    pub offset: Option<f64>,
1385    pub gamma: Option<f64>,
1386}
1387
1388/// TS `VibranceAdjustment` (`type: 'vibrance'`).
1389#[derive(Debug, Clone, Default)]
1390pub struct VibranceAdjustment {
1391    pub vibrance: Option<f64>,
1392    pub saturation: Option<f64>,
1393}
1394
1395/// TS `HueSaturationAdjustmentChannel`.
1396#[derive(Debug, Clone, Default)]
1397pub struct HueSaturationAdjustmentChannel {
1398    pub a: f64,
1399    pub b: f64,
1400    pub c: f64,
1401    pub d: f64,
1402    pub hue: f64,
1403    pub saturation: f64,
1404    pub lightness: f64,
1405}
1406
1407/// TS `HueSaturationAdjustment extends PresetInfo` (`type: 'hue/saturation'`).
1408#[derive(Debug, Clone, Default)]
1409pub struct HueSaturationAdjustment {
1410    pub preset: PresetInfo,
1411    pub master: Option<HueSaturationAdjustmentChannel>,
1412    pub reds: Option<HueSaturationAdjustmentChannel>,
1413    pub yellows: Option<HueSaturationAdjustmentChannel>,
1414    pub greens: Option<HueSaturationAdjustmentChannel>,
1415    pub cyans: Option<HueSaturationAdjustmentChannel>,
1416    pub blues: Option<HueSaturationAdjustmentChannel>,
1417    pub magentas: Option<HueSaturationAdjustmentChannel>,
1418}
1419
1420/// TS `ColorBalanceValues`.
1421#[derive(Debug, Clone, Default)]
1422pub struct ColorBalanceValues {
1423    pub cyan_red: f64,
1424    pub magenta_green: f64,
1425    pub yellow_blue: f64,
1426}
1427
1428/// TS `ColorBalanceAdjustment` (`type: 'color balance'`).
1429#[derive(Debug, Clone, Default)]
1430pub struct ColorBalanceAdjustment {
1431    pub shadows: Option<ColorBalanceValues>,
1432    pub midtones: Option<ColorBalanceValues>,
1433    pub highlights: Option<ColorBalanceValues>,
1434    pub preserve_luminosity: Option<bool>,
1435}
1436
1437/// TS `BlackAndWhiteAdjustment extends PresetInfo` (`type: 'black & white'`).
1438#[derive(Debug, Clone, Default)]
1439pub struct BlackAndWhiteAdjustment {
1440    pub preset: PresetInfo,
1441    pub reds: Option<f64>,
1442    pub yellows: Option<f64>,
1443    pub greens: Option<f64>,
1444    pub cyans: Option<f64>,
1445    pub blues: Option<f64>,
1446    pub magentas: Option<f64>,
1447    pub use_tint: Option<bool>,
1448    pub tint_color: Option<Color>,
1449}
1450
1451/// TS `PhotoFilterAdjustment` (`type: 'photo filter'`).
1452#[derive(Debug, Clone, Default)]
1453pub struct PhotoFilterAdjustment {
1454    pub color: Option<Color>,
1455    pub density: Option<f64>,
1456    pub preserve_luminosity: Option<bool>,
1457}
1458
1459/// TS `ChannelMixerChannel`.
1460#[derive(Debug, Clone, Default)]
1461pub struct ChannelMixerChannel {
1462    pub red: f64,
1463    pub green: f64,
1464    pub blue: f64,
1465    pub constant: f64,
1466}
1467
1468/// TS `ChannelMixerAdjustment extends PresetInfo` (`type: 'channel mixer'`).
1469#[derive(Debug, Clone, Default)]
1470pub struct ChannelMixerAdjustment {
1471    pub preset: PresetInfo,
1472    pub monochrome: Option<bool>,
1473    pub red: Option<ChannelMixerChannel>,
1474    pub green: Option<ChannelMixerChannel>,
1475    pub blue: Option<ChannelMixerChannel>,
1476    pub gray: Option<ChannelMixerChannel>,
1477}
1478
1479/// TS `ColorLookupAdjustment.lookupType`.
1480#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1481pub enum ColorLookupType {
1482    /// "3dlut"
1483    Lut3D,
1484    /// "abstractProfile"
1485    AbstractProfile,
1486    /// "deviceLinkProfile"
1487    DeviceLinkProfile,
1488}
1489
1490/// TS `ColorLookupAdjustment.lutFormat`.
1491#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1492pub enum LutFormat {
1493    /// "look"
1494    Look,
1495    /// "cube"
1496    Cube,
1497    /// "3dl"
1498    ThreeDl,
1499}
1500
1501/// TS `'rgb' | 'bgr'` (data/table order).
1502#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1503pub enum RgbBgrOrder {
1504    /// "rgb"
1505    Rgb,
1506    /// "bgr"
1507    Bgr,
1508}
1509
1510/// TS `ColorLookupAdjustment` (`type: 'color lookup'`).
1511#[derive(Debug, Clone, Default)]
1512pub struct ColorLookupAdjustment {
1513    pub lookup_type: Option<ColorLookupType>,
1514    pub name: Option<String>,
1515    pub dither: Option<bool>,
1516    pub profile: Option<Vec<u8>>,
1517    pub lut_format: Option<LutFormat>,
1518    pub data_order: Option<RgbBgrOrder>,
1519    pub table_order: Option<RgbBgrOrder>,
1520    pub lut3d_file_data: Option<Vec<u8>>,
1521    pub lut3d_file_name: Option<String>,
1522}
1523
1524/// TS `InvertAdjustment` (`type: 'invert'`).
1525#[derive(Debug, Clone, Default)]
1526pub struct InvertAdjustment;
1527
1528/// TS `PosterizeAdjustment` (`type: 'posterize'`).
1529#[derive(Debug, Clone, Default)]
1530pub struct PosterizeAdjustment {
1531    pub levels: Option<f64>,
1532}
1533
1534/// TS `ThresholdAdjustment` (`type: 'threshold'`).
1535#[derive(Debug, Clone, Default)]
1536pub struct ThresholdAdjustment {
1537    pub level: Option<f64>,
1538}
1539
1540/// TS `GradientMapAdjustment.gradientType = 'solid' | 'noise'`.
1541#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1542pub enum GradientMapType {
1543    /// "solid"
1544    Solid,
1545    /// "noise"
1546    Noise,
1547}
1548
1549/// TS `GradientMapAdjustment` (`type: 'gradient map'`).
1550#[derive(Debug, Clone)]
1551pub struct GradientMapAdjustment {
1552    pub name: Option<String>,
1553    pub gradient_type: GradientMapType,
1554    pub dither: Option<bool>,
1555    pub reverse: Option<bool>,
1556    pub method: Option<InterpolationMethod>,
1557    // solid
1558    pub smoothness: Option<f64>,
1559    pub color_stops: Option<Vec<ColorStop>>,
1560    pub opacity_stops: Option<Vec<OpacityStop>>,
1561    // noise
1562    pub roughness: Option<f64>,
1563    pub color_model: Option<GradientColorModel>,
1564    pub random_seed: Option<f64>,
1565    pub restrict_colors: Option<bool>,
1566    pub add_transparency: Option<bool>,
1567    pub min: Option<Vec<f64>>,
1568    pub max: Option<Vec<f64>>,
1569}
1570
1571/// TS `SelectiveColorAdjustment.mode = 'relative' | 'absolute'`.
1572#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1573pub enum SelectiveColorMode {
1574    /// "relative"
1575    Relative,
1576    /// "absolute"
1577    Absolute,
1578}
1579
1580/// TS `SelectiveColorAdjustment` (`type: 'selective color'`).
1581#[derive(Debug, Clone, Default)]
1582pub struct SelectiveColorAdjustment {
1583    pub mode: Option<SelectiveColorMode>,
1584    pub reds: Option<Cmyk>,
1585    pub yellows: Option<Cmyk>,
1586    pub greens: Option<Cmyk>,
1587    pub cyans: Option<Cmyk>,
1588    pub blues: Option<Cmyk>,
1589    pub magentas: Option<Cmyk>,
1590    pub whites: Option<Cmyk>,
1591    pub neutrals: Option<Cmyk>,
1592    pub blacks: Option<Cmyk>,
1593}
1594
1595/// TS `AdjustmentLayer` union (the `type` tag is encoded by the variant).
1596#[derive(Debug, Clone)]
1597pub enum AdjustmentLayer {
1598    /// "brightness/contrast"
1599    Brightness(BrightnessAdjustment),
1600    /// "levels"
1601    Levels(LevelsAdjustment),
1602    /// "curves"
1603    Curves(CurvesAdjustment),
1604    /// "exposure"
1605    Exposure(ExposureAdjustment),
1606    /// "vibrance"
1607    Vibrance(VibranceAdjustment),
1608    /// "hue/saturation"
1609    HueSaturation(HueSaturationAdjustment),
1610    /// "color balance"
1611    ColorBalance(ColorBalanceAdjustment),
1612    /// "black & white"
1613    BlackAndWhite(BlackAndWhiteAdjustment),
1614    /// "photo filter"
1615    PhotoFilter(PhotoFilterAdjustment),
1616    /// "channel mixer"
1617    ChannelMixer(ChannelMixerAdjustment),
1618    /// "color lookup"
1619    ColorLookup(ColorLookupAdjustment),
1620    /// "invert"
1621    Invert(InvertAdjustment),
1622    /// "posterize"
1623    Posterize(PosterizeAdjustment),
1624    /// "threshold"
1625    Threshold(ThresholdAdjustment),
1626    /// "gradient map"
1627    GradientMap(GradientMapAdjustment),
1628    /// "selective color"
1629    SelectiveColor(SelectiveColorAdjustment),
1630}
1631
1632// ===========================================================================
1633// Linked files
1634// ===========================================================================
1635
1636/// TS `LinkedFile.descriptor.compInfo` and `PlacedLayer.compInfo`.
1637#[derive(Debug, Clone, Copy, Default)]
1638pub struct CompInfo {
1639    pub comp_id: f64,
1640    pub original_comp_id: f64,
1641}
1642
1643/// TS `LinkedFile.descriptor`.
1644#[derive(Debug, Clone, Default)]
1645pub struct LinkedFileDescriptor {
1646    pub comp_info: CompInfo,
1647}
1648
1649/// TS `LinkedFile.linkedFile` (external files).
1650#[derive(Debug, Clone, Default)]
1651pub struct ExternalLinkedFile {
1652    pub file_size: f64,
1653    pub name: String,
1654    pub full_path: String,
1655    pub original_path: String,
1656    pub relative_path: String,
1657}
1658
1659/// TS `LinkedFile`.
1660#[derive(Debug, Clone, Default)]
1661pub struct LinkedFile {
1662    /// GUID format, e.g. 20953ddb-9391-11ec-b4f1-c15674f50bc4
1663    pub id: String,
1664    pub name: String,
1665    /// TS field `type`
1666    pub file_type: Option<String>,
1667    pub creator: Option<String>,
1668    pub data: Option<Vec<u8>>,
1669    /// for external files
1670    pub time: Option<String>,
1671    pub descriptor: Option<LinkedFileDescriptor>,
1672    pub child_document_id: Option<String>,
1673    pub asset_mod_time: Option<f64>,
1674    pub asset_locked_state: Option<f64>,
1675    pub linked_file: Option<ExternalLinkedFile>,
1676}
1677
1678// ===========================================================================
1679// Smart filters (FilterVariant + Filter)
1680// ===========================================================================
1681
1682/// Generic `{ radius: UnitsValue }` filter parameter set.
1683#[derive(Debug, Clone, Copy)]
1684pub struct RadiusFilter {
1685    pub radius: UnitsValue,
1686}
1687
1688/// TS `FilterVariant` union. Each variant carries the TS `type` tag and its
1689/// `filter` payload (where present). The exact string tags are in doc-comments.
1690#[derive(Debug, Clone)]
1691pub enum FilterVariant {
1692    /// "average"
1693    Average,
1694    /// "blur"
1695    Blur,
1696    /// "blur more"
1697    BlurMore,
1698    /// "box blur"
1699    BoxBlur(RadiusFilter),
1700    /// "gaussian blur"
1701    GaussianBlur(RadiusFilter),
1702    /// "motion blur"
1703    MotionBlur {
1704        /// in degrees
1705        angle: f64,
1706        distance: UnitsValue,
1707    },
1708    /// "radial blur"
1709    RadialBlur {
1710        amount: f64,
1711        method: RadialBlurMethod,
1712        quality: RadialBlurQuality,
1713    },
1714    /// "shape blur"
1715    ShapeBlur {
1716        radius: UnitsValue,
1717        custom_shape: NamedId,
1718    },
1719    /// "smart blur"
1720    SmartBlur {
1721        radius: f64,
1722        threshold: f64,
1723        quality: LowMediumHigh,
1724        mode: SmartBlurMode,
1725    },
1726    /// "surface blur"
1727    SurfaceBlur { radius: UnitsValue, threshold: f64 },
1728    /// "displace"
1729    Displace {
1730        horizontal_scale: f64,
1731        vertical_scale: f64,
1732        displacement_map: DisplacementMap,
1733        undefined_areas: WrapOrRepeat,
1734        displacement_file: DisplacementFile,
1735    },
1736    /// "pinch"
1737    Pinch { amount: f64 },
1738    /// "polar coordinates"
1739    PolarCoordinates { conversion: PolarConversion },
1740    /// "ripple"
1741    Ripple {
1742        amount: f64,
1743        size: SmallMediumLarge,
1744    },
1745    /// "shear"
1746    Shear {
1747        shear_points: Vec<PointF>,
1748        shear_start: f64,
1749        shear_end: f64,
1750        undefined_areas: WrapOrRepeat,
1751    },
1752    /// "spherize"
1753    Spherize {
1754        amount: f64,
1755        mode: SpherizeMode,
1756    },
1757    /// "twirl"
1758    Twirl {
1759        /// degrees
1760        angle: f64,
1761    },
1762    /// "wave"
1763    Wave {
1764        number_of_generators: f64,
1765        /// TS field `type`
1766        wave_type: WaveType,
1767        wavelength: MinMax,
1768        amplitude: MinMax,
1769        scale: PointF,
1770        random_seed: f64,
1771        undefined_areas: WrapOrRepeat,
1772    },
1773    /// "zigzag"
1774    ZigZag {
1775        amount: f64,
1776        ridges: f64,
1777        style: ZigZagStyle,
1778    },
1779    /// "add noise"
1780    AddNoise {
1781        /// 0..1
1782        amount: f64,
1783        distribution: NoiseDistribution,
1784        monochromatic: bool,
1785        random_seed: f64,
1786    },
1787    /// "despeckle"
1788    Despeckle,
1789    /// "dust and scratches"
1790    DustAndScratches {
1791        /// pixels
1792        radius: f64,
1793        /// levels
1794        threshold: f64,
1795    },
1796    /// "median"
1797    Median(RadiusFilter),
1798    /// "reduce noise"
1799    ReduceNoise {
1800        preset: String,
1801        remove_jpeg_artifact: bool,
1802        /// 0..1
1803        reduce_color_noise: f64,
1804        /// 0..1
1805        sharpen_details: f64,
1806        channel_denoise: Vec<ChannelDenoise>,
1807    },
1808    /// "color halftone"
1809    ColorHalftone {
1810        /// pixels
1811        radius: f64,
1812        /// degrees
1813        angle1: f64,
1814        angle2: f64,
1815        angle3: f64,
1816        angle4: f64,
1817    },
1818    /// "crystallize"
1819    Crystallize { cell_size: f64, random_seed: f64 },
1820    /// "facet"
1821    Facet,
1822    /// "fragment"
1823    Fragment,
1824    /// "mezzotint"
1825    Mezzotint {
1826        /// TS field `type`
1827        mezzotint_type: MezzotintType,
1828        random_seed: f64,
1829    },
1830    /// "mosaic"
1831    Mosaic { cell_size: UnitsValue },
1832    /// "pointillize"
1833    Pointillize { cell_size: f64, random_seed: f64 },
1834    /// "clouds"
1835    Clouds { random_seed: f64 },
1836    /// "difference clouds"
1837    DifferenceClouds { random_seed: f64 },
1838    /// "fibers"
1839    Fibers {
1840        variance: f64,
1841        strength: f64,
1842        random_seed: f64,
1843    },
1844    /// "lens flare"
1845    LensFlare {
1846        /// percent
1847        brightness: f64,
1848        position: PointF,
1849        lens_type: LensType,
1850    },
1851    /// "sharpen"
1852    Sharpen,
1853    /// "sharpen edges"
1854    SharpenEdges,
1855    /// "sharpen more"
1856    SharpenMore,
1857    /// "smart sharpen"
1858    SmartSharpen {
1859        /// 0..1
1860        amount: f64,
1861        radius: UnitsValue,
1862        threshold: f64,
1863        /// degrees
1864        angle: f64,
1865        more_accurate: bool,
1866        blur: SmartSharpenBlur,
1867        preset: String,
1868        shadow: SmartSharpenTone,
1869        highlight: SmartSharpenTone,
1870    },
1871    /// "unsharp mask"
1872    UnsharpMask {
1873        /// 0..1
1874        amount: f64,
1875        radius: UnitsValue,
1876        /// levels
1877        threshold: f64,
1878    },
1879    /// "diffuse"
1880    Diffuse {
1881        mode: DiffuseMode,
1882        random_seed: f64,
1883    },
1884    /// "emboss"
1885    Emboss {
1886        /// degrees
1887        angle: f64,
1888        /// pixels
1889        height: f64,
1890        /// percent
1891        amount: f64,
1892    },
1893    /// "extrude"
1894    Extrude {
1895        /// TS field `type`
1896        extrude_type: ExtrudeType,
1897        /// pixels
1898        size: f64,
1899        depth: f64,
1900        depth_mode: ExtrudeDepthMode,
1901        random_seed: f64,
1902        solid_front_faces: bool,
1903        mask_incomplete_blocks: bool,
1904    },
1905    /// "find edges"
1906    FindEdges,
1907    /// "solarize"
1908    Solarize,
1909    /// "tiles"
1910    Tiles {
1911        number_of_tiles: f64,
1912        /// percent
1913        maximum_offset: f64,
1914        fill_empty_area_with: TilesFill,
1915        random_seed: f64,
1916    },
1917    /// "trace contour"
1918    TraceContour { level: f64, edge: LowerUpper },
1919    /// "wind"
1920    Wind {
1921        method: WindMethod,
1922        direction: LeftRight,
1923    },
1924    /// "de-interlace"
1925    DeInterlace {
1926        eliminate: DeInterlaceEliminate,
1927        new_fields_by: DeInterlaceNewFields,
1928    },
1929    /// "ntsc colors"
1930    NtscColors,
1931    /// "custom"
1932    Custom {
1933        scale: f64,
1934        offset: f64,
1935        matrix: Vec<f64>,
1936    },
1937    /// "high pass"
1938    HighPass(RadiusFilter),
1939    /// "maximum"
1940    Maximum(RadiusFilter),
1941    /// "minimum"
1942    Minimum(RadiusFilter),
1943    /// "offset"
1944    Offset {
1945        /// pixels
1946        horizontal: f64,
1947        /// pixels
1948        vertical: f64,
1949        undefined_areas: OffsetUndefinedAreas,
1950    },
1951    /// "puppet"
1952    Puppet {
1953        rigid_type: bool,
1954        bounds: Vec<PointF>,
1955        puppet_shape_list: Vec<PuppetShape>,
1956    },
1957    /// "oil paint plugin"
1958    OilPaintPlugin {
1959        name: String,
1960        gpu: bool,
1961        lighting: bool,
1962        parameters: Vec<NamedValue>,
1963    },
1964    /// "hsb/hsl"
1965    HsbHsl {
1966        input_mode: RgbHsbHsl,
1967        row_order: RgbHsbHsl,
1968    },
1969    /// "oil paint"
1970    OilPaint {
1971        lighting_on: bool,
1972        stylization: f64,
1973        cleanliness: f64,
1974        brush_scale: f64,
1975        micro_brush: f64,
1976        /// degrees
1977        light_direction: f64,
1978        specularity: f64,
1979    },
1980    /// "liquify"
1981    Liquify { liquify_mesh: Vec<u8> },
1982    /// "perspective warp"
1983    PerspectiveWarp {
1984        /// quad indices
1985        quads: Vec<Vec<f64>>,
1986        vertices: Vec<UnitsPoint>,
1987        warped_vertices: Vec<UnitsPoint>,
1988    },
1989    /// "curves"
1990    Curves {
1991        preset_kind: CurvesPresetKind,
1992        adjustments: Option<Vec<CurvesFilterAdjustment>>,
1993    },
1994    /// "invert"
1995    Invert,
1996    /// "brightness/contrast"
1997    BrightnessContrast {
1998        brightness: f64,
1999        contrast: f64,
2000        use_legacy: bool,
2001    },
2002}
2003
2004/// `{ name: string; id: string }` (filter custom shape).
2005#[derive(Debug, Clone, Default)]
2006pub struct NamedId {
2007    pub name: String,
2008    pub id: String,
2009}
2010
2011/// `{ name: string; value: number }` (oil paint plugin parameter).
2012#[derive(Debug, Clone, Default)]
2013pub struct NamedValue {
2014    pub name: String,
2015    pub value: f64,
2016}
2017
2018/// `{ min: number; max: number }`.
2019#[derive(Debug, Clone, Copy, Default)]
2020pub struct MinMax {
2021    pub min: f64,
2022    pub max: f64,
2023}
2024
2025/// "spin" | "zoom"
2026#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2027pub enum RadialBlurMethod {
2028    /// "spin"
2029    Spin,
2030    /// "zoom"
2031    Zoom,
2032}
2033
2034/// "draft" | "good" | "best"
2035#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2036pub enum RadialBlurQuality {
2037    /// "draft"
2038    Draft,
2039    /// "good"
2040    Good,
2041    /// "best"
2042    Best,
2043}
2044
2045/// "low" | "medium" | "high"
2046#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2047pub enum LowMediumHigh {
2048    /// "low"
2049    Low,
2050    /// "medium"
2051    Medium,
2052    /// "high"
2053    High,
2054}
2055
2056/// smart blur mode: "normal" | "edge only" | "overlay edge"
2057#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2058pub enum SmartBlurMode {
2059    /// "normal"
2060    Normal,
2061    /// "edge only"
2062    EdgeOnly,
2063    /// "overlay edge"
2064    OverlayEdge,
2065}
2066
2067/// displace displacementMap: "stretch to fit" | "tile"
2068#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2069pub enum DisplacementMap {
2070    /// "stretch to fit"
2071    StretchToFit,
2072    /// "tile"
2073    Tile,
2074}
2075
2076/// "wrap around" | "repeat edge pixels"
2077#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2078pub enum WrapOrRepeat {
2079    /// "wrap around"
2080    WrapAround,
2081    /// "repeat edge pixels"
2082    RepeatEdgePixels,
2083}
2084
2085/// displace displacementFile `{ signature; path; }`.
2086#[derive(Debug, Clone, Default)]
2087pub struct DisplacementFile {
2088    pub signature: String,
2089    pub path: String,
2090}
2091
2092/// "rectangular to polar" | "polar to rectangular"
2093#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2094pub enum PolarConversion {
2095    /// "rectangular to polar"
2096    RectangularToPolar,
2097    /// "polar to rectangular"
2098    PolarToRectangular,
2099}
2100
2101/// "small" | "medium" | "large"
2102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2103pub enum SmallMediumLarge {
2104    /// "small"
2105    Small,
2106    /// "medium"
2107    Medium,
2108    /// "large"
2109    Large,
2110}
2111
2112/// spherize mode: "normal" | "horizontal only" | "vertical only"
2113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2114pub enum SpherizeMode {
2115    /// "normal"
2116    Normal,
2117    /// "horizontal only"
2118    HorizontalOnly,
2119    /// "vertical only"
2120    VerticalOnly,
2121}
2122
2123/// wave type: "sine" | "triangle" | "square"
2124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2125pub enum WaveType {
2126    /// "sine"
2127    Sine,
2128    /// "triangle"
2129    Triangle,
2130    /// "square"
2131    Square,
2132}
2133
2134/// zigzag style: "around center" | "out from center" | "pond ripples"
2135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2136pub enum ZigZagStyle {
2137    /// "around center"
2138    AroundCenter,
2139    /// "out from center"
2140    OutFromCenter,
2141    /// "pond ripples"
2142    PondRipples,
2143}
2144
2145/// "uniform" | "gaussian"
2146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2147pub enum NoiseDistribution {
2148    /// "uniform"
2149    Uniform,
2150    /// "gaussian"
2151    Gaussian,
2152}
2153
2154/// reduce noise channelDenoise channel: "red" | "green" | "blue" | "composite"
2155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2156pub enum DenoiseChannel {
2157    /// "red"
2158    Red,
2159    /// "green"
2160    Green,
2161    /// "blue"
2162    Blue,
2163    /// "composite"
2164    Composite,
2165}
2166
2167/// reduce noise `channelDenoise[]` element.
2168#[derive(Debug, Clone, Default)]
2169pub struct ChannelDenoise {
2170    pub channels: Vec<DenoiseChannel>,
2171    pub amount: f64,
2172    /// percent
2173    pub preserve_details: Option<f64>,
2174}
2175
2176/// mezzotint type union.
2177#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2178pub enum MezzotintType {
2179    /// "fine dots"
2180    FineDots,
2181    /// "medium dots"
2182    MediumDots,
2183    /// "grainy dots"
2184    GrainyDots,
2185    /// "coarse dots"
2186    CoarseDots,
2187    /// "short lines"
2188    ShortLines,
2189    /// "medium lines"
2190    MediumLines,
2191    /// "long lines"
2192    LongLines,
2193    /// "short strokes"
2194    ShortStrokes,
2195    /// "medium strokes"
2196    MediumStrokes,
2197    /// "long strokes"
2198    LongStrokes,
2199}
2200
2201/// lens flare lensType.
2202#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2203pub enum LensType {
2204    /// "50-300mm zoom"
2205    Zoom50To300,
2206    /// "32mm prime"
2207    Prime32,
2208    /// "105mm prime"
2209    Prime105,
2210    /// "movie prime"
2211    MoviePrime,
2212}
2213
2214/// smart sharpen blur: "gaussian blur" | "lens blur" | "motion blur"
2215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2216pub enum SmartSharpenBlur {
2217    /// "gaussian blur"
2218    GaussianBlur,
2219    /// "lens blur"
2220    LensBlur,
2221    /// "motion blur"
2222    MotionBlur,
2223}
2224
2225/// smart sharpen shadow/highlight tone.
2226#[derive(Debug, Clone, Copy, Default)]
2227pub struct SmartSharpenTone {
2228    /// 0..1
2229    pub fade_amount: f64,
2230    /// 0..1
2231    pub tonal_width: f64,
2232    /// px
2233    pub radius: f64,
2234}
2235
2236/// diffuse mode.
2237#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2238pub enum DiffuseMode {
2239    /// "normal"
2240    Normal,
2241    /// "darken only"
2242    DarkenOnly,
2243    /// "lighten only"
2244    LightenOnly,
2245    /// "anisotropic"
2246    Anisotropic,
2247}
2248
2249/// extrude type: "blocks" | "pyramids"
2250#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2251pub enum ExtrudeType {
2252    /// "blocks"
2253    Blocks,
2254    /// "pyramids"
2255    Pyramids,
2256}
2257
2258/// extrude depthMode: "random" | "level-based"
2259#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2260pub enum ExtrudeDepthMode {
2261    /// "random"
2262    Random,
2263    /// "level-based"
2264    LevelBased,
2265}
2266
2267/// tiles fill: "background color" | "foreground color" | "inverse image" | "unaltered image"
2268#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2269pub enum TilesFill {
2270    /// "background color"
2271    BackgroundColor,
2272    /// "foreground color"
2273    ForegroundColor,
2274    /// "inverse image"
2275    InverseImage,
2276    /// "unaltered image"
2277    UnalteredImage,
2278}
2279
2280/// trace contour edge: "lower" | "upper"
2281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2282pub enum LowerUpper {
2283    /// "lower"
2284    Lower,
2285    /// "upper"
2286    Upper,
2287}
2288
2289/// wind method: "wind" | "blast" | "stagger"
2290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2291pub enum WindMethod {
2292    /// "wind"
2293    Wind,
2294    /// "blast"
2295    Blast,
2296    /// "stagger"
2297    Stagger,
2298}
2299
2300/// "left" | "right"
2301#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2302pub enum LeftRight {
2303    /// "left"
2304    Left,
2305    /// "right"
2306    Right,
2307}
2308
2309/// de-interlace eliminate: "odd lines" | "even lines"
2310#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2311pub enum DeInterlaceEliminate {
2312    /// "odd lines"
2313    OddLines,
2314    /// "even lines"
2315    EvenLines,
2316}
2317
2318/// de-interlace newFieldsBy: "duplication" | "interpolation"
2319#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2320pub enum DeInterlaceNewFields {
2321    /// "duplication"
2322    Duplication,
2323    /// "interpolation"
2324    Interpolation,
2325}
2326
2327/// offset undefinedAreas: "set to transparent" | "repeat edge pixels" | "wrap around"
2328#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2329pub enum OffsetUndefinedAreas {
2330    /// "set to transparent"
2331    SetToTransparent,
2332    /// "repeat edge pixels"
2333    RepeatEdgePixels,
2334    /// "wrap around"
2335    WrapAround,
2336}
2337
2338/// "rgb" | "hsb" | "hsl"
2339#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2340pub enum RgbHsbHsl {
2341    /// "rgb"
2342    Rgb,
2343    /// "hsb"
2344    Hsb,
2345    /// "hsl"
2346    Hsl,
2347}
2348
2349/// curves filter presetKind: "custom" | "default"
2350#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2351pub enum CurvesPresetKind {
2352    /// "custom"
2353    Custom,
2354    /// "default"
2355    Default,
2356}
2357
2358/// curves filter channel: "composite" | "red" | "green" | "blue"
2359#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2360pub enum CurvesFilterChannel {
2361    /// "composite"
2362    Composite,
2363    /// "red"
2364    Red,
2365    /// "green"
2366    Green,
2367    /// "blue"
2368    Blue,
2369}
2370
2371/// curves filter point `{ x; y; curved?; }`.
2372#[derive(Debug, Clone, Copy, Default)]
2373pub struct CurvesFilterPoint {
2374    pub x: f64,
2375    pub y: f64,
2376    pub curved: Option<bool>,
2377}
2378
2379/// curves filter adjustment (union of curve-points vs raw values forms).
2380#[derive(Debug, Clone)]
2381pub enum CurvesFilterAdjustment {
2382    Curve {
2383        channels: Vec<CurvesFilterChannel>,
2384        curve: Vec<CurvesFilterPoint>,
2385    },
2386    Values {
2387        channels: Vec<CurvesFilterChannel>,
2388        values: Vec<f64>,
2389    },
2390}
2391
2392/// puppet shape mesh boundary point.
2393#[derive(Debug, Clone, Copy)]
2394pub struct PuppetMeshPoint {
2395    pub anchor: UnitsPoint,
2396    pub forward: UnitsPoint,
2397    pub backward: UnitsPoint,
2398    pub smooth: bool,
2399}
2400
2401/// puppet mesh boundary path.
2402#[derive(Debug, Clone, Default)]
2403pub struct PuppetMeshPath {
2404    pub closed: bool,
2405    pub points: Vec<PuppetMeshPoint>,
2406}
2407
2408/// puppet mesh boundary path component.
2409#[derive(Debug, Clone, Default)]
2410pub struct PuppetPathComponent {
2411    pub shape_operation: String,
2412    pub paths: Vec<PuppetMeshPath>,
2413}
2414
2415/// puppet shape entry.
2416#[derive(Debug, Clone, Default)]
2417pub struct PuppetShape {
2418    pub rigid_type: bool,
2419    pub original_vertex_array: Vec<PointF>,
2420    pub deformed_vertex_array: Vec<PointF>,
2421    pub index_array: Vec<f64>,
2422    pub pin_offsets: Vec<PointF>,
2423    pub pos_final_pins: Vec<PointF>,
2424    pub pin_vertex_indices: Vec<f64>,
2425    pub selected_pin: Vec<f64>,
2426    pub pin_position: Vec<PointF>,
2427    /// in degrees
2428    pub pin_rotation: Vec<f64>,
2429    pub pin_overlay: Vec<bool>,
2430    pub pin_depth: Vec<f64>,
2431    pub mesh_quality: f64,
2432    pub mesh_expansion: f64,
2433    pub mesh_rigidity: f64,
2434    pub image_resolution: f64,
2435    /// `{ pathComponents: [...] }`
2436    pub mesh_boundary_path: Vec<PuppetPathComponent>,
2437}
2438
2439/// TS `Filter = FilterVariant & { ...common fields... }`.
2440#[derive(Debug, Clone)]
2441pub struct Filter {
2442    pub variant: FilterVariant,
2443    pub name: String,
2444    pub opacity: f64,
2445    pub blend_mode: BlendMode,
2446    pub enabled: bool,
2447    pub has_options: bool,
2448    pub foreground_color: Color,
2449    pub background_color: Color,
2450}
2451
2452/// TS `PlacedLayerFilter`.
2453#[derive(Debug, Clone, Default)]
2454pub struct PlacedLayerFilter {
2455    pub enabled: bool,
2456    pub valid_at_position: bool,
2457    pub mask_enabled: bool,
2458    pub mask_linked: bool,
2459    pub mask_extend_with_white: bool,
2460    pub list: Vec<Filter>,
2461}
2462
2463/// TS `PlacedLayer.frameStep` / `duration` `{ numerator; denominator; }`.
2464#[derive(Debug, Clone, Copy, Default)]
2465pub struct NumDenom {
2466    pub numerator: f64,
2467    pub denominator: f64,
2468}
2469
2470/// TS `PlacedLayer`.
2471#[derive(Debug, Clone, Default)]
2472pub struct PlacedLayer {
2473    /// id of linked image file (psd.linkedFiles), GUID format
2474    pub id: String,
2475    /// unique id
2476    pub placed: Option<String>,
2477    /// TS field `type`
2478    pub layer_type: Option<PlacedLayerType>,
2479    pub page_number: Option<f64>,
2480    pub total_pages: Option<f64>,
2481    pub frame_step: Option<NumDenom>,
2482    pub duration: Option<NumDenom>,
2483    pub frame_count: Option<f64>,
2484    /// x, y of 4 corners of the transform
2485    pub transform: Vec<f64>,
2486    /// x, y of 4 corners of the transform
2487    pub non_affine_transform: Option<Vec<f64>>,
2488    /// width of the linked image
2489    pub width: Option<f64>,
2490    /// height of the linked image
2491    pub height: Option<f64>,
2492    pub resolution: Option<UnitsValue>,
2493    /// warp coordinates are relative to the linked image size
2494    pub warp: Option<Warp>,
2495    pub crop: Option<f64>,
2496    pub comp: Option<f64>,
2497    pub comp_info: Option<CompInfo>,
2498    pub filter: Option<PlacedLayerFilter>,
2499}
2500
2501// ===========================================================================
2502// Vector origination / vector mask / timeline / animation
2503// ===========================================================================
2504
2505/// TS `KeyDescriptorItem.keyOriginRRectRadii`.
2506#[derive(Debug, Clone, Copy)]
2507pub struct RRectRadii {
2508    pub top_right: UnitsValue,
2509    pub top_left: UnitsValue,
2510    pub bottom_left: UnitsValue,
2511    pub bottom_right: UnitsValue,
2512}
2513
2514/// TS `KeyDescriptorItem`.
2515#[derive(Debug, Clone, Default)]
2516pub struct KeyDescriptorItem {
2517    pub key_shape_invalidated: Option<bool>,
2518    pub key_origin_type: Option<f64>,
2519    pub key_origin_resolution: Option<f64>,
2520    pub key_origin_r_rect_radii: Option<RRectRadii>,
2521    pub key_origin_shape_bounding_box: Option<UnitsBounds>,
2522    pub key_origin_box_corners: Option<Vec<PointF>>,
2523    /// 2d transform matrix [xx, xy, yx, yy, tx, ty]
2524    pub transform: Option<Vec<f64>>,
2525}
2526
2527/// TS `LayerVectorMask.clipboard`.
2528#[derive(Debug, Clone, Copy, Default)]
2529pub struct VectorMaskClipboard {
2530    pub top: f64,
2531    pub left: f64,
2532    pub bottom: f64,
2533    pub right: f64,
2534    pub resolution: f64,
2535}
2536
2537/// TS `LayerVectorMask`.
2538#[derive(Debug, Clone, Default)]
2539pub struct LayerVectorMask {
2540    pub invert: Option<bool>,
2541    pub not_link: Option<bool>,
2542    pub disable: Option<bool>,
2543    pub fill_starts_with_all_pixels: Option<bool>,
2544    pub clipboard: Option<VectorMaskClipboard>,
2545    pub paths: Vec<BezierPath>,
2546}
2547
2548/// TS `AnimationFrame`.
2549#[derive(Debug, Clone, Default)]
2550pub struct AnimationFrame {
2551    /// IDs of frames that this modifier applies to
2552    pub frames: Vec<f64>,
2553    pub enable: Option<bool>,
2554    pub offset: Option<PointF>,
2555    pub reference_point: Option<PointF>,
2556    pub opacity: Option<f64>,
2557    pub effects: Option<LayerEffectsInfo>,
2558}
2559
2560/// TS `TimelineKey` payload (the `type`-tagged second half of the union).
2561#[derive(Debug, Clone)]
2562pub enum TimelineKeyData {
2563    /// "opacity"
2564    Opacity { value: f64 },
2565    /// "position"
2566    Position { x: f64, y: f64 },
2567    /// "transform"
2568    Transform {
2569        scale: PointF,
2570        skew: PointF,
2571        rotation: f64,
2572        translation: PointF,
2573    },
2574    /// "style"
2575    Style { style: Option<LayerEffectsInfo> },
2576    /// "globalLighting"
2577    GlobalLighting {
2578        global_angle: f64,
2579        global_altitude: f64,
2580    },
2581}
2582
2583/// TS `TimelineKey` (common fields intersected with the tagged union).
2584#[derive(Debug, Clone)]
2585pub struct TimelineKey {
2586    pub interpolation: TimelineKeyInterpolation,
2587    pub time: Fraction,
2588    pub selected: Option<bool>,
2589    pub data: TimelineKeyData,
2590}
2591
2592/// TS `TimelineTrack.effectParams`.
2593#[derive(Debug, Clone, Default)]
2594pub struct TimelineEffectParams {
2595    pub keys: Vec<TimelineKey>,
2596    pub fill_canvas: bool,
2597    pub zoom_origin: f64,
2598}
2599
2600/// TS `TimelineTrack`.
2601#[derive(Debug, Clone)]
2602pub struct TimelineTrack {
2603    /// TS field `type`
2604    pub track_type: TimelineTrackType,
2605    pub enabled: Option<bool>,
2606    pub effect_params: Option<TimelineEffectParams>,
2607    pub keys: Vec<TimelineKey>,
2608}
2609
2610/// TS `Timeline`.
2611#[derive(Debug, Clone, Default)]
2612pub struct Timeline {
2613    pub start: Fraction,
2614    pub duration: Fraction,
2615    pub in_time: Fraction,
2616    pub out_time: Fraction,
2617    pub auto_scope: bool,
2618    pub audio_level: f64,
2619    pub tracks: Option<Vec<TimelineTrack>>,
2620}
2621
2622// ===========================================================================
2623// LayerAdditionalInfo sub-shapes
2624// ===========================================================================
2625
2626/// TS `LayerAdditionalInfo.protected`.
2627#[derive(Debug, Clone, Default)]
2628pub struct ProtectedInfo {
2629    pub transparency: Option<bool>,
2630    pub composite: Option<bool>,
2631    pub position: Option<bool>,
2632    pub artboards: Option<bool>,
2633}
2634
2635/// TS `LayerAdditionalInfo.sectionDivider`.
2636#[derive(Debug, Clone)]
2637pub struct SectionDivider {
2638    /// TS field `type`
2639    pub divider_type: SectionDividerType,
2640    pub key: Option<String>,
2641    /// 0 = normal, 1 = scene group, affects animation timeline.
2642    pub sub_type: Option<f64>,
2643}
2644
2645/// TS `LayerAdditionalInfo.filterMask` and `.userMask`.
2646#[derive(Debug, Clone)]
2647pub struct ColorSpaceMask {
2648    pub color_space: Color,
2649    pub opacity: f64,
2650}
2651
2652/// TS `LayerAdditionalInfo.vectorStroke`.
2653#[derive(Debug, Clone, Default)]
2654pub struct VectorStroke {
2655    pub stroke_enabled: Option<bool>,
2656    pub fill_enabled: Option<bool>,
2657    pub line_width: Option<UnitsValue>,
2658    pub line_dash_offset: Option<UnitsValue>,
2659    pub miter_limit: Option<f64>,
2660    pub line_cap_type: Option<LineCapType>,
2661    pub line_join_type: Option<LineJoinType>,
2662    pub line_alignment: Option<LineAlignment>,
2663    pub scale_lock: Option<bool>,
2664    pub stroke_adjust: Option<bool>,
2665    pub line_dash_set: Option<Vec<UnitsValue>>,
2666    pub blend_mode: Option<BlendMode>,
2667    pub opacity: Option<f64>,
2668    pub content: Option<VectorContent>,
2669    pub resolution: Option<f64>,
2670}
2671
2672/// TS `LayerAdditionalInfo.vectorOrigination`.
2673#[derive(Debug, Clone, Default)]
2674pub struct VectorOrigination {
2675    pub key_descriptor_list: Vec<KeyDescriptorItem>,
2676}
2677
2678/// TS version triple `{ major; minor; fix; }`.
2679#[derive(Debug, Clone, Copy, Default)]
2680pub struct VersionTriple {
2681    pub major: f64,
2682    pub minor: f64,
2683    pub fix: f64,
2684}
2685
2686/// TS `LayerAdditionalInfo.compositorUsed`.
2687#[derive(Debug, Clone, Default)]
2688pub struct CompositorUsed {
2689    pub version: Option<VersionTriple>,
2690    pub photoshop_version: Option<VersionTriple>,
2691    pub description: String,
2692    pub reason: String,
2693    pub engine: String,
2694    pub enable_comp_core: Option<String>,
2695    pub enable_comp_core_gpu: Option<String>,
2696    pub enable_comp_core_threads: Option<String>,
2697    pub comp_core_support: Option<String>,
2698    pub comp_core_gpu_support: Option<String>,
2699}
2700
2701/// TS `LayerAdditionalInfo.artboard`.
2702#[derive(Debug, Clone, Default)]
2703pub struct LayerArtboard {
2704    pub rect: Bounds,
2705    /// TS `any[]` — kept as opaque count of entries is not modeled; raw f64s.
2706    pub guide_indices: Option<Vec<f64>>,
2707    pub preset_name: Option<String>,
2708    pub color: Option<Color>,
2709    pub background_type: Option<f64>,
2710}
2711
2712/// TS `LayerAdditionalInfo.animationFrameFlags`.
2713#[derive(Debug, Clone, Default)]
2714pub struct AnimationFrameFlags {
2715    pub propagate_frame_one: Option<bool>,
2716    pub unify_layer_position: Option<bool>,
2717    pub unify_layer_style: Option<bool>,
2718    pub unify_layer_visibility: Option<bool>,
2719}
2720
2721/// TS `filterEffectsMasks[].channels[]` element (may be `undefined` in TS).
2722#[derive(Debug, Clone, Default)]
2723pub struct FilterEffectsChannel {
2724    pub compression_mode: f64,
2725    pub data: Vec<u8>,
2726}
2727
2728/// TS `filterEffectsMasks[].extra`.
2729#[derive(Debug, Clone, Default)]
2730pub struct FilterEffectsExtra {
2731    pub top: f64,
2732    pub left: f64,
2733    pub bottom: f64,
2734    pub right: f64,
2735    pub compression_mode: f64,
2736    pub data: Vec<u8>,
2737}
2738
2739/// TS `LayerAdditionalInfo.filterEffectsMasks[]` element.
2740#[derive(Debug, Clone, Default)]
2741pub struct FilterEffectsMask {
2742    pub id: String,
2743    pub top: f64,
2744    pub left: f64,
2745    pub bottom: f64,
2746    pub right: f64,
2747    pub depth: f64,
2748    /// `(channel | undefined)[]`
2749    pub channels: Vec<Option<FilterEffectsChannel>>,
2750    pub extra: Option<FilterEffectsExtra>,
2751}
2752
2753/// TS `comps.settings[]` element.
2754#[derive(Debug, Clone, Default)]
2755pub struct LayerCompSettings {
2756    pub enabled: Option<bool>,
2757    pub comp_list: Vec<f64>,
2758    pub offset: Option<PointF>,
2759    pub effects_reference_point: Option<PointF>,
2760}
2761
2762/// TS `LayerAdditionalInfo.comps`.
2763#[derive(Debug, Clone, Default)]
2764pub struct LayerComps {
2765    pub original_effects_reference_point: Option<PointF>,
2766    pub settings: Vec<LayerCompSettings>,
2767}
2768
2769/// TS `blendingRanges.ranges[]` element.
2770#[derive(Debug, Clone, Default)]
2771pub struct BlendingRange {
2772    pub source_range: Vec<f64>,
2773    pub dest_range: Vec<f64>,
2774}
2775
2776/// TS `LayerAdditionalInfo.blendingRanges`.
2777#[derive(Debug, Clone, Default)]
2778pub struct BlendingRanges {
2779    pub composite_gray_blend_source: Vec<f64>,
2780    pub composite_graph_blend_destination_range: Vec<f64>,
2781    pub ranges: Vec<BlendingRange>,
2782}
2783
2784/// TS `pixelSource.interpretation`.
2785#[derive(Debug, Clone, Default)]
2786pub struct PixelSourceInterpretation {
2787    /// 'straight' | ...
2788    pub interpret_alpha: String,
2789    pub profile: Vec<u8>,
2790}
2791
2792/// TS `pixelSource.frameReader.link`.
2793#[derive(Debug, Clone, Default)]
2794pub struct PixelSourceFrameReaderLink {
2795    pub name: String,
2796    pub full_path: String,
2797    pub original_path: String,
2798    pub relative_path: String,
2799    pub alias: String,
2800}
2801
2802/// TS `pixelSource.frameReader`.
2803#[derive(Debug, Clone, Default)]
2804pub struct PixelSourceFrameReader {
2805    /// TS field `type` = 'QTFR'
2806    pub reader_type: String,
2807    pub link: PixelSourceFrameReaderLink,
2808    pub media_descriptor: String,
2809}
2810
2811/// TS `LayerAdditionalInfo.pixelSource`.
2812#[derive(Debug, Clone, Default)]
2813pub struct PixelSource {
2814    /// TS field `type` = 'vdPS'
2815    pub source_type: String,
2816    pub origin: PointF,
2817    pub interpretation: PixelSourceInterpretation,
2818    pub frame_reader: PixelSourceFrameReader,
2819    pub show_altered_video: bool,
2820}
2821
2822/// TS `LayerAdditionalInfo`.
2823#[derive(Debug, Clone, Default)]
2824pub struct LayerAdditionalInfo {
2825    /// layer name
2826    pub name: Option<String>,
2827    /// layer name source
2828    pub name_source: Option<String>,
2829    /// layer id
2830    pub id: Option<f64>,
2831    /// layer version
2832    pub version: Option<f64>,
2833    pub mask: Option<LayerMaskData>,
2834    pub real_mask: Option<LayerMaskData>,
2835    /// must be `true` when using `color burn` blend mode.
2836    pub blend_clippend_elements: Option<bool>,
2837    pub blend_interior_elements: Option<bool>,
2838    pub knockout: Option<bool>,
2839    pub layer_mask_as_global_mask: Option<bool>,
2840    /// TS field `protected`
2841    pub protected_info: Option<ProtectedInfo>,
2842    pub layer_color: Option<LayerColor>,
2843    pub reference_point: Option<PointF>,
2844    pub section_divider: Option<SectionDivider>,
2845    pub filter_mask: Option<ColorSpaceMask>,
2846    pub effects: Option<LayerEffectsInfo>,
2847    pub text: Option<LayerTextData>,
2848    /// not supported yet upstream
2849    pub patterns: Option<Vec<PatternInfo>>,
2850    pub vector_fill: Option<VectorContent>,
2851    pub vector_stroke: Option<VectorStroke>,
2852    pub vector_mask: Option<LayerVectorMask>,
2853    pub using_aligned_rendering: Option<bool>,
2854    /// seconds
2855    pub timestamp: Option<f64>,
2856    /// TS `pathList?: {}[]` — opaque entries; count preserved as empty structs.
2857    pub path_list: Option<Vec<PathListItem>>,
2858    pub adjustment: Option<AdjustmentLayer>,
2859    pub placed_layer: Option<PlacedLayer>,
2860    pub vector_origination: Option<VectorOrigination>,
2861    pub compositor_used: Option<CompositorUsed>,
2862    pub artboard: Option<LayerArtboard>,
2863    pub fill_opacity: Option<f64>,
2864    pub transparency_shapes_layer: Option<bool>,
2865    pub channel_blending_restrictions: Option<Vec<f64>>,
2866    pub animation_frames: Option<Vec<AnimationFrame>>,
2867    pub animation_frame_flags: Option<AnimationFrameFlags>,
2868    pub timeline: Option<Timeline>,
2869    pub filter_effects_masks: Option<Vec<FilterEffectsMask>>,
2870    pub comps: Option<LayerComps>,
2871    pub user_mask: Option<ColorSpaceMask>,
2872    pub blending_ranges: Option<BlendingRanges>,
2873    /// ??? (upstream comment)
2874    pub vowv: Option<f64>,
2875    pub pixel_source: Option<PixelSource>,
2876    /// Base64 encoded raw EngineData, kept in original state.
2877    pub engine_data: Option<String>,
2878}
2879
2880/// TS `pathList[]` element (`{}` with TODO upstream).
2881#[derive(Debug, Clone, Default)]
2882pub struct PathListItem;
2883
2884// ===========================================================================
2885// Image resources
2886// ===========================================================================
2887
2888/// TS `ImageResources.versionInfo`.
2889#[derive(Debug, Clone, Default)]
2890pub struct VersionInfo {
2891    pub has_real_merged_data: bool,
2892    pub writer_name: String,
2893    pub reader_name: String,
2894    pub file_version: f64,
2895}
2896
2897/// TS `ImageResources.urlsList[]` element.
2898#[derive(Debug, Clone, Default)]
2899pub struct UrlListItem {
2900    pub id: f64,
2901    /// 'slice'
2902    pub r#ref: String,
2903    pub url: String,
2904}
2905
2906/// TS `gridAndGuidesInformation.grid`.
2907#[derive(Debug, Clone, Copy, Default)]
2908pub struct GridInfo {
2909    pub horizontal: f64,
2910    pub vertical: f64,
2911}
2912
2913/// guide direction: "horizontal" | "vertical"
2914#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2915pub enum GuideDirection {
2916    /// "horizontal"
2917    Horizontal,
2918    /// "vertical"
2919    Vertical,
2920}
2921
2922/// TS `gridAndGuidesInformation.guides[]` element.
2923#[derive(Debug, Clone, Copy)]
2924pub struct GuideInfo {
2925    pub location: f64,
2926    pub direction: GuideDirection,
2927}
2928
2929/// TS `ImageResources.gridAndGuidesInformation`.
2930#[derive(Debug, Clone, Default)]
2931pub struct GridAndGuidesInformation {
2932    pub grid: Option<GridInfo>,
2933    pub guides: Option<Vec<GuideInfo>>,
2934}
2935
2936/// "PPI" | "PPCM"
2937#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2938pub enum ResolutionUnit {
2939    /// "PPI"
2940    Ppi,
2941    /// "PPCM"
2942    Ppcm,
2943}
2944
2945/// width/height unit: "Inches" | "Centimeters" | "Points" | "Picas" | "Columns"
2946#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2947pub enum DimensionUnit {
2948    /// "Inches"
2949    Inches,
2950    /// "Centimeters"
2951    Centimeters,
2952    /// "Points"
2953    Points,
2954    /// "Picas"
2955    Picas,
2956    /// "Columns"
2957    Columns,
2958}
2959
2960/// TS `ImageResources.resolutionInfo`.
2961#[derive(Debug, Clone, Copy)]
2962pub struct ResolutionInfo {
2963    pub horizontal_resolution: f64,
2964    pub horizontal_resolution_unit: ResolutionUnit,
2965    pub width_unit: DimensionUnit,
2966    pub vertical_resolution: f64,
2967    pub vertical_resolution_unit: ResolutionUnit,
2968    pub height_unit: DimensionUnit,
2969}
2970
2971/// TS `ImageResources.thumbnailRaw`.
2972#[derive(Debug, Clone, Default)]
2973pub struct ThumbnailRaw {
2974    pub width: f64,
2975    pub height: f64,
2976    pub data: Vec<u8>,
2977}
2978
2979/// print scale style: "centered" | "size to fit" | "user defined"
2980#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2981pub enum PrintScaleStyle {
2982    /// "centered"
2983    Centered,
2984    /// "size to fit"
2985    SizeToFit,
2986    /// "user defined"
2987    UserDefined,
2988}
2989
2990/// TS `ImageResources.printScale`.
2991#[derive(Debug, Clone, Default)]
2992pub struct PrintScale {
2993    pub style: Option<PrintScaleStyle>,
2994    pub x: Option<f64>,
2995    pub y: Option<f64>,
2996    pub scale: Option<f64>,
2997}
2998
2999/// TS `printInformation.proofSetup` union.
3000#[derive(Debug, Clone)]
3001pub enum ProofSetup {
3002    /// `{ builtin: string; }`
3003    Builtin { builtin: String },
3004    /// `{ profile; renderingIntent?; blackPointCompensation?; paperWhite?; }`
3005    Profile {
3006        profile: String,
3007        rendering_intent: Option<RenderingIntent>,
3008        black_point_compensation: Option<bool>,
3009        paper_white: Option<bool>,
3010    },
3011}
3012
3013/// TS `ImageResources.printInformation`.
3014#[derive(Debug, Clone, Default)]
3015pub struct PrintInformation {
3016    pub printer_manages_colors: Option<bool>,
3017    pub printer_name: Option<String>,
3018    pub printer_profile: Option<String>,
3019    pub print_sixteen_bit: Option<bool>,
3020    pub rendering_intent: Option<RenderingIntent>,
3021    pub hard_proof: Option<bool>,
3022    pub black_point_compensation: Option<bool>,
3023    pub proof_setup: Option<ProofSetup>,
3024}
3025
3026/// TS `ImageResources.printFlags`.
3027#[derive(Debug, Clone, Default)]
3028pub struct PrintFlags {
3029    pub labels: Option<bool>,
3030    pub crop_marks: Option<bool>,
3031    pub color_bars: Option<bool>,
3032    pub registration_marks: Option<bool>,
3033    pub negative: Option<bool>,
3034    pub flip: Option<bool>,
3035    pub interpolate: Option<bool>,
3036    pub caption: Option<bool>,
3037    /// nested field also named `printFlags`
3038    pub print_flags: Option<bool>,
3039}
3040
3041/// TS `ImageResources.onionSkins`.
3042#[derive(Debug, Clone)]
3043pub struct OnionSkins {
3044    pub enabled: bool,
3045    pub frames_before: f64,
3046    pub frames_after: f64,
3047    pub frame_spacing: f64,
3048    pub min_opacity: f64,
3049    pub max_opacity: f64,
3050    pub blend_mode: BlendMode,
3051}
3052
3053/// TS `timelineInformation.audioClipGroups[].audioClips[].frameReader.link`.
3054#[derive(Debug, Clone, Default)]
3055pub struct AudioClipFrameReaderLink {
3056    pub name: String,
3057    pub full_path: String,
3058    pub relative_path: String,
3059}
3060
3061/// TS `timelineInformation.audioClipGroups[].audioClips[].frameReader`.
3062#[derive(Debug, Clone, Default)]
3063pub struct AudioClipFrameReader {
3064    /// TS field `type`
3065    pub reader_type: f64,
3066    pub media_descriptor: String,
3067    pub link: AudioClipFrameReaderLink,
3068}
3069
3070/// TS `timelineInformation.audioClipGroups[].audioClips[]` element.
3071#[derive(Debug, Clone, Default)]
3072pub struct AudioClip {
3073    pub id: String,
3074    pub start: Fraction,
3075    pub duration: Fraction,
3076    pub in_time: Fraction,
3077    pub out_time: Fraction,
3078    pub muted: bool,
3079    pub audio_level: f64,
3080    pub frame_reader: AudioClipFrameReader,
3081}
3082
3083/// TS `timelineInformation.audioClipGroups[]` element.
3084#[derive(Debug, Clone, Default)]
3085pub struct AudioClipGroup {
3086    pub id: String,
3087    pub muted: bool,
3088    pub audio_clips: Vec<AudioClip>,
3089}
3090
3091/// TS `ImageResources.timelineInformation`.
3092#[derive(Debug, Clone, Default)]
3093pub struct TimelineInformation {
3094    pub enabled: bool,
3095    pub frame_step: Fraction,
3096    pub frame_rate: f64,
3097    pub time: Fraction,
3098    pub duration: Fraction,
3099    pub work_in_time: Fraction,
3100    pub work_out_time: Fraction,
3101    pub repeats: f64,
3102    pub has_motion: bool,
3103    pub global_tracks: Vec<TimelineTrack>,
3104    pub audio_clip_groups: Option<Vec<AudioClipGroup>>,
3105}
3106
3107/// TS `sheetDisclosure.sheetTimelineOptions[]` element.
3108#[derive(Debug, Clone, Copy, Default)]
3109pub struct SheetTimelineOption {
3110    pub sheet_id: f64,
3111    pub sheet_disclosed: bool,
3112    pub lights_disclosed: bool,
3113    pub meshes_disclosed: bool,
3114    pub materials_disclosed: bool,
3115}
3116
3117/// TS `ImageResources.sheetDisclosure`.
3118#[derive(Debug, Clone, Default)]
3119pub struct SheetDisclosure {
3120    pub sheet_timeline_options: Option<Vec<SheetTimelineOption>>,
3121}
3122
3123/// TS `ImageResources.countInformation[]` element.
3124#[derive(Debug, Clone, Default)]
3125pub struct CountInformation {
3126    pub color: Rgb,
3127    pub name: String,
3128    pub size: f64,
3129    pub font_size: f64,
3130    pub visible: bool,
3131    pub points: Vec<PointF>,
3132}
3133
3134/// slice origin: "userGenerated" | "autoGenerated" | "layer"
3135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3136pub enum SliceOrigin {
3137    /// "userGenerated"
3138    UserGenerated,
3139    /// "autoGenerated"
3140    AutoGenerated,
3141    /// "layer"
3142    Layer,
3143}
3144
3145/// slice type: "image" | "noImage"
3146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3147pub enum SliceType {
3148    /// "image"
3149    Image,
3150    /// "noImage"
3151    NoImage,
3152}
3153
3154/// slice alignment (only "default" observed).
3155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3156pub enum SliceAlignment {
3157    /// "default"
3158    Default,
3159}
3160
3161/// slice background color type: "none" | "matte" | "color"
3162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3163pub enum SliceBackgroundColorType {
3164    /// "none"
3165    None,
3166    /// "matte"
3167    Matte,
3168    /// "color"
3169    Color,
3170}
3171
3172/// TS `slices[].slices[]` element.
3173#[derive(Debug, Clone, Default)]
3174pub struct Slice {
3175    pub id: f64,
3176    pub group_id: f64,
3177    pub origin: Option<SliceOrigin>,
3178    pub associated_layer_id: f64,
3179    pub name: Option<String>,
3180    /// TS field `type`
3181    pub slice_type: Option<SliceType>,
3182    pub bounds: LtrbBounds,
3183    pub url: String,
3184    pub target: String,
3185    pub message: String,
3186    pub alt_tag: String,
3187    pub cell_text_is_html: bool,
3188    pub cell_text: String,
3189    pub horizontal_alignment: Option<SliceAlignment>,
3190    pub vertical_alignment: Option<SliceAlignment>,
3191    pub background_color_type: Option<SliceBackgroundColorType>,
3192    pub background_color: Rgba,
3193    pub top_outset: Option<f64>,
3194    pub left_outset: Option<f64>,
3195    pub bottom_outset: Option<f64>,
3196    pub right_outset: Option<f64>,
3197}
3198
3199/// TS `ImageResources.slices[]` element.
3200#[derive(Debug, Clone, Default)]
3201pub struct SliceGroup {
3202    pub bounds: LtrbBounds,
3203    pub group_name: String,
3204    pub slices: Vec<Slice>,
3205}
3206
3207/// TS `layerComps.list[]` element.
3208#[derive(Debug, Clone)]
3209pub struct LayerCompListItem {
3210    pub id: f64,
3211    pub name: String,
3212    pub comment: Option<String>,
3213    pub captured_info: LayerCompCapturedInfo,
3214}
3215
3216/// TS `ImageResources.layerComps`.
3217#[derive(Debug, Clone, Default)]
3218pub struct LayerCompsResource {
3219    pub list: Vec<LayerCompListItem>,
3220    pub last_applied: Option<f64>,
3221}
3222
3223/// TS `ImageResources.pixelAspectRatio`.
3224#[derive(Debug, Clone, Copy, Default)]
3225pub struct PixelAspectRatio {
3226    pub aspect: f64,
3227}
3228
3229/// TS `ImageResources`.
3230#[derive(Debug, Clone, Default)]
3231pub struct ImageResources {
3232    pub layer_state: Option<f64>,
3233    pub layer_selection_ids: Option<Vec<f64>>,
3234    pub version_info: Option<VersionInfo>,
3235    pub alpha_identifiers: Option<Vec<f64>>,
3236    pub alpha_channel_names: Option<Vec<String>>,
3237    pub global_angle: Option<f64>,
3238    pub global_altitude: Option<f64>,
3239    pub pixel_aspect_ratio: Option<PixelAspectRatio>,
3240    pub urls_list: Option<Vec<UrlListItem>>,
3241    pub grid_and_guides_information: Option<GridAndGuidesInformation>,
3242    pub resolution_info: Option<ResolutionInfo>,
3243    /// TS `thumbnail?: HTMLCanvasElement` -> raw pixels.
3244    pub thumbnail: Option<PixelData>,
3245    pub thumbnail_raw: Option<ThumbnailRaw>,
3246    pub caption_digest: Option<String>,
3247    pub xmp_metadata: Option<String>,
3248    pub print_scale: Option<PrintScale>,
3249    pub print_information: Option<PrintInformation>,
3250    pub background_color: Option<Color>,
3251    pub ids_seed_number: Option<f64>,
3252    pub print_flags: Option<PrintFlags>,
3253    pub icc_untagged_profile: Option<bool>,
3254    pub path_selection_state: Option<Vec<String>>,
3255    pub image_ready_variables: Option<String>,
3256    pub image_ready_data_sets: Option<String>,
3257    pub animations: Option<Animations>,
3258    pub onion_skins: Option<OnionSkins>,
3259    pub timeline_information: Option<TimelineInformation>,
3260    pub sheet_disclosure: Option<SheetDisclosure>,
3261    pub count_information: Option<Vec<CountInformation>>,
3262    pub slices: Option<Vec<SliceGroup>>,
3263    pub layer_comps: Option<LayerCompsResource>,
3264    pub copyrighted: Option<bool>,
3265    pub url: Option<String>,
3266}
3267
3268// ===========================================================================
3269// Global mask info / annotations
3270// ===========================================================================
3271
3272/// TS `GlobalLayerMaskInfo`.
3273#[derive(Debug, Clone, Default)]
3274pub struct GlobalLayerMaskInfo {
3275    pub overlay_color_space: f64,
3276    pub color_space1: f64,
3277    pub color_space2: f64,
3278    pub color_space3: f64,
3279    pub color_space4: f64,
3280    pub opacity: f64,
3281    pub kind: f64,
3282}
3283
3284/// annotation type: "text" | "sound"
3285#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3286pub enum AnnotationType {
3287    /// "text"
3288    Text,
3289    /// "sound"
3290    Sound,
3291}
3292
3293/// TS `Annotation.data = string | Uint8Array`.
3294#[derive(Debug, Clone)]
3295pub enum AnnotationData {
3296    Text(String),
3297    Binary(Vec<u8>),
3298}
3299
3300/// TS `Annotation`.
3301#[derive(Debug, Clone)]
3302pub struct Annotation {
3303    /// TS field `type`
3304    pub annotation_type: AnnotationType,
3305    pub open: bool,
3306    pub icon_location: LtrbBounds,
3307    pub popup_location: LtrbBounds,
3308    pub color: Color,
3309    pub author: String,
3310    pub name: String,
3311    pub date: String,
3312    pub data: AnnotationData,
3313}
3314
3315// ===========================================================================
3316// Raw channel data
3317// ===========================================================================
3318
3319/// TS `LayerRawDataChannel`.
3320#[derive(Debug, Clone)]
3321pub struct LayerRawDataChannel {
3322    pub id: ChannelId,
3323    pub compression: Compression,
3324    pub data: Option<Vec<u8>>,
3325}
3326
3327/// TS `LayerRawData`.
3328#[derive(Debug, Clone)]
3329pub struct LayerRawData {
3330    pub color_mode: ColorMode,
3331    pub bits_per_channel: f64,
3332    pub channels: Vec<LayerRawDataChannel>,
3333    pub large: bool,
3334}
3335
3336// ===========================================================================
3337// Layer / Psd
3338// ===========================================================================
3339
3340/// TS `Layer extends LayerAdditionalInfo`.
3341///
3342/// `children` is `Vec<Layer>` (recursive); since it lives behind a `Vec`, no
3343/// `Box` is needed to break the recursion.
3344#[derive(Debug, Clone, Default)]
3345pub struct Layer {
3346    /// flattened `LayerAdditionalInfo` base.
3347    pub additional_info: LayerAdditionalInfo,
3348
3349    pub top: Option<f64>,
3350    pub left: Option<f64>,
3351    pub bottom: Option<f64>,
3352    pub right: Option<f64>,
3353    pub blend_mode: Option<BlendMode>,
3354    pub opacity: Option<f64>,
3355    pub transparency_protected: Option<bool>,
3356    /// effects/filters panel is expanded
3357    pub effects_open: Option<bool>,
3358    pub hidden: Option<bool>,
3359    pub clipping: Option<bool>,
3360    /// TS `canvas?: HTMLCanvasElement` -> raw pixels.
3361    pub canvas: Option<PixelData>,
3362    pub image_data: Option<PixelData>,
3363    pub raw_data: Option<LayerRawData>,
3364    pub children: Option<Vec<Layer>>,
3365    /// Applies only for layer groups.
3366    pub opened: Option<bool>,
3367    pub link_group: Option<f64>,
3368    pub link_group_enabled: Option<bool>,
3369}
3370
3371/// TS `Psd.artboards`.
3372#[derive(Debug, Clone, Default)]
3373pub struct PsdArtboards {
3374    /// number of artboards in the document
3375    pub count: f64,
3376    pub auto_expand_offset: Option<HorizontalVertical>,
3377    pub origin: Option<HorizontalVertical>,
3378    pub auto_expand_enabled: Option<bool>,
3379    pub auto_nest_enabled: Option<bool>,
3380    pub auto_position_enabled: Option<bool>,
3381    pub shrinkwrap_on_save_enabled: Option<bool>,
3382    pub doc_default_new_artboard_background_color: Option<Color>,
3383    pub doc_default_new_artboard_background_type: Option<f64>,
3384}
3385
3386/// TS `Psd extends LayerAdditionalInfo`.
3387#[derive(Debug, Clone, Default)]
3388pub struct Psd {
3389    /// flattened `LayerAdditionalInfo` base.
3390    pub additional_info: LayerAdditionalInfo,
3391
3392    pub width: f64,
3393    pub height: f64,
3394    pub channels: Option<f64>,
3395    pub bits_per_channel: Option<f64>,
3396    pub color_mode: Option<ColorMode>,
3397    /// colors for indexed color mode
3398    pub palette: Option<Vec<Rgb>>,
3399    pub children: Option<Vec<Layer>>,
3400    /// TS `canvas?: HTMLCanvasElement` -> raw pixels.
3401    pub canvas: Option<PixelData>,
3402    pub image_data: Option<PixelData>,
3403    pub image_resources: Option<ImageResources>,
3404    /// used in smart objects
3405    pub linked_files: Option<Vec<LinkedFile>>,
3406    pub artboards: Option<PsdArtboards>,
3407    pub global_layer_mask_info: Option<GlobalLayerMaskInfo>,
3408    pub annotations: Option<Vec<Annotation>>,
3409}
3410
3411// ===========================================================================
3412// Read / Write options
3413// ===========================================================================
3414
3415/// TS `ReadOptions`.
3416///
3417/// The development-only `log?: (...args) => void` callback is not modeled here
3418/// (it is behaviour, not data); other dev flags are kept.
3419#[derive(Debug, Clone, Default)]
3420pub struct ReadOptions {
3421    /// Does not load layer image data.
3422    pub skip_layer_image_data: Option<bool>,
3423    /// Does not load composite image data.
3424    pub skip_composite_image_data: Option<bool>,
3425    /// Does not load thumbnail.
3426    pub skip_thumbnail: Option<bool>,
3427    /// Does not load linked files (used in smart-objects).
3428    pub skip_linked_files_data: Option<bool>,
3429    /// Throws exception if features are missing.
3430    pub throw_for_missing_features: Option<bool>,
3431    /// Logs if features are missing.
3432    pub log_missing_features: Option<bool>,
3433    /// Keep image data as byte array instead of canvas.
3434    pub use_image_data: Option<bool>,
3435    pub use_raw_data: Option<bool>,
3436    /// Loads thumbnail raw data instead of decoding into canvas.
3437    pub use_raw_thumbnail: Option<bool>,
3438    /// Used only for development.
3439    pub log_dev_features: Option<bool>,
3440    /// Used only for development.
3441    pub strict: Option<bool>,
3442    /// Used only for development.
3443    pub debug: Option<bool>,
3444    // TS `log?: (...args: any[]) => void;` — поведение, не данные; не портируем.
3445}
3446
3447/// TS `WriteOptions`.
3448#[derive(Debug, Clone, Default)]
3449pub struct WriteOptions {
3450    /// Automatically generates thumbnail from composite image.
3451    pub generate_thumbnail: Option<bool>,
3452    /// Trims transparent pixels from layer image data.
3453    pub trim_image_data: Option<bool>,
3454    /// Invalidates text layer data, forcing Photoshop to redraw on load.
3455    pub invalidate_text_layers: Option<bool>,
3456    /// Logs if features are missing.
3457    pub log_missing_features: Option<bool>,
3458    /// Forces bottom layer to be treated as layer and not background.
3459    pub no_background: Option<bool>,
3460    /// Saves document as PSB (Large Document Format) file.
3461    pub psb: Option<bool>,
3462    /// Uses zip compression when writing PSD file.
3463    pub compress: Option<bool>,
3464}