diff --git a/Project.toml b/Project.toml index 903579c..ecfd389 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "WordCloud" uuid = "6385f0a0-cb03-45b6-9089-4e0acc74b26b" authors = ["guoyongzhi "] -version = "0.9.0" +version = "0.9.1" [deps] ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" diff --git a/README.md b/README.md index 367f95e..4bbc480 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ paint(wc, "alice.png", ratio=0.5) *The variable `WordCloud.examples` holds all available examples.* You can also [**see more examples**](https://github.com/guo-yong-zhi/WordCloud-Gallery) or [**try it online**](https://mybinder.org/v2/gh/guo-yong-zhi/WordCloud.jl/master?filepath=examples.ipynb). # About Implementation -Unlike most other implementations, WordCloud.jl is programmed based on image local gradient optimization. It’s a non-greedy algorithm in which words can be further [moved](res/animation.gif) after they are positioned. This means shrinking words is unnecessary, thus the word size can be kept unchanged during the adjustment. In addition, it allows words to be assigned to any initial position whether or not there will be an overlap. This enables the program to achieve the maximum flexibility. See also [Stuffing.jl - Algorithm Description](https://github.com/guo-yong-zhi/Stuffing.jl#algorithm-description). +Unlike most other implementations, WordCloud.jl is programmed based on image local gradient optimization. It’s a non-greedy algorithm in which words can be further [moved](res/animation2.gif) after they are positioned. This means shrinking words is unnecessary, thus the word size can be kept unchanged during the adjustment. In addition, it allows words to be assigned to any initial position whether or not there will be an overlap. This enables the program to achieve the maximum flexibility. See also [Stuffing.jl - Algorithm Description](https://github.com/guo-yong-zhi/Stuffing.jl#algorithm-description). * [x] 权重计算和单词位置初始化 * [x] 基于四叉树(层次包围盒)的碰撞检测 * [x] 根据局部灰度梯度平移单词(训练迭代) diff --git a/examples/lettermask.jl b/examples/lettermask.jl index 18076d2..86de0f6 100644 --- a/examples/lettermask.jl +++ b/examples/lettermask.jl @@ -8,6 +8,7 @@ wc = wordcloud( angles=0, colors=("#006BB0", "#EFA90D", "#1D1815", "#059341", "#DC2F1F"), density=0.55, + spacing=0, ) |> generate! println("results are saved to lettermask.svg") paint(wc, "lettermask.svg" , background=false) diff --git a/examples/outline.jl b/examples/outline.jl index 45c843e..f619c73 100644 --- a/examples/outline.jl +++ b/examples/outline.jl @@ -3,20 +3,18 @@ words = (1:200) .% 10 .|> string weights = (1:200) .% 11 .+ 1 #md# ### SVG #md# You can directly set the `outline` and `maskcolor` in `wordcloud` -#md# ```julia -#md# wc1 = wordcloud( -#md# words, weights, -#md# mask = squircle, rt=0.5, -#md# masksize = (300, 200), -#md# maskcolor = "AliceBlue", -#md# outline = 6, linecolor = "navy" -#md# ) |> generate! -#md# ``` +wc1 = wordcloud( + words, weights, + mask = squircle, rt=0.5, + masksize = (300, 200), + maskcolor = "AliceBlue", + outline = 6, linecolor = "navy" +) |> generate! #md# Or if you already have a SVG mask with outline, you should set a proper transparent region in `wordcloud` svgmask = shape(squircle, 300, 200, outline=6, linecolor="navy", color="AliceBlue") wc1 = wordcloud( words, weights, - mask=svgmask, + mask = svgmask, transparent=c -> c != WordCloud.torgba("AliceBlue"), # the outline should be regarded as transparent too ) |> generate! @@ -28,7 +26,7 @@ println("results are saved to outline.svg") bitmapmask = WordCloud.svg2bitmap(shape(squircle, 300, 200, color="AliceBlue", backgroundsize=(312, 212))) wc2 = wordcloud( words, weights, - mask=bitmapmask, + mask = bitmapmask, ) |> generate! paint(wc2, "outline.png", background=outline(bitmapmask, color="navy", linewidth=6, smoothness=0.8)) println("results are saved to outline.png") diff --git a/src/rendering.jl b/src/rendering.jl index 798c248..044293c 100644 --- a/src/rendering.jl +++ b/src/rendering.jl @@ -162,9 +162,8 @@ function _backgroundcolor(img, c=:auto) end end imagemask(img::AbstractArray{Bool,2}) = img -function imagemask(img, istransparent::Function) - .! istransparent.(torgba.(img)) -end +imagemask(img, istransparent::Function) = .!istransparent.(torgba.(img)) +imagemask(img, transparent::AbstractArray{Bool,2}) = .!transparent function imagemask(img, transparent=:auto) if transparent == :auto if img[1] == img[end] && any(c -> c != img[1], img) diff --git a/src/wc-class.jl b/src/wc-class.jl index 4bbdb18..5bf1dc2 100644 --- a/src/wc-class.jl +++ b/src/wc-class.jl @@ -158,6 +158,7 @@ function getstylescheme(words, weights; colors=:auto, angles=:auto, mask=:auto, end padding in DEFAULTSYMBOLS && (padding = round(Int, maximum(masksize) ÷ 10)) mask = randommask(masksize; maskshape=mask ,color=maskcolor, padding=padding, keeparea=keepmaskarea, kg..., kargs...) + transparent = c -> c != torgba(maskcolor) else ms = masksize in DEFAULTSYMBOLS ? () : masksize if maskcolor == :auto && !issvg(loadmask(mask)) @@ -187,9 +188,11 @@ function getstylescheme(words, weights; colors=:auto, angles=:auto, mask=:auto, linecolor = randomlinecolor(colors) end padding in DEFAULTSYMBOLS && (padding = 0) - mask = loadmask(mask, ms...; color=maskcolor, transparent=transparent, backgroundcolor=bc, - outline=outline, linecolor=linecolor,padding=padding, kargs...) + mask, binarymask = loadmask(mask, ms...; color=maskcolor, transparent=transparent, backgroundcolor=bc, + outline=outline, linecolor=linecolor,padding=padding, return_binarymask=true, kargs...) + binarymask === nothing || (transparent = .!binarymask) end + # under this line: both mask == :auto or not if transparent == :auto if maskcolor ∉ DEFAULTSYMBOLS transparent = c -> c[4] == 0 || c[1:3] != WordCloud.torgba(maskcolor)[1:3] #ignore the alpha channel when alpha!=0 diff --git a/src/wc-helper.jl b/src/wc-helper.jl index 4fe7c94..5be9ef2 100644 --- a/src/wc-helper.jl +++ b/src/wc-helper.jl @@ -25,15 +25,17 @@ About orther keyword arguments like outline, linecolor, smoothness, see function """ function loadmask(img::AbstractMatrix{<:TransparentRGB}, args...; color=:auto, backgroundcolor=:auto, transparent=:auto, - outline=0, linecolor="black", smoothness=0.5, padding=0, kargs...) + outline=0, linecolor="black", smoothness=0.5, padding=0, return_binarymask=false, kargs...) copied = false if !(isempty(args) && isempty(kargs)) img = imresize(img, args...; kargs...) copied = true end + if return_binarymask || color ∉ DEFAULTSYMBOLS || backgroundcolor ∉ DEFAULTSYMBOLS + mask = imagemask(img, transparent) + end if color ∉ DEFAULTSYMBOLS || backgroundcolor ∉ DEFAULTSYMBOLS copied || (img = copy(img)) - mask = imagemask(img, transparent) if color ∉ DEFAULTSYMBOLS color = parsecolor(color) alpha(color) == 1 || @warn "the alpha channel is ignored" @@ -54,12 +56,13 @@ function loadmask(img::AbstractMatrix{<:TransparentRGB}, args...; bc = backgroundcolor in DEFAULTSYMBOLS ? :auto : backgroundcolor img = Render.padding(img, padding, backgroundcolor=bc) end - img + return_binarymask ? (img, mask) : img end function loadmask(img::AbstractMatrix{<:Colorant}, args...; kargs...) loadmask(ARGB.(img), args...; kargs...) end -function loadmask(img::SVGImageType, args...; padding=0, transparent=:auto, outline=0, linecolor=:auto, kargs...) +function loadmask(img::SVGImageType, args...; + padding=0, transparent=:auto, outline=0, linecolor=:auto, return_binarymask=false, kargs...) if !isempty(args) || !isempty(v for v in values(values(kargs)) if v ∉ DEFAULTSYMBOLS) || outline != 0 @warn "editing svg file is not supported: $args $kargs" end @@ -68,7 +71,7 @@ function loadmask(img::SVGImageType, args...; padding=0, transparent=:auto, outl bc in DEFAULTSYMBOLS && (bc = (0,0,0,0)) img = Render.padding(img, padding, backgroundcolor=bc) end - img + return_binarymask ? (img, nothing) : img end function loadmask(file, args...; kargs...) mask = Render.load(file)