ag-psd 20.2.2 → 20.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { fromByteArray, toByteArray } from 'base64-js';
2
2
  import { readEffects, writeEffects } from './effectsHelpers';
3
3
  import { clamp, createEnum, layerColors, MOCK_HANDLERS } from './helpers';
4
- import { LayerAdditionalInfo, BezierPath, Psd, BrightnessAdjustment, ExposureAdjustment, VibranceAdjustment, ColorBalanceAdjustment, BlackAndWhiteAdjustment, PhotoFilterAdjustment, ChannelMixerChannel, ChannelMixerAdjustment, PosterizeAdjustment, ThresholdAdjustment, GradientMapAdjustment, CMYK, SelectiveColorAdjustment, ColorLookupAdjustment, LevelsAdjustmentChannel, LevelsAdjustment, CurvesAdjustment, CurvesAdjustmentChannel, HueSaturationAdjustment, HueSaturationAdjustmentChannel, PresetInfo, Color, ColorBalanceValues, WriteOptions, LinkedFile, PlacedLayerType, Warp, KeyDescriptorItem, BooleanOperation, LayerEffectsInfo, Annotation, LayerVectorMask, AnimationFrame, Timeline, PlacedLayerFilter, UnitsValue, Filter, PlacedLayer } from './psd';
4
+ import { LayerAdditionalInfo, BezierPath, Psd, BrightnessAdjustment, ExposureAdjustment, VibranceAdjustment, ColorBalanceAdjustment, BlackAndWhiteAdjustment, PhotoFilterAdjustment, ChannelMixerChannel, ChannelMixerAdjustment, PosterizeAdjustment, ThresholdAdjustment, GradientMapAdjustment, CMYK, SelectiveColorAdjustment, ColorLookupAdjustment, LevelsAdjustmentChannel, LevelsAdjustment, CurvesAdjustment, CurvesAdjustmentChannel, HueSaturationAdjustment, HueSaturationAdjustmentChannel, PresetInfo, Color, ColorBalanceValues, WriteOptions, LinkedFile, PlacedLayerType, Warp, KeyDescriptorItem, BooleanOperation, LayerEffectsInfo, Annotation, LayerVectorMask, AnimationFrame, Timeline, PlacedLayerFilter, UnitsValue, Filter, PlacedLayer, ReadOptions } from './psd';
5
5
  import { PsdReader, readSignature, readUnicodeString, skipBytes, readUint32, readUint8, readFloat64, readUint16, readBytes, readInt16, checkSignature, readFloat32, readFixedPointPath32, readSection, readColor, readInt32, readPascalString, readUnicodeStringWithLength, readAsciiString, readPattern, readLayerInfo, ReadOptionsExt } from './psdReader';
6
6
  import { PsdWriter, writeZeros, writeSignature, writeBytes, writeUint32, writeUint16, writeFloat64, writeUint8, writeInt16, writeFloat32, writeFixedPointPath32, writeUnicodeString, writeSection, writeUnicodeStringWithPadding, writeColor, writePascalString, writeInt32 } from './psdWriter';
7
7
  import { Annt, BlnM, DescriptorColor, DescriptorUnitsValue, parsePercent, parseUnits, parseUnitsOrNumber, QuiltWarpDescriptor, strokeStyleLineAlignment, strokeStyleLineCapType, strokeStyleLineJoinType, TextDescriptor, textGridding, unitsPercent, unitsValue, WarpDescriptor, warpStyle, writeVersionAndDescriptor, readVersionAndDescriptor, StrokeDescriptor, Ornt, horzVrtcToXY, LmfxDescriptor, Lfx2Descriptor, FrameListDescriptor, TimelineDescriptor, FrameDescriptor, xyToHorzVrtc, serializeEffects, parseEffects, parseColor, serializeColor, serializeVectorContent, parseVectorContent, parseTrackList, serializeTrackList, FractionDescriptor, BlrM, BlrQ, SmBQ, SmBM, DspM, UndA, Cnvr, RplS, SphM, Wvtp, ZZTy, Dstr, Chnl, MztT, Lns, blurType, DfsM, ExtT, ExtR, FlCl, CntE, WndM, Drct, IntE, IntC, FlMd, unitsPercentF, frac, ClrS, descBoundsToBounds, boundsToDescBounds } from './descriptor';
@@ -1945,7 +1945,7 @@ function pointToHrznVrtc(point: { x: UnitsValue; y: UnitsValue; }): HrznVrtcDesc
1945
1945
  };
1946
1946
  }
1947
1947
 
1948
- function parseFilterFXItem(f: SoLdDescriptorFilterItem): Filter {
1948
+ function parseFilterFXItem(f: SoLdDescriptorFilterItem, options: ReadOptions): Filter | undefined {
1949
1949
  const base: Omit<Filter, 'type' | 'filter'> = {
1950
1950
  name: f['Nm '],
1951
1951
  opacity: parsePercent(f.blendOptions.Opct),
@@ -1956,540 +1956,551 @@ function parseFilterFXItem(f: SoLdDescriptorFilterItem): Filter {
1956
1956
  backgroundColor: parseColor(f.BckC),
1957
1957
  };
1958
1958
 
1959
- switch (f.filterID) {
1960
- case 1098281575: return { ...base, type: 'average' };
1961
- case 1114403360: return { ...base, type: 'blur' };
1962
- case 1114403405: return { ...base, type: 'blur more' };
1963
- case 697: return {
1964
- ...base,
1965
- type: 'box blur',
1966
- filter: {
1967
- radius: parseUnits(f.Fltr['Rds ']),
1968
- },
1969
- };
1970
- case 1198747202: return {
1971
- ...base,
1972
- type: 'gaussian blur',
1973
- filter: {
1974
- radius: parseUnits(f.Fltr['Rds ']),
1975
- },
1976
- };
1977
- case 1299476034: return {
1978
- ...base,
1979
- type: 'motion blur',
1980
- filter: {
1981
- angle: f.Fltr.Angl,
1982
- distance: parseUnits(f.Fltr.Dstn),
1983
- },
1984
- };
1985
- case 1382313026: return {
1986
- ...base,
1987
- type: 'radial blur',
1988
- filter: {
1989
- amount: f.Fltr.Amnt,
1990
- method: BlrM.decode(f.Fltr.BlrM),
1991
- quality: BlrQ.decode(f.Fltr.BlrQ),
1992
- },
1993
- };
1994
- case 702: return {
1995
- ...base,
1996
- type: 'shape blur',
1997
- filter: {
1998
- radius: parseUnits(f.Fltr['Rds ']),
1999
- customShape: { name: f.Fltr.customShape['Nm '], id: f.Fltr.customShape.Idnt },
2000
- },
2001
- };
2002
- case 1399681602: return {
2003
- ...base,
2004
- type: 'smart blur',
2005
- filter: {
2006
- radius: f.Fltr['Rds '],
2007
- threshold: f.Fltr.Thsh,
2008
- quality: SmBQ.decode(f.Fltr.SmBQ),
2009
- mode: SmBM.decode(f.Fltr.SmBM),
2010
- },
2011
- };
2012
- case 701: return {
2013
- ...base,
2014
- type: 'surface blur',
2015
- filter: {
2016
- radius: parseUnits(f.Fltr['Rds ']),
2017
- threshold: f.Fltr.Thsh,
2018
- },
2019
- };
2020
- case 1148416108: return {
2021
- ...base,
2022
- type: 'displace',
2023
- filter: {
2024
- horizontalScale: f.Fltr.HrzS,
2025
- verticalScale: f.Fltr.VrtS,
2026
- displacementMap: DspM.decode(f.Fltr.DspM),
2027
- undefinedAreas: UndA.decode(f.Fltr.UndA),
2028
- displacementFile: {
2029
- signature: f.Fltr.DspF.sig,
2030
- path: f.Fltr.DspF.path, // TODO: this is decoded incorrectly ???
1959
+ if ('Fltr' in f) {
1960
+ switch (f.Fltr._classID) {
1961
+ case 'boxblur': return {
1962
+ ...base,
1963
+ type: 'box blur',
1964
+ filter: {
1965
+ radius: parseUnits(f.Fltr['Rds ']),
2031
1966
  },
2032
- },
2033
- };
2034
- case 1349411688: return {
2035
- ...base,
2036
- type: 'pinch',
2037
- filter: {
2038
- amount: f.Fltr.Amnt,
2039
- },
2040
- };
2041
- case 1349284384: return {
2042
- ...base,
2043
- type: 'polar coordinates',
2044
- filter: {
2045
- conversion: Cnvr.decode(f.Fltr.Cnvr),
2046
- },
2047
- };
2048
- case 1383099493: return {
2049
- ...base,
2050
- type: 'ripple',
2051
- filter: {
2052
- amount: f.Fltr.Amnt,
2053
- size: RplS.decode(f.Fltr.RplS),
2054
- },
2055
- };
2056
- case 1399353888: return {
2057
- ...base,
2058
- type: 'shear',
2059
- filter: {
2060
- shearPoints: f.Fltr.ShrP.map(p => ({ x: p.Hrzn, y: p.Vrtc })),
2061
- shearStart: f.Fltr.ShrS,
2062
- shearEnd: f.Fltr.ShrE,
2063
- undefinedAreas: UndA.decode(f.Fltr.UndA),
2064
- },
2065
- };
2066
- case 1399875698: return {
2067
- ...base,
2068
- type: 'spherize',
2069
- filter: {
2070
- amount: f.Fltr.Amnt,
2071
- mode: SphM.decode(f.Fltr.SphM),
2072
- },
2073
- };
2074
- case 1417114220: return {
2075
- ...base,
2076
- type: 'twirl',
2077
- filter: {
2078
- angle: f.Fltr.Angl,
2079
- },
2080
- };
2081
- case 1466005093: return {
2082
- ...base,
2083
- type: 'wave',
2084
- filter: {
2085
- numberOfGenerators: f.Fltr.NmbG,
2086
- type: Wvtp.decode(f.Fltr.Wvtp),
2087
- wavelength: { min: f.Fltr.WLMn, max: f.Fltr.WLMx },
2088
- amplitude: { min: f.Fltr.AmMn, max: f.Fltr.AmMx },
2089
- scale: { x: f.Fltr.SclH, y: f.Fltr.SclV },
2090
- randomSeed: f.Fltr.RndS,
2091
- undefinedAreas: UndA.decode(f.Fltr.UndA),
2092
- },
2093
- };
2094
- case 1516722791: return {
2095
- ...base,
2096
- type: 'zigzag',
2097
- filter: {
2098
- amount: f.Fltr.Amnt,
2099
- ridges: f.Fltr.NmbR,
2100
- style: ZZTy.decode(f.Fltr.ZZTy),
2101
- },
2102
- };
2103
- case 1097092723: return {
2104
- ...base,
2105
- type: 'add noise',
2106
- filter: {
2107
- amount: parsePercent(f.Fltr.Nose),
2108
- distribution: Dstr.decode(f.Fltr.Dstr),
2109
- monochromatic: f.Fltr.Mnch,
2110
- randomSeed: f.Fltr.FlRs,
2111
- },
2112
- };
2113
- case 1148416099: return { ...base, type: 'despeckle' };
2114
- case 1148417107: return {
2115
- ...base,
2116
- type: 'dust and scratches',
2117
- filter: {
2118
- radius: f.Fltr['Rds '],
2119
- threshold: f.Fltr.Thsh,
2120
- },
2121
- };
2122
- case 1298427424: return {
2123
- ...base,
2124
- type: 'median',
2125
- filter: {
2126
- radius: parseUnits(f.Fltr['Rds ']),
2127
- },
2128
- };
2129
- case 633: return {
2130
- ...base,
2131
- type: 'reduce noise',
2132
- filter: {
2133
- preset: f.Fltr.preset,
2134
- removeJpegArtifact: f.Fltr.removeJPEGArtifact,
2135
- reduceColorNoise: parsePercent(f.Fltr.ClNs),
2136
- sharpenDetails: parsePercent(f.Fltr.Shrp),
2137
- channelDenoise: f.Fltr.channelDenoise.map(c => ({
2138
- channels: c.Chnl.map(i => Chnl.decode(i)),
2139
- amount: c.Amnt,
2140
- ...(c.EdgF ? { preserveDetails: c.EdgF } : {}),
2141
- })),
2142
- },
2143
- };
2144
- case 1131180616: return {
2145
- ...base,
2146
- type: 'color halftone',
2147
- filter: {
2148
- radius: f.Fltr['Rds '],
2149
- angle1: f.Fltr.Ang1,
2150
- angle2: f.Fltr.Ang2,
2151
- angle3: f.Fltr.Ang3,
2152
- angle4: f.Fltr.Ang4,
2153
- },
2154
- };
2155
- case 1131574132: return {
2156
- ...base,
2157
- type: 'crystallize',
2158
- filter: {
2159
- cellSize: f.Fltr.ClSz,
2160
- randomSeed: f.Fltr.FlRs,
2161
- },
2162
- };
2163
- case 1180922912: return { ...base, type: 'facet' };
2164
- case 1181902701: return { ...base, type: 'fragment' };
2165
- case 1299870830: return {
2166
- ...base,
2167
- type: 'mezzotint',
2168
- filter: {
2169
- type: MztT.decode(f.Fltr.MztT),
2170
- randomSeed: f.Fltr.FlRs,
2171
- },
2172
- };
2173
- case 1299407648: return {
2174
- ...base,
2175
- type: 'mosaic',
2176
- filter: {
2177
- cellSize: parseUnits(f.Fltr.ClSz),
2178
- },
2179
- };
2180
- case 1349416044: return {
2181
- ...base,
2182
- type: 'pointillize',
2183
- filter: {
2184
- cellSize: f.Fltr.ClSz,
2185
- randomSeed: f.Fltr.FlRs,
2186
- },
2187
- };
2188
- case 1131177075: return {
2189
- ...base,
2190
- type: 'clouds',
2191
- filter: {
2192
- randomSeed: f.Fltr.FlRs,
2193
- },
2194
- };
2195
- case 1147564611: return {
2196
- ...base,
2197
- type: 'difference clouds',
2198
- filter: {
2199
- randomSeed: f.Fltr.FlRs,
2200
- },
2201
- };
2202
- case 1180856947: return {
2203
- ...base,
2204
- type: 'fibers',
2205
- filter: {
2206
- variance: f.Fltr.Vrnc,
2207
- strength: f.Fltr.Strg,
2208
- randomSeed: f.Fltr.RndS,
2209
- },
2210
- };
2211
- case 1282306886: return {
2212
- ...base,
2213
- type: 'lens flare',
2214
- filter: {
2215
- brightness: f.Fltr.Brgh,
2216
- position: { x: f.Fltr.FlrC.Hrzn, y: f.Fltr.FlrC.Vrtc },
2217
- lensType: Lns.decode(f.Fltr['Lns ']),
2218
- },
2219
- };
2220
- case 1399353968: return { ...base, type: 'sharpen' };
2221
- case 1399353925: return { ...base, type: 'sharpen edges' };
2222
- case 1399353933: return { ...base, type: 'sharpen more' };
2223
- case 698: return {
2224
- ...base,
2225
- type: 'smart sharpen',
2226
- filter: {
2227
- amount: parsePercent(f.Fltr.Amnt),
2228
- radius: parseUnits(f.Fltr['Rds ']),
2229
- threshold: f.Fltr.Thsh,
2230
- angle: f.Fltr.Angl,
2231
- moreAccurate: f.Fltr.moreAccurate,
2232
- blur: blurType.decode(f.Fltr.blur),
2233
- preset: f.Fltr.preset,
2234
- shadow: {
2235
- fadeAmount: parsePercent(f.Fltr.sdwM.Amnt),
2236
- tonalWidth: parsePercent(f.Fltr.sdwM.Wdth),
2237
- radius: f.Fltr.sdwM['Rds '],
1967
+ };
1968
+ case 'GsnB': return {
1969
+ ...base,
1970
+ type: 'gaussian blur',
1971
+ filter: {
1972
+ radius: parseUnits(f.Fltr['Rds ']),
2238
1973
  },
2239
- highlight: {
2240
- fadeAmount: parsePercent(f.Fltr.hglM.Amnt),
2241
- tonalWidth: parsePercent(f.Fltr.hglM.Wdth),
2242
- radius: f.Fltr.hglM['Rds '],
1974
+ };
1975
+ case 'MtnB': return {
1976
+ ...base,
1977
+ type: 'motion blur',
1978
+ filter: {
1979
+ angle: f.Fltr.Angl,
1980
+ distance: parseUnits(f.Fltr.Dstn),
2243
1981
  },
2244
- },
2245
- };
2246
- case 1433301837: return {
2247
- ...base,
2248
- type: 'unsharp mask',
2249
- filter: {
2250
- amount: parsePercent(f.Fltr.Amnt),
2251
- radius: parseUnits(f.Fltr['Rds ']),
2252
- threshold: f.Fltr.Thsh,
2253
- },
2254
- };
2255
- case 1147564832: return {
2256
- ...base,
2257
- type: 'diffuse',
2258
- filter: {
2259
- mode: DfsM.decode(f.Fltr['Md ']),
2260
- randomSeed: f.Fltr.FlRs,
2261
- },
2262
- };
2263
- case 1164796531: return {
2264
- ...base,
2265
- type: 'emboss',
2266
- filter: {
2267
- angle: f.Fltr.Angl,
2268
- height: f.Fltr.Hght,
2269
- amount: f.Fltr.Amnt,
2270
- },
2271
- };
2272
- case 1165522034: return {
2273
- ...base,
2274
- type: 'extrude',
2275
- filter: {
2276
- type: ExtT.decode(f.Fltr.ExtT),
2277
- size: f.Fltr.ExtS,
2278
- depth: f.Fltr.ExtD,
2279
- depthMode: ExtR.decode(f.Fltr.ExtR),
2280
- randomSeed: f.Fltr.FlRs,
2281
- solidFrontFaces: f.Fltr.ExtF,
2282
- maskIncompleteBlocks: f.Fltr.ExtM,
2283
- },
2284
- };
2285
- case 1181639749: return { ...base, type: 'find edges' };
2286
- case 1399616122: return { ...base, type: 'solarize' };
2287
- case 1416393504: return {
2288
- ...base,
2289
- type: 'tiles',
2290
- filter: {
2291
- numberOfTiles: f.Fltr.TlNm,
2292
- maximumOffset: f.Fltr.TlOf,
2293
- fillEmptyAreaWith: FlCl.decode(f.Fltr.FlCl),
2294
- randomSeed: f.Fltr.FlRs,
2295
- },
2296
- };
2297
- case 1416782659: return {
2298
- ...base,
2299
- type: 'trace contour',
2300
- filter: {
2301
- level: f.Fltr['Lvl '],
2302
- edge: CntE.decode(f.Fltr['Edg ']),
2303
- },
2304
- };
2305
- case 1466852384: return {
2306
- ...base,
2307
- type: 'wind',
2308
- filter: {
2309
- method: WndM.decode(f.Fltr.WndM),
2310
- direction: Drct.decode(f.Fltr.Drct),
2311
- },
2312
- };
2313
- case 1148089458: return {
2314
- ...base,
2315
- type: 'de-interlace',
2316
- filter: {
2317
- eliminate: IntE.decode(f.Fltr.IntE),
2318
- newFieldsBy: IntC.decode(f.Fltr.IntC),
2319
- },
2320
- };
2321
- case 1314149187: return { ...base, type: 'ntsc colors' };
2322
- case 1131639917: return {
2323
- ...base,
2324
- type: 'custom',
2325
- filter: {
2326
- scale: f.Fltr['Scl '],
2327
- offset: f.Fltr.Ofst,
2328
- matrix: f.Fltr.Mtrx,
2329
- },
2330
- };
2331
- case 1214736464: return {
2332
- ...base,
2333
- type: 'high pass',
2334
- filter: {
2335
- radius: parseUnits(f.Fltr['Rds ']),
2336
- },
2337
- };
2338
- case 1299737888: return {
2339
- ...base,
2340
- type: 'maximum',
2341
- filter: {
2342
- radius: parseUnits(f.Fltr['Rds ']),
2343
- },
2344
- };
2345
- case 1299082528: return {
2346
- ...base,
2347
- type: 'minimum',
2348
- filter: {
2349
- radius: parseUnits(f.Fltr['Rds ']),
2350
- },
2351
- };
2352
- case 1332114292: return {
2353
- ...base,
2354
- type: 'offset',
2355
- filter: {
2356
- horizontal: f.Fltr.Hrzn,
2357
- vertical: f.Fltr.Vrtc,
2358
- undefinedAreas: FlMd.decode(f.Fltr['Fl ']),
2359
- },
2360
- };
2361
- case 943:
2362
- case 991: return {
2363
- ...base,
2364
- type: 'puppet',
2365
- filter: {
2366
- rigidType: f.Fltr.rigidType,
2367
- bounds: [
2368
- { x: f.Fltr.PuX0, y: f.Fltr.PuY0, },
2369
- { x: f.Fltr.PuX1, y: f.Fltr.PuY1, },
2370
- { x: f.Fltr.PuX2, y: f.Fltr.PuY2, },
2371
- { x: f.Fltr.PuX3, y: f.Fltr.PuY3, },
2372
- ],
2373
- puppetShapeList: f.Fltr.puppetShapeList!.map(p => ({
2374
- rigidType: p.rigidType,
2375
- // TODO: VrsM
2376
- // TODO: VrsN
2377
- originalVertexArray: uint8ToPoints(p.originalVertexArray),
2378
- deformedVertexArray: uint8ToPoints(p.deformedVertexArray),
2379
- indexArray: Array.from(uint8ToUint32(p.indexArray)),
2380
- pinOffsets: arrayToPoints(p.pinOffsets),
2381
- posFinalPins: arrayToPoints(p.posFinalPins),
2382
- pinVertexIndices: p.pinVertexIndices,
2383
- selectedPin: p.selectedPin,
2384
- pinPosition: arrayToPoints(p.PinP),
2385
- pinRotation: p.PnRt,
2386
- pinOverlay: p.PnOv,
2387
- pinDepth: p.PnDp,
2388
- meshQuality: p.meshQuality,
2389
- meshExpansion: p.meshExpansion,
2390
- meshRigidity: p.meshRigidity,
2391
- imageResolution: p.imageResolution,
2392
- meshBoundaryPath: {
2393
- pathComponents: p.meshBoundaryPath.pathComponents.map(c => ({
2394
- shapeOperation: c.shapeOperation.split('.')[1],
2395
- paths: c.SbpL.map(t => ({
2396
- closed: t.Clsp,
2397
- points: t['Pts '].map(pt => ({
2398
- anchor: hrznVrtcToPoint(pt.Anch),
2399
- forward: hrznVrtcToPoint(pt['Fwd ']),
2400
- backward: hrznVrtcToPoint(pt['Bwd ']),
2401
- smooth: pt.Smoo,
1982
+ };
1983
+ case 'RdlB': return {
1984
+ ...base,
1985
+ type: 'radial blur',
1986
+ filter: {
1987
+ amount: f.Fltr.Amnt,
1988
+ method: BlrM.decode(f.Fltr.BlrM),
1989
+ quality: BlrQ.decode(f.Fltr.BlrQ),
1990
+ },
1991
+ };
1992
+ case 'shapeBlur': return {
1993
+ ...base,
1994
+ type: 'shape blur',
1995
+ filter: {
1996
+ radius: parseUnits(f.Fltr['Rds ']),
1997
+ customShape: { name: f.Fltr.customShape['Nm '], id: f.Fltr.customShape.Idnt },
1998
+ },
1999
+ };
2000
+ case 'SmrB': return {
2001
+ ...base,
2002
+ type: 'smart blur',
2003
+ filter: {
2004
+ radius: f.Fltr['Rds '],
2005
+ threshold: f.Fltr.Thsh,
2006
+ quality: SmBQ.decode(f.Fltr.SmBQ),
2007
+ mode: SmBM.decode(f.Fltr.SmBM),
2008
+ },
2009
+ };
2010
+ case 'surfaceBlur': return {
2011
+ ...base,
2012
+ type: 'surface blur',
2013
+ filter: {
2014
+ radius: parseUnits(f.Fltr['Rds ']),
2015
+ threshold: f.Fltr.Thsh,
2016
+ },
2017
+ };
2018
+ case 'Dspl': return {
2019
+ ...base,
2020
+ type: 'displace',
2021
+ filter: {
2022
+ horizontalScale: f.Fltr.HrzS,
2023
+ verticalScale: f.Fltr.VrtS,
2024
+ displacementMap: DspM.decode(f.Fltr.DspM),
2025
+ undefinedAreas: UndA.decode(f.Fltr.UndA),
2026
+ displacementFile: {
2027
+ signature: f.Fltr.DspF.sig,
2028
+ path: f.Fltr.DspF.path, // TODO: this is decoded incorrectly ???
2029
+ },
2030
+ },
2031
+ };
2032
+ case 'Pnch': return {
2033
+ ...base,
2034
+ type: 'pinch',
2035
+ filter: {
2036
+ amount: f.Fltr.Amnt,
2037
+ },
2038
+ };
2039
+ case 'Plr ': return {
2040
+ ...base,
2041
+ type: 'polar coordinates',
2042
+ filter: {
2043
+ conversion: Cnvr.decode(f.Fltr.Cnvr),
2044
+ },
2045
+ };
2046
+ case 'Rple': return {
2047
+ ...base,
2048
+ type: 'ripple',
2049
+ filter: {
2050
+ amount: f.Fltr.Amnt,
2051
+ size: RplS.decode(f.Fltr.RplS),
2052
+ },
2053
+ };
2054
+ case 'Shr ': return {
2055
+ ...base,
2056
+ type: 'shear',
2057
+ filter: {
2058
+ shearPoints: f.Fltr.ShrP.map(p => ({ x: p.Hrzn, y: p.Vrtc })),
2059
+ shearStart: f.Fltr.ShrS,
2060
+ shearEnd: f.Fltr.ShrE,
2061
+ undefinedAreas: UndA.decode(f.Fltr.UndA),
2062
+ },
2063
+ };
2064
+ case 'Sphr': return {
2065
+ ...base,
2066
+ type: 'spherize',
2067
+ filter: {
2068
+ amount: f.Fltr.Amnt,
2069
+ mode: SphM.decode(f.Fltr.SphM),
2070
+ },
2071
+ };
2072
+ case 'Twrl': return {
2073
+ ...base,
2074
+ type: 'twirl',
2075
+ filter: {
2076
+ angle: f.Fltr.Angl,
2077
+ },
2078
+ };
2079
+ case 'Wave': return {
2080
+ ...base,
2081
+ type: 'wave',
2082
+ filter: {
2083
+ numberOfGenerators: f.Fltr.NmbG,
2084
+ type: Wvtp.decode(f.Fltr.Wvtp),
2085
+ wavelength: { min: f.Fltr.WLMn, max: f.Fltr.WLMx },
2086
+ amplitude: { min: f.Fltr.AmMn, max: f.Fltr.AmMx },
2087
+ scale: { x: f.Fltr.SclH, y: f.Fltr.SclV },
2088
+ randomSeed: f.Fltr.RndS,
2089
+ undefinedAreas: UndA.decode(f.Fltr.UndA),
2090
+ },
2091
+ };
2092
+ case 'ZgZg': return {
2093
+ ...base,
2094
+ type: 'zigzag',
2095
+ filter: {
2096
+ amount: f.Fltr.Amnt,
2097
+ ridges: f.Fltr.NmbR,
2098
+ style: ZZTy.decode(f.Fltr.ZZTy),
2099
+ },
2100
+ };
2101
+ case 'AdNs': return {
2102
+ ...base,
2103
+ type: 'add noise',
2104
+ filter: {
2105
+ amount: parsePercent(f.Fltr.Nose),
2106
+ distribution: Dstr.decode(f.Fltr.Dstr),
2107
+ monochromatic: f.Fltr.Mnch,
2108
+ randomSeed: f.Fltr.FlRs,
2109
+ },
2110
+ };
2111
+ case 'DstS': return {
2112
+ ...base,
2113
+ type: 'dust and scratches',
2114
+ filter: {
2115
+ radius: f.Fltr['Rds '],
2116
+ threshold: f.Fltr.Thsh,
2117
+ },
2118
+ };
2119
+ case 'Mdn ': return {
2120
+ ...base,
2121
+ type: 'median',
2122
+ filter: {
2123
+ radius: parseUnits(f.Fltr['Rds ']),
2124
+ },
2125
+ };
2126
+ case 'denoise': return {
2127
+ ...base,
2128
+ type: 'reduce noise',
2129
+ filter: {
2130
+ preset: f.Fltr.preset,
2131
+ removeJpegArtifact: f.Fltr.removeJPEGArtifact,
2132
+ reduceColorNoise: parsePercent(f.Fltr.ClNs),
2133
+ sharpenDetails: parsePercent(f.Fltr.Shrp),
2134
+ channelDenoise: f.Fltr.channelDenoise.map(c => ({
2135
+ channels: c.Chnl.map(i => Chnl.decode(i)),
2136
+ amount: c.Amnt,
2137
+ ...(c.EdgF ? { preserveDetails: c.EdgF } : {}),
2138
+ })),
2139
+ },
2140
+ };
2141
+ case 'ClrH': return {
2142
+ ...base,
2143
+ type: 'color halftone',
2144
+ filter: {
2145
+ radius: f.Fltr['Rds '],
2146
+ angle1: f.Fltr.Ang1,
2147
+ angle2: f.Fltr.Ang2,
2148
+ angle3: f.Fltr.Ang3,
2149
+ angle4: f.Fltr.Ang4,
2150
+ },
2151
+ };
2152
+ case 'Crst': return {
2153
+ ...base,
2154
+ type: 'crystallize',
2155
+ filter: {
2156
+ cellSize: f.Fltr.ClSz,
2157
+ randomSeed: f.Fltr.FlRs,
2158
+ },
2159
+ };
2160
+ case 'Mztn': return {
2161
+ ...base,
2162
+ type: 'mezzotint',
2163
+ filter: {
2164
+ type: MztT.decode(f.Fltr.MztT),
2165
+ randomSeed: f.Fltr.FlRs,
2166
+ },
2167
+ };
2168
+ case 'Msc ': return {
2169
+ ...base,
2170
+ type: 'mosaic',
2171
+ filter: {
2172
+ cellSize: parseUnits(f.Fltr.ClSz),
2173
+ },
2174
+ };
2175
+ case 'Pntl': return {
2176
+ ...base,
2177
+ type: 'pointillize',
2178
+ filter: {
2179
+ cellSize: f.Fltr.ClSz,
2180
+ randomSeed: f.Fltr.FlRs,
2181
+ },
2182
+ };
2183
+ case 'Clds': return {
2184
+ ...base,
2185
+ type: 'clouds',
2186
+ filter: {
2187
+ randomSeed: f.Fltr.FlRs,
2188
+ },
2189
+ };
2190
+ case 'DfrC': return {
2191
+ ...base,
2192
+ type: 'difference clouds',
2193
+ filter: {
2194
+ randomSeed: f.Fltr.FlRs,
2195
+ },
2196
+ };
2197
+ case 'Fbrs': return {
2198
+ ...base,
2199
+ type: 'fibers',
2200
+ filter: {
2201
+ variance: f.Fltr.Vrnc,
2202
+ strength: f.Fltr.Strg,
2203
+ randomSeed: f.Fltr.RndS,
2204
+ },
2205
+ };
2206
+ case 'LnsF': return {
2207
+ ...base,
2208
+ type: 'lens flare',
2209
+ filter: {
2210
+ brightness: f.Fltr.Brgh,
2211
+ position: { x: f.Fltr.FlrC.Hrzn, y: f.Fltr.FlrC.Vrtc },
2212
+ lensType: Lns.decode(f.Fltr['Lns ']),
2213
+ },
2214
+ };
2215
+ case 'smartSharpen': return {
2216
+ ...base,
2217
+ type: 'smart sharpen',
2218
+ filter: {
2219
+ amount: parsePercent(f.Fltr.Amnt),
2220
+ radius: parseUnits(f.Fltr['Rds ']),
2221
+ threshold: f.Fltr.Thsh,
2222
+ angle: f.Fltr.Angl,
2223
+ moreAccurate: f.Fltr.moreAccurate,
2224
+ blur: blurType.decode(f.Fltr.blur),
2225
+ preset: f.Fltr.preset,
2226
+ shadow: {
2227
+ fadeAmount: parsePercent(f.Fltr.sdwM.Amnt),
2228
+ tonalWidth: parsePercent(f.Fltr.sdwM.Wdth),
2229
+ radius: f.Fltr.sdwM['Rds '],
2230
+ },
2231
+ highlight: {
2232
+ fadeAmount: parsePercent(f.Fltr.hglM.Amnt),
2233
+ tonalWidth: parsePercent(f.Fltr.hglM.Wdth),
2234
+ radius: f.Fltr.hglM['Rds '],
2235
+ },
2236
+ },
2237
+ };
2238
+ case 'UnsM': return {
2239
+ ...base,
2240
+ type: 'unsharp mask',
2241
+ filter: {
2242
+ amount: parsePercent(f.Fltr.Amnt),
2243
+ radius: parseUnits(f.Fltr['Rds ']),
2244
+ threshold: f.Fltr.Thsh,
2245
+ },
2246
+ };
2247
+ case 'Dfs ': return {
2248
+ ...base,
2249
+ type: 'diffuse',
2250
+ filter: {
2251
+ mode: DfsM.decode(f.Fltr['Md ']),
2252
+ randomSeed: f.Fltr.FlRs,
2253
+ },
2254
+ };
2255
+ case 'Embs': return {
2256
+ ...base,
2257
+ type: 'emboss',
2258
+ filter: {
2259
+ angle: f.Fltr.Angl,
2260
+ height: f.Fltr.Hght,
2261
+ amount: f.Fltr.Amnt,
2262
+ },
2263
+ };
2264
+ case 'Extr': return {
2265
+ ...base,
2266
+ type: 'extrude',
2267
+ filter: {
2268
+ type: ExtT.decode(f.Fltr.ExtT),
2269
+ size: f.Fltr.ExtS,
2270
+ depth: f.Fltr.ExtD,
2271
+ depthMode: ExtR.decode(f.Fltr.ExtR),
2272
+ randomSeed: f.Fltr.FlRs,
2273
+ solidFrontFaces: f.Fltr.ExtF,
2274
+ maskIncompleteBlocks: f.Fltr.ExtM,
2275
+ },
2276
+ };
2277
+ case 'Tls ': return {
2278
+ ...base,
2279
+ type: 'tiles',
2280
+ filter: {
2281
+ numberOfTiles: f.Fltr.TlNm,
2282
+ maximumOffset: f.Fltr.TlOf,
2283
+ fillEmptyAreaWith: FlCl.decode(f.Fltr.FlCl),
2284
+ randomSeed: f.Fltr.FlRs,
2285
+ },
2286
+ };
2287
+ case 'TrcC': return {
2288
+ ...base,
2289
+ type: 'trace contour',
2290
+ filter: {
2291
+ level: f.Fltr['Lvl '],
2292
+ edge: CntE.decode(f.Fltr['Edg ']),
2293
+ },
2294
+ };
2295
+ case 'Wnd ': return {
2296
+ ...base,
2297
+ type: 'wind',
2298
+ filter: {
2299
+ method: WndM.decode(f.Fltr.WndM),
2300
+ direction: Drct.decode(f.Fltr.Drct),
2301
+ },
2302
+ };
2303
+ case 'Dntr': return {
2304
+ ...base,
2305
+ type: 'de-interlace',
2306
+ filter: {
2307
+ eliminate: IntE.decode(f.Fltr.IntE),
2308
+ newFieldsBy: IntC.decode(f.Fltr.IntC),
2309
+ },
2310
+ };
2311
+ case 'Cstm': return {
2312
+ ...base,
2313
+ type: 'custom',
2314
+ filter: {
2315
+ scale: f.Fltr['Scl '],
2316
+ offset: f.Fltr.Ofst,
2317
+ matrix: f.Fltr.Mtrx,
2318
+ },
2319
+ };
2320
+ case 'HghP': return {
2321
+ ...base,
2322
+ type: 'high pass',
2323
+ filter: {
2324
+ radius: parseUnits(f.Fltr['Rds ']),
2325
+ },
2326
+ };
2327
+ case 'Mxm ': return {
2328
+ ...base,
2329
+ type: 'maximum',
2330
+ filter: {
2331
+ radius: parseUnits(f.Fltr['Rds ']),
2332
+ },
2333
+ };
2334
+ case 'Mnm ': return {
2335
+ ...base,
2336
+ type: 'minimum',
2337
+ filter: {
2338
+ radius: parseUnits(f.Fltr['Rds ']),
2339
+ },
2340
+ };
2341
+ case 'Ofst': return {
2342
+ ...base,
2343
+ type: 'offset',
2344
+ filter: {
2345
+ horizontal: f.Fltr.Hrzn,
2346
+ vertical: f.Fltr.Vrtc,
2347
+ undefinedAreas: FlMd.decode(f.Fltr['Fl ']),
2348
+ },
2349
+ };
2350
+ case 'rigidTransform': return {
2351
+ ...base,
2352
+ type: 'puppet',
2353
+ filter: {
2354
+ rigidType: f.Fltr.rigidType,
2355
+ bounds: [
2356
+ { x: f.Fltr.PuX0, y: f.Fltr.PuY0, },
2357
+ { x: f.Fltr.PuX1, y: f.Fltr.PuY1, },
2358
+ { x: f.Fltr.PuX2, y: f.Fltr.PuY2, },
2359
+ { x: f.Fltr.PuX3, y: f.Fltr.PuY3, },
2360
+ ],
2361
+ puppetShapeList: f.Fltr.puppetShapeList!.map(p => ({
2362
+ rigidType: p.rigidType,
2363
+ // TODO: VrsM
2364
+ // TODO: VrsN
2365
+ originalVertexArray: uint8ToPoints(p.originalVertexArray),
2366
+ deformedVertexArray: uint8ToPoints(p.deformedVertexArray),
2367
+ indexArray: Array.from(uint8ToUint32(p.indexArray)),
2368
+ pinOffsets: arrayToPoints(p.pinOffsets),
2369
+ posFinalPins: arrayToPoints(p.posFinalPins),
2370
+ pinVertexIndices: p.pinVertexIndices,
2371
+ selectedPin: p.selectedPin,
2372
+ pinPosition: arrayToPoints(p.PinP),
2373
+ pinRotation: p.PnRt,
2374
+ pinOverlay: p.PnOv,
2375
+ pinDepth: p.PnDp,
2376
+ meshQuality: p.meshQuality,
2377
+ meshExpansion: p.meshExpansion,
2378
+ meshRigidity: p.meshRigidity,
2379
+ imageResolution: p.imageResolution,
2380
+ meshBoundaryPath: {
2381
+ pathComponents: p.meshBoundaryPath.pathComponents.map(c => ({
2382
+ shapeOperation: c.shapeOperation.split('.')[1],
2383
+ paths: c.SbpL.map(t => ({
2384
+ closed: t.Clsp,
2385
+ points: t['Pts '].map(pt => ({
2386
+ anchor: hrznVrtcToPoint(pt.Anch),
2387
+ forward: hrznVrtcToPoint(pt['Fwd ']),
2388
+ backward: hrznVrtcToPoint(pt['Bwd ']),
2389
+ smooth: pt.Smoo,
2390
+ })),
2402
2391
  })),
2403
2392
  })),
2404
- })),
2405
- },
2406
- })),
2407
- },
2408
- };
2409
- case 1348620396: {
2410
- const parameters: { name: string; value: number; }[] = [];
2411
- const Flrt = f.Fltr as any;
2393
+ },
2394
+ })),
2395
+ },
2396
+ };
2397
+ case 'PbPl': {
2398
+ const parameters: { name: string; value: number; }[] = [];
2399
+ const Flrt = f.Fltr as any;
2412
2400
 
2413
- for (let i = 0; i < fromAtoZ.length; i++) {
2414
- if (!Flrt[`PN${fromAtoZ[i]}a`]) break;
2401
+ for (let i = 0; i < fromAtoZ.length; i++) {
2402
+ if (!Flrt[`PN${fromAtoZ[i]}a`]) break;
2415
2403
 
2416
- for (let j = 0; j < fromAtoZ.length; j++) {
2417
- if (!Flrt[`PN${fromAtoZ[i]}${fromAtoZ[j]}`]) break;
2404
+ for (let j = 0; j < fromAtoZ.length; j++) {
2405
+ if (!Flrt[`PN${fromAtoZ[i]}${fromAtoZ[j]}`]) break;
2418
2406
 
2419
- parameters.push({
2420
- name: Flrt[`PN${fromAtoZ[i]}${fromAtoZ[j]}`],
2421
- value: Flrt[`PF${fromAtoZ[i]}${fromAtoZ[j]}`]
2422
- });
2407
+ parameters.push({
2408
+ name: Flrt[`PN${fromAtoZ[i]}${fromAtoZ[j]}`],
2409
+ value: Flrt[`PF${fromAtoZ[i]}${fromAtoZ[j]}`]
2410
+ });
2411
+ }
2423
2412
  }
2424
- }
2425
2413
 
2426
- return {
2414
+ return {
2415
+ ...base,
2416
+ type: 'oil paint plugin',
2417
+ filter: {
2418
+ name: f.Fltr.KnNm,
2419
+ gpu: f.Fltr.GpuY,
2420
+ lighting: f.Fltr.LIWy,
2421
+ parameters,
2422
+ },
2423
+ }
2424
+ }
2425
+ // case 2089: return {
2426
+ // ...base,
2427
+ // type: 'adaptive wide angle',
2428
+ // params: {
2429
+ // correction: prjM.decode(f.Fltr.prjM),
2430
+ // focalLength: f.Fltr.focL,
2431
+ // cropFactor: f.Fltr.CrpF,
2432
+ // imageScale: f.Fltr.imgS,
2433
+ // imageX: f.Fltr.imgX,
2434
+ // imageY: f.Fltr.imgY,
2435
+ // },
2436
+ // };
2437
+ case 'HsbP': return {
2427
2438
  ...base,
2428
- type: 'oil paint plugin',
2439
+ type: 'hsb/hsl',
2429
2440
  filter: {
2430
- name: f.Fltr.KnNm,
2431
- gpu: f.Fltr.GpuY,
2432
- lighting: f.Fltr.LIWy,
2433
- parameters,
2441
+ inputMode: ClrS.decode(f.Fltr.Inpt) as any,
2442
+ rowOrder: ClrS.decode(f.Fltr.Otpt) as any,
2434
2443
  },
2435
- }
2436
- }
2437
- // case 2089: return {
2438
- // ...base,
2439
- // type: 'adaptive wide angle',
2440
- // params: {
2441
- // correction: prjM.decode(f.Fltr.prjM),
2442
- // focalLength: f.Fltr.focL,
2443
- // cropFactor: f.Fltr.CrpF,
2444
- // imageScale: f.Fltr.imgS,
2445
- // imageX: f.Fltr.imgX,
2446
- // imageY: f.Fltr.imgY,
2447
- // },
2448
- // };
2449
- case 1215521360: return {
2450
- ...base,
2451
- type: 'hsb/hsl',
2452
- filter: {
2453
- inputMode: ClrS.decode(f.Fltr.Inpt) as any,
2454
- rowOrder: ClrS.decode(f.Fltr.Otpt) as any,
2455
- },
2456
- };
2457
- case 1122: return {
2458
- ...base,
2459
- type: 'oil paint',
2460
- filter: {
2461
- lightingOn: f.Fltr.lightingOn,
2462
- stylization: f.Fltr.stylization,
2463
- cleanliness: f.Fltr.cleanliness,
2464
- brushScale: f.Fltr.brushScale,
2465
- microBrush: f.Fltr.microBrush,
2466
- lightDirection: f.Fltr.LghD,
2467
- specularity: f.Fltr.specularity,
2468
- },
2469
- };
2470
- case 1282492025: {
2471
- return {
2444
+ };
2445
+ case 'oilPaint': return {
2472
2446
  ...base,
2473
- type: 'liquify',
2447
+ type: 'oil paint',
2474
2448
  filter: {
2475
- liquifyMesh: f.Fltr.LqMe,
2449
+ lightingOn: f.Fltr.lightingOn,
2450
+ stylization: f.Fltr.stylization,
2451
+ cleanliness: f.Fltr.cleanliness,
2452
+ brushScale: f.Fltr.brushScale,
2453
+ microBrush: f.Fltr.microBrush,
2454
+ lightDirection: f.Fltr.LghD,
2455
+ specularity: f.Fltr.specularity,
2476
2456
  },
2477
2457
  };
2458
+ case 'LqFy': {
2459
+ return {
2460
+ ...base,
2461
+ type: 'liquify',
2462
+ filter: {
2463
+ liquifyMesh: f.Fltr.LqMe,
2464
+ },
2465
+ };
2466
+ }
2467
+ default:
2468
+ if (options.throwForMissingFeatures) {
2469
+ throw new Error(`Unknown filter classId: ${(f as any).Fltr._classID}`);
2470
+ }
2471
+ return undefined;
2472
+ }
2473
+ } else {
2474
+ switch (f.filterID) {
2475
+ case 1098281575: return { ...base, type: 'average' };
2476
+ case 1114403360: return { ...base, type: 'blur' };
2477
+ case 1114403405: return { ...base, type: 'blur more' };
2478
+ case 1148416099: return { ...base, type: 'despeckle' };
2479
+ case 1180922912: return { ...base, type: 'facet' };
2480
+ case 1181902701: return { ...base, type: 'fragment' };
2481
+ case 1399353968: return { ...base, type: 'sharpen' };
2482
+ case 1399353925: return { ...base, type: 'sharpen edges' };
2483
+ case 1399353933: return { ...base, type: 'sharpen more' };
2484
+ case 1181639749: return { ...base, type: 'find edges' };
2485
+ case 1399616122: return { ...base, type: 'solarize' };
2486
+ case 1314149187: return { ...base, type: 'ntsc colors' };
2487
+ default:
2488
+ if (options.throwForMissingFeatures) {
2489
+ // console.log('FILTER', require('util').inspect(f, false, 99, true));
2490
+ throw new Error(`Unknown filterID: ${(f as any).filterID}`);
2491
+ }
2478
2492
  }
2479
- default:
2480
- // console.log('FILTER', require('util').inspect(f, false, 99, true));
2481
- throw new Error(`Unknown filterID: ${(f as any).filterID}`);
2482
2493
  }
2483
2494
  }
2484
2495
 
2485
- function parseFilterFX(desc: SoLdDescriptorFilter): PlacedLayerFilter {
2496
+ function parseFilterFX(desc: SoLdDescriptorFilter, options: ReadOptions): PlacedLayerFilter {
2486
2497
  return {
2487
2498
  enabled: desc.enab,
2488
2499
  validAtPosition: desc.validAtPosition,
2489
2500
  maskEnabled: desc.filterMaskEnable,
2490
2501
  maskLinked: desc.filterMaskLinked,
2491
2502
  maskExtendWithWhite: desc.filterMaskExtendWithWhite,
2492
- list: desc.filterFXList.map(parseFilterFXItem),
2503
+ list: desc.filterFXList.map(x => parseFilterFXItem(x, options)).filter((x): x is Filter => !!x),
2493
2504
  };
2494
2505
  }
2495
2506
 
@@ -3199,11 +3210,11 @@ function getWarpFromPlacedLayer(placed: PlacedLayer): Warp {
3199
3210
  addHandler(
3200
3211
  'SoLd',
3201
3212
  hasKey('placedLayer'),
3202
- (reader, target, left) => {
3213
+ (reader, target, left, _, options) => {
3203
3214
  if (readSignature(reader) !== 'soLD') throw new Error(`Invalid SoLd type`);
3204
3215
  const version = readInt32(reader);
3205
3216
  if (version !== 4 && version !== 5) throw new Error(`Invalid SoLd version`);
3206
- const desc: SoLdDescriptor = readVersionAndDescriptor(reader);
3217
+ const desc: SoLdDescriptor = readVersionAndDescriptor(reader, true);
3207
3218
  // console.log('SoLd', require('util').inspect(desc, false, 99, true));
3208
3219
  // console.log('SoLd.warp', require('util').inspect(desc.warp, false, 99, true));
3209
3220
  // console.log('SoLd.quiltWarp', require('util').inspect(desc.quiltWarp, false, 99, true));
@@ -3240,7 +3251,7 @@ addHandler(
3240
3251
  originalCompID: desc.compInfo.originalCompID,
3241
3252
  };
3242
3253
  }
3243
- if (desc.filterFX) target.placedLayer.filter = parseFilterFX(desc.filterFX);
3254
+ if (desc.filterFX) target.placedLayer.filter = parseFilterFX(desc.filterFX, options);
3244
3255
 
3245
3256
  // console.log('filter', require('util').inspect(target.placedLayer.filter, false, 99, true));
3246
3257