5
$\begingroup$

So...Mathematica broke PDF export on macOS recently (or rather they simply failed to keep up with macOS changes and refused to issue a patch via paclet).

This is a problem, to say the least, since I use tons of PDFs. Moreover who knows when/if I will get v12 so I can't just wait it out.

In the meantime I came up with a hack that involves editing PDFs saved via the Save As... dialog and then programmatically patching the generated file dimensions.

I now want to go further with this and do more PDF edits such as giving them a background image, so is there a clean way to manually patch a PDF file in Mathematica without using Export?

For Reference:

My current patch code looks like this:

openEditPDF[file_, fn_] :=

 Module[{openR, openW, string, patches, exp},
  openR = Check[OpenRead[file], $Failed, OpenRead::noopen];
  If[openR === $Failed,
   $Failed,
   string = ReadString[openR];
   Close[openR];
   openW = OpenWrite[file, BinaryFormat -> True];
   exp = Catch@fn[string];
   If[StringQ@exp,
    WriteString[openW, exp];
    Close[openW];
    file,
    WriteString[openW, string];
    Close[openW];
    $Failed
    ]
   ]
  ]
compilePDFPropReplacement[ass_] :=
  If[AssociationQ@ass,
   KeyValueMap[
    If[ListQ@#2,
      Shortest[(k : ("/" ~~ # ~~ " [") ~~ __ ~~ "]")] :>

       k <> " " <> StringRiffle[#2] <> " ]",
      (k : ("/" ~~ #)) ~~ Except["\n" | "\r"] .. :>

       k <> " " <> #2
      ] &,
    KeyMap[ToString]@ass
    ],
   Throw@$Failed
   ];
compilePDFPropInsertion[ass_] :=
  If[AssociationQ@ass,
   If[Length@ass > 0,
StringRiffle[
  KeyValueMap[
   "   /" <> # <> " " <> #2 &,
   KeyMap[ToString]@ass
   ], 
  "\r"
  ] <> "\r",
""
],
   Throw@$Failed
   ];
compilePDFEditFunction[reps_, inserts_] :=

  With[{baseReps = compilePDFPropReplacement[reps], 
    ins = compilePDFPropInsertion[inserts]},
   If[StringLength[ins] > 0,
    Function@
     StringReplace[
      StringReplace[#, baseReps],
      h : ">>>" ~~ Whitespace ~~ "endobj" :>
       ins <> h,
      1
      ],
    Function@StringReplace[#, baseReps]
    ]
   ];
compilePDFEditFunction[reps_] :=
 compilePDFEditFunction[reps, <||>]
changePDFMargins[pdf_, pageSize : {width_, height_}, 
  margins : {marginL_, marginR_}, padding_] :=
 openEditPDF[
  pdf,
  compilePDFEditFunction@
   <|
    "MediaBox" ->
     Join[
      margins - padding,
      margins + pageSize + padding
      ]
    |>
  ]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.