From 3db3aed2b5c95257d1d59b8898c6144be7b1109f Mon Sep 17 00:00:00 2001 From: matthijscox-asml Date: Wed, 16 Oct 2024 09:52:03 +0200 Subject: [PATCH 1/4] added fontsize, refactored text style --- Project.toml | 5 +- docs/src/index.md | 12 ++++- src/PPTX.jl | 2 +- src/Picture.jl | 5 +- src/Tables.jl | 12 +++-- src/TextBox.jl | 99 +++++++++++++++++++++++++++++++--------- test/runtests.jl | 7 ++- test/testConstructors.jl | 14 ++++++ test/testSlideXML.jl | 7 +++ 9 files changed, 129 insertions(+), 34 deletions(-) diff --git a/Project.toml b/Project.toml index bbb8a7a..a158948 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PPTX" uuid = "14a86994-10a4-4a7d-b9ad-ef6f3b1fac6a" authors = ["Xander de Vries", "Matthijs Cox"] -version = "0.8.1" +version = "0.9.0" [deps] DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" @@ -30,6 +30,7 @@ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TestSetExtensions = "98d24dd4-01ad-11ea-1b02-c9a08f80db04" p7zip_jll = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" [targets] -test = ["DataFrames", "Test", "TestSetExtensions", "p7zip_jll"] +test = ["DataFrames", "Test", "TestSetExtensions", "p7zip_jll", "Documenter"] diff --git a/docs/src/index.md b/docs/src/index.md index 3a09a19..b867171 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -26,7 +26,11 @@ pres = Presentation(; title="My First PowerPoint") s2 = Slide(; title="My First Slide") text = TextBox(; content="hello world!", offset_x=100, offset_y=100, size_x=150, size_y=20) push!(s2, text) -text2 = TextBox(; content="here we are again", offset_x=100, offset_y=120, size_x=150, size_y=20) +text2 = TextBox(; + content="here we are again", + offset_x=100, offset_y=120, size_x=150, size_y=20, + style=(italic=true, fontsize=16) +) push!(s2, text2) push!(pres, s2) @@ -50,7 +54,11 @@ push!(s4, my_table) push!(pres, s4) # and what about a nice link in slide 2 to the table-slide -text = TextBox(; content="Click here to see a nice table", offset_x=100, offset_y=140, size_x=150, size_y=20, hlink = s4) +text = TextBox(; + content="Click here to see a nice table", + offset_x=100, offset_y=140, size_x=150, size_y=20, + hlink = s4 # link to slide 4 +) push!(s2, text) pres diff --git a/src/PPTX.jl b/src/PPTX.jl index 2db23e6..653f541 100644 --- a/src/PPTX.jl +++ b/src/PPTX.jl @@ -10,7 +10,7 @@ using ZipArchives: import Tables import Tables: columns, columnnames, rows -export Presentation, Slide, TextBox, Picture, Table +export Presentation, Slide, TextBox, TextStyle, Picture, Table include("AbstractShape.jl") include("constants.jl") diff --git a/src/Picture.jl b/src/Picture.jl index 9997e4a..9a1e296 100644 --- a/src/Picture.jl +++ b/src/Picture.jl @@ -56,8 +56,9 @@ function Picture( source::String; top::Real=0, left::Real=0, - offset_x::Real=left, - offset_y::Real=top, + offset=(left, top), + offset_x::Real=offset[1], + offset_y::Real=offset[2], size::Real=40, size_x::Real=size, size_y::Union{Nothing, Real}=nothing, diff --git a/src/Tables.jl b/src/Tables.jl index 23cb3cf..81f66fd 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -29,7 +29,7 @@ julia> df = DataFrame(a = [1,2], b = [3,4], c = [5,6]) julia> t = Table(content=df, size_x=30) Table - content isa DataFrames.DataFrame + content isa DataFrame offset_x is 1800000 EMUs offset_y is 1800000 EMUs size_x is 1080000 EMUs @@ -67,10 +67,12 @@ end # keyword argument constructor function Table(; content, - offset_x::Real=50, # millimeters - offset_y::Real=50, # millimeters - size_x::Real=150, # millimeters - size_y::Real=100, # millimeters + offset=(50,50), + offset_x::Real=offset[1], # millimeters + offset_y::Real=offset[2], # millimeters + size=(150, 100), + size_x::Real=size[1], # millimeters + size_y::Real=size[2], # millimeters ) return Table(content, offset_x, offset_y, size_x, size_y) end diff --git a/src/TextBox.jl b/src/TextBox.jl index 6ccce2f..8f41ad9 100644 --- a/src/TextBox.jl +++ b/src/TextBox.jl @@ -1,7 +1,37 @@ +Base.@kwdef struct TextStyle + bold::Bool = false + italic::Bool = false + fontsize::Union{Nothing, Float64} = nothing # nothing will use default font +end + +function TextStyle(style::AbstractDict{String}) + return TextStyle(; + bold = get(style, "bold", false), + italic = get(style, "italic", false), + fontsize = get(style, "fontsize", nothing), + ) +end + +function Base.show(io::IO, ::MIME"text/plain", t::TextStyle) + print(io, summary(t)) + print_style_properties(io, t) +end + +function print_style_properties(io::IO, t::TextStyle, whitespace::Int=1) + for p in propertynames(t) + print(io, "\n" * " "^whitespace * "$p is $(getproperty(t, p))") + end +end + +function style_properties_string(t::TextStyle, whitespace::Int=1) + io = IOBuffer() + print_style_properties(io, t, whitespace) + return String(take!(io)) +end Base.@kwdef struct TextBody text::String - style::AbstractDict = Dict("bold" => false, "italic" => false) + style::TextStyle = TextStyle() body_properties::Union{Nothing, AbstractVector} = default_body_properties() end @@ -10,6 +40,14 @@ function TextBody(text::AbstractString; kwargs...) end function TextBody(text::AbstractString, style::AbstractDict) + return TextBody(;text=convert(String, text), style=TextStyle(style)) +end + +function TextBody(text::AbstractString, style::NamedTuple) + return TextBody(;text=convert(String, text), style=TextStyle(;style...)) +end + +function TextBody(text::AbstractString, style::TextStyle) return TextBody(;text=convert(String, text), style=style) end @@ -29,14 +67,16 @@ function default_body_properties() end """ -```julia -TextBox(; +``` +function TextBox(; content::String = "", - offset_x::Real = 50, - offset_y::Real = 50, - size_x::Real = 40, - size_y::Real = 30, - style::Dict = Dict("bold" => false, "italic" => false), + offset = (50,50), + offset_x::Real = offset[1], # millimeters + offset_y::Real = offset[2], # millimeters + size = (40,30), + size_x::Real = size[1], # millimeters + size_y::Real = size[2], # millimeters + style = (italic = false, bold = false, fontsize = nothing), ) ``` @@ -47,17 +87,21 @@ Offsets and sizes are in millimeters, but will be converted to EMU. ```jldoctest julia> using PPTX -julia> text = TextBox(content="Hello world!", size_x=30) +julia> text = TextBox(content="Hello world!", offset=(100, 50), size=(30,50), style = (italic = true, fontsize = 24)) TextBox content is "Hello world!" - offset_x is 1800000 EMUs + content.style has + bold is false + italic is true + fontsize is 24.0 + offset_x is 3600000 EMUs offset_y is 1800000 EMUs size_x is 1080000 EMUs - size_y is 1080000 EMUs + size_y is 1800000 EMUs ``` """ -struct TextBox <: AbstractShape +struct TextBox<: AbstractShape content::TextBody offset_x::Int # EMUs offset_y::Int # EMUs @@ -70,7 +114,7 @@ struct TextBox <: AbstractShape offset_y::Real, # millimeters size_x::Real, # millimeters size_y::Real, # millimeters - style::Dict=Dict("bold" => false, "italic" => false), + style = TextStyle(), hlink::Union{Nothing, Any} = nothing ) # input is in mm @@ -88,12 +132,14 @@ end # keyword argument constructor function TextBox(; content::AbstractString="", - offset_x::Real=50, # millimeters - offset_y::Real=50, # millimeters - size_x::Real=40, # millimeters - size_y::Real=30, # millimeters - style::Dict=Dict("bold" => false, "italic" => false), - hlink::Union{Nothing, Any} = nothing + offset=(50,50), + offset_x::Real=offset[1], # millimeters + offset_y::Real=offset[2], # millimeters + size=(40,30), + size_x::Real=size[1], # millimeters + size_y::Real=size[2], # millimeters + style = TextStyle(), + hlink::Union{Nothing, Any}=nothing ) return TextBox( content, @@ -112,6 +158,8 @@ function _show_string(p::TextBox, compact::Bool) show_string = "TextBox" if !compact show_string *= "\n content is \"$(String(p.content))\"" + show_string *= "\n content.style has" + show_string *= style_properties_string(p.content.style, 2) show_string *= "\n offset_x is $(p.offset_x) EMUs" show_string *= "\n offset_y is $(p.offset_y) EMUs" show_string *= "\n size_x is $(p.size_x) EMUs" @@ -121,15 +169,24 @@ function _show_string(p::TextBox, compact::Bool) end function text_style_xml(t::TextBody) + return text_style_xml(t.style) +end + +function text_style_xml(t::TextStyle) style = [Dict("lang" => "en-US")] - if t.style["bold"] + if t.bold push!(style, Dict("b" => "1")) end - if t.style["italic"] + if t.italic push!(style, Dict("i" => "1")) end + if !isnothing(t.fontsize) + sz = string(Int(round(t.fontsize*100))) + push!(style, Dict("sz" => sz)) + end + push!(style, Dict("dirty" => "0")) return style end diff --git a/test/runtests.jl b/test/runtests.jl index dbb816b..4d0b30e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,6 +2,7 @@ using PPTX using Test import PPTX: slides, shapes, rid import p7zip_jll +import Documenter if !p7zip_jll.is_available() # see source code of Pkg.PlatformEngines.exe7z() @@ -13,4 +14,8 @@ include("testConstructors.jl") include("testTables.jl") include("testHyperlinks.jl") include("testSlideXML.jl") -include("testWriting.jl") \ No newline at end of file +include("testWriting.jl") + +@testset "Doctests" begin + Documenter.doctest(PPTX) +end \ No newline at end of file diff --git a/test/testConstructors.jl b/test/testConstructors.jl index 12eb4db..5ec1d3f 100644 --- a/test/testConstructors.jl +++ b/test/testConstructors.jl @@ -13,6 +13,20 @@ using Test @test sprint(show, box) == "TextBox" + # legacy dict style interface + box = TextBox("content"; size_y = 80, style=Dict("italic" => true, "bold" => true, "fontsize" => 24.5)) + @test box.content.style.fontsize == 24.5 + @test box.content.style.italic == true + @test box.content.style.bold == true + + t = TextStyle(fontsize = 24, italic = true) + box2 = TextBox("content"; size_y = 80, style=t) + @test box2.content.style == t + + args = (fontsize = 24, italic = true) + box2 = TextBox("content"; size_y = 80, style=args) + @test box2.content.style == TextStyle(; args...) + io = IOBuffer() Base.show(io, MIME"text/plain"(), box) show_string = String(take!(io)) diff --git a/test/testSlideXML.jl b/test/testSlideXML.jl index e4e2481..8179501 100644 --- a/test/testSlideXML.jl +++ b/test/testSlideXML.jl @@ -4,8 +4,15 @@ using EzXML using ZipArchives: ZipBufferReader, zip_readentry @testset "Slide XML structure" begin + text_box = TextBox(content="bla", style = TextStyle(bold = true, italic = true, fontsize = 24)) + style_xml = PPTX.text_style_xml(text_box.content) + @test any(x->get(x, "i", false)=="1", style_xml) + @test any(x->get(x, "b", false)=="1", style_xml) + @test any(x->get(x, "sz", false)=="2400", style_xml) + s = Slide() text_box = TextBox(content="bla") + push!(s, text_box) xml = PPTX.make_slide(s) @test haskey(xml, "p:sld") From 9b2169cc68bad64885245437ec0334f7adb8e6c9 Mon Sep 17 00:00:00 2001 From: matthijscox-asml Date: Wed, 16 Oct 2024 10:32:48 +0200 Subject: [PATCH 2/4] doctestsetup using DataFrames --- docs/make.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index c2bc7b3..a78095d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,7 +1,7 @@ using PPTX using Documenter -DocMeta.setdocmeta!(PPTX, :DocTestSetup, :(using PPTX); recursive=true) +DocMeta.setdocmeta!(PPTX, :DocTestSetup, :(using PPTX, DataFrames); recursive=true) makedocs(; modules=[PPTX], From 5f89aa742d64be57042f6596e09ebc898dce6060 Mon Sep 17 00:00:00 2001 From: matthijscox-asml Date: Wed, 16 Oct 2024 14:03:23 +0200 Subject: [PATCH 3/4] revert DataFrames.DataFrame namespace for docs --- src/Tables.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tables.jl b/src/Tables.jl index 81f66fd..9997f14 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -29,7 +29,7 @@ julia> df = DataFrame(a = [1,2], b = [3,4], c = [5,6]) julia> t = Table(content=df, size_x=30) Table - content isa DataFrame + content isa DataFrames.DataFrame offset_x is 1800000 EMUs offset_y is 1800000 EMUs size_x is 1080000 EMUs From 6c68d4d18670d28ee326c4f0a81a45900c42fe35 Mon Sep 17 00:00:00 2001 From: matthijscox-asml Date: Thu, 17 Oct 2024 08:22:37 +0200 Subject: [PATCH 4/4] remove doctests --- Project.toml | 2 +- test/runtests.jl | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Project.toml b/Project.toml index a158948..e908f8c 100644 --- a/Project.toml +++ b/Project.toml @@ -33,4 +33,4 @@ p7zip_jll = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" [targets] -test = ["DataFrames", "Test", "TestSetExtensions", "p7zip_jll", "Documenter"] +test = ["DataFrames", "Test", "TestSetExtensions", "p7zip_jll"] diff --git a/test/runtests.jl b/test/runtests.jl index 4d0b30e..dbb816b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,7 +2,6 @@ using PPTX using Test import PPTX: slides, shapes, rid import p7zip_jll -import Documenter if !p7zip_jll.is_available() # see source code of Pkg.PlatformEngines.exe7z() @@ -14,8 +13,4 @@ include("testConstructors.jl") include("testTables.jl") include("testHyperlinks.jl") include("testSlideXML.jl") -include("testWriting.jl") - -@testset "Doctests" begin - Documenter.doctest(PPTX) -end \ No newline at end of file +include("testWriting.jl") \ No newline at end of file