%% 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'.