2012-06-26 5 views
5

Estoy usando el mensaje EM_FORMATRANGE para procesar el resultado de un control de texto enriquecido en un contexto de dispositivo arbitrario. Sin embargo, al representar en un mapa de bits, los puntos por pulgada del contexto del dispositivo de mapa de bits son los mismos que los DPI del dispositivo de visualización, que son 96 puntos por pulgada. Esto es mucho más bajo de lo que me gustaría renderizar. Prefiero renderizar a un DPI mucho más alto para que el usuario pueda acercar, y quizás imprimir en una impresora de alta resolución más tarde.Errores de redondeo al escalar la salida representada del control de edición enriquecido a través de EM_FORMATRANGE

Sospecho que lo que ocurre es que el control RTF llama a GetDeviceCaps con LOGPIXELSX y LOGPIXELSY para obtener el número de píxeles por pulgada del dispositivo. A continuación, procesa el documento utilizando este valor DPI en un nivel de zoom del 100%. Los dispositivos de visualización de Windows siempre devuelven un valor de 96 ppp, a menos que se utilicen fuentes grandes en el sistema (como se establece en el Panel de control) y la aplicación reconoce los DPI.

Muchos ejemplos en Internet proponen escalar la salida de EM_FORMATRANGE. Esto es para que se pueda lograr cualquier resolución DPI arbitraria. La mayoría de los ejemplos generalmente implican el uso de SetMapMode, SetWindowExtEx y SetViewportExtEx (por ejemplo, ver http://social.msdn.microsoft.com/Forums/en-us/netfxbcl/thread/37fd1bfb-f07b-421d-9b5e-5f4492ffbbc3). Estas funciones se pueden usar para escalar la salida representada del control de texto enriquecido: por ejemplo, si especifico una escala de 400%, entonces si el control de texto enriquecido representa algo de 5 píxeles de ancho, en realidad tendría 20 píxeles de ancho.

Desafortunadamente, las antiguas funciones de GDI usan enteros en lugar de números de coma flotante. Por ejemplo, suponga que el control RTF decidió que un elemento debería dibujarse en (12.7, 15.3) píxeles. Esto se redondearía a una posición de (13, 15). Estas coordenadas redondeadas se pasan a GDI, que luego amplía la imagen usando la escala especificada por SetMapMode: para el ejemplo de 400%, sería (13 * 4, 15 * 4) o (52, 60). Pero esto no es exacto: el elemento se hubiera colocado mejor en (12.7 * 4, 15.3 * 4) o (51, 61). La peor parte es que, en algunos casos, el error se vuelve acumulativo.

Creo que esta es la causa subyacente de este error muy notable cuando se escala un poco de texto simple:

Rendered using EM_FORMATRANGE<code>and scaled with</code>SetMapMode

El ejemplo anterior es de 8 puntos Segoe UI, reducido a 400% utilizando EM_FORMATRANGE y SetMapMode en una Contexto del dispositivo de visualización de 96 DPI. El texto se ha convertido en un tamaño de 32 puntos, pero el espacio entre cada personaje es demasiado alto y no se ve natural.

Zoomed to 400% in WordPad

El ejemplo anterior fue creado en WordPad mediante la introducción de texto en 8 punto Segoe interfaz de usuario y a continuación, utilizando el control de zoom para ajustar a un nivel de zoom 400%. El espacio entre cada personaje parece normal. El mismo resultado exacto se logra con una fuente de 32 puntos y un nivel de zoom del 100%.

Para solucionar este problema, he intentado lo siguiente. Para cada cosa que se intentó, el resultado ha sido idénticamente insatisfactorio cuando se ha escalado al 400%.

  • El uso de un conjunto de transformación de escala usando SetWorldTransform en lugar de la escala hecho con SetMapMode y SetWindowExtEx etc.
  • Pasando el contexto de dispositivo para un metarchivo a EM_FORMATRANGE, y luego escalar el metarchivo más tarde.
  • Utilizando SetMapMode para escalar junto con la representación en un metarchivo, y luego mostrando el metarchivo más tarde sin escalar.

creo que los resultados son siempre satisfactorios debido a que el problema se reduce al hecho de que el control de edición enriquecida es el redondeo al entero más cercano y de la representación de lo que piensa que es un dispositivo de 96 ppp - haciendo caso omiso de las transformaciones en su lugar. Miré en el formato de metarchivo y descubrí que las posiciones de los personajes individuales se almacenan realmente en el metarchivo a resolución de píxel, por eso escalar el metarchivo obviamente no funcionó porque el redondeo ya ha ocurrido en ese punto.

me ocurren dos soluciones reales que trabajarían en torno a este tema:

  • Utilice un contexto de dispositivo con unos altos puntos especificados por el usuario por pulgada, de manera que GetDeviceCaps devuelve valores diferentes. (Nota: algunos ejemplos proponen usar el dispositivo de la impresora, ya que generalmente tienen una mayor DPI, pero quiero que mi código funcione en sistemas que no tienen una impresora y que pueden renderizar en un búfer fuera de la pantalla).
  • Una forma de decirle al control rich edit que el contexto del dispositivo tiene un punto diferente por pulgada que el GetDeviceCaps.

Cualquier otra cosa parece que todavía estará sujeto a estos errores de redondeo.

¿Alguien (1) tiene una idea de cómo implementar cualquiera de las soluciones que he propuesto, o (2) tiene una idea alternativa de cómo lograr mi objetivo de obtener una salida de alta definición precisa en un búfer?

Respuesta

0

Estoy teniendo exactamente el mismo problema.

Una solución rápida es dibujar el texto en un mapa de bits a escala del 100%, y luego simplemente escalar el mapa de bits. no es la mejor solución, pero podría funcionar para usted.

¿Encontró alguna solución mejor? si es así, por favor compártalos aquí.

Observe también que este problema también ocurre cuando dibuja el texto en un metaarchivo 100% y luego escala el metaarchivo a la pantalla. Creo que esto tiene algo que ver con las funciones de dibujo de texto GDI que no son t funcionando bien con la escala.

Roey

+0

El escalado de mapa de bits es simplemente intercambiar un mal por otro. La imagen resultante sería borrosa: ¿por qué molestarse en generar una imagen de alto DPI en primer lugar? El método de metarchivo tampoco funcionó para mí, creo que debido a los mismos problemas de error de redondeo, los resultados fueron idénticamente erróneos. –

+0

Solo pensé en dos soluciones posibles: (1) crear un control de edición rico sin ventanas, acercarlo y pedirle que lo renderice en un contexto de dispositivo arbitrario que no sea realmente una ventana. Esta podría ser la mejor manera porque usa una interfaz compatible. (2) enganche la función GetDeviceCaps y mienta acerca de LOGPIXELSX y LOGPIXELSY para su contexto de dispositivo específico, para engañar el rico control de edición en el procesamiento en el DPI deseado. Pero esto sería sin apoyo/indocumentado, obviamente. No he tenido tiempo de investigar ninguna de las soluciones. Si obtienes una solución funcionando, ¡me encantaría saberlo! –

+0

solución (1): según mi experiencia, tratar de dibujar texto gdi (no gdi +) en una superficie que no es una superficie de pantalla le dará malos resultados porque el suavizado de fuentes no funcionará (este problema me ha costado días). solución (2): no tengo ni idea de cómo hacerlo :) ¿tienes xp en ese campo? – Roey

0

Usted podría multiplicar el tamaño de punto de todo el texto en el control en un factor de 4 y representar el control de un mapa de bits que es 4 veces más grandes.

Si va a poblar el control por su cuenta, esto sería bastante sencillo. Si admite contenido arbitrario introducido por el usuario, sería mucho más trabajo y requeriría un esfuerzo adicional para manejar cualquier cosa que no fuera texto (por ejemplo, mapas de bits incrustados).

0

Acabo de pasar dos semanas en un problema similar. Necesitaba una edición enriquecida que fuera escalable para la edición WYSISWG. Como hemos encontrado, el control de edición rico de Windows no admite la escala correctamente con EM_FORMATRANGE y el espaciado entre caracteres no cambia entre los niveles de zoom y los tamaños de fuente, solo escala en pasos de tamaño de fuente discretos.

Como no necesitaba grandes diferencias de escala, la solución que establecí fue utilizar las interfaces de edición de texto sin ventana de ITextServices para renderizar en un mapa de bits interno con una resolución fija. Luego usé GDI + para volver a muestrear el mapa de bits interno al tamaño de pantalla necesario con el filtro trilineal. Los resultados emulaban una edición enriquecida escalable lo suficientemente bien siempre que la diferencia de escala no fuera demasiado grande, era lo suficientemente buena para mis necesidades.

Después de probar muchas opciones diferentes, estoy convencido de que no se puede obtener una escala precisa con el control de edición rico de Windows. Puede escribir su propio control que represente texto. Sin embargo, necesitaría tener una llamada de sorteo por separado para cada texto con un estilo diferente. También necesitaría manejar todos los controles de edición ricas para usted, como resaltar texto, colocar el cursor, manejar la entrada del mouse y el teclado, analizar el texto rtf, etc. Probablemente sería mejor comprar un componente de terceros en este caso (no pude encontrar ningún componente de código abierto gratuito adecuado). En caso de que alguien quiera intentarlo, señalaré los puntos de partida relevantes para el procesamiento de texto para diferentes API.

  • GDI - TextOut no establece el espaciado entre caracteres correctamente. Necesita GetCharacterPlacement y ExTextOut. También necesita calcular el escalado usted mismo. Probablemente no desee utilizar GDI
  • GDI + - DrawString controla la escala correctamente. GDI + es una opción razonable
  • DirectWrite: si está dispuesto a limitarse a Vista Platform Update o posterior, DirectWrite es la API de texto más reciente de Microsoft.

También aquí es enlace que describe cómo la representación de texto es diferente entre GDI y GDI +:

http://windowsclient.net/articles/gdiptext.aspx

0

Trate de usar el EM_SETZOOM message dejar que los ricos escala de control de edición de la salida de sí mismo.

+0

Estoy familiarizado con ese mensaje.No afecta la salida de EM_FORMATRANGE. Entonces, ¿cómo propone redirigir esta salida ampliada a otro lugar que no sea una ventana interactiva? (que era para lo que está diseñado EM_SETZOOM) –

+0

@JamesJohnston, nunca lo había probado y dado que tampoco lo mencionó, supuse que afectaría a todas las representaciones. Mi error. –

Cuestiones relacionadas