Set private data based on Pitstop Server log

Post Reply
User avatar
JimmyHartington
Advanced member
Posts: 384
Joined: Tue Mar 22, 2011 7:38 am

Set private data based on Pitstop Server log

Post by JimmyHartington »

In a flow I need to change the color of a mark on the pdf based on which colors are used.
So if the job contains Cyan the mark needs to be Cyan.
If it does not contain Cyan but contains Magenta the mark needs to Magenta.
Otherwise it needs to be Black.

My thought was to have Pitstop Server report the ink usage to me.
Then use a script expression to analyse the XML-log.

But I am a bit unsure how to read the XML dataset in a script expression.

I hope someone can point me in the right direction. :D

The logic for choosing the color seems pretty straight forward.

Code: Select all

  if (inkNames.includes("Cyan")) {
    return "Cyan";
  } else if (inkNames.includes("Magenta")) {
    return "Magenta";
  } else {
    return "Black";
  }
This is the XML I get returned from Pitstop Server.

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<EnfocusReport version="3.0" unit="mm" xml:lang="en-US">
  <PreflightReport errors="0" criticalfailures="0" noncriticalfailures="0" signoffs="0" fixes="0" warnings="0" informations="1">
    <Informations>
      <PreflightReportItem ActionID="3159">
        <Message>Document uses 4 separations, should be equal to 0. Those 4 separations are: Black, Cyan, Magenta, Yellow</Message>
        <StringContext>
          <BaseString>Document uses %NumberOfSeparations% separations, should be %Comparator% %ReferenceNumberOfSpotColors%. Those %NumberOfSeparations% separations are: %SeparationNames%</BaseString>
          <Var name="ReferenceNumberOfSpotColors">0</Var>
          <Var name="Comparator">equal to</Var>
          <Var name="NumberOfSeparations">4</Var>
          <Var name="SeparationNames">Black</Var>
          <Var name="SeparationNames">Cyan</Var>
          <Var name="SeparationNames">Magenta</Var>
          <Var name="SeparationNames">Yellow</Var>
        </StringContext>
      </PreflightReportItem>
    </Informations>
  </PreflightReport>
  <ProcessInfo>
    <PageRange>1</PageRange>
    <HostAppName>Enfocus PitStop Server 24.11</HostAppName>
    <EngineFlavor>Enfocus PitStop Library 24.11</EngineFlavor>
    <PreflightDateTime>2025-01-24T14:29:54+01:00</PreflightDateTime>
  </ProcessInfo>
  <GeneralDocInfo>
    <DocumentProperties>
      <DocumentName>_0P4LA_89215590.pdf</DocumentName>
      <NumPages>1</NumPages>
      <PDFVersion major="1" minor="6">1.6</PDFVersion>
      <CreationDate>2024-10-10T05:44:03+02:00</CreationDate>
      <ModificationDate>2024-10-10T05:44:03+02:00</ModificationDate>
      <Producer>Adobe PDF Library 17.0</Producer>
      <Creator>Adobe InDesign 19.5 (Macintosh)</Creator>
      <Author></Author>
      <Title></Title>
      <Subject></Subject>
      <Keywords></Keywords>
      <Trapped>false</Trapped>
      <PrinergyTraps>false</PrinergyTraps>
      <WasRepairedOnOpen>false</WasRepairedOnOpen>
      <IsLinearized>true</IsLinearized>
      <ContainsThumbnails>false</ContainsThumbnails>
      <LeftToRightReading>left</LeftToRightReading>
      <ContainsJobTicket>false</ContainsJobTicket>
    </DocumentProperties>
    <DocumentSecurity>
      <EncryptionType>none</EncryptionType>
      <Permissions>
        <ExtractAccessibility>true</ExtractAccessibility>
        <ExtractNonAccessibility>true</ExtractNonAccessibility>
        <ModifyNotes>true</ModifyNotes>
        <ModifyFillAndSign>true</ModifyFillAndSign>
        <ModifyAssembleDoc>true</ModifyAssembleDoc>
        <ModifyOther>true</ModifyOther>
        <ModifySecurity>true</ModifySecurity>
        <PrintLowQuality>true</PrintLowQuality>
        <PrintHighQuality>true</PrintHighQuality>
      </Permissions>
    </DocumentSecurity>
    <DocumentCompression>
      <DataFormat>binary</DataFormat>
      <IsCompressed>true</IsCompressed>
      <FilterType>ZIP</FilterType>
    </DocumentCompression>
  </GeneralDocInfo>
  <ColorInfo>
    <ColorSpace type="ICCBased" id="CS1" isValid="true">
      <ICCName>sRGB IEC61966-2.1</ICCName>
      <ICCSpace>DeviceRGB</ICCSpace>
      <ICCProfileID>1d3fda2edb4a89ab60a23c5f7c7d81dd</ICCProfileID>
      <Ranges>
        <Range name="R" min="0" max="1"/>
        <Range name="G" min="0" max="1"/>
        <Range name="B" min="0" max="1"/>
      </Ranges>
      <Location page="1" minX="0" minY="6.125" maxX="4.985" maxY="15.655"/>
    </ColorSpace>
  </ColorInfo>
  <PageColorTypeInfo emptyPages="0" blackAndWhitePages="0" colorPages="1">
    <Page index="1" colorType="color"/>
  </PageColorTypeInfo>
  <InkInfo>
    <DocumentInkInfo>
      <PaperArea>1100.16</PaperArea>
      <InkArea>147.58</InkArea>
      <InkPercentage>13.41</InkPercentage>
      <Ink name="Cyan">
        <Area>24.32</Area>
        <Percentage>2.21</Percentage>
      </Ink>
      <Ink name="Yellow">
        <Area>1.57</Area>
        <Percentage>0.14</Percentage>
      </Ink>
      <Ink name="Black">
        <Area>121.68</Area>
        <Percentage>11.06</Percentage>
      </Ink>
    </DocumentInkInfo>
    <PageInkInfo page="1">
      <PaperArea>1100.16</PaperArea>
      <InkArea>147.58</InkArea>
      <InkPercentage>13.41</InkPercentage>
      <Ink name="Cyan">
        <Area>24.32</Area>
        <Percentage>2.21</Percentage>
      </Ink>
      <Ink name="Yellow">
        <Area>1.57</Area>
        <Percentage>0.14</Percentage>
      </Ink>
      <Ink name="Black">
        <Area>121.68</Area>
        <Percentage>11.06</Percentage>
      </Ink>
    </PageInkInfo>
  </InkInfo>
</EnfocusReport>
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: Set private data based on Pitstop Server log

Post by mkayyyy »

Ended up taking me awhile to figure this one out, but reading the XML data set from a script expression looks like this:

Code: Select all

async function calculateScriptExpression(s: Switch, flowElement: FlowElement, job: Job): Promise<string> {
    const datasetPath = await job.getDataset("TestDataset", AccessLevel.ReadOnly);
    
    const xmlDocument = XmlDocument.open(datasetPath);
    const nsMap = xmlDocument.getDefaultNSMap();
    const inkNames = xmlDocument.evaluate("string(//PreflightReport/Informations/PreflightReportItem[@ActionID='3159']/Message)", nsMap) as string;

    await job.log(LogLevel.Info, "Ink Names: %1", [JSON.stringify(inkNames)]);

    if (inkNames.includes("Cyan")) {
        return "Cyan";
    } else if (inkNames.includes("Magenta")) {
        return "Magenta";
    } else {
        return "Black";
    }
}
The main bit that had me stuck for awhile is that you need to wrap the Xpath expression (in this case) with a string() function to get the value to be returned
User avatar
JimmyHartington
Advanced member
Posts: 384
Joined: Tue Mar 22, 2011 7:38 am

Re: Set private data based on Pitstop Server log

Post by JimmyHartington »

Thanks for this complete answer.

Your code looks at on part of the XML, but what I need to analyze is the section with "DocumentInkInfo".

Is it easy to change the path to look there?

Image
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: Set private data based on Pitstop Server log

Post by mkayyyy »

No worries, updating it to look at multiple nodes ends up getting a little bit janky due to the Node.js scripting engine. The scripting engine only supports Xpath expressions evaluating to boolean | number | string | undefined, so I don't think its possibly currently to get all the node values in one Xpath expression.

So to make it work for your use case of multiple nodes I made a version of the getXpath function from the Node.js Scripting docs that uses TS generics and called it twice checking if 'Cyan' or 'Magenta' is contained in the returned Xpath expression:

Code: Select all

async function calculateScriptExpression(s: Switch, flowElement: FlowElement, job: Job): Promise<string> {
    const datasetName = "TestDataset";
    const baseXPathExpression = "//DocumentInkInfo/Ink/@name";

    const containsCyan = await getXPath<boolean>(job, datasetName, `contains(${baseXPathExpression}, 'Cyan')`);
    const containsMagenta = await getXPath<boolean>(job, datasetName, `contains(${baseXPathExpression}, 'Magenta')`);

    if (containsCyan) {
        return "Cyan";
    } else if (containsMagenta) {
        return "Magenta";
    } else {
        return "Black";
    }
}

async function getXPath<T extends string | number | boolean>(job: Job, datasetName: string, xpath: string): Promise<T | null> {
    let result: string | number | boolean;

    try {
        const datasetPath = await job.getDataset(datasetName, AccessLevel.ReadOnly);

        const xmlDocument = XmlDocument.open(datasetPath);
        const nsMap = xmlDocument.getDefaultNSMap();
        result = xmlDocument.evaluate(xpath, nsMap) as T;
        
        await job.log(LogLevel.Info, "%1: %2", [xpath, (result as string)]);
    } catch (error: any) {
        await job.log(LogLevel.Error, "Error: %2", [(error as Error).message]);
        return null;
    }

    return result as T;
}
User avatar
JimmyHartington
Advanced member
Posts: 384
Joined: Tue Mar 22, 2011 7:38 am

Re: Set private data based on Pitstop Server log

Post by JimmyHartington »

Thanks, Matthew.

I will test it in my flow tomorrow.
User avatar
JimmyHartington
Advanced member
Posts: 384
Joined: Tue Mar 22, 2011 7:38 am

Re: Set private data based on Pitstop Server log

Post by JimmyHartington »

It works as I expect.
Just have to process the pdf to have it only report inks from the trim box first, since it is this info I need.

Thank you very much for the help.
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: Set private data based on Pitstop Server log

Post by mkayyyy »

Awesome, glad it works as you wanted
freddyp
Advanced member
Posts: 1098
Joined: Thu Feb 09, 2012 3:53 pm

Re: Set private data based on Pitstop Server log

Post by freddyp »

Matthew's solution is of course perfect and for the flow design easier than what I will suggest, but here is an approach that does not use scripting for those users that do not have the scripting module.

Define two pieces of private data on a folder after having run PitStop using the following XPath expression in Metadata:
count(//DocumentInkInfo/Ink[@name="Cyan"]) and one with Magenta of course.

You then test the private data key names that you defined for cyan and magenta being 1 or 0.
User avatar
JimmyHartington
Advanced member
Posts: 384
Joined: Tue Mar 22, 2011 7:38 am

Re: Set private data based on Pitstop Server log

Post by JimmyHartington »

Thanks Freddy.
I keep forgetting you can count with the XPath expressions.
mkayyyy
Member
Posts: 95
Joined: Mon Nov 21, 2016 6:31 pm
Location: UK

Re: Set private data based on Pitstop Server log

Post by mkayyyy »

freddyp wrote: Wed Jan 29, 2025 4:46 pm Matthew's solution is of course perfect and for the flow design easier than what I will suggest, but here is an approach that does not use scripting for those users that do not have the scripting module.

Define two pieces of private data on a folder after having run PitStop using the following XPath expression in Metadata:
count(//DocumentInkInfo/Ink[@name="Cyan"]) and one with Magenta of course.

You then test the private data key names that you defined for cyan and magenta being 1 or 0.
:idea: Totally forgot about using XPath Metadata, also a good shout
Post Reply