2012-06-26 10 views
5

Sto utilizzando il messaggio EM_FORMATRANGE per rendere l'output di un controllo RTF in un contesto dispositivo arbitrario. Tuttavia, quando si esegue il rendering su una bitmap, i punti per pollice del contesto del dispositivo bitmap sono gli stessi del DPI del dispositivo di visualizzazione, ovvero 96 punti per pollice. Questo è molto più basso di quello che mi piacerebbe rendere. Preferirei eseguire il rendering a un DPI molto più alto in modo che l'utente possa eseguire lo zoom e magari stampare su una stampante ad alta DPI in un secondo momento.Arrotondamento degli errori durante il ridimensionamento dell'output di rendering del controllo Rich Edit tramite EM_FORMATRANGE

Sospetto che ciò che accade è che il controllo RTF chiama GetDeviceCaps con LOGPIXELSX e LOGPIXELSY per ottenere il numero di pixel per pollice del dispositivo. Quindi esegue il rendering del documento utilizzando questo valore DPI con un livello di zoom del 100%. I dispositivi di visualizzazione Windows restituiscono sempre un valore di 96 DPI, a meno che non vengano utilizzati font di grandi dimensioni nel sistema (come impostato nel Pannello di controllo) e l'applicazione sia compatibile con DPI.

Molti esempi su Internet propongono di ridimensionare l'output di EM_FORMATRANGE. Questo è così che qualsiasi risoluzione DPI arbitraria può essere raggiunta. La maggior parte degli esempi riguarda generalmente l'utilizzo di SetMapMode, SetWindowExtEx e SetViewportExtEx (ad esempio, vedere http://social.msdn.microsoft.com/Forums/en-us/netfxbcl/thread/37fd1bfb-f07b-421d-9b5e-5f4492ffbbc3). Queste funzioni possono essere utilizzate per ridimensionare l'output di rendering del controllo rich text: ad esempio, se si specifica il ridimensionamento del 400%, se il controllo RTF ha reso un oggetto largo 5 pixel, diventerebbe effettivamente largo 20 pixel.

Sfortunatamente, le vecchie funzioni GDI utilizzano numeri interi anziché numeri in virgola mobile. Ad esempio, supponiamo che il controllo RTF abbia deciso di disegnare un elemento a (12,7, 15,3) pixel. Questo sarebbe arrotondato ad una posizione di (13, 15). Queste coordinate arrotondate vengono passate a GDI, che quindi ridimensiona l'immagine utilizzando il ridimensionamento specificato da SetMapMode: per l'esempio del 400%, sarebbe (13 * 4, 15 * 4) o (52, 60). Ma questo non è accurato: l'elemento sarebbe stato meglio posizionato in (12.7 * 4, 15.3 * 4) o (51, 61). La parte peggiore è che, in alcuni casi, l'errore diventa cumulativo.

Credo che questa sia la causa di questo errore molto evidente quando ridimensionamento qualche semplice testo:

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

L'esempio precedente è 8 punti Segoe UI, in scala al 400% utilizzando EM_FORMATRANGE e SetMapMode su una Contesto del dispositivo di visualizzazione a 96 DPI. Il testo ora è diventato di 32 punti, ma lo spazio tra ogni personaggio è troppo alto e sembra innaturale.

Zoomed to 400% in WordPad

L'esempio precedente è stato creato in WordPad inserendo il testo come punto 8 Segoe UI e quindi utilizzando il controllo zoom per impostare un livello di zoom 400%. Lo spazio tra ogni personaggio sembra normale. Lo stesso risultato è ottenuto con un font a 32 punti e un livello di zoom del 100%.

Per risolvere questo problema, ho provato quanto segue. Per ogni cosa provata, il risultato è stato identicamente insoddisfacente quando ridimensionato al 400%.

  • Utilizzando una scala set di trasformazione utilizzando SetWorldTransform invece della scala fatta con SetMapMode e SetWindowExtEx ecc
  • Passare il contesto di periferica di metafile EM_FORMATRANGE, e poi scalare il metafile tardi.
  • Utilizzare SetMapMode per ridimensionare insieme al rendering in un metafile e quindi mostrare il metafile in seguito senza ridimensionamento.

credo che i risultati sono sempre insoddisfacenti perché il problema si riduce al fatto che i ricchi controllo di modifica è arrotondamento al numero intero più vicino e il rendering di quello che pensa è un dispositivo di 96 DPI - ignorando le trasformazioni in atto. Ho esaminato il formato del metafile e ciò che ho scoperto è che le singole posizioni dei caratteri sono effettivamente memorizzate nel metafile a una risoluzione a livello di pixel: ecco perché il metafile in scala ovviamente non ha funzionato poiché l'arrotondamento è già avvenuto a quel punto.

Mi vengono in mente due soluzioni reali che avrebbero risolvere questo problema:

  • Utilizzare un contesto di periferica con un più elevato punti specificati dall'utente per pollice, in modo tale che GetDeviceCaps restituisce valori diversi. (Nota: alcuni esempi propongono di utilizzare il dispositivo della stampante poiché generalmente hanno DPI più elevato, ma voglio che il mio codice funzioni su sistemi che non dispongono di una stampante e che siano in grado di eseguire il rendering su un buffer fuori schermo).
  • Un modo per dire al ricco controllo di modifica per assumere che il contesto del dispositivo abbia punti diversi per pollice rispetto a quelli riportati da GetDeviceCaps.

Qualsiasi altra cosa sembra essere ancora soggetta a questi errori di arrotondamento.

Qualcuno (1) ha un'idea di come implementare una delle soluzioni che ho proposto o (2) ha un'idea alternativa su come raggiungere il mio obiettivo di ottenere un'accurata uscita DPI alta in un buffer?

risposta

0

Ho lo stesso identico problema.

Una soluzione rapida consiste nel disegnare il testo in scala di bit del 100% e quindi ridimensionare la bitmap. non è la soluzione migliore, ma potrebbe funzionare per te.

Hai trovato soluzioni migliori? se è così, per favore condividili qui.

Si noti inoltre che questo problema si verifica anche quando si disegna il testo in un meta-file al 100% e quindi si ridimensiona il meta-file sullo schermo - credo che questo abbia qualcosa a che fare con le funzioni di disegno del testo GDI che non sono " funziona bene con il ridimensionamento.

Roey

+0

Il ridimensionamento bitmap sta scambiando un male per un altro. L'immagine risultante sarebbe sfocata: perché preoccuparsi di pubblicare l'immagine DPI alta in primo luogo? L'approccio metafile non ha funzionato neanche per me - penso a causa degli stessi problemi di errore di arrotondamento - i risultati erano identicamente errati. –

+0

Ho pensato solo a due possibili soluzioni: (1) creare un controllo Rich Edit senza finestre, ingrandirlo e chiedergli di eseguire il rendering su un contesto di dispositivo arbitrario che in realtà non è una finestra. Questo potrebbe essere il modo migliore perché utilizza un'interfaccia supportata. (2) aggancia la funzione GetDeviceCaps e falla su LOGPIXELSX e LOGPIXELSY per il tuo specifico contesto di dispositivo, per ingannare il ricco controllo di modifica in rendering al DPI desiderato. Ma questo non sarebbe supportato/non documentato, ovviamente. Non ho avuto il tempo di indagare su nessuna delle due soluzioni. Se trovi una soluzione funzionante mi piacerebbe sentirne parlare! –

+0

soluzione (1): dalla mia esperienza, provare a disegnare il testo gdi (non gdi +) su una superficie che non è una superficie dello schermo ti darà risultati negativi perché la levigatura dei caratteri non funzionerà (ho faticato per giorni). soluzione (2): non ho idea di come farlo :) hai xp in quel campo? – Roey

0

Si potrebbe moltiplicare la dimensione del punto di tutto il testo nel controllo di un fattore 4 e il rendering del controllo in una bitmap che è 4 volte più grandi.

Se si sta compilando il controllo da soli, questo sarebbe abbastanza semplice. Se supportate contenuti arbitrari inseriti dall'utente, il lavoro sarebbe molto più complesso e richiederebbe un ulteriore sforzo per gestire tutto ciò che non era testo (ad esempio bitmap incorporati).

0

Ho appena trascorso due settimane per un problema simile. Avevo bisogno di un Rich Edit scalabile per la modifica di WYSISWG. Come abbiamo scoperto, il controllo di modifica di Windows Rich non supporta il ridimensionamento in modo corretto con EM_FORMATRANGE e la spaziatura tra caratteri inter non cambia tra i livelli di zoom e le dimensioni dei caratteri vengono ridimensionate solo in passaggi di dimensioni carattere discrete.

Poiché non avevo bisogno di grandi differenze di scala, la soluzione su cui ho optato consisteva nell'usare le interfacce di modifica del testo senza finestre da ITextServices per eseguire il rendering su una bitmap interna a una risoluzione fissa. Quindi ho usato GDI + per ricampionare la bitmap interna alla dimensione dello schermo necessaria con il filtro trilineare. I risultati emulavano una modifica ricca scalabile abbastanza bene finché la differenza di scala non era troppo grande, era abbastanza buono per le mie esigenze.

Dopo aver provato diverse opzioni, sono convinto che non è possibile ottenere un ridimensionamento preciso con il controllo di modifica di Windows. Puoi scrivere il tuo controllo che esegue il rendering del testo. Tuttavia, è necessario avere una chiamata separata per ogni testo con uno stile diverso. Inoltre, dovresti gestire tutte le maniglie di modifica avanzate di nicchie per te come evidenziare il testo, posizionare il cursore, gestire input del mouse e della tastiera, analizzare il testo rtf, eccetera. Probabilmente sarebbe meglio comprare solo un componente di terze parti in questo caso (non ho trovato nessun componente open source adatto adatto). Nel caso in cui qualcuno voglia tentarlo, indicherò i punti di partenza rilevanti per il rendering del testo per diverse API.

  • GDI - TextOut non imposta correttamente la spaziatura tra caratteri. Hai bisogno di GetCharacterPlacement e ExTextOut. È inoltre necessario calcolare il ridimensionamento. Probabilmente non si desidera utilizzare GDI
  • GDI + - DrawString gestisce il ridimensionamento in modo corretto. GDI + è un'opzione ragionevole
  • DirectWrite - Se si è disposti a limitarsi a Vista Platform Update o versioni successive, DirectWrite è la più recente API di testo di Microsoft.

Anche qui è il collegamento descrivere come rendering del testo è diverso tra GDI e GDI +:

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

0

Provare a utilizzare il EM_SETZOOM message di lasciare che la scala ricchi controllo di modifica l'uscita stessa.

+0

Ho familiarità con quel messaggio.Non influisce sull'output di EM_FORMATRANGE. In che modo quindi ti proponi di reindirizzare questo output ingrandito verso un altro posto diverso da una finestra interattiva? (che era a cosa è destinato EM_SETZOOM) –

+0

@JamesJohnston, non avendolo mai provato e visto che non lo hai nemmeno menzionato, ho pensato che avrebbe influenzato tutto il rendering. Colpa mia. –

Problemi correlati