From cb14c16722533ee99b36a2e6efd9a6e4820954a3 Mon Sep 17 00:00:00 2001 From: Reinhard Kotucha Date: Fri, 9 Apr 2021 21:01:58 +0000 Subject: Upgrade gs-9.53.3 -> gs-9.54.0 git-svn-id: svn://tug.org/texlive/trunk@58805 c570f23f-e606-0410-a88d-b1316a301751 --- Master/tlpkg/tlgs/lib/zugferd.ps | 316 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 Master/tlpkg/tlgs/lib/zugferd.ps (limited to 'Master/tlpkg/tlgs/lib/zugferd.ps') diff --git a/Master/tlpkg/tlgs/lib/zugferd.ps b/Master/tlpkg/tlgs/lib/zugferd.ps new file mode 100644 index 00000000000..0320fb69e8e --- /dev/null +++ b/Master/tlpkg/tlgs/lib/zugferd.ps @@ -0,0 +1,316 @@ +% Copyright (C) 2001-2021 Artifex Software, Inc. +% All Rights Reserved. +% +% This software is provided AS-IS with no warranty, either express or +% implied. +% +% This software is distributed under license and may not be copied, +% modified or distributed except as expressly authorized under the terms +% of the license contained in the file LICENSE in this distribution. +% +% Refer to licensing information at http://www.artifex.com or contact +% Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, +% CA 94945, U.S.A., +1(415)492-9861, for further information. +% +% zugferd.ps +% This program will create an (unsigned) ZUGFeRD compliant PDF file. In +% order to do so the user must provide certain information, or edit this program. +% +% Required information is the path to the XML file containing the invoice data, +% and the path to an ICC profile appropriate for the chosen ColorConversionStrategy. +% -sZUGFeRDXMLFile defines a path to the XML invoice file and -sZUGFeRDProfile +% defines the path to the ICC profile. +% +% The user must additionally set -dPDFA=3 and -sColorConversionStrategy on the +% Ghostscript command line, and set the permissions for Ghostscript to read +% both these files. It is simplest to put the files in a directory and then +% permit reading of the entire directory. +% +% Example command line : +% +% gs --permit-file-read=/usr/home/me/zugferd/ -sDEVICE=pdfwrite -dPDFA=3 -sColorConversionStrategy=RGB \ +% -sZUGFeRDXMLFile=/usr/home/me/zugferd/invoice.xml -sZUGFeRDProfile=/usr/home/me/rgb.icc \ +% -o /usr/home/me/zugferd/zugferd.pdf /usr/home/me/zugferd/zugferd.ps /usr/home/me/zugferd/original.pdf +% +% Much of this program results from a Ghostscript bug report, the thread can be found at +% https://bugs.ghostscript.com/show_bug.cgi?id=696472 Portions of the code below were +% supplied by Reinhard Nissl and I'm indebted to him for his efforts in helping me create +% a solution for this problem as well as for the code he supplied, particularly for the +% SimpleUTF16BE routine. +% +% It should not be necessary to modify this program, the comments in the code are there purely for information, +% but there are two areas which might reasonably be altered. The section with the --8<-- lines could be replaced +% with a simpler /N 3 or /N 4 if you always intend to produce the same kind of files; RGB or CMYK. +% In step 7, the large XML string will need to be replaced if you want to produce a ZUGFeRD 2.1 +% file, and in future may require similar modification for later versions. +% + +% istring SimpleUTF16BE ostring +/SimpleUTF16BE +{ + dup length + 1 add + 2 mul + string + + % istring ostring + dup 0 16#FE put + dup 1 16#FF put + 2 + 3 -1 roll + + % ostring index istring + { + % ostring index ichar + 3 1 roll + % ichar ostring index + 2 copy 16#00 put + 1 add + 2 copy + 5 -1 roll + % ostring index ostring index ichar + put + 1 add + % ostring index + } + forall + + % ostring index + pop +} +bind def + +% First check that the user has defined the XML invoice file on the command line +% +/ZUGFeRDXMLFile where { + pop % Discard the dictionary + % + % Now check that the ICC Profile is defined + % + /ZUGFeRDProfile where { + pop % Discard the dictionary + + % Step 1, add the required PDF/A boilerplate. This is mostly copied from lib/pdfa_de.ps + % Create a PDF stream object to hold the ICC profile. + [ /_objdef {icc_PDFA} /type /stream /OBJ pdfmark + + % Add the required entries to the stream dictionary (/N only) + [ {icc_PDFA} + << + %% This code attempts to set the /N (number of components) key for the ICC colour space. + %% To do this it checks the ColorConversionStrategy or the device ProcessColorModel if + %% ColorConversionStrategy is not set. + %% This is not 100% reliable. A better solution is for the user to edit this and replace + %% the code between the ---8<--- lines with a simple declaration like: + %% /N 3 + %% where the value of N is the number of components from the profile defined in ZUGFeRDProfile. + %% + %% ----------8<--------------8<-------------8<--------------8<---------- + systemdict /ColorConversionStrategy known { + systemdict /ColorConversionStrategy get cvn dup /Gray eq { + pop /N 1 false + }{ + dup /RGB eq { + pop /N 3 false + }{ + /CMYK eq { + /N 4 false + }{ + (ColorConversionStrategy not a device space, falling back to ProcessColorModel, output may not be valid PDF/A.)= + true + } ifelse + } ifelse + } ifelse + } { + (ColorConversionStrategy not set, falling back to ProcessColorModel, output may not be valid PDF/A.)= + true + } ifelse + + { + currentpagedevice /ProcessColorModel get + dup /DeviceGray eq { + pop /N 1 + }{ + dup /DeviceRGB eq { + pop /N 3 + }{ + dup /DeviceCMYK eq { + pop /N 4 + } { + (ProcessColorModel not a device space.)= + /ProcessColorModel cvx /rangecheck signalerror + } ifelse + } ifelse + } ifelse + } if + %% ----------8<--------------8<-------------8<--------------8<---------- + >> /PUT pdfmark + + % Now read the ICC profile from the file into the stream + [ {icc_PDFA} ZUGFeRDProfile (r) file /PUT pdfmark + + % Define the output intent dictionary : + [/_objdef {OutputIntent_PDFA} /type /dict /OBJ pdfmark + + % Add the required keys to the dictionary + [{OutputIntent_PDFA} << + /Type /OutputIntent + /S /GTS_PDFA1 % Required for PDF/A. + /DestOutputProfile {icc_PDFA} % The actual profile. + /OutputConditionIdentifier (Custom) % A better solution is a string from the ICC Registry, but Custom is always valid. + >> /PUT pdfmark + + % And now add the OutputIntent to the Catalog dictionary + [ {Catalog} << /OutputIntents [ {OutputIntent_PDFA} ]>> /PUT pdfmark + + + % Step 2, define the XML file and read it into the PDF + % First we define the PDF stream to contain the XML invoice + [ /_objdef {InvoiceStream} /type /stream /OBJ pdfmark + + % Fill in the dictionary elements we need. We believe the + % ModDate is not useful so it's just set to a valid value. + [ {InvoiceStream} << + /Type /EmbeddedFile + /Subtype (text/xml) cvn + /Params << + /ModDate (D:20130121081433+01’00’) + >> + >> /PUT pdfmark + + % Now read the data from the file and store it in the stream + [ {InvoiceStream} ZUGFeRDXMLFile (r) file /PUT pdfmark + + % and close the stream + [ {InvoiceStream} /CLOSE pdfmark + + + % Step 3 create the File Specification dictionary for the embedded file + % Create the dictionary + [ /_objdef {FSDict} /type /dict /OBJ pdfmark + + % Fill in the required dictionary elements + [ {FSDict} << + /Type /FileSpec + /F ZUGFeRDXMLFile + /UF ZUGFeRDXMLFile SimpleUTF16BE + /Desc (ZUGFeRD electronic invoice) + /AFRelationship /Alternative + /EF << + /F {InvoiceStream} + /UF {InvoiceStream} + >> + >> + /PUT pdfmark + + + % Step 4 Create the Associated Files dictionary to hold the FS dict + % Create the dictionary + [ /_objdef {AFArray} /type /array /OBJ pdfmark + + % Put (append) the FS dictionary into the Associated Files array + [ {AFArray} {FSDict} /APPEND pdfmark + + + % Step 5 Add an entry in the Catalog dictionary containing the AF array + [ {Catalog} << /AF {AFArray} >> /PUT pdfmark + + + % Step 6 use the EMBED pdfmark to add the XML file and FS dictionary to the PDF name tree + [ /Name ZUGFeRDXMLFile /FS {FSDict} /EMBED pdfmark + + + % Step 7 Add the extra ZUGFeRD XML data to the Metadata + [ /XML +( + + + + + + + + + ZUGFeRD PDFA Extension Schema + + urn:ferd:pdfa:invoice:rc# + + zf + + + + ! + + + DocumentFileName + Text + external + name of the embedded xml invoice file + + + + DocumentType + Text + external + INVOICE + + + + Version + Text + external + The actual version of the ZUGFeRD data + + + + ConformanceLevel + Text + external + The conformance level of the ZUGFeRD data + + + + + + + + + + INVOICE + ZUGFeRD-invoice.xml + RC + BASIC + +) /Ext_Metadata pdfmark + } + { + % No ICC Profile definition on the command line; chide the user and give them an example + % + (\nERROR - ZUGFeRDProfile has not been supplied, you must supply an ICC profile\n) print + ( Producing a potentially invalid PDF/A file!!\n) print + (example usage - gs --permit-file-read=/usr/home/me/zugferd/ -sDEVICE=pdfwrite -dPDFA=3\\\n) print + ( -sColorConversionStrategy=RGB -sZUGFeRDXMLFile=/usr/home/me/zugferd/invoice.xml\\\n) print + ( -sZUGFeRDProfile=/usr/home/me/rgb.icc -o /usr/home/me/zugferd/zugferd.pdf\\\n) print + ( /usr/home/me/zugferd/zugferd.ps /usr/home/me/zugferd/original.pdf\n\n) print flush + } ifelse +} +{ + % No XML invoice definition on the command line; chide the user and give them an example + % + (\nERROR - ZUGFeRDXMLFile has not been supplied, you must supply an XML invoice file\n) print + ( Producing a PDF/A file not a ZUGFeRD file.\n) print + (example usage - gs --permit-file-read=/usr/home/me/zugferd/ -sDEVICE=pdfwrite -dPDFA=3\\\n) print + ( -sColorConversionStrategy=RGB -sZUGFeRDXMLFile=/usr/home/me/zugferd/invoice.xml\\\n) print + ( -sZUGFeRDProfile=/usr/home/me/rgb.icc -o /usr/home/me/zugferd/zugferd.pdf\\\n) print + ( /usr/home/me/zugferd/zugferd.ps /usr/home/me/zugferd/original.pdf\n\n) print flush +} ifelse + +% That's all the ZUGFeRD and PDF/A-3 setup completed, all that remains now is to run the input file -- cgit v1.2.3