Open jdtrat opened 4 years ago
Maybe you can do the drawing in a second image, that you can resize before overlaying it? Eg
library(magick)
frink <- image_read("https://jeroen.github.io/images/frink.png")
fig <- image_draw(image_blank(800, 800))
rect(20, 20, 200, 100, border = "red", lty = "dashed", lwd = 5)
text(110, 55, "Jonathan", cex = 3.5)
dev.off()
image_composite(frink, image_trim(fig), operator = 'SrcOver')
Here is another example, using image_annotate
and then rescaling:
library(magick)
frink <- image_read("https://jeroen.github.io/images/frink.png")
width <- image_info(frink)$width
fig <- image_blank(800, 800) %>%
image_annotate('Jeroen', size = 100) %>%
image_trim() %>%
image_border('none') %>%
image_border('red') %>%
image_resize(paste0(width, 'x'))
image_composite(frink, fig, operator = 'SrcOver')
Thanks for your help, @jeroen! I ended up using the second method. This allowed me to keep the names within a border on the first image. I've set it up so the relative heights of each name are the same, too. One thing I noticed with this, however, is that the names left-flush. Do you have any suggestions as to how I could make the offset the composite image based on its center? I came across this discussion, but I don't believe there is a geometry argument available for image_composite
function. Any advice you can give would be greatly appreciated! Reprex below shows what I'm trying to do.
library(magick)
#> Linking to ImageMagick 6.9.9.39
#> Enabled features: cairo, fontconfig, freetype, lcms, pango, rsvg, webp
#> Disabled features: fftw, ghostscript, x11
frink <- image_read("https://jeroen.github.io/images/frink.png")
# set border width to be 90%
width <- image_info(frink)$width * 0.90
fig <- image_draw(frink)
rect(20, 20, width, 100, border = "red", lty = "dashed", lwd = 5)
dev.off()
#> quartz_off_screen
#> 2
name1 <- image_blank(800, 800) %>%
image_annotate('Jonathan', size = 100) %>%
image_trim() %>%
image_resize(paste0(width * 0.9, 'x30'))
name2 <- image_blank(800, 800) %>%
image_annotate('Jeroen', size = 100) %>%
image_trim() %>%
image_resize(paste0(width * 0.9, 'x30'))
fig %>%
image_composite(name1, offset = paste0("+", 0.1 * width,"+40"), operator = "SrcOver")
fig %>%
image_composite(name2, offset = paste0("+", 0.1 * width,"+40"), operator = "SrcOver")
# Manually center names
fig %>%
image_composite(name1, offset = paste0("+", (0.1 * width) + 6,"+40"), operator = "SrcOver")
fig %>%
image_composite(name2, offset = paste0("+", (0.1 * width) + 30,"+40"), operator = "SrcOver")
Created on 2020-08-26 by the reprex package (v0.3.0)
Maybe try gravity = "center"
in image_composite
?
I thought the same thing, but that places the name in relation to the background picture:
library(magick)
#> Linking to ImageMagick 6.9.9.39
#> Enabled features: cairo, fontconfig, freetype, lcms, pango, rsvg, webp
#> Disabled features: fftw, ghostscript, x11
frink <- image_read("https://jeroen.github.io/images/frink.png")
# set border width to be 90%
width <- image_info(frink)$width * 0.90
fig <- image_draw(frink)
rect(20, 20, width, 100, border = "red", lty = "dashed", lwd = 5)
dev.off()
#> quartz_off_screen
#> 2
name <- image_blank(800, 800) %>%
image_annotate('Jonathan', size = 100) %>%
image_trim() %>%
image_resize(paste0(width * 0.9, 'x30'))
fig %>%
image_composite(name, offset = paste0("+", 0.1 * width,"+40"), operator = "SrcOver", gravity = "center")
Created on 2020-08-27 by the reprex package (v0.3.0)
I ended up creating a blank image with a border and compositing it with the name using the gravity = "center"
argument, and then compositing that on top of the background image. That seems to work as I wanted, but I'm having a different issue: I'm unable to place the new border/image over the original border created using the rect
function. I attempted to rescale it with the same width/height used, but it doesn't overlap and I'm not sure why. If you have time, I would greatly appreciate your thoughts! If not, no worries. I am very grateful that you helped me solve my problem!
library(magick)
#> Linking to ImageMagick 6.9.9.39
#> Enabled features: cairo, fontconfig, freetype, lcms, pango, rsvg, webp
#> Disabled features: fftw, ghostscript, x11
frink <- image_read("https://jeroen.github.io/images/frink.png")
# set border width to be 90%
width <- image_info(frink)$width * 0.90
fig <- image_draw(frink)
rect(20, 20, width, 100, border = "red", lty = "dashed", lwd = 5)
dev.off()
#> quartz_off_screen
#> 2
name <- image_blank(800, 800) %>%
image_annotate('Jonathan', size = 100) %>%
image_trim() %>%
image_resize(paste0(width * 0.9, 'x30'))
rect <- image_blank(width, 100) %>%
image_border(color = "blue", geometry = "5x5") %>%
image_resize(width)
# add name to rect
rectName <- rect %>%
image_composite(name, operator = "SrcOver", gravity = "center") %>%
image_resize(paste0(width, "x100")) # x100 comes from the original rect function
# add rectName to fig
fig %>% image_composite(rectName,
offset = "+20+20",
operator = "SrcOver")
# name 2
name2 <- image_blank(800, 800) %>%
image_annotate('Jeroen', size = 100) %>%
image_trim() %>%
image_resize(paste0(width * 0.9, 'x30'))
rect2 <- image_blank(width, 100) %>%
image_border(color = "blue", geometry = "5x5") %>%
image_resize(width)
# add name to rect
rectName2 <- rect2 %>%
image_composite(name2, operator = "SrcOver", gravity = "center") %>%
image_resize(paste0(width, "x100")) # x100 comes from the original rect function
# add rectName to fig
fig %>% image_composite(rectName2,
offset = "+20+20",
operator = "SrcOver")
Created on 2020-08-27 by the reprex package (v0.3.0)
I wonder if exposing fontTypeMetrics
could help (ref #216). Wouldn't it be cool to just
# do not run
image_annotate("Jeroen",.., width=100, height=50)
and have Magick figure out what font size it needs to use (given the font family) to fit the bounding box. It sounds like a reverse problem compared to what fontTypeMetrics
does, though (from bbox -> font
not font ->bbox
). So, never mind.
Printing on arbitrary(blank) raster and then scaling it before image_composite()
sounds like a plausible strategy.
Hello! I'm working on a Shiny app where images will be annotated based on users' input. I need to have the annotation fit within a certain region of the image, and have been unable to figure that out. For example, if the input is someone's name, I would like it to size automatically within a certain border. "Jonathan," for instance, would be smaller than "Hadley." A hard coded example:
This is possible with the ImageMagick engine (see the Best Fit to Image section) by not specifying a pointsize argument for a label. According to the website, IM would "have the freedom to try and select a font size that best fits the image size requested. That is the drawn text will be adjusted to fit the given size!" The code they provide as an example is seen below:
The
image_draw
function does have a pointsize argument, but if I set it to NULL it throws an error and nothing changes (see reprex below). Am I missing something? If there is another way to achieve this, I would greatly appreciate a nudge in the right direction. If there is not a way to do this, would it be possible to add this as a feature?