How to get terminal size or font size in pixels?
Asked Answered
M

6

7

I've seen some posts and answers about how to get the terminal size in numbers of columns and rows. Can I get the terminal size, or equivalently, the size of the font used in the terminal, in pixels?

(I wrote equivalently because terminal width[px] = font width[px]*number of columns. or that is what I mean by terminal width.)

I'm looking for a way that works with python 2 on linux, but I do appreciate answers that works only with python 3. Thanks!

Meaghan answered 1/4, 2014 at 10:7 Comment(0)
C
6

Maybe. If your terminal software supports XTerm Control Sequences, then the sequence \e[14t will give you the size width*height in pixels.

Related:

  • xtermctl - Put standard xterm/dtterm window control codes in shell parameters for easy use. Note that some terminals do not support all combinations.
Cosby answered 1/4, 2014 at 12:14 Comment(0)
N
4

Another possible approach, with limited support, is checking the ws_xpixel and ws_ypixel values of struct terminfo.

A python snippet to query these values:

import array, fcntl, termios
buf = array.array('H', [0, 0, 0, 0])
fcntl.ioctl(1, termios.TIOCGWINSZ, buf)
print(buf[2], buf[3])

This only works in certain terminal emulators, others always report 0 0. See e.g. the VTE feature request to set these fields for a support matrix.

Negron answered 12/5, 2017 at 22:57 Comment(8)
Any idea why it isn't working with stdout redirects? (ie. when used with read)Gig
The first argument to the ioctl is the file descriptor. Use a number that's not redirected, e.g. 0 if you read from the terminal but write to a file.Negron
That's because your python's stdin is not the terminal either, it's the echo command. Use a proper python script.Negron
Note that in the near future, there is going to be a new portable function tcgetsize() to get this value. See this issue for details.Christinchristina
@Christinchristina Halfway through that discussion "ws_xpixel and ws_ypixel were removed from the proposal".Negron
@Negron I know. ws_xpixel and ws_xpixel are still in the structure on Linux though.Christinchristina
@Christinchristina I guess it's still okay to have these fields, they are just not (yet) standardized.Negron
@Negron This was fiercely debated! The main reason for their exclusion is that they have type unsigned short but the committee feared that screens might get larger than that in the near future.Christinchristina
H
2

The data structure that stores terminal info in linux is terminfo. This is the structure that any general terminal query would be reading from. It does not contain pixel information, since that is not relevant for the text-only terminals it was designed to specify.

If you're running the code in an X compatible terminal, it is probably possible with control codes, but that would very likely not be portable.

Hessler answered 1/4, 2014 at 12:21 Comment(0)
I
1

So, you already know how to get terminal size (here) in characters.

I'm afraid it is not possible. TTY is a text terminal and doesn't have control of where it is running. So if your console program is executed in the terminal, you can't know where is it displaying.

However, you can use graphical mode to take control of fonts, display, etc. But why terminal? You can use GUI for that.

Importune answered 1/4, 2014 at 12:16 Comment(0)
M
1

Here's egmont's and Aaron Digulla's answers combined into one script:

import termios
import array
import fcntl
import tty
import sys

def get_text_area_size(): # https://gist.github.com/secemp9/ab0ce0bfb0eaf73d831033dbfade44d9 + ...
    # Save the terminal's original settings
    fd = sys.stdin.fileno()
    original_attributes = termios.tcgetattr(fd)

    try:
        # Set the terminal to raw mode
        tty.setraw(sys.stdin.fileno())

        # Query the text area size
        print("\x1b[14t", end="", flush=True)

        # Read the response (format: "\x1b[4;height;widtht")
        response = ""
        while True: 
            char = sys.stdin.read(1) # (in nvim-toogleterm for some reason stucks)
            response += char
            if char == "t":
                break

        # Parse the response to extract height and width
        if response:
            return tuple(map(int, response[:-1].split(';')[1:]))
        else: # ... https://mcmap.net/q/1433245/-how-to-get-terminal-size-or-font-size-in-pixels
            buf = array.array('H', [0, 0, 0, 0])
            fcntl.ioctl(1, termios.TIOCGWINSZ, buf)
            return (buf[3], buf[2])
    finally:
        # Restore the terminal's original settings
        termios.tcsetattr(fd, termios.TCSADRAIN, original_attributes)


# Example usage
text_area_size = get_text_area_size()
if text_area_size:
    print(f"Text area size is {text_area_size[0]} rows by {text_area_size[1]} columns")
else:
    print("Failed to get text area size")

Thanks to: source

Musk answered 24/4 at 20:47 Comment(0)
W
0

tput cols tells you the number of columns.
tput lines tells you the number of rows.

so

from subprocess import check_output
cols = int(check_output(['tput', 'cols']))
lines = int(check_output(['tput', 'lines']))
Wyndham answered 30/12, 2022 at 9:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.