Mathematica

I have been using Mathemtica to write notes. It’s really convenient to use notebook files because we can write program, formular, figures and text in one file. However, not everyone uses Mathematica, If we want to share our notes with others, exporting nb files into pdf format is necessary.

In default, the generated pdf by Mathematica is relatively simple, and there is no TOC or bookmarks in the generated pdf files. It will be very inconvenient to read if the notes are very long. I have searched on stack exchange, but it seems that there is no existing good solution. According to the question, may be we can save the nb files into tex format and then compile it into pdf, but (according to my experience) problem exists when the nb file is long and the formular is complicated.

Finally, I myself try to add bookmarks mannually. I use python to process the generated pdf files, what I want to realize can be summarized as follows:

  • Using Mathematica: For a long notebook file, we directly generate the pdf files (pdf file 1)
  • Using Mathematica: Then I will extract the chapter/section information and generate a pdf file (pdf file 2) containing the table of contents (with suitable pdf page numbers)
  • Using Python:Finally, I will use python to merge the two pdfs into pdf file 3 and add bookmarks into this merged pdf (pdf file 3).

It seems that the above process is cumbersome, but it can be automated by the program, and the operation is very simple. I will show an example:

Assuming that the notebook file to be processed is test.nb, then in Mathematica

(1) we just need run the following program to generate the helping files

1
2
3
4
5
6
(*The notebook directory*)
fileDir =
"./";
(*The notebook file*)
fileNb = "test.nb";
GenTOCtoPDFTZH[fileDir, fileNb];

NOTES:

By runing above Mathematica program, two pdf files will be generated (pdf file 1, pdf file 2). Extra txt file names test.txt is also generated. In this txt file, information about the TOC are saved.

(2)then we use the corresponding python program (see appendix II) to generate the final pdf files.

If you don’t want to install python, I have also written a program with simple GUI and compiled it into Exe format. This can be directly run on windows. Original code can be found on this

the final pdf files will have toc and bookmarks:

However, by using python, the original links in PDF will be lost, so you can’t jump into certain page by clicking the links, this is the problem of the python package PyPDF2.

Appendix

the Mathematica function

modefied from the question

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
*helper file for creating cell*)
createCell[text_,tag_,level_]:=Cell[BoxData[TagBox[GridBox[{{"",text,CounterBox["Page",{bookUrl,tag}]}},GridBoxAlignment->{"Columns"->{Left,Left,Right}},GridBoxItemSize->{"Columns"->{2 level-1,35-2 level,5}}],"Grid"]],"Text",FontColor->Blue];
(*helper file for creating cell version II*)
createCellPy[text_,tag_,level_]:=Cell[BoxData[TagBox[GridBox[{{"",text,";",level,";",CounterBox["Page",{bookUrl,tag}],";"}},GridBoxAlignment->{"Columns"->{Left,Left,Left,Left,Right}},GridBoxItemSize->{"Columns"->{2 level-1,35-2 level,5}}],"Grid"]],"Text"];
GenTOCtoPDFTZH[fileDir_,fileNb_]:=Block[{typeList,filepdf,filepdfToc,filetxt,bookUrl,tocPDF,tocPy,book,fexp},
typeList={"Section","Subsection"};

filepdf=StringReplace[fileNb,".nb"->".pdf"];
filepdfToc=StringReplace[fileNb,".nb"->"Toc.pdf"];
filetxt=StringReplace[fileNb,".nb"->".txt"];
bookUrl=FileNameJoin[{fileDir,fileNb}];
SetDirectory[fileDir];
tocPDF=CreateDocument[];
SelectionMove[tocPDF,Before,Notebook];
NotebookWrite[tocPDF,Cell["目录","Text",20,Blue]];

tocPy=CreateDocument[];
book=NotebookOpen[bookUrl];
SetOptions[book,ShowPageBreaks->True];
(*iterate over cells to set tags and write lines to TOC*)
Scan[(counter[#]=0)&,typeList];
SelectionMove[book,Before,Notebook];
SelectionMove[book,Next,Cell];
While[(cell=NotebookRead[book])=!={},If[Length[cell]>=2,type=cell[[2]];
If[MemberQ[typeList,type],counter[type]+=1;
tag=type<>ToString[counter[type]];
SetOptions[NotebookSelection[book],CellTags->Union[Flatten[{Options[NotebookSelection[book],CellTags][[1,2]],tag}]]];
SelectionMove[book,All,CellContents];
NotebookWrite[tocPDF,createCell[NotebookRead[book],tag,Position[typeList,type][[1,1]]]];

NotebookWrite[tocPy,createCellPy[NotebookRead[book],tag,Position[typeList,type][[1,1]]]]];];
SelectionMove[book,Next,Cell]];
(*存储为txt文件*)
fexp=FileNameJoin[{fileDir,filetxt}];
FrontEndExecute[FrontEndToken[tocPy,"Save",{fexp,"Text"}]];
(*存储笔记本文件为pdf文件供Python使用*)
fexp=FileNameJoin[{fileDir,filepdf}];
Export[fexp,book];
(*存储目录文件为pdf文件供Python使用*)
fexp=FileNameJoin[{fileDir,filepdfToc}];
Export[fexp,tocPDF];
(*关闭所有*)
NotebookClose[book];
NotebookClose[tocPDF];
NotebookClose[tocPy];]
(*(*复制目录到目标笔记本*)
SelectionMove[tocPDF,All,Notebook];
data=NotebookRead[tocPDF];
SelectionMove[book,Before,Notebook];
NotebookWrite[book,Cell["目录","Text",20,Blue]];
NotebookWrite[book,NotebookRead[tocPDF]];*)
(*存储为txt文件供Python使用*)

Python program to generate TOC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# we set the file name to be processed
dir='./'
fileName='test'
dele=0 # 0代表删除,1代表不删除

from PyPDF2 import PdfReader, PdfWriter
import os
import sys
#sys.path.insert(1, '') # 为了可以让python将当前文件夹加入环境变量

os.chdir(dir)



filetxt=fileName+'.txt'
filepdf=fileName+'.pdf'
filepdfTOC=fileName+'Toc.pdf'
filepdfout=fileName+'WithToc.pdf'

# read lines from txt
with open(filetxt,'r',encoding='utf-8') as f:
lines = f.read().split(";")


numlines=int(len(lines)/3)

tit_list=[]
level_list=[]
page_list=[]
for l in range(numlines):
tit_list.append(lines[3*l].replace("\t", "").replace("\n", ""))
level_list.append(lines[3*l+1].replace("\t", "").replace("\n", ""))
page_list.append(lines[3*l+2].replace("\t", "").replace("\n", ""))

#print(tit_list)
#print(level_list)
#print(page_list)


# generate bookmarks

reader_Main = PdfReader(filepdf) # open input
reader_Toc = PdfReader(filepdfTOC) # open input
writer = PdfWriter() # open output

n_Main = len(reader_Main.pages)
n_Toc = len(reader_Toc.pages)

for i in range(n_Toc):
writer.add_page(reader_Toc.pages[i]) # insert page of TOC

for i in range(n_Main):
writer.add_page(reader_Main.pages[i]) # insert page of Main

for l in range(numlines):
if level_list[l]=="1":
par=writer.add_outline_item(tit_list[l], int(page_list[l]), parent=None)
elif level_list[l]=="2":
writer.add_outline_item(tit_list[l], int(page_list[l]), parent=par)

with open(filepdfout, "wb") as fp: # creating result pdf JCT
writer.write(fp) # writing to result pdf JCT

if dele==0:
# Delete the mid files
os.remove(filepdf)
os.remove(filepdfTOC)
os.remove(filetxt)