Converter a largura da coluna do Excel entre a unidade de caracteres e os pixels (pontos)

"uma unidade de largura da coluna é igual à largura de um caractere no estilo Normal. Para tipos de letra proporcionais, é usada a largura do carácter 0 (zero)."

assim ColumnWidth no Excel é medido como um número de "0" caracteres que se encaixa numa coluna. Como é que este valor pode ser convertido em pixels e vice-versa?

Image from https://bettersolutions.com/excel/rows-columns/column-widths.htm

Author: Winand, 2020-04-05

1 answers

Como já mencionado ColumnWidth o valor no Excel depende do tipo de letra predefinido de um livro que pode ser obtido via Workbook.Styles("Normal").Font. Também depende do PPP do ecrã actual.

Depois de realizar algumas pesquisas para diferentes fontes e tamanhos no Excel 2013 descobri que temos 2 funções lineares (o Arial não pode ser visto porque se sobrepõe ao Tahoma.):

enter image description here

Como pode ser visto na imagem a função para {[3] } é diferente da maior parte da o mapa das linhas. É calculado como um número de pixels em uma coluna / Número de pixels necessários para caber um "0" caráter em uma coluna.

Agora vamos ver em que consiste uma típica largura celular.

enter image description here

  • A - " 0 " Largura de caracteres no estilo Normal
  • B - enchimento esquerdo e direito
  • C - 1px margem direita

A pode ser calculado com a função GetTextExtentPoint32 da API do Windows, mas o tamanho da letra deve ser um pouco maior. Por experiência eu escolhi + 0.3 pt que trabalhou para mim para diferentes fontes com tamanho de base 8-48pt. B é (A + 1) / 4 arredondado às unidades usando "round half up" . Também serão necessários DPI no ecrã (ver implementação em Python 3 abaixo)

Aqui estão as equações para a conversão de caracteres-pixels e a sua implementação em Python 3:

enter image description here

enter image description here

enter image description here

import win32print, win32gui
from math import floor

def get_screen_dpi():
    dc = win32gui.GetDC(0)
    LOGPIXELSX, LOGPIXELSY = 88, 90
    dpi = [win32print.GetDeviceCaps(dc, i) for i in (LOGPIXELSX,
                                                        LOGPIXELSY)]
    win32gui.ReleaseDC(0, dc)
    return dpi

def get_text_metrics(fontname, fontsize):
    "Measures '0' char size for the specified font name and size in pt"
    dc = win32gui.GetDC(0)
    font = win32gui.LOGFONT()
    font.lfFaceName = fontname
    font.lfHeight = -fontsize * dpi[1] / 72
    hfont = win32gui.CreateFontIndirect(font)
    win32gui.SelectObject(dc, hfont)
    metrics = win32gui.GetTextExtentPoint32(dc, "0")
    win32gui.ReleaseDC(0, dc)
    return metrics

def ch_px(v, unit="ch"):
    """
    Convert between Excel character width and pixel width.
    `unit` - unit to convert from: 'ch' (default) or 'px'
    """
    rd = lambda x: floor(x + 0.5)  # round half up
    # pad = left cell padding + right cell padding + cell border(1)
    pad = rd((z + 1) / 4) * 2 + 1
    z_p = z + pad  # space (px) for "0" character with padding
    if unit == "ch":
        return v * z_p if v < 1 else v * z + pad
    else:
        return v / z_p if v < z_p else (v - pad) / z

font = "Calibri", 11
dpi = get_screen_dpi()
z = get_text_metrics(font[0], font[1] + 0.3)[0]  # "0" char width in px
px = ch_px(30, "ch")
ch = ch_px(px, "px")
print("Characters:", ch, "Pixels:", px, "for", font)
 2
Author: Winand, 2020-04-05 21:00:23