Skip to content

Commit

Permalink
CairoMakie: Allow restricting PDF version
Browse files Browse the repository at this point in the history
  • Loading branch information
barucden committed May 22, 2024
1 parent f44c4a5 commit fc572a2
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## [Unreleased]
- CairoMakie: Add argument `pdf_version` to restrict the PDF version when saving a figure as a PDF [#3845](https://github.com/MakieOrg/Makie.jl/pull/3845).

## [0.21.0] - 2024-05-21

Expand Down
20 changes: 20 additions & 0 deletions CairoMakie/src/cairo-extension.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,23 @@ function get_render_type(surface::Cairo.CairoSurface)
typ == Cairo.CAIRO_SURFACE_TYPE_IMAGE && return IMAGE
return IMAGE # By default assume that the render type is IMAGE
end

const CAIRO_PDF_VERSION_1_4 = 0
const CAIRO_PDF_VERSION_1_5 = 1
const CAIRO_PDF_VERSION_1_6 = 2
const CAIRO_PDF_VERSION_1_7 = 3

function restrict_pdf_version!(surface::Cairo.CairoSurface, pdf_version::String)
@assert surface.ptr != C_NULL
versions = Dict("1.4" => CAIRO_PDF_VERSION_1_4,
"1.5" => CAIRO_PDF_VERSION_1_5,
"1.6" => CAIRO_PDF_VERSION_1_6,
"1.7" => CAIRO_PDF_VERSION_1_7)
if !haskey(versions, pdf_version)
versionlist = join(sort(collect(keys(versions))), ", ")
throw(ArgumentError("PDF version must be one of $versionlist (received '$pdf_version')"))
end
cairo_pdf_version = versions[pdf_version]
ccall((:cairo_pdf_surface_restrict_to_version, Cairo.libcairo), Nothing,
(Ptr{UInt8},Int32), surface.ptr, cairo_pdf_version)
end
12 changes: 12 additions & 0 deletions CairoMakie/src/screen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,15 @@ to_cairo_antialias(aa::Int) = aa
* `pt_per_unit = 0.75`
* `antialias::Union{Symbol, Int} = :best`: antialias modus Cairo uses to draw. Applicable options: `[:best => Cairo.ANTIALIAS_BEST, :good => Cairo.ANTIALIAS_GOOD, :subpixel => Cairo.ANTIALIAS_SUBPIXEL, :none => Cairo.ANTIALIAS_NONE]`.
* `visible::Bool`: if true, a browser/image viewer will open to display rendered output.
* `pdf_version::String = ""`: the version of output PDFs. Applicable options are `"1.4"`, `"1.5"`, `"1.6"`, `"1.7"`, or the default, `""`, which leaves the PDF version unrestricted.
"""
struct ScreenConfig
px_per_unit::Float64
pt_per_unit::Float64
antialias::Symbol
visible::Bool
start_renderloop::Bool # Only used to satisfy the interface for record using `Screen(...; start_renderloop=false)` for GLMakie
pdf_version::String
end

function device_scaling_factor(rendertype, sc::ScreenConfig)
Expand Down Expand Up @@ -213,6 +215,11 @@ function apply_config!(screen::Screen, config::ScreenConfig)
aa = to_cairo_antialias(config.antialias)
Cairo.set_antialias(context, aa)
set_miter_limit(context, 2.0)

if get_render_type(surface) === PDF && !isempty(config.pdf_version)
restrict_pdf_version!(surface, config.pdf_version)
end

screen.antialias = aa
screen.device_scaling_factor = dsf
screen.config = config
Expand Down Expand Up @@ -285,6 +292,11 @@ function Screen(scene::Scene, config::ScreenConfig, surface::Cairo.CairoSurface)
aa = to_cairo_antialias(config.antialias)
Cairo.set_antialias(ctx, aa)
set_miter_limit(ctx, 2.0)

if get_render_type(surface) === PDF && !isempty(config.pdf_version)
restrict_pdf_version!(surface, config.pdf_version)
end

return Screen{get_render_type(surface)}(scene, surface, ctx, dsf, aa, config.visible, config)
end

Expand Down
26 changes: 26 additions & 0 deletions CairoMakie/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,29 @@ functions = [:volume, :volume!, :uv_mesh]
missing_images, scores = ReferenceTests.record_comparison(recording_dir)
ReferenceTests.test_comparison(scores; threshold = 0.05)
end

@testset "restrict PDF version" begin
magic_number(filename) = open(filename) do f
return String(read(f, sizeof("%PDF-X.Y")))
end

filename = "$(tempname()).pdf"

try
save(filename, Figure(), pdf_version="")
@test startswith(magic_number(filename), "%PDF-")
finally
rm(filename)
end

for version in ["1.4", "1.5", "1.6", "1.7"]
try
save(filename, Figure(), pdf_version=version)
@test magic_number(filename) == "%PDF-$version"
finally
rm(filename)
end
end

@test_throws ArgumentError save(filename, Figure(), pdf_version="foo")
end
10 changes: 10 additions & 0 deletions docs/explanations/backends/cairomakie.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,13 @@ v = rand(10,2)
scatter(v[:,1], v[:,2], rasterize = 10, markersize = 30.0)
```
\end{examplefigure}

#### PDF version

The version of output PDFs can be restricted via the `pdf_version` argument of the screen config. Conveniently, it can be also passed as an argument of the `save` function:
```julia
using CairoMakie
fig = Figure()
# ...
save("figure.pdf", fig, pdf_version="1.4")
```
3 changes: 2 additions & 1 deletion src/theming.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ const MAKIE_DEFAULT_THEME = Attributes(
pt_per_unit = 0.75,
antialias = :best,
visible = true,
start_renderloop = false
start_renderloop = false,
pdf_version = ""
),

GLMakie = Attributes(
Expand Down

0 comments on commit fc572a2

Please sign in to comment.