Skip to content

Instantly share code, notes, and snippets.

@vladdancer
Last active July 21, 2021 21:46
Show Gist options
  • Save vladdancer/3714445dc02280a6cf45c4d823065a57 to your computer and use it in GitHub Desktop.
Save vladdancer/3714445dc02280a6cf45c4d823065a57 to your computer and use it in GitHub Desktop.
Photoshop Xtools performance optimisation for the process of converting a large raw data (AD.write["DescValueType.RAWTYPE"]) (Color Lookup layers) #concept #photoshop #nodejs #jsx #tools #atn #binary #post-process
import {padWord, toByteInHex} from "../utils";
import FileSystem from "./FileSystem";
import { Buffer } from 'buffer';
declare interface Marker {
marker: string,
data: BufferSource
}
class Replacer {
private map: Marker[];
private atnBuffer: Buffer;
private readonly resultFilePath: string;
constructor(map: Array<Marker>, atnFilePath, resultFilePath) {
this.map = map;
this.atnBuffer = Buffer.from(FileSystem.readFileSync(atnFilePath));
this.resultFilePath = resultFilePath;
}
process() {
let chunks = {
lastPos: 0,
items: []
};
this.map.forEach((el: Marker) => {
this.processItem(el, chunks);
});
// Add a last chunk.
if (chunks.lastPos > 0) {
chunks.items.push(this.atnBuffer.slice(chunks.lastPos));
}
try {
const resultBuffer = new Buffer.concat(chunks.items);
FileSystem.writeFileSync(this.resultFilePath, resultBuffer, {encoding: 'hex'});
}
catch (e) {
console.log(`Cant save fixed ATN file, Error: ${e.toString()}`);
return false;
}
return true;
}
processItem(el, chunks) {
const markerSelector = Buffer.from(el.marker, 'hex');
if (!this.atnBuffer.includes(markerSelector)) {
return false;
}
const markerPos = this.atnBuffer.indexOf(markerSelector);
// before data length
// data size is u4
// push "before marker" chunk, w/o an old data size field.
// Later we will add an updated data size value.
chunks.items.push(this.atnBuffer.slice(chunks.lastPos, markerPos - 4));
// data
// We already have a buffer, so we just need an index of this buffer.
const dataBuffer = Buffer.from(el.data);
const length = padWord(toByteInHex(dataBuffer.length));
// Add the updated data size field.
chunks.items.push(
Buffer.from(length, 'hex')
);
// Add an updated data.
chunks.items.push(dataBuffer);
// Calculate a start lastPos of the next data chunk
chunks.lastPos = markerPos + markerSelector.length;
}
}
<ActionDescriptor key="1411391520" symname="To" sym="T ">
<DescValueType.ENUMERATEDTYPE key="938" symname="lookupType" sym="lookupType" enumeratedTypeString="colorLookupType" enumeratedType="colorLookupType" enumeratedValueString="3DLUT" enumeratedValue="3DLUT"/>
<DescValueType.STRINGTYPE key="1315774496" symname="Name" sym="Nm " string="/Users/demo/Canon C-LOG to LOG.cube"/>
<DescValueType.BOOLEANTYPE key="1148479602" symname="Dither" sym="Dthr" boolean="true"/>
<DescValueType.RAWTYPE key="429" symname="profile" sym="profile">21402324 255e262a 5f2b3d01</DescValueType.RAWTYPE>
<DescValueType.ENUMERATEDTYPE key="940" symname="LUTFormat" sym="LUTFormat" enumeratedTypeString="LUTFormatType" enumeratedType="LUTFormatType" enumeratedValueString="LUTFormatCUBE" enumeratedValue="LUTFormatCUBE"/>
<DescValueType.ENUMERATEDTYPE key="942" symname="dataOrder" sym="dataOrder" enumeratedTypeString="colorLookupOrder" enumeratedType="colorLookupOrder" enumeratedValueString="rgbOrder" enumeratedValue="rgbOrder"/>
<DescValueType.ENUMERATEDTYPE key="944" symname="tableOrder" sym="tableOrder" enumeratedTypeString="colorLookupOrder" enumeratedType="colorLookupOrder" enumeratedValueString="bgrOrder" enumeratedValue="bgrOrder"/>
<DescValueType.RAWTYPE key="2796" symname="LUT3DFileData" sym="LUT3DFileData">21402324 255e262a 5f2b3d02</DescValueType.RAWTYPE>
<DescValueType.STRINGTYPE key="2797" symname="LUT3DFileName" sym="LUT3DFileName" string="/Users/demo/Canon C-LOG to LOG.cube"/>
</ActionDescriptor>
@vladdancer
Copy link
Author

Showing the concept in a Hex editor

@vladdancer
Copy link
Author

vladdancer commented Jun 11, 2019

There could be some variations about input and output data.
For example we could store raw data in files instead of inside markers.
We could save buffers using Node.js writeable streams, but there is less sense because ATN files are quite small files regulary (< 100 MB)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment