# CairoMakie: Restrict PDF version

**URL:** https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939
**Category:** Visualization
**Tags:** makie, cairomakie
**Created:** [May 7, 2024, 10:27am UTC](https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939 "2024-05-07T10:27:51Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)
#### Post date: [May 7, 2024, 10:27am UTC](https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939/1 "2024-05-07T10:27:51Z")

</div>

I need to restrict the version of output PDFs to 1.5. I didn’t figure out how to do it. I could only find a [Discourse topic](https://discourse.julialang.org/t/pdf-version-used-when-saving-a-figure-in-cairomakie/102282), where it was pointed out that cairo provides a [function to restrict the version](https://www.cairographics.org/manual/cairo-PDF-Surfaces.html#cairo-pdf-surface-restrict-to-version).

I am not familiar with Makie’s codebase and I needed the feature quickly, so I hacked it in the following way. I `]dev`ed Makie, and changed [`surface_from_output_type`](https://github.com/MakieOrg/Makie.jl/blob/99f94fe6ae57a28e1535e77c274737026e46c405/CairoMakie/src/screen.jl#L60) to:

```julia
function surface_from_output_type(type::RenderType, io, w, h)
    # ...
    elseif type === PDF
        surface = Cairo.CairoPDFSurface(io, w, h)
        ccall((:cairo_pdf_surface_restrict_to_version, Cairo.libcairo), Nothing,
          (Ptr{UInt8},Int32), surface.ptr, 1) # 1 means 1.5
        return surface
     # ...
end

```

It worked, but it is obviously not the ideal way. I have two questions:

1. Have I missed an easier way to set the PDF version?
2. If not, can we turn this into a PR (not sure if it belongs to Makie or Cairo.jl) to provide a more convenient way?

---

<div class="post-metadata">

### Author: ![Egwene\_al\_Vere](https://avatars.discourse-cdn.com/v4/letter/e/df788c/32.png) [@Egwene\_al\_Vere](https://discourse.julialang.org/u/Egwene_al_Vere)
#### Post date: [May 9, 2024, 1:30am UTC](https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939/2 "2024-05-09T01:30:38Z")

</div>

Looking to do the same thing, looks like it might be easier to make changes in the `save` [function](https://github.com/MakieOrg/Makie.jl/blob/bbf8e7873b8825244bf94d62ce09a74daec3ea56/src/display.jl#L335), between the `screen = getscreen` and `backend_show` call

```julia
using CairoMakie
using CairoMakie.Makie: FigureLike, current_backend, update_state_before_display!, getscreen, get_scene, filetype, isvisible, backend_show
using CairoMakie.Makie.FileIO

CairoMakie.activate!()

function save_pdf(
    filename::String, fig::FigureLike; args...
)
    save_pdf(FileIO.query(filename), fig; args...)
end

function save_pdf(
    file::FileIO.Formatted, fig::FigureLike;
    size=Base.size(get_scene(fig)),
    resolution=nothing,
    backend=current_backend(),
    update=true,
    pdf_vers=1,
    screen_config...
)
    scene = get_scene(fig)
    if resolution !== nothing
        @warn "The keyword argument `resolution` for `save()` has been deprecated. Use `size` instead, which better reflects that this is a unitless size and not a pixel resolution."
        size = resolution
    end
    if size != Base.size(scene)
        resize!(scene, size)
    end
    filename = FileIO.filename(file)
    # Delete previous file if it exists and query only the file string for type.
    # We overwrite existing files anyway, so this doesn't change the behavior.
    # But otherwise we could get a filetype :UNKNOWN from a corrupt existing file
    # (from an error during save, e.g.), therefore we don't want to rely on the
    # type readout from an existing file.
    isfile(filename) && rm(filename)
    # query the filetype only from the file extension
    F = filetype(file)
    mime = MIME("application/pdf")

    try
        return open(filename, "w") do io
            # If the scene already got displayed, we get the current screen its displayed on
            # Else, we create a new scene and update the state of the fig
            update && update_state_before_display!(fig)
            visible = isvisible(getscreen(scene)) # if already has a screen, don't hide it!
            config = Dict{Symbol,Any}(screen_config)
            get!(config, :visible, visible)
            screen = getscreen(backend, scene, config, io, mime)
            ccall((:cairo_pdf_surface_restrict_to_version, CairoMakie.Cairo.libcairo), Nothing,
                (Ptr{UInt8}, Int32), screen.surface.ptr, pdf_vers)
            backend_show(screen, io, mime, scene)
        end
    catch e
        # So, if open(io-> error(...), "w"), the file will get created, but not removed...
        isfile(filename) && rm(filename; force=true)
        rethrow(e)
    end
end

# ---

begin
    fig = Figure()
    ax = Axis(fig[1, 1])
    x = 0:0.05:pi
    lines!(x, sin.(x))
    fig
end

save_pdf("test2.pdf", fig)

```

gives

```bash
pdfinfo test2.pdf 09:04:35 PM
Producer: cairo 1.18.0 (https://cairographics.org)
CreationDate: Wed May 8 21:09:23 2024 EDT
Custom Metadata: no
Metadata Stream: no
Tagged: no
UserProperties: no
Suspects: no
Form: none
JavaScript: no
Pages: 1
Encrypted: no
Page size: 450 x 338 pts
Page rot: 0
File size: 4071 bytes
Optimized: no
PDF version: 1.5

```

---

<div class="post-metadata">

### Author: ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)
#### Post date: [May 9, 2024, 8:17am UTC](https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939/3 "2024-05-09T08:17:26Z")

</div>

I took some time to look around the codebase and proposed a PR: [CairoMakie: Allow restricting PDF version by barucden · Pull Request #3845 · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/pull/3845)

I am sure the maintainers will have some suggestions but it already allows to do this:

```julia
fig = Figure()
ax = Axis(fig[1, 1])
x = range(0, 10, length=100)
y = sin.(x)
save("version_1-4.pdf", fig, pdf_version="1.4")
save("version_1-7.pdf", fig, pdf_version="1.7")

shell> file version_1-4.pdf
version_1-4.pdf: PDF document, version 1.4, 1 page(s)

shell> file version_1-7.pdf
version_1-7.pdf: PDF document, version 1.7

```

---

<div class="post-metadata">

### Author: ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)
#### Post date: [May 27, 2024, 11:58am UTC](https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939/4 "2024-05-27T11:58:00Z")

</div>

Good news for anyone interested: the feature has been merged ([Restrict pdf version by SimonDanisch · Pull Request #3885 · MakieOrg/Makie.jl · GitHub](https://github.com/MakieOrg/Makie.jl/pull/3885)). It should be a part of the next release, v0.21.3.

---

<div class="post-metadata">

### Author: ![affans](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/affans/32/11911_2.png) [@affans](https://discourse.julialang.org/u/affans)
#### Post date: [May 27, 2024, 1:51pm UTC](https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939/5 "2024-05-27T13:51:05Z")

</div>

@barucden just out of curiosity, did you need to restrict to 1.5 for latex purposes? If so,

```julia
\pdfminorversion=7 % needs to be before the documentclass (i.e. pdf can not be started)

```

in the preamble (or pre-preamble?) should allow you to use later pdf versions.

For example

```julia
\pdfminorversion=7 
\documentclass[aspectratio=1610]{beamer}

```

---

<div class="post-metadata">

### Author: ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)
#### Post date: [May 27, 2024, 2:07pm UTC](https://discourse.julialang.org/t/cairomakie-restrict-pdf-version/113939/6 "2024-05-27T14:07:50Z")

</div>

It was indeed for a figure in a paper written in latex.

I did not know about `\pdfminorversion`. Anyway, I am not sure if the paper is even allowed to be of a version higher than 1.4. I might have tried it. Thanks for letting me know.
