Created
June 11, 2019 10:31
-
-
Save vladdancer/832aec8790995a5676dae0839993807a to your computer and use it in GitHub Desktop.
#photoshop #raw-data #parser #mapper #art-layers #adjustment-layers #curves #kaitai-struct #deserializer Example of Curves Art Layer parser based on KaitaiStruct declarative parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
kaitai-struct-compiler -t javascript curves.format_spec.ksy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
meta: | |
id: ps_curves | |
title: PS Curves Art Layer settings parser | |
application: Adobe Photoshop | |
endian: be | |
doc: | | |
Binary parser of PS action descriptor code, | |
getted via legacyContentData() method. | |
doc-ref: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1056330 | |
seq: | |
- id: magic_1 | |
contents: [0,0] | |
- id: magic_2 | |
contents: [1] | |
- id: unknowns_data1 | |
type: u2 | |
- id: unknowns_data2 | |
type: u1 | |
- id: channel_state | |
type: bitmap_u1 | |
- id: raw_curves | |
type: curve | |
repeat: expr | |
repeat-expr: channel_state.active | |
- id: extra_data_magic | |
contents: [0x43, 0x72, 0x76, 0x20] | |
- id: extra_data_ver | |
contents: [0,4] | |
- id: unknown_data3 | |
type: u2 | |
- id: extra_data_items_count | |
type: u2 | |
- id: extra_data_items | |
type: extra_data_item | |
repeat: expr | |
repeat-expr: extra_data_items_count | |
types: | |
bitmap_u1: | |
seq: | |
- id: b8 | |
type: b1 | |
- id: b7 | |
type: b1 | |
- id: b6 | |
type: b1 | |
- id: b5 | |
type: b1 | |
- id: b4 | |
type: b1 | |
- id: b3 | |
type: b1 | |
- id: b2 | |
type: b1 | |
- id: b1 | |
type: b1 | |
instances: | |
active: | |
value: > | |
b1.to_i + | |
b2.to_i + | |
b3.to_i + | |
b4.to_i + | |
b5.to_i + | |
b6.to_i + | |
b7.to_i + | |
b8.to_i | |
curve: | |
seq: | |
- id: points_count | |
type: u2 | |
- id: points | |
type: curve_point | |
repeat: expr | |
repeat-expr: points_count | |
curve_point: | |
seq: | |
- id: input | |
type: u2 | |
- id: output | |
type: u2 | |
extra_data_item: | |
seq: | |
- id: channel_index | |
type: u2 | |
- id: item | |
type: curve |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// somewhere in html | |
//<script type="text/javascript"> | |
// window.require = window.require || window.cep_node.require; | |
// window.process = window.process || window.cep_node.process; | |
//</script> | |
import PsCurves from "./PsCurves"; | |
const rawData = window.require('fs').readFileSync('PATH_FILE_W_DATA_GEN_BY_AM_METHOD_legacyContentData') | |
const KaitaiStream = window.require('kaitai-struct/KaitaiStream'); | |
const dataStream = new KaitaiStream( | |
!isTypeOf(rawData, 'Uint8Array') | |
? convertOldBufferToArrayBuffer(rawData) | |
: rawData | |
); | |
const parsedData = new PsCurves(dataStream); | |
if (!parsedData) { | |
return false; | |
} | |
const mapper = new PsCurvesMapper(parsedData); | |
const data = mapper.map(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild | |
(function (root, factory) { | |
if (typeof define === 'function' && define.amd) { | |
define(['kaitai-struct/KaitaiStream'], factory); | |
} else if (typeof module === 'object' && module.exports) { | |
module.exports = factory(require('kaitai-struct/KaitaiStream')); | |
} else { | |
root.PsCurves = factory(root.KaitaiStream); | |
} | |
}(this, function (KaitaiStream) { | |
/** | |
* Binary parser of PS action descriptor code, | |
* getted via legacyContentData() method. | |
* @see {@link https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1056330|Source} | |
*/ | |
var PsCurves = (function() { | |
function PsCurves(_io, _parent, _root) { | |
this._io = _io; | |
this._parent = _parent; | |
this._root = _root || this; | |
this._read(); | |
} | |
PsCurves.prototype._read = function() { | |
this.magic1 = this._io.ensureFixedContents([0, 0]); | |
this.magic2 = this._io.ensureFixedContents([1]); | |
this.unknownsData1 = this._io.readU2be(); | |
this.unknownsData2 = this._io.readU1(); | |
this.channelState = new BitmapU1(this._io, this, this._root); | |
this.rawCurves = new Array(this.channelState.active); | |
for (var i = 0; i < this.channelState.active; i++) { | |
this.rawCurves[i] = new Curve(this._io, this, this._root); | |
} | |
this.extraDataMagic = this._io.ensureFixedContents([67, 114, 118, 32]); | |
this.extraDataVer = this._io.ensureFixedContents([0, 4]); | |
this.unknownData3 = this._io.readU2be(); | |
this.extraDataItemsCount = this._io.readU2be(); | |
this.extraDataItems = new Array(this.extraDataItemsCount); | |
for (var i = 0; i < this.extraDataItemsCount; i++) { | |
this.extraDataItems[i] = new ExtraDataItem(this._io, this, this._root); | |
} | |
} | |
var BitmapU1 = PsCurves.BitmapU1 = (function() { | |
function BitmapU1(_io, _parent, _root) { | |
this._io = _io; | |
this._parent = _parent; | |
this._root = _root || this; | |
this._read(); | |
} | |
BitmapU1.prototype._read = function() { | |
this.b8 = this._io.readBitsInt(1) != 0; | |
this.b7 = this._io.readBitsInt(1) != 0; | |
this.b6 = this._io.readBitsInt(1) != 0; | |
this.b5 = this._io.readBitsInt(1) != 0; | |
this.b4 = this._io.readBitsInt(1) != 0; | |
this.b3 = this._io.readBitsInt(1) != 0; | |
this.b2 = this._io.readBitsInt(1) != 0; | |
this.b1 = this._io.readBitsInt(1) != 0; | |
} | |
Object.defineProperty(BitmapU1.prototype, 'active', { | |
get: function() { | |
if (this._m_active !== undefined) | |
return this._m_active; | |
this._m_active = ((((((((this.b1 | 0) + (this.b2 | 0)) + (this.b3 | 0)) + (this.b4 | 0)) + (this.b5 | 0)) + (this.b6 | 0)) + (this.b7 | 0)) + (this.b8 | 0)); | |
return this._m_active; | |
} | |
}); | |
return BitmapU1; | |
})(); | |
var Curve = PsCurves.Curve = (function() { | |
function Curve(_io, _parent, _root) { | |
this._io = _io; | |
this._parent = _parent; | |
this._root = _root || this; | |
this._read(); | |
} | |
Curve.prototype._read = function() { | |
this.pointsCount = this._io.readU2be(); | |
this.points = new Array(this.pointsCount); | |
for (var i = 0; i < this.pointsCount; i++) { | |
this.points[i] = new CurvePoint(this._io, this, this._root); | |
} | |
} | |
return Curve; | |
})(); | |
var CurvePoint = PsCurves.CurvePoint = (function() { | |
function CurvePoint(_io, _parent, _root) { | |
this._io = _io; | |
this._parent = _parent; | |
this._root = _root || this; | |
this._read(); | |
} | |
CurvePoint.prototype._read = function() { | |
this.input = this._io.readU2be(); | |
this.output = this._io.readU2be(); | |
} | |
return CurvePoint; | |
})(); | |
var ExtraDataItem = PsCurves.ExtraDataItem = (function() { | |
function ExtraDataItem(_io, _parent, _root) { | |
this._io = _io; | |
this._parent = _parent; | |
this._root = _root || this; | |
this._read(); | |
} | |
ExtraDataItem.prototype._read = function() { | |
this.channelIndex = this._io.readU2be(); | |
this.item = new Curve(this._io, this, this._root); | |
} | |
return ExtraDataItem; | |
})(); | |
return PsCurves; | |
})(); | |
return PsCurves; | |
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import PsCurves from './PsCurves'; | |
import __zipObject from 'lodash.zipobject'; | |
import __isEmpty from 'lodash.isempty'; | |
interface LayerInfo { | |
docChannelOneName: string; | |
id: number, | |
name: string, | |
opacity: number, | |
blendMore: string, | |
fillOpacity: string, | |
kind: string, | |
docColorMode: string, | |
jsonData?: object | |
filename: string | boolean | |
sizeKb: number | boolean | |
} | |
interface AdnvancedLayerParser { | |
setLayerInfo(info:LayerInfo):void; | |
} | |
class PsCurvesMapper implements AdnvancedLayerParser { | |
private readonly obj: PsCurves; | |
private layerInfo: LayerInfo; | |
constructor(obj) { | |
this.obj = obj; | |
} | |
map() { | |
this.obj.colorMode = this.layerInfo.docColorMode.replace('DocumentMode.', ''); | |
let channelColorNames = []; | |
if (this.obj.colorMode === 'RGB') { | |
channelColorNames = ['composite', 'red', 'green', 'blue']; | |
} | |
else if (this.obj.colorMode === 'CMYK') { | |
channelColorNames = ['composite', 'cyan', 'magenta', 'yellow', 'keyColor']; | |
} | |
else if (this.obj.colorMode === 'LAB') { | |
channelColorNames = ['lightness', 'a', 'b']; | |
} | |
else if (this.obj.colorMode === 'GRAYSCALE') { | |
channelColorNames = ['black']; | |
} | |
else { | |
throw Error(`Unsupported colormode: ${this.obj.colorMode} in Curves Art Layer type.`) | |
} | |
this.obj.curves = []; | |
this.obj.extraDataItems.forEach((curve, index) => { | |
if (!__isEmpty(curve.item)) { | |
curve.name = channelColorNames[curve.channelIndex]; | |
curve.points = curve.item.points; | |
this.obj.curves.push(curve); | |
} | |
}); | |
return this.obj; | |
} | |
setLayerInfo(info): void { | |
this.layerInfo = info; | |
} | |
} | |
export default PsCurvesMapper; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0000 0100 0000 1f00 0300 0000 0000 d400 | |
a700 ff00 ff00 0500 0000 0000 6b00 4300 | |
6300 4a00 b100 8f00 ff00 ff00 0300 0000 | |
0000 8c00 6600 ff00 ff00 0400 0000 0000 | |
6800 4500 7d00 4c00 ff00 ff00 0400 0000 | |
0000 4300 3000 e100 c200 ff00 ff43 7276 | |
2000 0400 0000 0500 0000 0300 0000 0000 | |
d400 a700 ff00 ff00 0100 0500 0000 0000 | |
6b00 4300 6300 4a00 b100 8f00 ff00 ff00 | |
0200 0300 0000 0000 8c00 6600 ff00 ff00 | |
0300 0400 0000 0000 6800 4500 7d00 4c00 | |
ff00 ff00 0400 0400 0000 0000 4300 3000 | |
e100 c200 ff00 ff00 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment