arajcany / pre-press-tricks
常见PrePress任务的技巧箱。
Requires
- php: >=8.2
- ext-dom: *
- ext-exif: *
- ext-gd: *
- ext-json: *
- ext-soap: *
- arajcany/tool-box: ^2.3
- cakephp/core: >=5.0
- cakephp/i18n: >=5.0
- intervention/image: ^2.7
- league/mime-type-detection: ^1.11
- tecnickcom/tc-lib-pdf: ^8.0
Requires (Dev)
Suggests
- ext-imagick: *
README
常见PrePress任务的技巧箱。
目录
目的
如果你曾经问过以下任何一个问题,这个类集合可能对你有帮助。
Pages 类
- 我需要将这张图片缩放到什么百分比,使其能够放入这个框中?
Boxes 类
- 如何将一系列页面清理为可读的格式,例如 '3,4,6,12,13,10-20,1,2,8' => '1-4,6,8,10-20'?
票务类
- 我该如何为施乐打印设备生成XPIF票?
安装
推荐的安装方法是使用Composer。
{ "require": { "php": ">=8.0", "arajcany/pre-press-tricks": "" } }
版本兼容性
PHP 7.4 (last compatible version for PHP 7.4)
composer require arajcany/pre-press-tricks:^0.0.7
PHP 8.x
composer require arajcany/pre-press-tricks:^1.0.0
基本用法 - XPIF票制作器
示例1 - 基础票
<?php use arajcany\PrePressTricks\Ticketing\XPIF\XpifTicket; /* * Probably the most basic ticket you can make. * * Notes: * Finishing values of * 28 = staple-dual-left * 92 = punch-4-hole * 93 = punch-left * The 'media' is defined as 'A4-White-80gsm' as my RIP has a stock catalogue with such defined * */ //create a ticket object based on a specific XPIF version $ticket = new XpifTicket('2.082a'); //populate the ticket with properties $ticket ->setJobName("For_the_Term_of_His_Natural_Life.pdf") ->setRequestingUserName("John Smith") ->setCopies(2) ->setFinishings([28, 93, 92]) ->setSheetCollate('collated') ->setSides('two-sided-long-edge') ->setMedia('A4-White-80gsm'); //render the ticket (returns xml string AND optionally writes to filesystem) $string = $ticket->render("C:\\tmp\\Example_01.xpf");
$string
包含以下XML
<?xml version="1.0"?> <!DOCTYPE xpif SYSTEM "xpif-v02082a.dtd"> <xpif version="1.0" cpss-version="2.082a" xml:lang="en"> <xpif-operation-attributes> <job-name syntax="name" xml:space="preserve">For_the_Term_of_His_Natural_Life.pdf</job-name> <requesting-user-name syntax="name" xml:space="preserve">John Smith</requesting-user-name> </xpif-operation-attributes> <job-template-attributes> <copies syntax="integer">2</copies> <finishings syntax="1setOf"> <value syntax="enum">28</value> <value syntax="enum">93</value> <value syntax="enum">92</value> </finishings> <sheet-collate syntax="keyword">collated</sheet-collate> <sides syntax="keyword">two-sided-long-edge</sides> <media syntax="keyword">A4-White-80gsm</media> </job-template-attributes> </xpif>
示例2 - 基础票支持的属性
XPIF规范在票中支持近650个属性。您可以控制标准属性,例如 ' copies',也可以控制特殊属性,例如 'rgb-monochrome-grayline-mapping'。我选择了一些最常用的属性,并创建了具体的设置这些属性的方法。对于设置很少使用的属性,请参阅示例3。
<?php //name of the job, typically the filename $ticket->setJobName("For_the_Term_of_His_Natural_Life.pdf"); //name of user printing the job $ticket->setRequestingUserName("Joe Citizen"); //number of copies $ticket->setCopies(2); //print only the pages within this range inclusive $ticket->setPageRanges([1, 77]); //the finishing values, you will need to know what each number represents $ticket->setFinishings([28, 93, 92]); //mime type $ticket->setDocumentFormat("application/pdf"); //name of the stock as defined in the RIP or printer $ticket->setMedia('Plain-White-A4-80gsm'); //print the job as 'color' │ 'monochrome-grayscale' $ticket->setColorEffectsType('color'); //id for accounting / reconciliation purposes $ticket->setJobAccountId('123'); //user id requesting job accounting data $ticket->setJobAccountingUserId('AU004133'); //extra data that is useful for accounting and reconciliation purposes $ticket->setJobAccountingData("From Web-2-Portal System A"); //name of the user that will receive the job $ticket->setJobRecipientName("Jane Doe"); //message that is passed to the RIP or printer with the job, typically printed on a banner page $ticket->setJobSheetMessage("Please refer to work ticket for additional instructions"); //message that is passed to the RIP or printer with the job, typically displayed to the operator $ticket->setJobMessageToOperator("Urgent and fussy client"); //use the indicated orientation (portrait, landscape, reverse-landscape, reverse-portrait) $ticket->setOrientationRequested(3); //job collation $ticket->setSheetCollate("Collated"); //sides to print on 'one-sided' │ 'two-sided' │ 'two-sided-short-edge' │ 'two-sided-long-edge' $ticket->setSides("one-sided"); //commonly used in forcing a page to print on the RHS for double sided printing (i.e. chapter starts) $ticket->setForceFrontSide([1, 5, 9, 12]); //render the ticket (returns xml string AND optionally writes to filesystem) $string = $ticket->render("C:\\tmp\\Example_02.xpf");
示例3 - 设置附加属性
对于没有具体方法的属性,您可以使用通用的setProperty()
方法。
<?php /* * The following examples achieve the same result */ //concrete method $ticket->setJobName("For the Term of His Natural Life"); //generic $ticket->setProperty("job-name", "For the Term of His Natural Life"); //concrete method $ticket->setSides("one-sided"); //generic $ticket->setProperty("sides", "one-sided"); //concrete method $ticket->setSheetCollate("Collated"); //generic $ticket->setProperty("sheet-collate", "Collated"); //example of other properties you might like to set $ticket->setProperty("file-name", "For_the_Term_of_His_Natural_Life.pdf"); $ticket->setProperty("job-id-from-client", "D704432_SEQ001"); $ticket->setProperty("printer-resolution", "1200");
示例4 - 设置附加属性的问题
setProperty()
可能对某个属性有效或无效。这是因为代码使用一些智能功能来尝试确定相关属性的属性。这是通过已发布的xpif.dtd
文件(我将它们自动转换为JSON格式以方便阅读)完成的。
考虑以下XPIF票
<?xml version="1.0"?> <!DOCTYPE xpif SYSTEM "xpif-v02082a.dtd"> <xpif version="1.0" cpss-version="2.082a" xml:lang="en"> <xpif-operation-attributes> <job-name syntax="name" xml:space="preserve">For_the_Term_of_His_Natural_Life.pdf</job-name> <requesting-user-name syntax="name" xml:space="preserve">John Smith</requesting-user-name> </xpif-operation-attributes> <job-template-attributes> <copies syntax="integer">2</copies> <finishings syntax="1setOf"> <value syntax="enum">28</value> <value syntax="enum">93</value> <value syntax="enum">92</value> </finishings> <page-ranges syntax="1setOf"> <value syntax="rangeOfInteger"> <lower-bound syntax="integer">1</lower-bound> <upper-bound syntax="integer">50</upper-bound> </value> </page-ranges> <sheet-collate syntax="keyword">collated</sheet-collate> <sides syntax="keyword">two-sided-long-edge</sides> <media syntax="keyword">A4-White-80gsm</media> <pad-printing> <pad-printing-type syntax="keyword">pads-single-back-cover</pad-printing-type> <number-of-sheets-per-pad syntax="integer">50</number-of-sheets-per-pad> </pad-printing> <finishings-col> <finishings-media-sheets-min-max> <upper-bound syntax="integer">1</upper-bound> <lower-bound syntax="integer">50</lower-bound> </finishings-media-sheets-min-max> </finishings-col> </job-template-attributes> </xpif>
问题1 - 模糊属性
如果您尝试以下方式设置'lower-bound'属性,$ticket->setProperty('lower-bound', 1)
您是在设置以下哪个属性的值?
/xpif/job-template-attributes/finishings-col/finishings-media-sheets-min-max/lower-bound
或
/xpif/job-template-attributes/page-ranges/value/lower-bound
?
解决方案
使用点符号明确指定路径。注意第一个参数中的点符号
$ticket->setProperty('finishings-media-sheets-min-max.lower-bound', 1)
这明确指定了在xpif.dtd
文件中使用哪个'lower-bound'。
您可以使用完整的xPath以点符号格式执行此操作
$ticket->setProperty('xpif.job-template-attributes.finishings-col.finishings-media-sheets-min-max.lower-bound', 1)
但是,定义父级和祖父级通常是足够的。
问题2 - 'Value'的未定义子元素
由于某种原因,施乐的xpif.dtd
文件没有公布' value'的有效子节点。查看上面的示例XPIF
/xpif/job-template-attributes/finishings/value
包含文本值 28, 93 和 92。
/xpif/job-template-attributes/page-ranges/value
包含子节点 'lower-bound' 和 'upper-bound'。
这非常令人困惑,因为实际上' value'可以包含任何内容,它没有在xpif.dtd中定义。
解决方案
不幸的是,您必须知道以下属性的XPIF结构' value'之后
xpif.job-template-attributes.finishings.value
xpif.job-template-attributes.page-ranges.value
xpif.job-template-attributes.force-front-side.value
xpif.job-template-attributes.insert-sheet.value
xpif.job-template-attributes.page-overrides.value
xpif.job-template-attributes.job-save-disposition.save-info.value
xpif.job-template-attributes.pages-per-subset.value
xpif.job-template-attributes.finishings-col.stitching.stitching-locations.value
xpif.job-template-attributes.finishings-col.creasing-col.crease-position-specifications-col.value
xpif.job-template-attributes.resource-cleanup.value
xpif.job-template-attributes.pdl-init-file.value
xpif.job-template-attributes.forms-col.value
xpif.job-template-attributes.job-offset.value
xpif.job-template-attributes.form-save.form-save-info.value
xpif.job-template-attributes.imposition-mark-front.value
xpif.job-template-attributes.pcl-paper-source-col.value
xpif.job-template-attributes.edge-enhancement-disable.value
xpif.job-template-attributes.job-print-with-saved-jobs.value
xpif.job-template-attributes.adjust-custom-color-col.value
xpif.job-template-attributes.natural-language-adjustment-col.natural-language-adjustment-string.value
xpif.job-template-attributes.fax-out-col.recipients-col.value
xpif.job-template-attributes.output-gloss-col.value
xpif.job-template-attributes.edge-enhancement-col.value
xpif.job-template-attributes.black-enhancement-col.value
xpif.job-template-attributes.colorant-set-col.colorant-col.value
xpif.job-template-attributes.output-white-col.value
我编写了一些技巧,您可以使用它们
<?php //concrete methods for 3 of the most common undefined children of value //concrete method $ticket->setFinishings([28, 93, 92]); //generic equivalent $ticket->setProperty('xpif.job-template-attributes.finishings.value.0', '28', ['syntax' => "enum"]); $ticket->setProperty('xpif.job-template-attributes.finishings.value.1', '93', ['syntax' => "enum"]); $ticket->setProperty('xpif.job-template-attributes.finishings.value.2', '92', ['syntax' => "enum"]); //concrete method $ticket->setPageRanges([1, 50]); //generic equivalent $ticket->setProperty('xpif.job-template-attributes.page-ranges.value.lower-bound', '1'); $ticket->setProperty('xpif.job-template-attributes.page-ranges.value.upper-bound', '50'); //concrete method $ticket->setForceFrontSide([1, 10, 19, 32]); //generic equivalent $ticket->setProperty('xpif.job-template-attributes.force-front-side.value.0', '1', ['syntax' => "integer"]); $ticket->setProperty('xpif.job-template-attributes.force-front-side.value.2', '10', ['syntax' => "integer"]); $ticket->setProperty('xpif.job-template-attributes.force-front-side.value.3', '19', ['syntax' => "integer"]); $ticket->setProperty('xpif.job-template-attributes.force-front-side.value.4', '32', ['syntax' => "integer"]);
示例5 - 处理媒体和媒体集合
根据您使用的RIP,您可以使用媒体或媒体集合
媒体 当您的RIP有一个定义的媒体目录并且您知道该目录中的媒体名称时使用此选项。
<?php use arajcany\PrePressTricks\Ticketing\XPIF\XpifTicket; $ticket = new XpifTicket('2.082a'); $ticket->setJobName("For_the_Term_of_His_Natural_Life.pdf"); $ticket->setMedia('Plain-White-A4-80gsm');
<?xml version="1.0"?> <!DOCTYPE xpif SYSTEM "xpif-v02082a.dtd"> <xpif version="1.0" cpss-version="2.082a" xml:lang="en"> <xpif-operation-attributes> <job-name syntax="name" xml:space="preserve">For_the_Term_of_His_Natural_Life.pdf</job-name> </xpif-operation-attributes> <job-template-attributes> <media syntax="keyword">Plain-White-A4-80gsm</media> </job-template-attributes> </xpif>
媒体集合 当您的RIP没有定义媒体目录并且您需要设置库存的属性时使用此选项。
<?php use arajcany\PrePressTricks\Ticketing\XPIF\XpifTicket; use arajcany\PrePressTricks\Ticketing\XPIF\XpifMediaCollection; $mediaCollection = new XpifMediaCollection('2.082a'); $mediaCollection ->setMediaKey('plain-white-a4-80gsm') ->setMediaType('plain') ->setMediaInfo('This is our standard white paper') ->setMediaColor('white') ->setMediaPrePrinted('blank') ->setMediaHoleCount(0) ->setMediaOrderCount(1) ->setMediaSize([21000, 29700]) ->setMediaWeightMetric(80) ->setMediaBackCoating('plain') ->setMediaFrontCoating('plain') ->setMediaRecycled('') ->setMediaDescription('') ->setMediaTooth('') ->setMediaGrain('') ->setMediaMaterial('') ->setMediaThickness('') ->setMediaSizeName('A4') ->setInputTray('') ->setTrayFeed('') ->setFeedOrientation('') ->setMediaMismatchPropertyPolicy('') ->setMediaMismatchSizePolicy(''); //note: the above is a complete list of concrete methods, you do not need to set all of them! $ticket = new XpifTicket('2.082a'); $ticket->setJobName("For_the_Term_of_His_Natural_Life.pdf"); $ticket->setMediaCollection($mediaCollection);
<?xml version="1.0"?> <!DOCTYPE xpif SYSTEM "xpif-v02082a.dtd"> <xpif version="1.0" cpss-version="2.082a" xml:lang="en"> <xpif-operation-attributes> <job-name syntax="name" xml:space="preserve">For_the_Term_of_His_Natural_Life.pdf</job-name> </xpif-operation-attributes> <job-template-attributes> <media-col syntax="collection"> <media-key syntax="keyword">plain-white-a4-80gsm</media-key> <media-type syntax="keyword">plain</media-type> <media-info syntax="text" xml:space="preserve">This is our standard white paper</media-info> <media-color syntax="keyword">white</media-color> <media-pre-printed syntax="keyword"/> <media-hole-count syntax="integer">0</media-hole-count> <media-order-count syntax="integer">1</media-order-count> <media-size syntax="collection"> <x-dimension syntax="integer">21000</x-dimension> <y-dimension syntax="integer">29700</y-dimension> </media-size> <media-weight-metric syntax="integer">80</media-weight-metric> <media-back-coating syntax="keyword">plain</media-back-coating> <media-front-coating syntax="keyword">plain</media-front-coating> <media-recycled syntax="keyword"/> <media-description syntax="keyword"/> <media-tooth syntax="keyword"/> <media-grain syntax="keyword"/> <media-material syntax="keyword"/> <media-thickness syntax="integer"/> <media-size-name syntax="keyword">A4</media-size-name> <input-tray syntax="keyword"/> <tray-feed syntax="keyword"/> <feed-orientation syntax="keyword"/> <media-mismatch-property-policy syntax="keyword"/> <media-mismatch-size-policy syntax="keyword"/> </media-col> </job-template-attributes> </xpif>
媒体集合很棒,因为您可以克隆/修改/重用它们
<?php use arajcany\PrePressTricks\Ticketing\XPIF\XpifMediaCollection; $whiteMediaCollection = new XpifMediaCollection('2.082a'); $whiteMediaCollection ->setMediaType('plain') ->setMediaColor('white') ->setMediaPrePrinted(false) ->setMediaSize([21000, 29700]) ->setMediaWeightMetric(80); $pinkMediaCollection = (clone $whiteMediaCollection)->setMediaColor('pink'); $greenMediaCollection = (clone $whiteMediaCollection)->setMediaColor('green'); $blueMediaCollection = (clone $whiteMediaCollection)->setMediaColor('blue'); $yellowMediaCollection = (clone $whiteMediaCollection)->setMediaColor('yellow'); $blueCoverMediaCollection = (clone $blueMediaCollection)->setMediaWeightMetric(200); $greenCoverMediaCollection = (clone $greenMediaCollection)->setMediaWeightMetric(200);
要了解如何重用媒体集合,请参阅示例6。
示例6 - 其他集合
除了媒体集合,以下集合也可用
- 封面集合
- 封底集合
- 插入页集合
- 页面覆盖集合
<?php use arajcany\PrePressTricks\Ticketing\XPIF\XpifCoverFrontCollection; use arajcany\PrePressTricks\Ticketing\XPIF\XpifCoverBackCollection; use arajcany\PrePressTricks\Ticketing\XPIF\XpifInsertSheetCollection; use arajcany\PrePressTricks\Ticketing\XPIF\XpifPageOverridesCollection; //front cover collection $coverFrontCollection = new XpifCoverFrontCollection('2.082a'); $coverFrontCollection ->setCoverType('print-both') ->setMediaCollection($blueCoverMediaCollection) //we created $blueCoverMedia in Example 5 ->setMedia('the-name-of-the-stock'); //not necessary if you use setMediaCollection() //back cover collection $coverBackCollection = new XpifCoverBackCollection('2.082a'); $coverBackCollection ->setCoverType('print-both') ->setMediaCollection($greenCoverMediaCollection) //we created $greenCoverMedia in Example 5 ->setMedia('the-name-of-the-stock'); //not necessary if you use setMediaCollection() //insert sheet collection $pinkInsertSheetCollection = new XpifInsertSheetCollection('2.082a'); $pinkInsertSheetCollection ->setInsertAfterPageNumber('0') ->setInsertCount(1) ->setMediaCollection($pinkMediaCollection) //we created $pinkMediaCollection in Example 5 ->setMedia('the-name-of-the-stock'); //not necessary if you use setMediaCollection() //page overrides collection $yellowPageOverridesCollection = new XpifPageOverridesCollection('2.082a'); $yellowPageOverridesCollection ->setPages('1-5') ->setMediaCollection($yellowMediaCollection) //we created $yellowMediaCollection in Example 5 ->setMedia('the-name-of-the-stock'); //not necessary if you use setMediaCollection() //insert the above 4 collections into your xpif ticket with the following 4 concrete methods $ticket->setCoverFrontCollection($coverFrontCollection); $ticket->setCoverBackCollection($coverBackCollection); $ticket->setInsertSheetCollection($pinkInsertSheetCollection); $ticket->setPageOverridesCollection($yellowPageOverridesCollection);
示例7 - 在您的XPIF票务中使用集合(大杂烩)
如果您在示例6中关于媒体集合的部分感到困惑,这里有一个可视化,展示了媒体集合可以在XPIF票务中放置的位置
xpif
├── Media Collection
│
├── Cover Front Collection
│ └── Media Collection
│
├── Cover Back Collection
│ └── Media Collection
│
├── Slip Sheets (many)
│ ├── Insert Sheet Collection
│ │ └── Media Collection
│ ├── Insert Sheet Collection
│ │ └── Media Collection
│ │
│ ├── <...>
│ │
│ └── Insert Sheet Collection
│ └── Media Collection
│
└── Page Exceptions (many)
├── Page Overrides Collection
│ └── Media Collection
├── Page Overrides Collection
│ └── Media Collection
│
├── <...>
│
└── Page Overrides Collection
└── Media Collection
从上面的表示中,您可能可以看出我为什么说集合很棒
- 它们允许您编写更少的代码。
- 您不需要知道您要设置的属性的完整xPath - 由集合自动完成。
- 创建一个基本集合,然后在票务的不同部分克隆/修改/重用该集合。
因此,这里有一个集合大杂烩示例,我想这个示例将涵盖您需要用xpif票务做的约90%的内容。这个大杂烩示例基于历史小说《他自然之寿》(Marcus Clarke著,公共领域)。您可以从这里下载这部经典小说的副本https://adc.library.usyd.edu.au/data-2/p00023.pdf
该PDF有以下属性
- 该PDF有433页
- 该PDF有8个部分
- 标题 & 印刷信息
- 前言
- 序言
- 第一卷。——海。1827。
- 第二卷。——麦夸里港。1833。
- 第三卷。波特阿瑟 1838。
- 第四卷。诺福克岛 1846。
- 尾声
- 上述每一卷都有几个章节
我想让xpif按以下方式打印PDF
- 双面打印在A4白色80gsm纸上
- 四孔打孔,因为它需要插入到活页夹中
- 封面是PDF的第一页,单面打印在A4蓝色200gsm卡片纸上
- 单面打印印刷信息页在A4白色80gsm纸上
- 前言打印在A4粉色80gsm纸上
- 对于序言、尾声和4卷中的每一卷,插入一张A4黄色200gsm分隔卡片
- 对于每个章节,打印前两页PDF在A4粉色80gsm纸上
- 需要封底,使用一块A4蓝色200gsm卡片(即不打印)
<?php use arajcany\PrePressTricks\Ticketing\XPIF\XpifTicket; use arajcany\PrePressTricks\Ticketing\XPIF\XpifMediaCollection; use arajcany\PrePressTricks\Ticketing\XPIF\XpifCoverFrontCollection; use arajcany\PrePressTricks\Ticketing\XPIF\XpifCoverBackCollection; use arajcany\PrePressTricks\Ticketing\XPIF\XpifInsertSheetCollection; use arajcany\PrePressTricks\Ticketing\XPIF\XpifPageOverridesCollection; $titleStart = '1'; $imprintStart = '2'; $prefaceStart = '3'; $prologueStart = '4'; $bookStarts ='13,79,173,331'; $chapterStarts ='14,21,28,31,35,41,49,56,62,67,75,78,80,83,86,95,98,101,108,113,118,123,129,140,147,151,158,164,168,174,185,194,201,208,212,217,221,225,233,243,245,249,253,260,265,269,273,276,279,282,290,300,305,311,315,325,332,341,351,357,361,365,371,375,379,383,389,392,397,402,410,415,418,423'; $epilogueStart = '428'; //Start by setting up a default white media collection. $defaultWhiteMediaCollection = (new XpifMediaCollection('2.082a')) ->setMediaType('plain') ->setMediaColor('white') ->setMediaPrePrinted(false) ->setMediaSize([21000, 29700]) ->setMediaWeightMetric(80); //Create the other needed media collections by cloning and modifying $blueCoverMediaCollection = (clone $defaultWhiteMediaCollection)->setMediaColor('blue')->setMediaWeightMetric(200); $yellowDividerMediaCollection = (clone $defaultWhiteMediaCollection)->setMediaColor('yellow')->setMediaWeightMetric(200); $pinkMediaCollection = (clone $defaultWhiteMediaCollection)->setMediaColor('pink'); //Create the exception and insert pages that don't require looping $frontCoverException = (new XpifCoverFrontCollection()) ->setCoverType('print-front') ->setMediaCollection($blueCoverMediaCollection); $backCoverException = (new XpifCoverBackCollection()) ->setCoverType('print-none') ->setMediaCollection($blueCoverMediaCollection); $imprintException = (new XpifPageOverridesCollection()) ->setPages($imprintStart) ->setSides('one-sided'); $prefaceException = (new XpifPageOverridesCollection()) ->setPages($prefaceStart) ->setMediaCollection($pinkMediaCollection); $prologueInsert = (new XpifInsertSheetCollection()) ->setInsertBeforePageNumber($prologueStart) ->setMediaCollection($yellowDividerMediaCollection); $epilogueInsert = (new XpifInsertSheetCollection()) ->setInsertBeforePageNumber($epilogueStart) ->setMediaCollection($yellowDividerMediaCollection); //Create the ticket and set the properties created so far $ticket = (new XpifTicket('2.082a')) ->setJobName("For_the_Term_of_His_Natural_Life.pdf") ->setMediaCollection($defaultWhiteMediaCollection) ->setCoverFrontCollection($frontCoverException) ->setCoverBackCollection($backCoverException) ->setPageOverridesCollection($imprintException) ->setPageOverridesCollection($prefaceException) ->setInsertSheetCollection($prologueInsert) ->setInsertSheetCollection($epilogueInsert) ; //we need to loop the book starts foreach (explode(',', $bookStarts) as $bookStart) { $bookStartInsert = (new XpifInsertSheetCollection('2.082a')) ->setInsertBeforePageNumber($bookStart) ->setInsertCount(1) ->setMediaCollection($yellowDividerMediaCollection); //push into the xpif ticket $ticket = $ticket->setInsertSheetCollection($bookStartInsert); } //we need to loop the chapter starts foreach (explode(',', $chapterStarts) as $chapterStart) { $chapterStartException = (new XpifPageOverridesCollection('2.082a')) ->setPages([$chapterStart, $chapterStart + 1]) ->setMediaCollection($pinkMediaCollection); //push into the xpif ticket $ticket = $ticket->setPageOverridesCollection($chapterStartException); } $xpifXml = $ticket->render(); print_r($xpifXml);