%% This is file `novel-pdfx.sty', part of `novel' document class.
%% Copyright (c) 2017-2024 Robert Allgeyer.
%%
%% This file may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, version 1.3c.
%% License URL: https://www.latex-project.org/lppl/lppl-1-3c/
%%
%% ----------------------------------------------------------------------------
%%
%% File `novel-pdfx.sty' uses code, directly copied or modified,
%% from file `pdfx.sty', part of LaTeX package `pdfx': Copyright (c) 2015,
%% CV Radhakrishnan, Han The Thanh, Ross Moore, Peter Selinger.
%% Licensed LPPL 1.2+ -> 1.3c.
%%
%% ----------------------------------------------------------------------------
%%
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{novel-pdfx.sty}%
[2024/04/26 v2.2 LaTeX file (PDF/X support for novel class)]
% This package supports, and is part of, class `novel'.
% No support for anything but LuaLaTeX.
% DO NOT ATTEMPT TO USE OUTSIDE `NOVEL' DOCUMENT CLASS.
% Reason: Other files in this class define stuff that is used here.
%%
%% This file is loaded \AtEndPreamble.
%%
%% Preliminary tests for cases forbidding PDF/X:
\ifdraftdoc
\global\@pdfxISofftrue
\fi
\if@sandbox
\global\@pdfxISofftrue
\fi
%
\gdef\@AlertNoPDFX{% called by `novel.cls' AtBeginDocument
\if@pdfxSEToff\else
\ifdraftdoc
\typeout{^^JClass `novel' Alert: No PDF/X in draft mode. ^^J%
Your document was processed with \string\SetPDFX{off}. ^^J}%
\fi
\if@sandbox
\typeout{^^JClass `novel' Alert: No PDF/X with sandbox option. ^^J%
Your document was processed with \string\SetPDFX{off}. ^^J}%
\fi
\fi
} % end @AlertNoPDFX
%%
% Hyperref options for PDF/X with LuaLaTeX:
\def\pdfx@pdfX@opts@luatex{%
draft,pdfpagemode=UseNone,bookmarks=false,hyperfootnotes=false,%
hyperindex=false,implicit=false,pdfversion=1.\the\pdfminorversion,%
pdfpagelabels=true,pageanchor=false,pdfstartview=}
%
\RequirePackage[\pdfx@pdfX@opts@luatex]{hyperref}
%
\hypersetup{pdfencoding=auto}
\expandafter\ifx\csname KV@Hyp@psdextra\endcsname\relax\else
\hypersetup{psdextra}
\fi
\Hy@bookmarksfalse
%
\ifthenelse{\equal{\@title}{} \OR \equal{\@title}{ }}{%
\global\@HasTitlefalse}{\global\@HasTitletrue%
}
\ifthenelse{\equal{\@title}{IMPORTANT: Provide Book Title}}{%
\ClassWarning{novel}{^^JDid not provide title using \string\SetTitle. ^^J%
Default used: `IMPORTANT: Provide Book Title'. Be sure to change it! ^^J}%
}{}%
%
% Sanity check: If title is missing at this step, then compliance must be off:
\if@pdfxISoff\else
\if@HasTitle\else
\ClassError{novel}{PDF/X requires non-empty \string\SetTitle\space}%
{Unless \string\SetPDFX\space is off, must use \string\SetTitle\space ^^J%
with non-empty title. Blank space counts as empty.}%
\fi
\fi
%
\if@HasTitle\else
\ClassWarning{novel}{^^JYour file has been compiled without standard ^^J%
PDF internal metadata, such as the title. This is allowable, and in ^^J%
some cases desirable. But in most cases it is not what you intended. ^^J%
If you want title and other metadata to be in PDF internal metadata, ^^J%
then you must place them prior to the \string\SetPDFX. ^^J}
\fi
%
\expandafter\ifx\csname pdfresetpageorigin\endcsname\relax\else
\pdfresetpageorigin=0
\fi
\edef\pdfcreationdate{\pdfcreationdate}%
\let\pdfx@mdfivesum\pdf@mdfivesum
%
%% CALCULATE AND SPECIFY CROPBOX AND TRIMBOX
%% ----------------------------------------------------------------------------
%%
% The MediaBox is automatically provided, so there is no need to write
% MediaBox in /pdfInfo (because it would be a duplicate).
% TrimBox is always necessary for PDF/X.
% Although CropBox is not necessary, it seems that it is often written
% by professional PDF software. For that reason, and for proper centering
% of TrimBox when MediaBox is larger, CropBox is created (= MediaBox).
%
\newcommand\@myMWN{\strip@pt\paperwidth}
\FPmul{\@myMWN}{\@myMWN}{0.99626401}
\FPround{\@myMWN}{\@myMWN}{3}
\FPclip{\@myMWN}{\@myMWN}
\newcommand\@myMHN{\strip@pt\paperheight}
\FPmul{\@myMHN}{\@myMHN}{0.99626401}
\FPround{\@myMHN}{\@myMHN}{3}
\FPclip{\@myMHN}{\@myMHN}
\newcommand\@myTWN{\strip@pt\@TrimWidth}
\FPmul{\@myTWN}{\@myTWN}{0.99626401}
\FPround{\@myTWN}{\@myTWN}{3}
\newcommand\@myTHN{\strip@pt\@TrimHeight}
\FPmul{\@myTHN}{\@myTHN}{0.99626401}
\FPround{\@myTHN}{\@myTHN}{3}
%
\FPsub{\@myTWorigin}{\@myMWN}{\@myTWN}
\FPmul{\@myTWorigin}{\@myTWorigin}{0.5}
\FPround{\@myTWorigin}{\@myTWorigin}{3}
\FPadd{\@myTWcorner}{\@myTWorigin}{\@myTWN}
\FPround{\@myTWcorner}{\@myTWcorner}{3}
\FPsub{\@myTHorigin}{\@myMHN}{\@myTHN}
\FPmul{\@myTHorigin}{\@myTHorigin}{0.5}
\FPround{\@myTHorigin}{\@myTHorigin}{3}
\FPadd{\@myTHcorner}{\@myTHorigin}{\@myTHN}
\FPround{\@myTHcorner}{\@myTHcorner}{3}
%
\FPclip{\@myTWorigin}{\@myTWorigin}
\FPclip{\@myTWcorner}{\@myTWcorner}
\FPclip{\@myTHorigin}{\@myTHorigin}
\FPclip{\@myTHcorner}{\@myTHcorner}
%
\newcommand\novel@CropBox{%
\if@cropview%
/CropBox[\@myTWorigin\space\@myTHorigin\space\@myTWcorner\space\@myTHcorner]%
\else%
/CropBox[0\space0\space\@myMWN\space\@myMHN]%
\fi%
}
%
\newcommand\novel@TrimBox{%
/TrimBox[\@myTWorigin\space\@myTHorigin\space\@myTWcorner\space\@myTHcorner]%
}
%
% BleedBox, only for cover art. Same size as MediaBox.
\newcommand\novel@BleedBox{%
\if@coverart%
/BleedBox[0\space0\space\@myMWN\space\@myMHN]%
\fi%
}
%
\begingroup\edef\next{%
\endgroup\pdfpageattr{\novel@CropBox^^J\novel@BleedBox^^J\novel@TrimBox}}\next
%
%% End calculate and specify TrimBox.
%% GENERAL PDF INTERNAL METADATA PREPARATION
%% ----------------------------------------------------------------------------
%
% Create hashes that will be used for uuid data. Does not need to be fancy:
\def\tweak@temp@s{
\lowercase\expandafter{% Per 'egreg' tex.stackexchange.com q.351065.
\expandafter\def\expandafter\temp@s\expandafter{\temp@s}%
}
\StrLeft{\temp@s}{8}[\temp@n]
\StrRight{\temp@s}{24}[\temp@d]
\edef\temp@s{\temp@n-\temp@d}
\StrLeft{\temp@s}{13}[\temp@n]
\StrRight{\temp@s}{19}[\temp@d] % Omit character, becomes 4.
\edef\temp@s{\temp@n-4\temp@d}
\StrLeft{\temp@s}{18}[\temp@n]
\StrRight{\temp@s}{15}[\temp@d] % Omit character, becomes 8.
\edef\temp@s{\temp@n-8\temp@d}
\StrLeft{\temp@s}{23}[\temp@n]
\StrRight{\temp@s}{12}[\temp@d]
\edef\temp@s{\temp@n-\temp@d}
}
\edef\temp@s{\pdf@mdfivesum{\jobname\@title\@author novel}}
\tweak@temp@s
\edef\@documentID{uuid:\temp@s}
\edef\temp@s{\pdf@mdfivesum{\pdffeedback creationdate}}
\tweak@temp@s
\edef\@instanceID{uuid:\temp@s}
%%
%
%% End general PDF in internal metadata preparation.
%% PREPARATION OF XMP METADATA
%% ----------------------------------------------------------------------------
%% Data prepared here, will later be inserted into the XMP packet template,
%% then the processed template will be incuded in the PDF.
%% XMP metadata is in utf-8 encoding.
%
% Make the XMP look pretty:
\def\pad@ii{\space\space}
\def\pad@iv{\pad@ii\pad@ii}
\def\pad@vi{\pad@iv\pad@ii}
\def\pad@viii{\pad@vi\pad@ii}
\def\pad@x{\pad@viii\pad@ii}
\def\pad@xii{\pad@x\pad@ii}
\def\pad@xiv{\pad@xii\pad@ii}
\def\pad@xvi{\pad@xiv\pad@ii}
\def\pad@xviii{\pad@xvi\pad@ii}
\def\pad@xx{\pad@xviii\pad@ii}
\def\pad@xxxii{\pad@xvi\pad@xvi}
\def\pad@lxiv{\pad@xxxii\pad@xxxii}
\def\pad@cxxviii{\pad@lxiv\pad@lxiv}
\def\pad@cclvi{\pad@cxxviii\pad@cxxviii}
\def\pad@dxii{\pad@cclvi\pad@cclvi}
%
% Frankly, I am not sure if all this rigamarole is necessary, but it works!
% Here, portions of XMP code are prepared. Later, they will be inserted
% into the XMP packet template.
\gdef\@titleString{
\pad@vi^^J
\pad@viii^^J
\pad@x\@title^^J
\pad@viii^^J
\pad@vi^^J
}
%
\ifthenelse{\equal{\@author}{}}{
\gdef\@authorString{}
}{
\gdef\@authorString{
\pad@vi^^J
\pad@viii^^J
\pad@x\@author^^J
\pad@viii^^J
\pad@vi^^J
}
}
%
%
\def\@pdfVersion{1.\the\pdfminorversion}
%
\if@pdfxISoff
\gdef\@verconfString{}%
\else
\gdef\@verconfString{
\pad@vi\@PDFXversion^^J
\if@HasConformance
\pad@vi%
\@PDFXconformance^^J
\fi
}
\fi
%
\if@pdfxISoff
\gdef\@pdfidString{}%
\else
\gdef\@pdfidString{
\pad@vi\@PDFXversion^^J
}
\fi
%
\ifthenelse{\equal{\@novelApplication}{} \OR \equal{\@novelApplication}{ }}{
\gdef\@applicationString{}%
}{
\gdef\@applicationString{\pad@vi%
\@novelApplication^^J}%
}
%
\ifthenelse{\equal{\@novelProducer}{} \OR \equal{\@novelProducer}{ }}{
\gdef\@producerString{}%
}{
\gdef\@producerString{\pad@vi%
\@novelProducer^^J}%
}
%
% Calculation of Dates and Times, which must be in a specific format.
% Each time you process to PDF, the current date/time is used,
% for all of the several metadata date/time strings.
\def\xmp@cDate{\pdfx@getYear}
{\catcode`\D=12 \catcode`\:=12
\gdef\pdfx@getYear D:#1#2#3#4{\edef\pdfx@xYear{#1#2#3#4}\pdfx@getMonth}
}
\def\pdfx@getMonth#1#2{\edef\pdfx@xMonth{#1#2}\pdfx@getDay}
\def\pdfx@getDay#1#2{\edef\pdfx@xDay{#1#2}\pdfx@getHour}
\def\pdfx@getHour#1#2{\edef\pdfx@xHour{#1#2}\pdfx@getMin}
\def\pdfx@getMin#1#2{\edef\pdfx@xMin{#1#2}\pdfx@getSec}
\def\pdfx@getSec#1#2{\edef\pdfx@xSec{#1#2}\pdfx@getTZh}
\def\pdfx@getTZh{\futurelet\pdfx@next\pdfx@getTzh@branches}
%
{\catcode`\@=11 \catcode`\Z=12 \catcode`\+=12 \catcode`\-=12 % ends below
\gdef\pdfx@getTzh@branches{%
\ifx\pdfx@next Z\let\pdfx@getTzbranch\pdfx@getTznozone
\else\ifx\pdfx@next +\let\pdfx@getTzbranch\pdfx@getTzplus
\else\ifx\pdfx@next -\let\pdfx@getTzbranch\pdfx@getTzminus
\else\let\pdfx@getTzbranch\pdfx@getTzerror
\fi\fi\fi \pdfx@getTzbranch }
%
\catcode`\0=12
\gdef\pdfx@getTznozone Z#1\pdfx@getTzend{%
\edef\pdfx@xTzh{+00}\edef\pdfx@xTzm{00}}
\gdef\pdfx@getTzplus +#1'#2'#3\pdfx@getTzend{%
\edef\pdfx@xTzh{+#1}\edef\pdfx@xTzm{#2}%
\ifx\relax#2\relax\def\pdfx@xTzm{00}\fi}
\gdef\pdfx@getTzminus -#1'#2'#3\pdfx@getTzend{%
\edef\pdfx@xTzh{-#1}\edef\pdfx@xTzm{#2}%
\ifx\relax#2\relax\def\pdfx@xTzm{00}\fi}
%
\expandafter\ifx\csname pdfcreationdate\endcsname\relax
\else
\expandafter\expandafter\expandafter\xmp@cDate\pdfcreationdate''\pdfx@getTzend
\xdef\pdfx@convDate{\pdfx@xYear\pdfx@xMonth\pdfx@xDay\pdfx@xHour
\pdfx@xMin\pdfx@xSec\pdfx@xTzh'\pdfx@xTzm'}%
\xdef\xmp@cDate{\pdfx@xYear-\pdfx@xMonth-\pdfx@xDay
T\pdfx@xHour:\pdfx@xMin:\pdfx@xSec\pdfx@xTzh:\pdfx@xTzm}%
\fi
}% End of \catcode`\@=11 etc.
\let\@modifyDate\xmp@cDate
\let\@createDate\xmp@cDate
\let\@metadataDate\xmp@cDate
% End dates and times.
%
%% End Prepare XMP metadata.
%% WRITE THE XMP METADATA, UNLESS PDF/X IS OFF OR NO TITLE
%%-----------------------------------------------------------------------------
%% Inserts the prepared XMP metadata into XMP packet template, then writes
%% the result at the start of the PDF, right now, before the document.
%
\if@pdfxISoff\else
\if@HasTitle
\begingroup
\makeatletter
\input{novel-xmppacket.sty}
\global\let\@xmpData\@xmpPacket % from the above file
\begingroup
\pdfcompresslevel=0
\immediate\pdfobj stream attr {/Type /Metadata /Subtype /XML} {\@xmpData}
\pdfcatalog{/Metadata \the\pdflastobj\space 0 R}
\endgroup
\endgroup
% Creates external xml file, if requested:
\if@wantXMPasXML
\newwrite\file
\immediate\openout\file=\jobname-XMPasXML.xml
\immediate\write\file{^^J}
\immediate\write\file{^^J}
\immediate\write\file{^^J}
\immediate\write\file{^^J}
\immediate\write\file{^^J}
\immediate\write\file{^^J}
\immediate\write\file{^^J}
\immediate\write\file{\@xmpData^^J}
\closeout\file
\fi
\fi
\fi
%
%
%% End write the XMP metadata.
%% PREPARE PDF /INFO METADATA
%% ----------------------------------------------------------------------------
%% PDF /Info is another form of metadata, older than XMP but still used.
%% It is NOT in utf-8 encoding. Depending on content, one of two encodings
%% will be automatically used: PDFDoc encoding if metadata uses only
%% characters within Latin-1, or utf-16 if metadata is not within Latin-1.
%% Either way, the input was utf-8 before processing.
%% In principle, PDF /Info is obsolete whenever PDF/X is used, because
%% XMP metadata is supposed to prevail through the printing workflow.
%% In practice, things don't always work that way. So, unless your PDF
%% has no metadata, essential items are re-encoded and copied to PDF /Info.
%% Other than encoding, XMP metadata and PDF /Info must be exactly the same.
%% All of those issues are handled automatically here.
%% The result is written at the end of the PDF, after the document.
%
% Macro for massaging encodings:
\def\@infotopdfstring#1#2{%
\ifx#2\@empty
\global\let#1\empty
\else
\begingroup
\hypersetup{pdfencoding=auto}%
\pdfstringdef#1{#2}%
\endgroup
\fi
}
% Now, massage the metadata:
\@infotopdfstring{\@infotitle}{\@title}
\@infotopdfstring{\@infoauthor}{\@author}
\@infotopdfstring{\@infoapplication}{\@novelApplication}
\@infotopdfstring{\@infoproducer}{\@novelProducer}
%
%% End prepare PDF /Info.
%% WRITE THE OUTPUT INTENT, UNLESS PDFX IS OFF.
%% ----------------------------------------------------------------------------
% Data for CGATS TR 001, FOGRA39, and JC200103 are in file novel-FileData.sty.
\if@pdfxISoff\else
\begingroup
\edef\@pctchar{\expandafter\@gobble\string\%} % Escaped in TeX, not PDF.
\edef\@bchar{\expandafter\@gobble\string\\} % For use as escape, below.
\edef\0{\string\0} % Not sure why, but it works.
\edef\({\string\(} % PDF Catalog requires escaped parentheses.
\edef\){\string\)} % PDF Catalog requires escaped parentheses.
\catcode`\_ 12 % The icc file name might contain underscores.
%
\if@EmbedICC
\IfFileExists{\@OIprofile}{%
\immediate\pdfobj stream attr{/N 4} file{\@OIprofile}%
\edef\OBJ@OI{\the\pdflastobj\space 0 R}%
}{%
\ClassError{novel}{Requested icc color profile not found}%
{You used the starred \string\SetPDFX*\space which embeds the ^^J%
associated icc color profile. But the file could not be located. ^^J%
If necessary, put it in the same folder as your *.tex document. ^^J%
Incidentally: Do you really need to embed the profile?}%
}
\fi
\ifthenelse{\equal{\@OIcondition}{}}{
\edef\@OIconditionString{}%
}{
\edef\@OIconditionString{/OutputCondition (\@OIcondition)}%
}
\ifthenelse{\equal{\@OIidentifier}{}}{
\edef\@OIidentifierString{}%
}{
\edef\@OIidentifierString{/OutputConditionIdentifier (\@OIidentifier)}%
}
\ifthenelse{\equal{\@OIinfo}{}}{
\edef\@OIinfoString{}%
}{
\edef\@OIinfoString{/Info (\@OIinfo)}%
}
\ifthenelse{\equal{\@OIregistry}{}}{
\edef\@OIregistryString{}%
}{
\edef\@OIregistryString{/RegistryName (\@OIregistry)}%
}
\pdfcatalog{%
/OutputIntents [ <<%
/Type/OutputIntent%
/S/GTS_PDFX%
\@OIconditionString%
\@OIidentifierString%
\@OIinfoString%
\@OIregistryString%
\if@EmbedICC/DestOutputProfile \OBJ@OI\fi%
>> ]%
}%
\endgroup
\fi
%
%% End write the output intent.
%% DISABLE HYPERREF OPTIONS
%%-----------------------------------------------------------------------------
%% Prevents changes that will cause an incompatibility.
%
\Hy@DisableOption{pdfauthor}%
\Hy@DisableOption{pdftitle}%
\Hy@DisableOption{pdfsubject}%
\Hy@DisableOption{pdfcreator}%
\Hy@DisableOption{pdfcreationdate}%
\Hy@DisableOption{pdfmoddate}%
\Hy@DisableOption{pdfproducer}%
\Hy@DisableOption{pdfkeywords}%
%
%% End disable hyperref options.
%% PREPARE PDF/Info
%% ----------------------------------------------------------------------------
\gdef\@ActivatePDFInfo{% called by `novel.cls' \AtBeginDocument
\if@HasTitle
\pdfinfo{
\ifx\@infotitle\@empty\else /Title(\@infotitle)\fi
\ifx\@infoauthor\@empty\else /Author(\@infoauthor)\fi
\ifx\@infoapplication\@empty\else /Creator(\@infoapplication)\fi
\ifx\@pdfcreationdate\@empty
/CreationDate(D:\pdfx@convDate)%
\else
/CreationDate(\@pdfcreationdate)%
\fi
\ifx\@pdfmoddate\@empty
/ModDate(D:\pdfx@convDate)%
\else
/ModDate(\@pdfmoddate)%
\fi
\ifx\@infoproducer\@empty\else /Producer(\@infoproducer)\fi%
/Trapped/False%
\if@pdfxISoff\else
/GTS_PDFXVersion(\@PDFXversion)%
\if@HasConformance /GTS_PDFXConformance(\@PDFXconformance)\fi%
\fi
}
\fi
}%
%% End \@ActivatePDFInfo.
%%
\endinput
%%
%% End of file `novel-pdfx.sty'.