This is a possible solution that I came up with after looking at another answer by @Ragfield: Encoding format used by GraphicsData?
I had to modify the function decodePICT in that post to cut out the leading zero bytes:
DecodePDF[data_String] :=
Module[{slash, backslash, zero, LF, CR, decode, codes, len,
i}, {slash, backslash, zero, LF, CR} = ToCharacterCode["/\\0\n\r"];
decode[char_] := If[char == slash, backslash - zero, char - zero];
len = Length[codes = ToCharacterCode[data]];
i = 1;
Last@Last@
Reap@While[i <= len - 1,
Which[codes[[i]] == LF || codes[[i]] == CR, i++,
codes[[i]] == backslash, i += 4, True,
Sow@BitAnd[
BitOr[BitShiftLeft[decode[codes[[i]]], 2],
BitShiftRight[decode[codes[[i + 1]]], 4]], 255];
i++;
If[i <= len - 1,
Sow@BitAnd[
BitOr[BitShiftLeft[decode[codes[[i]]], 4],
BitShiftRight[decode[codes[[i + 1]]], 2]], 255]];
i++;
If[i <= len - 1,
Sow@BitAnd[
BitOr[BitShiftLeft[decode[codes[[i]]], 6],
BitShiftRight[decode[codes[[i + 1]]], 0]], 255]];
i += 2;]]];
convertPDF[badPDF_RawBoxes] := Module[
{
str = First@
Cases[InputForm[badPDF], GraphicsData["PDF", dat_] :> dat,
Infinity],
out = "/tmp/MathematicaOutput.pdf"
},
Export[out, DecodePDF[str], "Binary"];
First@Import[out]
]
Now if you type
convertPDF[ ]
and paste the externally generated PDF into the space above, then the result will be the "fixed" PDF which satisfies both requirements: it looks smooth and it can be exported as usual, with no apparent problem.
The next step is to put this into a Palette again. I'll do that after testing this approach some more (unless someone comes up with a better idea).
Edit
The above was exposition to explain what I did; you don't need to copy that code
Here is the final result: a Palette that implements the above conversion for a PDF on the clipboard. It's a drop-in replacement for the Palette I posted in the question, but it doesn't require python and it doesn't run any external commands. It's also faster than the python-based conversion:
CreatePalette[Column[{Button["Convert PDF on clipboard",
Module[
{
str,
out = "/tmp/MathematicaOutput.pdf",
decodePDF
},
decodePDF[data_String] :=
Module[{slash, backslash, zero, LF, CR, decode, codes, len,
i}, {slash, backslash, zero, LF, CR} =
ToCharacterCode["/\\0\n\r"];
decode[char_] :=
If[char == slash, backslash - zero, char - zero];
len = Length[codes = ToCharacterCode[data]];
i = 1;
Last@
Last@Reap@
While[i <= len - 1,
Which[codes[[i]] == LF || codes[[i]] == CR, i++,
codes[[i]] == backslash, i += 4, True,
Sow@BitAnd[
BitOr[BitShiftLeft[decode[codes[[i]]], 2],
BitShiftRight[decode[codes[[i + 1]]], 4]], 255];
i++;
If[i <= len - 1,
Sow@BitAnd[
BitOr[BitShiftLeft[decode[codes[[i]]], 4],
BitShiftRight[decode[codes[[i + 1]]], 2]], 255]];
i++;
If[i <= len - 1,
Sow@BitAnd[
BitOr[BitShiftLeft[decode[codes[[i]]], 6],
BitShiftRight[decode[codes[[i + 1]]], 0]], 255]];
i += 2;]]];
str = First@Append[
Cases[NotebookGet[
ClipboardNotebook[]],
GraphicsData["PDF", dat_] :> dat, Infinity], ""]
;
CopyToClipboard[
If[str =!= "",
Export[out, decodePDF[str], "Binary"];
First@Import[out],
"No PDF"
]
];
], Appearance -> "Palette"],
"Click before pasting externally generated PDF"}],
WindowTitle -> "Convert External PDF"];
There are some things that don't work correctly with this PDF conversion, but that was the same in my original approach: when copying from multipage PDF documents, some color and background information can be lost. However, the main reason why PDF copy and paste on the Mac is nice (as opposed to bitmaps which are always a viable alternative) is that it produces resolution independent outlines for fonts, lines and shapes - and those properties are definitely preserved with this Palette.
Edit 2
The remaining problems mentioned above imply that this solution doesn't produce a better outcome than my original one, but this answer does run faster because it doesn't have to initialize python and the AppKit module every time.
To fix the problems that remain, I have always been using an additional intermediate step that uses ghostscript. The Mac Application for this is called FontBegone and can be downloaded from my web site. It requires ghostscript, which can be obtained conveniently as part of a $\TeX$ installation.
With this, my personal workflow for copying PDF is: highlight the desired crop area in Skim and copy. Tap the FontBegone icon, then tap the button for the Palette in this answer. Now paste into Mathematica, and you're done.
Having this ability to paste PDF into a notebook completes the circle in a workflow that is quite unique to Mac OS X. The other half of the circle is the ability to copy as PDF from Mathematica into other applications such as LyX to create $\LaTeX$ documents with vector graphics produced in Mathematica (see this answer). We can move PDF graphics around freely in both directions via the clipboard.
More discussion (currently based on my original solution) can be found here.
PDFon other systems, then my guess would be that pastedPDFs should also be visible there. But I've never checked to make sure... – Jens Dec 23 '12 at 18:20