How do I convert from `pt` to `cm`?

199 Views Asked by At

How do I convert from pt to cm? I tried multiplying by the proper conversion, and it gives me the expected result, but not without the pt still appended to it.

Example:

#layout(size => {
  [The page (minus margins) is #size.width wide. \
   In centimeters, that's #{size.width * 0.035277777777778}.]
})

enter image description here

2

There are 2 best solutions below

0
On

From the Discord Q&A (Thanks PgSuper!), I learned that I can remove the unit by dividing by 1pt, but that sometime in the future it will be native functionality.

Here's how it works:

#layout(size => {
  [The page (minus margins) is #size.width wide. \
   In centimeters, that's #{calc.round(size.width * 0.035277777777778 / 1pt)}.]
})

enter image description here

0
On

There is now (since Typst v0.7.0) a native method to perform this conversion (of any absolute length to cm): length.cm() (along with other similar methods). See here for more info: https://typst.app/docs/reference/types/length/#methods-cm

Note that, as the documentation specifies, the method will fail with an error if the length has non-zero em units. For instance, you cannot convert a length such as 3em or one such as 1pt + 4em to cm directly (through .cm()), as the actual length of 3em or 4em is not known during code evaluation. This is because 1em translates to the current font size, whose value depends on where you are in the document, something that isn't known while code is being evaluated.

However, lengths without em units will work just fine, e.g. (2pt).cm() will return the expected conversion result.

If you have a length with non-zero em units and you're not interested in its em part, you can just discard the em units before conversion with the abs field: (5pt + 3em).abs returns 5pt, on which you can use .cm(). (For reference: https://typst.app/docs/reference/types/length/)

But, if you really need to convert em units to cm, you will have to convert it to pt first by means of measure, a function which you can only use inside a style element's callback function (the style element, in turn, is content, so it must be placed in the document in order to call your code - which makes sense: the style info depends on the document position). (For more info on these, see the style element's documentation at https://typst.app/docs/reference/meta/style/ and the measure function's documentation at https://typst.app/docs/reference/layout/measure/)

Here's some sample code showcasing usage of .cm() for each case I speak about.

// #(2pt + 3em).cm()  // error if you uncomment (can't convert 'em' to 'cm')

#(2pt + 3em).abs.cm()  // ok (discards the '3em' part, converts 2pt to cm)

#2pt.cm()  // ok (no em units, conversion works fine)

// or we can try to convert the em units to pt / an absolute length,
// and then convert that to cm
#style(styles => {
  // the length we want to convert
  let length = 2pt + 3em

  // its conversion to 'pt'
  // HACK: we create a line of width 'length',
  // and use 'measure' to obtain its width based on
  // the current styles (font size etc.), thus converting
  // our 'em' into a fixed, absolute length.
  let actual-length = measure(line(length: length), styles).width

  // now we can convert the absolute length we got to cm.
  actual-length.cm()
})

The Typst code above will produce, on Typst v0.7.0 (using the rendering bot on Discord):

Output of the previous Typst code, consisting of 3 lines (except for the double quotes): "0.07055544776251037", "0.07055544776251037", and "1.2347203358439314"