summaryrefslogtreecommitdiff
path: root/support/latexmk/example_rcfiles/hyperxmp-latexmkrc
diff options
context:
space:
mode:
Diffstat (limited to 'support/latexmk/example_rcfiles/hyperxmp-latexmkrc')
-rw-r--r--support/latexmk/example_rcfiles/hyperxmp-latexmkrc200
1 files changed, 200 insertions, 0 deletions
diff --git a/support/latexmk/example_rcfiles/hyperxmp-latexmkrc b/support/latexmk/example_rcfiles/hyperxmp-latexmkrc
new file mode 100644
index 0000000000..e0a80a7f40
--- /dev/null
+++ b/support/latexmk/example_rcfiles/hyperxmp-latexmkrc
@@ -0,0 +1,200 @@
+# Configuration of latexmk so that it works with the hyperxmp package.
+# Hyperxmp puts document xmp metadata in the pdf file, and one of the
+# fields in that metadata is byteCount, which is the size of the pdf file.
+# This configuration ensures that the byteCount is present and correctly
+# equals the pdf file's size.
+#
+# Method of operation:
+# For any command that might produce a pdf file, prepend "internal mycmd3 "
+# to the previously configured command, so that a subroutine mycmd3 is
+# called. It runs the expected command and then does post-processing if
+# the output file is a pdf file.
+
+foreach my $cmd ( "latex", "lualatex", "pdflatex", "xelatex",
+ "dvipdf", "xdvipdfmx", "ps2pdf" ) {
+ ${$cmd} = "internal mycmd ${$cmd}";
+}
+
+#======================================================
+
+sub mycmd {
+ # Run command, and do extra processing of output file, if it is a pdf
+ # file.
+ # This subroutine is run in a rule context, so that $rule is the name of
+ # the rule and $$Pdest is the destination file name.
+
+ # Identification string for messages:
+ local $name = "$My_name.mycmd";
+
+ my $retval = system @_;
+
+ if ( $$Pdest =~ /\.pdf$/ ) {
+ fix_pdf( $$Pdest );
+ }
+ return $retval;
+}
+
+#======================================================
+
+sub fix_pdf {
+ # Change/insert byteCount field with correct file length, while preserving
+ # the file size and the length of the stream containing xmp metadata.
+ # Return 1 on success, else 0.
+
+ local $pdf_name = shift;
+ local $tmp_name = "$pdf_name.new.pdf";
+ local $pdf_size = (stat($pdf_name))[7];
+ warn "Inserting/correcting byteCount field in '$pdf_name' ...\n";
+
+ # Strings surrounding (and identifying) the byteCount field, and other
+ # parts of the xmp packet:
+ local $xmp_start = '<x:xmpmeta xmlns:x="adobe:ns:meta/">';
+ local $decl_bC = '<pdfaProperty:name>byteCount</pdfaProperty:name>';
+ local $pre_bC = '<prism:byteCount>';
+ local $post_bC = '</prism:byteCount>';
+ local $pC = '<prism:pageCount>';
+ local $rd_end = '</rdf:Description>';
+ local $xmp_end = '</x:xmpmeta>';
+
+ local *PDF;
+ local *TMP;
+
+ if (! open PDF, "<", $pdf_name ) {
+ warn " Cannot read '$pdf_name'\n";
+ return 0;
+ }
+ if ( ! open TMP, ">", $tmp_name ) {
+ warn " Cannot write temporary file '$tmp_name'\n";
+ close PDF;
+ return 0;
+ }
+ local $status = 0; # 0 = no XMP packet, 1 = success, >= errors
+ while ( <PDF> ) {
+ # Only examine first XMP packet:
+ if ( ($status == 0) && /^\s*\Q$xmp_start\E/ ) {
+ local @xmp = $_;
+ local $len_padding = 0;
+ local $xmp_after_line = '';
+ &xmp_get_mod;
+ print TMP @xmp;
+ # Insert correct padding to leave file size unchanged:
+ while ( $len_padding > 0 ) {
+ my $len_line = 64;
+ if ( $len_line > $len_padding ) { $len_line = $len_padding; }
+ $len_padding -= $len_line;
+ print TMP (' ' x ($len_line - 1) ), "\n";
+ }
+ print TMP $xmp_after_line;
+ $xmp_after_line = '';
+ }
+ else {
+ print TMP "$_";
+ }
+ }
+ close PDF;
+ close TMP;
+
+ if ($status == 0) {
+ warn " Could not insert/modify byteCount, since no XMP packet was found.\n";
+ warn " So '$pdf_name' is unchanged,\n",
+ " and I will delete temporary file '$tmp_name'.\n";
+ unlink $tmp_name;
+ } elsif ($status == 1) {
+ rename $tmp_name, $pdf_name
+ or die " Cannot move temporary file '$tmp_name' to '$pdf_name'.\n",
+ " Error is '$!'\n";
+ } else {
+ warn " Could not insert correct byteCount. See above for reason.\n";
+ warn " So '$pdf_name' is unchanged,\n",
+ " and I will delete temporary file '$tmp_name'.\n";
+ unlink $tmp_name;
+ }
+ return ($status == 1);
+}
+
+#======================================================
+
+sub xmp_get_mod {
+ # Get xmp packet, given that @xmp contains its first line.
+ # Get amount of trailing padding, and line after that.
+ # If possible, insert a byteCount field:
+ # Either replace existing specification, if it exists,
+ # or insert one in expected place for hyperxmp, if the XMP packet
+ # matches what hyperxmp would produce.
+ # Return xmp packet in @xmp, amount of padding needed in $len_padding,
+ # line after that in $xmp_after_line, and error code in $error.
+ # Set $status appropriately: 1 for success; >=1 for failure.
+
+ $len_padding = 0;
+ $xmp_after_line = '';
+
+ my $bC_index = -1;
+ my $xmp_end_found = 0;
+ my $decl_bC_found = 0;
+ while ( <PDF> ) {
+ push @xmp, $_;
+ if ( /^\s*\Q$xmp_end\E/ ) {
+ $xmp_end_found = 1;
+ # Get amount of padding;
+ while (<PDF>) {
+ if ( /^\s*$/ ) {
+ $len_padding += length($_);
+ } else {
+ $xmp_after_line = $_;
+ last;
+ }
+ }
+ last;
+ }
+ elsif ( $bC_index >= 0 ){
+ next;
+ }
+ # Rest of conditions only apply if no place yet found for byteCount
+ # specification.
+ elsif ( /^(\s*)\Q$pre_bC\E.*?\Q$post_bC\E\s*$/ ) {
+ $bC_index = $#xmp;
+ }
+ elsif ( /^\s*\Q$decl_bC\E/ ) {
+ $decl_bC_found = 1;
+ }
+ elsif ( /^(\s*)\Q$rd_end\E/ ){
+ # End of rdf:Description block.
+ # So having previous declaration of byteCount is irrelevant.
+ $decl_bC_found = 0;
+ }
+ elsif ( $decl_bC_found && /^(\s*)\Q$pC\E/ ){
+ $bC_index = $#xmp;
+ pop @xmp;
+ push @xmp, '', $_;
+ }
+
+ } # End reading of XMP
+
+ if ($bC_index < 0) {
+ if ( ! $xmp_end_found ) {
+ warn " End of XMP packet not found.\n";
+ $status = 2;
+ }
+ elsif ( ! $decl_bC_found ) {
+ warn " XMP packet not in appropriate hyperxmp-compatible format.\n";
+ $status = 3;
+ }
+ return;
+ }
+ my $new_line = ' ' . $pre_bC . $pdf_size . $post_bC . "\n";
+ my $old_line = $xmp[$bC_index];
+ my $delta_len = length($new_line) - length($old_line);
+ if ($delta_len > $len_padding) {
+ warn " Cannot get padding correct for '$pdf_name'.\n",
+ " Length change of bC line = $delta_len; ",
+ " Padding bytes available = $len_padding.\n";
+ $status = 4;
+ return;
+ } else {
+ $len_padding -= $delta_len;
+ $xmp[$bC_index] = $new_line;
+ $status = 1;
+ }
+}
+
+#======================================================