6

Specifically, I'm interested in the width of characters in the default font assuming that the default font is mono-spaced. From reading the documentation, I got the impression that this should give me the correct value:

(aref (font-info (face-font 'default)) 2)

However, these values are consistently too big. For example, my current default font is

-unknown-DejaVu Sans Mono-normal-normal-normal-*-13-*-*-*-m-0-iso10646-1

and the code above gives me 13. However, when I make a screenshot and measure the characters their width is only 8 pixels. frame-char-widthgives me 8 pixels but if I change the default font size (using text-scale-increase) it continues to say 8, so that isn't useful.

I'm working with Emacs 25.0.50.2 on Ubuntu 14.04.

1
  • From the doc of font-info, the resulting array contains MAX-WIDTH, SPACE-WIDTH, AVERAGE-WIDTH, which should be same for a mono font. Does (aref (font-info ...) 7) gives you the correct result?
    – amdyes
    Commented Oct 28, 2019 at 6:56

2 Answers 2

8

The second element of the font-info is the font's pixelsize, which is (roughly speaking) its height. Getting the width of any particular glyph in the font is a little more work:

(aref (aref (font-get-glyphs (font-at (point)) 65 66) 0) 4)
6
  • While this answers my question (thank you!), I realize that my question wasn't precise enough. Given a face, I'd like to know how much horizontal space a character would take if I'd insert it in the buffer. Using your approach, I could insert the character in the buffer, measure it, and remove it. However, I'm looking for a solution that doesn't require any modifications in the buffer. Is that possible?
    – tmalsburg
    Commented Dec 18, 2014 at 1:39
  • I could be wrong, but I doubt it's possible in general -- I suspect the font hasn't been instantiated before it is displayed.
    – jch
    Commented Dec 18, 2014 at 1:50
  • @tmalsburg use a temp buffer. But I'm not sure how they interact with fonts.
    – Malabarba
    Commented Dec 18, 2014 at 2:31
  • @jch do you have a link or something explaining where this information can be found. The solution is fine, but it's a little cryptic on its own.
    – Malabarba
    Commented Dec 18, 2014 at 2:32
  • @Malabarba, the only source I'm aware of is the docstring of font-get-glyphs.
    – jch
    Commented Dec 18, 2014 at 2:47
7

Here is the complete solution for my original problem. Thanks to @jch and @Malabarba for contributing the crucial pieces.

(defun default-font-width () 
  "Return the width in pixels of a character in the current
window's default font.  More precisely, this returns the
width of the letter ‘m’.  If the font is mono-spaced, this
will also be the width of all other printable characters."
  (let ((window (selected-window))
        (remapping face-remapping-alist))
    (with-temp-buffer
      (make-local-variable 'face-remapping-alist)
      (setq face-remapping-alist remapping)
      (set-window-buffer window (current-buffer))
      (insert "m")
      (aref (aref (font-get-glyphs (font-at 1) 1 2) 0) 4))))

Update: This discussion led to the addition of three new functions in Emacs 25: default-font-width, window-font-width, and window-font-height (default-font-height was already part of emacs). window-font-width and window-font-height can be used to calculate the width and height or arbitrary faces.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.