-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support smartFilter (SoLd) #140
Comments
|
Ok , I will take a look at it |
@Agamnentzar Sorry to bother again , I read the spec and do some parsing stuff manually to the Here is what I got:
I got the RGB image , but the image is just the image in (If you are interested in the parsing process code , I can share it with u , it is written in Go , so I not paste here) |
I wrote parsing code like this, but for some reason it is ending up on the wrong byte after first filter entry, and the version is incorrect const version = readInt32(reader);
if (version < 1 || version > 3) throw new Error(`Invalid filterEffects version ${version}`);
if (readUint32(reader)) throw new Error('filterEffects: 64 bit length is not supported');
const length = readUint32(reader);
const end = reader.offset + length;
while (reader.offset < end) {
console.log('bytes to go', end - reader.offset, 'at', reader.offset.toString(16));
//
const id = readPascalString(reader, 1);
const effectVersion = readInt32(reader);
if (effectVersion !== 1) throw new Error(`Invalid filterEffect version ${effectVersion}`);
if (readUint32(reader)) throw new Error('filterEffect: 64 bit length is not supported');
const effectLength = readUint32(reader);
const endOfEffect = reader.offset + effectLength;
const top = readInt32(reader);
const left = readInt32(reader);
const bottom = readInt32(reader);
const right = readInt32(reader);
const depth = readInt32(reader);
const maxChannels = readInt32(reader);
const channels: any[] = [];
for (let i = 0; i < (maxChannels + 2); i++) {
const exists = readInt32(reader);
if (exists) {
if (readUint32(reader)) throw new Error('filterEffect: 64 bit length is not supported');
const channelLength = readUint32(reader);
const compressionMode = readUint16(reader);
const data = readBytes(reader, channelLength - 2);
channels.push({ channelLength, compressionMode, data: data?.length + ' bytes' });
} else {
channels.push(undefined);
}
}
console.log('left at the end', endOfEffect - reader.offset);
if (endOfEffect > reader.offset) {
if (readUint8(reader)) {
const compressionMode = readUint16(reader);
const data = endOfEffect > reader.offset ? readBytes(reader, endOfEffect - reader.offset) : undefined;
console.log('extra data', { compressionMode, data: data?.length + ' bytes' });
} else {
console.log('no extra');
}
}
console.log('effect', {
id,
effectVersion,
effectLength,
top,
left,
bottom,
right,
depth,
maxChannels,
channels,
});
console.log('bytes left after effect', endOfEffect - reader.offset);
// if (length % 4) skipBytes(reader, 4 - length % 4);
}
console.log({ version, length }); I don't really know where the control points might be stored, they should be somewhere here, but spec only mentions these RGB bitmap entries, so not sure where it would be. Could try diff on both files and check all sections that changed. |
@Agamnentzar Thank you , maybe I can help parsing the |
@scbizu ok I found it, it is in SoLd section, I'll look into implementing it properly. It should be fine for reading, although I'm not sure if for writing the FEid section wouldn't have to be written correctly too, for the filter to work properly. |
Sounds awesome 👍 , today I do not have enough time to look at this , tomorrow I will try , thanks for inspiring me :) |
Released version |
@Agamnentzar I see the PuppetShapeList now , so many args and hard to know actual though XD , seems hard to re-apply to other image use Canvas API |
I think it mainly uses mesh of triangles that is being distorted, so it could probably be implemented with webgl, although the quality might not be the best then. I don't know what are most of the other parameters for, but maybe just for controlling the deformation UI. |
I found that those params maybe refers to the ARAP(A.K.A As-Rigid-As-Possible Shape Manipulation) , and the source paper is here . |
TL;DR
This issue follows #72 , but not fully related . This thread focus on the discussion about the
smartFilter
parsing integration (and maybe the implementation ?) .Background
As #72 mentioned , Currently , the parser do not support parse the smartFilter of the smartObject contains . Per Adobe PSD spec , all the smartObject layer data stores in
SoLd
(after Photoshop CS3) orPlLd
(before Photoshop CS3) , because of the lack of detail explanation ofSoLd.Variable
, we should read the raw data and parse it by ... umm ... guessing ?Attempts
Since I am not familiar with node ecosystem , I use the Go library to get the raw data (especially the
SoLd
section) . With the psd file, I got the following result:click to show details
nullIdntTEXT%49b9a235-b7bb-534b-8a6a-747e80bf8949placedTEXT%97379f26-0cd7-5042-a0c8-6588da990816PgNmlong totalPageslongCroplong frameStepObjcnull numeratorlong denominatorlongdurationObjcnull numeratorlong denominatorlongX frameCountlongAnntlongTypelongTrnfVlLdoub{doubk`doub@ Xpdoubk`doub@ Xpdoub@Ldoub{doub@LnonAffineTransformVlLdoub{doubk`doub@ Xpdoubk`doub@ Xpdoub@Ldoub{doub@LSfilterFXStyleenabboolvalidAtPositionboolfilterMaskEnableboolfilterMaskLinkedboolfilterMaskExtendWithWhitebool filterFXListVlLsObjfilterFNm TEXTdcS_b blendOptionsObjc blendOptionsOpctUntF#Prc@YMd enumBlnMNrmlenabbool hasoptionsboolFrgCObjcRGBCRd doub@YGrn doub@T Bl doub@T BckCObjcRGBCRd doub@oGrn doub@oBl doub@oFltrObjcdcS_brigidTransform nullobj EnmrLyr OrdnTrgt rigidTypeboolpuppetShapeListVlLsObjc puppetShape rigidTypeboolVrsMlongVrsNlongoriginalVertexArraytdtaH_TY TN2&SS ËaOnfK|͇&GL�D`@At&B=B9#)BE5C0&s;C,Í_C0)*C$ Chf .C*ÕCHyCDDD3D2SDDDD}DDD~DIDDGDxDdحD#~DCD3KDʴDf^D!DfVDDLDD3CDnVD@D-#DDDDDCDCD`CDCD-CDtiCDCD4xCDTCDn1CD-FCDBDOBDKcBDDODD=/DaDKaäDbDb_DbèADbqnDb/DbDbDZcÌDcàDc`D3bæQDbÂƾDgbG;DbDYbù$D33b~D bZD9aD`D-`D`h `D`D`yDS^çpD_Ü9gD3^,]D4^RD3s^lHD33^ó D >D!]/Dj]R,#D]?DԷ]ÿ( D]Ñ%Cl]êCH]ùC']ïGC]{C]HyC ]ÉPC33]Í"CY]B]Bg]ÆA]kl3]g�]^~_ fZ>B=DVy�Di`D,DX{DAAwDAMyD? (`i91! gDlDDBSDDrDhD$ZeYBdCe±D!yK#D4D)+oDj*EVD~�uD=CC,Dh6dDChD-DX[D_BFDD#D:9AcD(6^6DyrDDxD杸D9DйDmDDlDDlDDDΣDDͣDӄDD)D^D0²"C˯fjC3Y C>v8DP2e,DDzDD6C!D'ÆkDCDCD%D}?@d׃CRDLCϺD@CD$% D2ӣDTM@YDU#DPDTDXDxDhD1DDDDD DDWDDD9D3DJCDE+£ >DD DD~4CDP=CD؞BDfDC?D DkXdC{SCF.y�L gCD)VDUDDtå D xD̘+BʻDqVD%DD ^>\D}D'3Ch~ D CX¨CWCw+g)D,\M?Bs/²DsDLM[CfD/BDD5D>eDCDD DܘnDD D=DNPDMWD>;C+D`|'C;D8D7CgDx!CCD_D;$BDIDlCϷD5!CoAD[9�D]"D퉋DAzDP!CaCfB#D80B`^DoBCɱAD>BCsm:DQD.DNDjJDLB2DWBOB>DYDB|DHBNA/BC:DDM7DY9CXCB@2]BD1D[DC FD(;DQC]Cıia(CFDC٤DD/DNDP?DwD.eDxBV٭CB.D[B&DgCMD1CDC[DCD[D`ֱDnB,CDCD&+C5DD DDD*CDDCD)DIDtC0DCڗDCӛD%CDs_xCjØD"D>DDsD85D6ʴD[HDXD'CHDNkD?8²Db!BD7#C@SD;D_jDD)WDDJDDg{DD(aDt4DIDnDYDD4YgDWDIDL"DЂDwrD$DH DKaC5-D'bA/N3D)BEDZC]ZCBfDB5JDBjfC'C8CCC)wCpCoD^D&DD,ͪD@Dm'DC:vDKDpDCCnD5GC?5DÀC|CSVDDyCD?"DxѼDDYDDDࠗBJDC$CD!CD4BtwDqm CDɋDC?DᜁC%xD OD~X{D#CDDI|C]"D Cb DJCn8CzC8DSD{D DæDFDDVd)D Db>D2gDKWD6DFDMzUD!C$DnC0?C?ND}ڝCoDZCJZ!DfAC| DCJD yCl DdD#DiDشÂlHDyÒQD)bZD+ dD!\mDv|vD#δ}~DOD٦�D�D|�pD4Cl4DT©qD@�9D(G/ţD-èD DCDgD HD' DD;DDDI$D#DDԈ,DBDb5D`D@>D'DGD>DPDD FD;IDDtDVmD?qD,͟&DaHpD(="Dk?QDyBDJBXD BD($C=DVRCdDC.DCZDeC?DCDgCQDqC YD5D{BbDO%D&kDDtsD2DV |Db`DDKCDD|+D2DDS%DD&vDDӘDeD=^DkDDV?Dpã6B!: B5,A`/*Vz#c%ü= ZÉsI'r ojãiaFyî0B:BDdݩ :Z߉DR`D@qL DWD̶A}DvBDplDDDDD& 0bD$COD35wDOwDV&eD(D hBDdf($CÏdÍC=#D &gDD??fD=*ʄDA DxDFBDϲ BDwDDD D @dldxǬDTDP4DkDrDXDaDDD#'DDkDPvD\DڔDsOB$k}hCWB CGC4FD%D WDjCDQC~D.ɖD@ADQ6C pDmC4ԿD/DDljDmDD4B D~DSD|Dt5D^DoD9DYD:#KD5DD>D7DZDDԃDVNJDD;SDnx�6DDD9D CD٘CUDgBiD7sD/ChD?'DA^BXZDXM "DBPAR!~DDBCLDED¾D̚%CfC"AsD|Dc3BD4bD0§D$"λD/DZD̓aC坴bAD8«ԸCoOClrDwiNL*L,ûRDÑC.�CDl`BIRDGD2rDD]C4DDD5gDZDFDoxD퓦DTDu_D&O0C]DRGCʨD' D{CXDlDC*BYDDٞPAD@D)DC �D?A$LDCBЙ@Dbfc)4DD@D:~DlVDp$DuA(ADmDD,C�BDCvDk @DpC9KC8@hBa"Z/D7DDLC:ED=DkC'C#A+bBsJDǦC ȢD٩DG3~D{hDDDWD5mpD~BC * �:D6gBDpCD"CCȞD1yCd DwDDDDE CxCD.CDCDfC#DDZƹD8tC[2DLC-DoC2Di$DkDdC;DVCuDJsCiĩD1C DbhCDDrD D5D1D~CC~C/$C�CRCCоDqrDxD'DQD|D}DkC.tDWLDIkqDpCsDCuDͱCnCbD"AfCADDD6eD}DFDD)>BYCtC0VCDBgD3CD$BtuCD CDK]DTDDTCIJDtCU cDD\D]tKD`xDH:DqfDQ/D$D/RD1ӍDBDGD00C0D$DnNDܱyD1IDYCt4D72DwjD@MDtRDiD^mdDԐDHlDlfCzD9Dr/Dp:DM.D2D\~D4DD+D ;DC4:/Dw DwCU(D|CMSDC6C.2C?mD]DugDtjDwDsdDd }DD indexArraytdta$`_`mnDE$),$P|}]Iw2^
u
:D9wo$8
@:;)2 ^<;stSTIz*$ VE( R2
[\0x(TUR2 JI0yz\c4%)=%wA#)*]HO]Q"
A(>$p0/A
$%
XW
sr
,5/!c c34I 5CDKtu<=ON#" 8!7PQC!T!?[!"%'%&*+)('(./-.,+?+Kbc-+-`4:
&'03KL45c7!6=>
.LQ?>,-=K120/9:(V"Q+(!9302x(HI !GH+
.A6FEA@$E)465@e
AB H"A@? &3=)#[H,X}
|GF(]vrrqLM6!{z
[ZG{|
kl&"hjkjhi&'mlpq{0
&opno YcVMNN,e.dQBC5RQ
__^dcm(UP7u-kg
_YZfeXYK''gOPfg )%"&u/
6d.8z{0 1-.
,5<K H7U=::4/{}9vyJpI<0xwv6SN3[?hl@7\VEPCEU,>X/uuZ
4>K3W?_?^yDpfpJmqsht8uYMqB<qJqqmrsrmK>>>XTWO@77u/8Y||RG22KWaBMT5XZTUI@;8ZMT7< J|Y pinOffsetsVlLs doub(B3 doub@5E doub@Kp0m doub@"рe doub@G}@0doubdoubMD
[doub@^vpRdoub=E*2doub@fdoub#rgdoubHXV posFinalPinsVlLs doub@}doub@rdoub@|8doub@doub@4doub@{(doub@tdoub@Ldoub@<doub@doub@doub@TpinVertexIndicesVlLslonglonglonglonglonglongPinPVlLs doub@} doub@rdoub@CJdoub@4doub@4 Adoub@{(>doub@t[doub@L !doub@;CBdoub@>Xkdoub@t 9Ndoub.PnRtVlLslonglong[long_longelonglongTPnOvVlLsboolboolboolboolboolboolPnDpVlLsdoub?pdoub?xdoub?doub?doub?doub? meshQualimeshExpansionlong meshRigiditylongimageResolutiondoub@TmeshBoundaryPathObjc pathClasspathComponentsVlLsObjcPaCmshapeOperationenumshapeOperationxorSbpLVlLsObjcSbplClspboolPts VlLsBObjcPthpAnchObjcPnt HrznUntF#PxlkVrtcUntF#Pxlj@Fwd ObjcPnt HrznUntF#Pxli VrtcUntF#PxljEx.Bwd ObjcPnt HrznUntF#PxlkѷYVrtcUntF#Pxl
u$SmooboolObjcPthpAnchObjcPnt HrznUntF#Pxlf VrtcUntF#PxliFwd ObjcPnt HrznUntF#PxleuY|VrtcUntF#PxliBwd ObjcPnt HrznUntF#PxlgɉVrtcUntF#Pxlj<SmooboolObjcPthpAnchObjcPnt HrznUntF#Pxld VrtcUntF#PxliFwd ObjcPnt HrznUntF#Pxlb҂dVrtcUntF#Pxli)EhBwd ObjcPnt HrznUntF#PxldʦL/{VrtcUntF#PxliSmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl_VrtcUntF#PxliFwd ObjcPnt HrznUntF#Pxl[?KVrtcUntF#PxlhgBwd ObjcPnt HrznUntF#Pxla%:P VrtcUntF#Pxlil"SmooboolObjcPthpAnchObjcPnt HrznUntF#PxlT@VrtcUntF#PxlhFwd ObjcPnt HrznUntF#PxlQUhr VrtcUntF#Pxlhʫ6zBwd ObjcPnt HrznUntF#PxlW WpVrtcUntF#PxliDiTXBSmooboolObjcPthpAnchObjcPnt HrznUntF#PxlGVrtcUntF#PxlhFwd ObjcPnt HrznUntF#Pxl,FYVrtcUntF#PxlgkkBwd ObjcPnt HrznUntF#PxlL/wVrtcUntF#PxlhTɅoSmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@JVrtcUntF#Pxlg@Fwd ObjcPnt HrznUntF#Pxl@QVrtcUntF#Pxlg 1&Bwd ObjcPnt HrznUntF#Pxl@4pVrtcUntF#Pxlh#YSmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@[@VrtcUntF#PxlfFwd ObjcPnt HrznUntF#Pxl@c,4pbVrtcUntF#PxleJAkBwd ObjcPnt HrznUntF#Pxl@V!-w2VrtcUntF#PxlfSSmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@pVrtcUntF#Pxld@Fwd ObjcPnt HrznUntF#Pxl@pZXy=VrtcUntF#Pxld5U=Bwd ObjcPnt HrznUntF#Pxl@j'YVrtcUntF#PxleȹSmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@qVrtcUntF#Pxld Fwd ObjcPnt HrznUntF#Pxl@r(|VrtcUntF#PxlcBwd ObjcPnt HrznUntF#Pxl@pW&VrtcUntF#Pxld*d8SmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@+VrtcUntF#Pxlc Fwd ObjcPnt HrznUntF#Pxl@tXy=VrtcUntF#PxlcU=Bwd ObjcPnt HrznUntF#Pxl@sw VrtcUntF#PxlcĜ?2SmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@uVrtcUntF#PxlcFwd ObjcPnt HrznUntF#Pxl@w5:?VrtcUntF#PxlbE\"aBwd ObjcPnt HrznUntF#Pxl@uEW&VrtcUntF#Pxlc Bwd ObjcPnt HrznUntF#PxllU=VrtcUntF#Pxl@SmooboolObjcPthpAnchObjcPnt HrznUntF#PxllVrtcUntF#Pxl@Fwd ObjcPnt HrznUntF#PxllVrtcUntF#Pxl@X*0Bwd ObjcPnt HrznUntF#PxlkkOVrtcUntF#[email protected] HrznUntF#PxllVrtcUntF#Pxl@Fwd ObjcPnt HrznUntF#PxllYpVrtcUntF#Pxl@j(Bwd ObjcPnt HrznUntF#PxllVrtcUntF#Pxl@fBSmooboolObjcPthpAnchObjcPnt HrzBwd ObjcPnt HrznUntF#Pxlko@VrtcUntF#Pxl@%Ҡ2~SmooboolObjcPthpAnchObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@
Fwd ObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@J2XBwd ObjcPnt HrznUntF#Pxlku\1VrtcUntF#Pxl@~VQSmooboolObjcPthpAnchObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@ Fwd ObjcPnt HrznUntF#PxlkvVVrtcUntF#Pxl@$]VrtcUntF#Pxl[n.Bwd ObjcPnt HrznUntF#Pxl@lOVrtcUntF#Pxl]$%SmooboBwd ObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@5N;5SmooboolObjcPthpAnchObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@Fwd ObjcPnt HrznUntF#Pxlk
VrtcUntF#Pxl@uBwd ObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@}d VrtcUntF#PxlZ\NSmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@Vl#SmooboolObjcPthpAnchObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@vFwd ObjcPnt HrznUntF#Pxlk
VrtcUntF#Pxl@oK]Bwd ObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@|??SmooboolObjcPthpAnchObjcPnt HrznUntF#Pxlk
VrtcUntF#Pxl@9Fwd ObjcPnt HrznUntF#Pxlk.HVrtcUntF#PxlJlBwd ObjcPnt HrznUntF#PxlkVrtcUntF#Pxl@aT74SmooboolSFwd ObjcPnt HrznUntF#Pxl@?n_&[VrtcUntF#PxlS:)$wd ObjcPnt HrznUntF#Pxl@gVrtcUntF#PxlU?Ik^SmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@HVrtcUntF#PxlS@Fwd ObjcPnt HrznUntF#Pxl@RpselectedPinVlLslongPuX0doub{PuX1doub@#Pxl@04VXpPuX2doub@SXpPuX3doub{PuY0doubk
PuY1doubk`PuY2doub@LPuY3doub@filterIDlongcomploncompInfoObjcnullcompIDlongoriginalCompIDlongImprObjcNonenonewarpObjcwarp warpStyleenum warpStyle SmooboolObjcPthpAnchObjwarpCustomntF#PxwarpValuedoubwarpPerspectivedoubwarpPerspectiveOtherdoubPBwd ObjcPnt HrznUntF#Pxl@kVrtcUntF#PxlR0SmooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@VrtcUntF#PxlQFwd OwarpRotateenumOrntHrznboundsObjcclassFloatRectTop doubLeftdoubBtomdoub@@Rghtdoub@@uOrderlongvOrderlongcustomEnvelopeWarpObjccustomEnvelopeWarp HrznUntF#Pxl@icVrtcUntF#PxlP8rationalPointHrznUnFl#Pxl@ĔN@2d3z@oR[@(<@pt$mooboolObjcPthpAnchObjcPnt HrznUntF#Pxl@VrtcUntF#PxlPFwd ObjcPnt HrznUntF#Pxl@L\VrtcUntF#PxlNc@pyd@D#@zu@A3M@UUUUU@UUUUU@@VrtcUnFl#Pxl@ .4Bwd ObjcPnt HrznUntF#Pxl@SVrtcUntF#PxlQVN w]7@kzW@[!oB@UUUUW@G�@@FF3u{@uuuuu@w=Iy@
}@XX#@@@@@@@@oboolObjcPthpAnchObjcPnt HrznUntF#Pxl@8VrtcUntF#PxlPFwd ObjcPnt HrznUntF#Pxl@>VrtcUntF#PxlOBwd ObjcPnt HrznUntF#Pxl@&&#pVrtcUntF#PxlPUSmooboolObjcPthpAnchObjcP
I compare the raw data with the SoLdDescriptor interface , I found that the
filterFXList
is missing , It seems that it contains the field:puppetShapeList
, which contains a series of data streams (seems like some binary data) , I am stuck in reading this out , and ask here if you have some exps in reading this ?Some Code Snippet
The text was updated successfully, but these errors were encountered: