diff --git a/src/rendering/pdf_utils.jl b/src/rendering/pdf_utils.jl index 5e88280..93737e1 100644 --- a/src/rendering/pdf_utils.jl +++ b/src/rendering/pdf_utils.jl @@ -144,4 +144,45 @@ Crop a PDF file using Ghostscript. This alters the crop box but does not actually remove elements. """ function crop_pdf(path::String; margin = _PDFCROP_DEFAULT_MARGINS[]) + # if pdf_num_pages("temp.pdf") > 1 + # @warn("The PDF has more than 1 page! Choosing the first page.") + # end + + # Generate the cropping margins + bbox = get_pdf_bbox(path) + crop_box = ( + bbox[1] - margin[1], + bbox[2] - margin[2], + bbox[3] + margin[3], + bbox[4] + margin[4] + ) + crop_cmd = join(crop_box, " ") + + + out = Pipe() + err = Pipe() + try + redirect_stderr(err) do + redirect_stdout(out) do + Ghostscript_jll.gs() do gs_exe + run(`$gs_exe -o temp_cropped.pdf -sDEVICE=pdfwrite -c "[/CropBox [$crop_cmd]" -c "/PAGES pdfmark" -f $path`) + end + end + end + catch e + finally + close(out.in) + close(err.in) + if !isfile("temp_cropped.pdf") + println("`gs` failed to crop the PDF!") + println("Files in temp directory are:\n" * join(readdir(), ',')) + printstyled("Stdout\n", bold=true, color = :blue) + println(read(out, String)) + printstyled("Stderr\n", bold=true, color = :red) + println(read(err, String)) + error() + end + end + + return isfile("temp_cropped.pdf") ? read("temp_cropped.pdf", String) : read(path, String) end diff --git a/src/rendering/tex.jl b/src/rendering/tex.jl index 8ad3aac..580800b 100644 --- a/src/rendering/tex.jl +++ b/src/rendering/tex.jl @@ -29,6 +29,7 @@ function compile_latex( # First, create the tex file and write the document to it. touch("temp.tex") + path = "temp.pdf" file = open("temp.tex", "w") print(file, document) close(file) @@ -48,8 +49,8 @@ function compile_latex( suc = success(latex) close(out.in) close(err.in) - if !isfile("temp.pdf") - println("Latex did not write temp.pdf! Using the $(tex_engine) engine.") + if !isfile(path) + println("Latex did not write $(path)! Using the $(tex_engine) engine.") println("Files in temp directory are:\n" * join(readdir(), ',')) printstyled("Stdout\n", bold=true, color = :blue) println(read(out, String)) @@ -58,47 +59,7 @@ function compile_latex( error() end finally - - # if pdf_num_pages("temp.pdf") > 1 - # @warn("The PDF has more than 1 page! Choosing the first page.") - # end - - # Generate the cropping margins - bbox = get_pdf_bbox("temp.pdf") - crop_box = ( - bbox[1] - _PDFCROP_DEFAULT_MARGINS[][1], - bbox[2] - _PDFCROP_DEFAULT_MARGINS[][2], - bbox[3] + _PDFCROP_DEFAULT_MARGINS[][3], - bbox[4] + _PDFCROP_DEFAULT_MARGINS[][4], - ) - crop_cmd = join(crop_box, " ") - - - out = Pipe() - err = Pipe() - try - redirect_stderr(err) do - redirect_stdout(out) do - Ghostscript_jll.gs() do gs_exe - run(`$gs_exe -o temp_cropped.pdf -sDEVICE=pdfwrite -c "[/CropBox [$crop_cmd]" -c "/PAGES pdfmark" -f temp.pdf`) - end - end - end - catch e - finally - close(out.in) - close(err.in) - if !isfile("temp_cropped.pdf") - println("`gs` failed to crop the PDF!") - println("Files in temp directory are:\n" * join(readdir(), ',')) - printstyled("Stdout\n", bold=true, color = :blue) - println(read(out, String)) - printstyled("Stderr\n", bold=true, color = :red) - println(read(err, String)) - error() - end - end - return isfile("temp_cropped.pdf") ? read("temp_cropped.pdf", String) : read("temp.pdf", String) + return crop_pdf(path) end end end diff --git a/src/rendering/typst.jl b/src/rendering/typst.jl index 6d54a25..2df9acf 100644 --- a/src/rendering/typst.jl +++ b/src/rendering/typst.jl @@ -27,6 +27,7 @@ function compile_typst(document::AbstractString) # First, create the typst file and write the document to it. touch("temp.typ") file = open("temp.typ", "w") + path = "temp.pdf" print(file, document) close(file) @@ -43,8 +44,8 @@ function compile_typst(document::AbstractString) close(out.in) close(err.in) - if !isfile("temp.pdf") - println("Typst did not write temp.pdf! Using Typst_jll.jl.") + if !isfile(path) + println("Typst did not write $(path)! Using Typst_jll.jl.") println("Files in temp directory are:\n" * join(readdir(), ',')) printstyled("Stdout\n", bold=true, color = :blue) println(read(out, String)) @@ -53,47 +54,7 @@ function compile_typst(document::AbstractString) error() end finally - - # if pdf_num_pages("temp.pdf") > 1 - # @warn("The PDF has more than 1 page! Choosing the first page.") - # end - - # Generate the cropping margins - bbox = get_pdf_bbox("temp.pdf") - crop_box = ( - bbox[1] - _PDFCROP_DEFAULT_MARGINS[][1], - bbox[2] - _PDFCROP_DEFAULT_MARGINS[][2], - bbox[3] + _PDFCROP_DEFAULT_MARGINS[][3], - bbox[4] + _PDFCROP_DEFAULT_MARGINS[][4], - ) - crop_cmd = join(crop_box, " ") - - - out = Pipe() - err = Pipe() - try - redirect_stderr(err) do - redirect_stdout(out) do - Ghostscript_jll.gs() do gs_exe - run(`$gs_exe -o temp_cropped.pdf -sDEVICE=pdfwrite -c "[/CropBox [$crop_cmd]" -c "/PAGES pdfmark" -f temp.pdf`) - end - end - end - catch e - finally - close(out.in) - close(err.in) - if !isfile("temp_cropped.pdf") - println("`gs` failed to crop the PDF!") - println("Files in temp directory are:\n" * join(readdir(), ',')) - printstyled("Stdout\n", bold=true, color = :blue) - println(read(out, String)) - printstyled("Stderr\n", bold=true, color = :red) - println(read(err, String)) - error() - end - end - return isfile("temp_cropped.pdf") ? read("temp_cropped.pdf", String) : read("temp.pdf", String) + return crop_pdf(path) end end end diff --git a/src/types.jl b/src/types.jl index 98f79c9..59060c5 100644 --- a/src/types.jl +++ b/src/types.jl @@ -450,23 +450,7 @@ $(FIELDS) It is also possible to manually construct a `CachedTEX` with `nothing` in the `doc` field, if you just want to insert a pre-rendered PDF into your figure. """ -function CachedTEX(doc::TEXDocument; kwargs...) - - pdf = Vector{UInt8}(latex2pdf(convert(String, doc); kwargs...)) - ptr = load_pdf(pdf) - surf = page2recordsurf(ptr, doc.page) - dims = (pdf_get_page_size(ptr, doc.page)) - - ct = CachedTEX( - doc, - pdf, - Ref(ptr), - surf, - dims# .+ (1, 1), - ) - - return ct -end +CachedTEX(doc::TEXDocument; kwargs...) = cached_doc(CachedTEX, latex2pdf, doc; kwargs...) function CachedTEX(str::String; kwargs...) return CachedTEX(implant_text(str); kwargs...) @@ -481,20 +465,7 @@ function CachedTEX(x::LaTeXString; kwargs...) end end -function CachedTEX(pdf::Vector{UInt8}; kwargs...) - ptr = load_pdf(pdf) - surf = firstpage2recordsurf(ptr) - dims = pdf_get_page_size(ptr, 0) - - ct = CachedTEX( - nothing, - pdf, - Ref(ptr), - surf, - dims# .+ (1, 1), - ) - return ct -end +CachedTEX(pdf::Vector{UInt8}; kwargs...) = cached_pdf(CachedTEX, pdf; kwargs...) # do not rerun the pipeline on CachedTEX CachedTEX(ct::CachedTEX) = ct @@ -533,13 +504,24 @@ $(FIELDS) It is also possible to manually construct a `CachedTypst` with `nothing` in the `doc` field, if you just want to insert a pre-rendered PDF into your figure. """ -function CachedTypst(doc::TypstDocument) - pdf = Vector{UInt8}(typst2pdf(convert(String, doc))) +CachedTypst(doc::TypstDocument) = cached_doc(CachedTypst, typst2pdf, doc) + +function CachedTypst(str::Union{String, TypstString}; kwargs...) + CachedTypst(TypstDocument(str); kwargs...) +end + +CachedTypst(pdf::Vector{UInt8}; kwargs...) = cached_pdf(CachedTypst, pdf; kwargs...) + +# do not rerun the pipeline on CachedTypst +CachedTypst(ct::CachedTypst) = ct + +function cached_doc(T, f, doc; kwargs...) + pdf = Vector{UInt8}(f(convert(String, doc); kwargs...)) ptr = load_pdf(pdf) surf = page2recordsurf(ptr, doc.page) dims = (pdf_get_page_size(ptr, doc.page)) - ct = CachedTypst( + ct = T( doc, pdf, Ref(ptr), @@ -550,16 +532,12 @@ function CachedTypst(doc::TypstDocument) return ct end -function CachedTypst(str::Union{String, TypstString}; kwargs...) - CachedTypst(TypstDocument(str); kwargs...) -end - -function CachedTypst(pdf::Vector{UInt8}; kwargs...) +function cached_pdf(T, pdf; kwargs...) ptr = load_pdf(pdf) surf = firstpage2recordsurf(ptr) dims = pdf_get_page_size(ptr, 0) - ct = CachedTypst( + ct = T( nothing, pdf, Ref(ptr), @@ -569,9 +547,6 @@ function CachedTypst(pdf::Vector{UInt8}; kwargs...) return ct end -# do not rerun the pipeline on CachedTypst -CachedTypst(ct::CachedTypst) = ct - function update_handle!(ct::Union{CachedTEX, CachedTypst}) ct.ptr[] = load_pdf(ct.pdf) return ct.ptr[] @@ -580,25 +555,18 @@ end Base.convert(::Type{CachedPDF}, ct::Union{CachedTEX, CachedTypst}) = CachedPDF(PDFDocument(String(deepcopy(ct.pdf)), ct.doc.page), ct.ptr, ct.dims, ct.surf, Ref{Tuple{Matrix{ARGB32}, Float64}}((Matrix{ARGB32}(undef, 0, 0), 0))) Base.convert(::Type{PDFDocument}, ct::Union{CachedTEX, CachedTypst}) = PDFDocument(String(deepcopy(ct.pdf)), ct.doc.page) -function Base.show(io::IO, ct::CachedTEX) +function _show(io, ct, x, y) if isnothing(ct.doc) - println(io, "CachedTEX(no document, $(ct.ptr), $(ct.dims))") + println(io, x, "(no document, $(ct.ptr), $(ct.dims))") elseif length(ct.doc.contents) > 1000 - println(io, "CachedTEX(TexDocument(...), $(ct.ptr), $(ct.dims))") + println(io, x, "(", y, "(...), $(ct.ptr), $(ct.dims))") else - println(io, "CachedTEX($(ct.doc), $(ct.ptr), $(ct.dims))") + println(io, x, "($(ct.doc), $(ct.ptr), $(ct.dims))") end end -function Base.show(io::IO, ct::CachedTypst) - if isnothing(ct.doc) - println(io, "CachedTypst(no document, $(ct.ptr), $(ct.dims))") - elseif length(ct.doc.contents) > 1000 - println(io, "CachedTypst(TypstDocument(...), $(ct.ptr), $(ct.dims))") - else - println(io, "CachedTypst($(ct.doc), $(ct.ptr), $(ct.dims))") - end -end +Base.show(io::IO, ct::CachedTEX) = _show(io, ct, "CachedTEX", "TEXDocument") +Base.show(io::IO, ct::CachedTypst) = _show(io, ct, "CachedTypst", "TypstDocument") function implant_math(str) return TEXDocument(