ag-psd 20.2.2 → 21.0.0

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