windows - instalar - En Win7 algunas fuentes no funcionan como lo hicieron en Win2K/XP
fuentes windows 10 (1)
Asegúrese de que su código tenga un alto reconocimiento de DPI , y luego informe al sistema operativo que su proceso es compatible con DPI .
Si no le dice al sistema operativo que tiene conocimiento de DPI, algunas de las funciones de medición se encontrarán y le dará números en base a la suposición de que la pantalla DPI es en realidad de 96 ppp, independientemente de lo que realmente sea. Mientras tanto, las funciones de dibujo intentarán escalar en la otra dirección. Para el dibujo de alto nivel simple, este enfoque generalmente funciona (aunque a menudo conduce a texto difuso). Para mediciones pequeñas y la colocación precisa de caracteres individuales, esto a menudo resulta en problemas de redondeo que conducen a cosas como tamaños de letra inconsistentes . Este comportamiento se introdujo en Windows Vista.
Puede verlo todo el tiempo en Visual Studio 2010+, ya que el resaltador de sintaxis colorea el texto y las palabras cambian por un par de píxeles aquí y allá mientras escribe. Realmente molesto.
En cuanto a la enmienda:
tmExternalLeading
es simplemente una recomendación del diseñador de fuentes en cuanto a la cantidad de espacio adicional para poner entre las líneas de texto. Normalmente, la documentación de MSDN dice "la cantidad de espacio adicional que agrega la aplicación entre las filas". Bueno, usted es la aplicación, por lo que "lo correcto es agregarla entre filas cuando está dibujando texto usted mismo, pero realmente depende de usted". (Sospecho que funciones de nivel superior como DrawText lo usarán.
Es perfectamente correcto que GetTextExtentPoint32
(y sus amigos) devuelvan size.cy
igual a tmHeight
e ignoren tmExternalLeading
. Como programador, en última instancia, es su elección la cantidad de liderazgo que realmente utiliza.
Puedes ver esto con un simple código de dibujo. Seleccione una fuente con un tmExternalLeading distinto de cero (Arial funciona para mí). Dibuja texto usando TextOut
y un color de fondo único. Luego mida el texto con GetTextExtentPoint32
y dibuje algunas líneas basadas en los valores que obtiene. Verá que el rectángulo de color de fondo excluye la ventaja externa. El liderazgo externo es solo eso: externo. No está dentro de los límites de la celda de caracteres.
// Draw the sample text with an opaque background.
assert(::GetMapMode(ps.hdc) == MM_TEXT);
assert(::GetBkMode(ps.hdc) == OPAQUE);
assert(::GetTextAlign(ps.hdc) == TA_TOP);
COLORREF rgbOld = ::SetBkColor(ps.hdc, RGB(0xC0, 0xFF, 0xC0));
::TextOutW(ps.hdc, x, y, pszText, cchText);
::SetBkColor(ps.hdc, rgbOld);
// This vertical line at the right side of the text shows that opaque
// background is exactly the height returned by GetTextExtentPoint32.
SIZE size = {0};
if (::GetTextExtentPoint32W(ps.hdc, pszText, cchText, &size)) {
::MoveToEx(ps.hdc, x + size.cx, y, NULL);
::LineTo(ps.hdc, x + size.cx, y + size.cy);
}
// These horizontal lines show the normal line spacing, taking into
// account tmExternalLeading.
assert(tm.tmExternalLeading > 0); // ensure it''s an interesting case
::MoveToEx(ps.hdc, x, y, NULL);
::LineTo(ps.hdc, x + size.cx, y); // top of this line
const int yNext = y + tm.tmHeight + tm.tmExternalLeading;
::MoveToEx(ps.hdc, x, yNext, NULL);
::LineTo(ps.hdc, x + size.cx, yNext); // top of next line
El espacio entre la parte inferior del rectángulo coloreado y la parte superior de la siguiente línea representa la entrada externa, que siempre está fuera de la celda de caracteres.
OCR-B está diseñado para reconocimiento de caracteres ópticos confiables en equipos bancarios. Tener una ventaja externa grande (relativa a la altura del texto real) puede ser apropiado para algunas aplicaciones de OCR. Para esta fuente en particular, probablemente no sea una elección estética.
Mi pregunta es acerca de cómo se debe cambiar el manejo de la fuente para que funcione correctamente en Windows 7. Estoy seguro de haber asumido algo que era válido antes, pero ya no es válido. ¡Pero ni siquiera sé por dónde empezar a buscar! ¡Estoy rezando para que alguien pueda ayudar! Aquí están los detalles tal como los entiendo (también he publicado esta pregunta en un foro de desarrolladores de Microsoft Windows, pero no están respondiendo):
Sí, estoy detrás de los tiempos (diablos, todavía escribo código WIN32 en C simple!) Tengo una DLL de 10 años que escribí que imita una biblioteca de E / S de pantalla de DOS aún más antigua dentro del área de cliente de una ventana. No hace falta decir que solo permite el uso de fuentes de ancho fijo. Cuando algunos de los programas que usan el DLL se han movido a Windows 7, hay un extraño parpadeo que aparece cuando se utiliza una fuente TRUE TYPE de ancho fijo (las fuentes de mapas de bits aún funcionan perfectamente). Hemos rastreado el problema hasta el hecho que un solo carácter escrito con ExtTextOut
es más ancho de lo que debería ser. He comprobado las mediciones de tres formas diferentes (usando GetTextExtentPoint32
en una cadena de 132 caracteres y dividiendo entre 132, llamando a GetTextMetrics
e incluso usando GetCharABCWidths
para los 256 caracteres) y todos coinciden en que la fuente es del mismo ancho. Pero ExtTextOut
está haciendo que el rectángulo del fondo de uno o dos píxeles sea más ancho que el ancho de la fuente. O bien, o está comenzando el fondo representando un píxel o dos a la izquierda de la posición dada en los parámetros [Yo lo llamo así: ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL )
.] Y recuerde, este código EXACT funcionaba perfectamente en Windows 2000, Windows XP y, con fuentes de mapa de bits en Windows 7, pero ya no funciona correctamente con fuentes de tipo verdadero de ancho fijo en Windows 7.
Para cualquiera que no esté comprendiendo lo que tengo que hacer: intente imaginarse escribiendo un carácter por cuadrado en un pedazo de papel cuadriculado. Cada cuadrado usa la misma fuente, pero puede tener un primer plano y / o color de fondo diferente. TA_TOP|TA_LEFT
alineación de texto TA_TOP|TA_LEFT
, porque es la más simple y cualquier alineación aplicada de manera consistente debería funcionar para una fuente de ancho fijo.
Lo que estoy viendo es que ExtTextOut está emitiendo un rectángulo de fondo más grande que el que he especificado en el parámetro RECT *
. Como el rectángulo que proporciono se crea a partir del tamaño de la fuente informado, esto NUNCA debería ocurrir, y nunca sucedió en Windows XP y versiones anteriores, y no ocurre con las fuentes de mapa de bits (es decir, .FON) en Windows 7. ya sea. Pero SIEMPRE sucede con fuentes TrueType de ancho fijo en Windows 7. Esto es con EXACTAMENTE EXACTAMENTE EJECUTADO corriendo en Windows 2000, Windows XP y Windows 7 (32 y 64). Aunque me encantaría decir simplemente que Windows 7 tiene un error, Estoy más inclinado a creer que alguna suposición fundamental que he hecho sobre el manejo de fuentes en Windows ya no es cierta (después de 20 años de escribir software para Windows).
¡Pero no tengo ni idea de cómo ni dónde descubrir qué podría ser eso! Por favor, ¡POR FAVOR ayúdenme!
--- enmienda
Para cualquier persona interesada, he logrado solucionar lo que estoy considerando como un error, hasta que encuentre documentación que indique lo contrario. Mi solución consiste en dos cambios a mi biblioteca:
- Utilice el tamaño devuelto por
GetTextExtentPoint32()
de una ''X'' en lugar de los datos deTEXTMETRICS
. - Incluya el indicador
ETO_CLIPPING
en todas las llamadasExtTextOut()
.
Anteriormente, estaba usando tmHeight+tmExternalLeading
para el número de píxeles entre las partes superiores de las filas consecutivas de texto, como está documentado. Descubrí que el valor de size.cy que regresaba de GetTextExtentPoint32(
) no era el mismo y parecía más preciso. El peor ejemplo que encontré fue la fuente de tipo verdadero OCRB. Esto es lo que vi en el depurador para la fuente OCRB que había creado (usando el diálogo de selección de fuente del sistema):
ocrbtm.tmHeight = 11
ocrbtm.tmExternalLeading = 7
ocrbsize.cy = 11
Entonces, por alguna razón que aún tengo que descubrir, Windows está ignorando el valor principal externo definido para la fuente OCRB. Usar el valor de tamaño en lugar de TM da como resultado un texto bonito, ordenado y cerrado, que es justo lo que quería.
La bandera ETO_CLIPPING
no debería ser necesaria para mí porque estoy configurando el rectángulo exactamente con las dimensiones de un solo carácter y usando ETO_OPAQUE
para completar el fondo (y sobrescribir el contenido de la celda anterior). Pero sin el indicador de recorte, un solo carácter es más ancho que el tamaño, la métrica de texto o el ancho ABC indicaría, al menos, eso es cierto en función de toda la documentación que he encontrado hasta ahora.
Creo que el problema HEIGHT ha existido durante mucho tiempo, pero el resto fue innecesario hasta que ejecutamos nuestro software en Windows 7. Añado esto a mi pregunta para ver si alguien puede explicar lo que obviamente no entiendo.
- enmienda 2 -
1: toda la documentación que puedo encontrar dice que tmHeight+tmExternalLeading
debe producir líneas de texto de espacio simple. Período. Pero eso no siempre es cierto y no puedo encontrar documentación que indique cómo Windows determina los diferentes valores que GetTextExtentPoint32()
veces devuelve.
2: en Win7 (tal vez Vista) ExtTextOut
comenzó a rellenar un poco más de fondo de lo que debería (agregando un par de píxeles adicionales a la derecha), pero solo cuando se selecciona un tipo de letra verdadero. Hace esto incluso si el rectángulo es el doble del tamaño esperado del personaje (en AMBAS dimensiones). DPI / Scaling podría ser un factor, pero como mi sistema está configurado al 100%, parecería que Windows está teniendo problemas con un 1 : 1 factor de escala y eso parecería ser un error. El hecho de que solo afecte las fuentes de tipo verdadero y no de mapa de bits (.FON) también parece descartar escalar (a menos que exista un error en el sistema de escalado), ya que Windows debería intentar escalar todo el texto, no solo parte del mismo . Además, hay un ajuste gris (pero verificado) "Usar escala de PPI estilo Windows XP" en el cuadro de diálogo "Configuración DPI personalizada". Por último, todo este problema puede ser el resultado de mi ejecución bajo el tema clásico de Windows en lugar de uno de los temas nativos de Aero u otros Win7 nativos.
- enmienda 3 -
Simplemente llamando a SetProcessDPIAware () no tiene ningún efecto sobre el problema que estoy teniendo. Como mi problema existe en la configuración 100% DPI (escala 1: 1), si mi problema está relacionado con DPI, entonces debo haber descubierto un error en la virtualización DPI porque así es como Microsoft describe la función:
Esta característica funciona al proporcionar métricas de sistema "virtualizadas" y elementos de IU a la aplicación, como si se ejecutara a 96 DPI. Luego, la aplicación se procesa en una superficie fuera de pantalla de 96 ppp, y el Administrador de escritorio de Windows escala la ventana de la aplicación resultante para que coincida con la configuración de ppp.
Todas mis configuraciones muestran que estoy al 100% de escala, y mirar en el cuadro de configuración personalizada muestra claramente que significa 96 DPI. Entonces, si la virtualización DPI de 96 DPI a 96 DPI no funciona para mis fuentes de tipo verdadero de ancho fijo, entonces Windows tiene un problema, ¿no? ¿O hay alguna función que necesito llamar (o dejar de llamar?) Para permitir que el virtualizador DPI funcione correctamente?
Todavía no estoy convencido de que el supuesto problema de escalado en realidad tenga tanto que ver con la fuente TAMAÑO como originalmente pensé. Esto se debe a que el problema se está manifestando en el rectángulo de fondo que se está rellenando con ExtTextOut()
lugar de emitirse el carácter de texto. El rectángulo de fondo se agranda un poco cuando la fuente es de tipo verdadero. También ahora he verificado que este problema ocurre ya sea usando el tema clásico de Windows o el tema estándar de Windows Aero. Ahora, construya un ejemplo simplificado para que otros puedan experimentar con él.
- enmienda 4 -
Creé un programa de demostración mínimo que muestra lo que estoy viendo (y lo que estoy haciendo). El proyecto / fuente de Visual Studio 2010 puede descargarse desde http://www.svalli.com/files/fwtt.7z - Intencionalmente no incluí los archivos ejecutables porque no quiero correr el riesgo de propagar malware. El programa le permite elegir una fuente de ancho fijo y luego escribe dos cuadrículas de caracteres de 5x5 en el área del cliente, una creada con el tamaño GetTextExtentPoint32
y otra con el tamaño TEXTMETRIC
según lo documentado por Microsoft. Las cuadrículas están en un patrón de tablero de ajedrez en blanco y negro con un carácter amarillo sobre rojo escrito en el centro para mostrar el efecto de superposición (puede necesitar una utilidad de zoom para verlo claramente). El programa también dibuja una cadena que comienza con 5 X justo debajo la cuadrícula, comenzando con el mismo desplazamiento a la izquierda, para usar como comparación para mi método de colocar caracteres individuales (juego con la cadena). El menú permite activar / desactivar el recorte en ExtTextOut
y la selección de otras fuentes. También hay una opción de línea de comando dpiaware
(sensible a mayúsculas y minúsculas) que hace que el programa llame a SetProcessDPIAware()
cuando se inicia, por lo que también se puede evaluar el efecto de esa llamada.
Al crear esto, he aprendido que ExtTextOut
está llenando el rectángulo de fondo correcto, pero el personaje que se está renderizando con un fondo opaco puede ser más ancho de lo que debería y ni siquiera puede comenzar donde se le dijo a ExtTextOut
que comience a dibujar. Dije que "debería ser" porque el espaciado entre caracteres que estoy terminando coincide con lo que obtengo cuando ExtTextOut
una cadena completa. La superposición puede estar aparentemente en uno o ambos lados del rectángulo dado, por ejemplo, OCRB agrega un píxel adicional a los lados izquierdo y derecho de la celda de caracteres, mientras que las otras fuentes de tipo verdadero que he comprobado agregan dos píxeles a la derecha borde.
Realmente quiero hacer esto de la manera "correcta", pero no puedo encontrar ninguna documentación que demuestre lo que estoy haciendo mal o me falta. Bueno, probablemente me esté perdiendo algo para DPI Aware a escalas distintas al 100%, pero de lo contrario, estoy desconcertado.
- enmienda 5 -
Un poco menos desconcertado ... el problema es causado por ClearType. Al desactivar ClearType, todas las fuentes volvieron a funcionar. Activar ClearType en XP causa el mismo problema. Aparentemente ClearType puede silenciosamente (hasta que alguien me diga cómo detectarlo) estirar caracteres horizontalmente por un par de píxeles para hacer espacio para los píxeles sombreados que agrega para suavizar las cosas.
¿El recorte es la única forma de solucionar este problema?
- enmienda 6 -
Respuesta parcial a mi pregunta de recorte anterior: al crear una nueva fuente, ahora hago lo siguiente (en pseudo código):
CreateFontIndirect
SelectFont
GetTextMetrics
if( (tmPitchAndFamily & TMPF_TRUETYPE) && Win6.x or above )
if( SystemParametersInfo( SPI_GETCLEARTYPE ) )
lfQuality = NONANTIALIASED_QUALITY
DeleteObject( font )
CreateFontIndirect
Sin habilitar el recorte, esto casi siempre funciona con los tamaños de fuente que estoy usando, aunque he encontrado algunos que aún representan un píxel extra a la derecha (o izquierda) de la celda de caracteres. Afortunadamente, esas parecen ser fuentes gratuitas encontradas en Internet, por lo que su calidad general puede estar por debajo de los estándares de las fundiciones de fuentes profesionales.
Si alguien puede encontrar una mejor respuesta, realmente, REALMENTE me encantaría escucharla. Hasta entonces, creo que esto es tan bueno como se obtendrá. ¡Gracias por leer hasta aquí!