diff --git a/docs/_layout/masthead.html b/docs/_layout/masthead.html index a8e5492f125..665d52fa67a 100644 --- a/docs/_layout/masthead.html +++ b/docs/_layout/masthead.html @@ -12,6 +12,7 @@
  • Reference
  • Tutorials
  • +
  • How-Tos
  • Explanations
  • API
  • News
  • diff --git a/docs/explanations.md b/docs/explanations.md index 3542f41c3d7..eae0ca075fa 100644 --- a/docs/explanations.md +++ b/docs/explanations.md @@ -1,4 +1,4 @@ -@def order = 3 +@def order = 4 # Explanations diff --git a/docs/how-to.md b/docs/how-to.md new file mode 100644 index 00000000000..9423ac5e16a --- /dev/null +++ b/docs/how-to.md @@ -0,0 +1,5 @@ +@def order = 3 + +# How-Tos + +{{list_folder how-to}} diff --git a/docs/how-to/save-figure-with-transparency.md b/docs/how-to/save-figure-with-transparency.md new file mode 100644 index 00000000000..aec0522f3a1 --- /dev/null +++ b/docs/how-to/save-figure-with-transparency.md @@ -0,0 +1,79 @@ +# How to save a `Figure` with transparency + +## CairoMakie + +In CairoMakie, set the background color to `:transparent` (converts to `RGBAf(0, 0, 0, 0)`) to get a fully transparent background. +In the following examples, I use a partially transparent blue because a transparent background is indistinguishable from the usual white on a white page. + +\begin{examplefigure}{svg = true} +```julia +using CairoMakie +CairoMakie.activate!() # hide + +f = Figure(backgroundcolor = (:blue, 0.4)) +Axis(f[1, 1], backgroundcolor = (:tomato, 0.5)) +f +``` +\end{examplefigure} + +## GLMakie + +For technical reasons, GLMakie's color buffer does not have an alpha component: + +\begin{examplefigure}{} +```julia +using GLMakie +GLMakie.activate!() # hide +Makie.inline!(true) # hide + +f = Figure(backgroundcolor = (:blue, 0.4)) +Axis(f[1, 1], backgroundcolor = (:tomato, 0.5)) +f +``` +\end{examplefigure} + + +With the following trick you can still save an image with transparent background. +It works by setting two different background colors and calculating the foreground color with alpha from the difference. + +```julia:transparent-glmakie +using GLMakie +GLMakie.activate!() # hide +Makie.inline!(true) # hide + +function calculate_rgba(rgb1, rgb2, rgba_bg)::RGBAf + rgb1 == rgb2 && return RGBAf(rgb1.r, rgb1.g, rgb1.b, 1) + c1 = Float64.((rgb1.r, rgb1.g, rgb1.b)) + c2 = Float64.((rgb2.r, rgb2.g, rgb2.b)) + alphas_fg = 1 .+ c1 .- c2 + alpha_fg = clamp(sum(alphas_fg) / 3, 0, 1) + alpha_fg == 0 && return rgba_bg + rgb_fg = clamp.((c1 ./ alpha_fg), 0, 1) + rgb_bg = Float64.((rgba_bg.r, rgba_bg.g, rgba_bg.b)) + alpha_final = alpha_fg + (1 - alpha_fg) * rgba_bg.alpha + rgb_final = @. 1 / alpha_final * (alpha_fg * rgb_fg + (1 - alpha_fg) * rgba_bg.alpha * rgb_bg) + return RGBAf(rgb_final..., alpha_final) +end + +function alpha_colorbuffer(figure) + scene = figure.scene + bg = scene.backgroundcolor[] + scene.backgroundcolor[] = RGBAf(0, 0, 0, 1) + b1 = copy(colorbuffer(scene)) + scene.backgroundcolor[] = RGBAf(1, 1, 1, 1) + b2 = colorbuffer(scene) + scene.backgroundcolor[] = bg + return map(b1, b2) do b1, b2 + calculate_rgba(b1, b2, bg) + end +end + +f = Figure(backgroundcolor = (:blue, 0.4)) +Axis(f[1, 1], backgroundcolor = (:tomato, 0.5)) +f + +save(joinpath(@OUTPUT, "transparent.png"), alpha_colorbuffer(f)) # hide +save("transparent.png", alpha_colorbuffer(f)) +``` + +\fig{transparent.png} \ No newline at end of file diff --git a/src/figures.jl b/src/figures.jl index b7d60ac8c6d..6590571dfec 100644 --- a/src/figures.jl +++ b/src/figures.jl @@ -98,7 +98,7 @@ function Figure(; kwargs...) kwargs_dict = Dict(kwargs) padding = pop!(kwargs_dict, :figure_padding, theme(:figure_padding)) - scene = Scene(; camera=campixel!, kwargs_dict...) + scene = Scene(; camera=campixel!, clear = true, kwargs_dict...) padding = convert(Observable{Any}, padding) alignmode = lift(Outside ∘ to_rectsides, padding)