How to align two images with different aspect ratio to have the same height, while taking up full horizontal space?

This is the code I currently use for aligning two images.

#figure(
  grid(
    columns: 2,
    gutter: 2mm,
    block(clip: true, radius: 4pt, image("path_to_image_a", height: auto)),
    block(clip: true, radius: 4pt, image("path_to_image_b", height: auto)),
  ),
  caption: [caption],
)

. However, under height: auto, when the two images don’t have the same aspect ratio, they don’t have the same height.
To let them have the same height and takes up the entire horizontal space (with a gutter in between), I want to use the following functions to determine the proper height. However, it keeps blaming that typst cannot subtract length from content or typst cannot divide length by content. How can I achieve my goal?

#let Aspect_Ratio(image_path) = context {
  let k = image(image_path)
  let (width, height) = measure(k)
  width.pt() / height.pt()
}

#let Height(image_a,image_b, gutter) = {
  let current_line_width = layout(size => {return size.width}) 
  let aspect_a = Aspect_Ratio(image_a)
  let aspect_b = Aspect_Ratio(image_b)
  let height = (current_line_width - gutter)/(aspect_a+aspect_b) // typst cannot subtract length from content
  return height
}
1 Like

The main issue here is that you cannot return a result from inside a context to be used outside of any context. That means you might need to use a context for the figure itself in order to do this. Check out this answer which explains how to implement this (some editing will be required). There’s no issue with using context repeatedly in your document, and it can be wrapped in its own function to avoid the need to type it every time (e.g., #let my-figure(..args) = context {figure ...more stuff here...})

If you want to avoid this, and happen to be using .jpeg images, you can use the function in my answer above the answer I linked here, which reads in the height and width of an image from the bytes of the file.

2 Likes

Here’s an example code based on the answer shared by miles-1.

#figure(
  context {
    let images = (
      image("test-image-a.png"),
      image("test-image-b.png"),
    )
    let widths = images
      .map(img => measure(img, height: 20pt).width)
      .map(x => x / 1pt * 1fr)
    //  20pt is an arbitrary ref height
    grid(
      columns: widths,
      gutter: 2mm,
      ..images
    )
  },
  caption: [caption],
)

2 Likes

Would oasis-align work here?

2 Likes

Thanks for your explanation! Now I understand why the first function always outputs content type.

1 Like