2012-06-26 13 views
5

Używam komunikatu do renderowania danych wyjściowych formantu tekstu formatowanego do dowolnego kontekstu urządzenia. Jednak podczas renderowania do bitmapy, kropki na cal w kontekście urządzenia bitmapy są takie same jak w przypadku DPI urządzenia wyświetlającego, czyli 96 punktów na cal. Jest to znacznie mniej niż to, na co chciałbym oddać. Wolałbym renderować przy znacznie wyższej wartości DPI, aby użytkownik mógł powiększać i być może później drukować na drukarce o wysokiej czułości.Błędy zaokrąglania podczas skalowania renderowanego wyjścia formantu edycji rozszerzonej za pomocą EM_FORMATRANGE

Podejrzewam, że dzieje się tak, że sterowanie RTF wywołuje GetDeviceCaps z LOGPIXELSX i LOGPIXELSY, aby uzyskać liczbę pikseli na cal urządzenia. Następnie renderuje dokument przy użyciu tej wartości DPI przy poziomie powiększenia 100%. Urządzenia wyświetlające Windows zawsze zwracają wartość 96 DPI, o ile w systemie nie są używane duże czcionki (ustawione w Panelu sterowania), a aplikacja obsługuje DPI.

Wiele przykładów w Internecie proponuje skalowanie wyjścia EM_FORMATRANGE. Jest tak, aby można było uzyskać dowolną rozdzielczość DPI. Większość przykładów na ogół obejmuje używanie SetMapMode, i SetViewportExtEx (np. Patrz http://social.msdn.microsoft.com/Forums/en-us/netfxbcl/thread/37fd1bfb-f07b-421d-9b5e-5f4492ffbbc3). Za pomocą tych funkcji można skalować wyniki renderowania formantu tekstu w formacie RTF: na przykład, jeśli określę skalowanie 400%, to jeśli formant tekstu sformatowanego wykona obraz o szerokości 5 pikseli, będzie on miał szerokość 20 pikseli.

Niestety, stare funkcje GDI używają liczb całkowitych zamiast liczb zmiennoprzecinkowych. Załóżmy na przykład, że kontrola RTF zdecydowała, że ​​element powinien zostać narysowany w (12,7, 15,3) pikselach. Zostałoby to zaokrąglone do pozycji (13, 15). Te zaokrąglone współrzędne są przekazywane do GDI, które następnie skalują obraz za pomocą skalowania określonego przez SetMapMode: na przykład 400%, będzie to (13 * 4, 15 * 4) lub (52, 60). Ale nie jest to dokładne: element lepiej byłoby umieścić w (12,7 * 4, 15,3 * 4) lub (51, 61). Najgorsze jest to, że w niektórych przypadkach błąd staje się kumulatywny.

Wierzę, że to jest przyczyna tego bardzo zauważalny błąd podczas skalowania jakiś prosty tekst:

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

Powyższy przykład jest 8 punkt Segoe UI, skalowane do 400% przy użyciu EM_FORMATRANGE i SetMapMode na zasadzie Kontekst urządzenia wyświetlającego 96 DPI. Tekst ma teraz rozmiar 32-punktowy, ale przestrzeń między poszczególnymi postaciami jest zbyt wysoka i wygląda nienaturalnie.

Zoomed to 400% in WordPad

Powyższy przykład został utworzony w WordPadzie wprowadzając tekst o 8 punktów Segoe interfejsu a następnie za pomocą regulatora powiększenia ustawiona na 400% stopniu powiększenia. Przestrzeń między każdą postacią wygląda normalnie. Dokładnie taki sam wynik uzyskuje się za pomocą czcionki 32-punktowej i 100-procentowego zoomu.

Aby obejść ten problem, próbowałem wykonać następujące czynności. Dla każdego wypróbowanego wyniku wynik był identycznie niezadowalający, gdy skalowany do 400%.

  • Korzystanie z transformacji skalowania ustawić za pomocą SetWorldTransform zamiast skalowania wykonanej z SetMapMode i SetWindowExtEx itp
  • Przechodząc kontekstu urządzenia dla metafile do EM_FORMATRANGE, a następnie skalowanie metapliku później.
  • Skalowanie w połączeniu z renderowaniem do metapliku, a następnie wyświetlenie metapliku później bez skalowania.

wierzę, wyniki zawsze są niezadowalające, ponieważ problem sprowadza się do tego, że bogaty kontrola edycji jest zaokrąglenie do najbliższej liczby całkowitej i renderowania do tego, co myśli, to urządzenie 96 DPI - ignorując transformacji w miejscu. Zajrzałem do formatu metapliku i odkryłem, że poszczególne pozycje postaci są przechowywane w metapliku w rozdzielczości pikseli - dlatego skalowanie metapliku oczywiście nie działało, ponieważ zaokrąglenie już nastąpiło w tym punkcie.

mogę myśleć o dwóch realnych rozwiązań, które obejść ten problem:

  • Użyj kontekst urządzenia z wyższych punktów określonych przez użytkownika na cal, tak że GetDeviceCaps zwroty różnych wartościach. (Uwaga: niektóre przykłady proponują używanie drukarki, ponieważ generalnie mają wyższą wartość DPI, ale chcę, aby mój kod działał na systemach, które nie mają drukarki i mogą być renderowane do bufora poza ekranem).
  • W jakiś sposób można powiedzieć, że formant edycji rozszerzonej przyjmuje, że kontekst urządzenia ma inną kropkę na cal niż raportowany przez GetDeviceCaps.

Wszystko inne wydaje się być nadal przedmiotem tych błędów zaokrąglania.

Czy ktokolwiek (1) ma pomysł, jak wdrożyć którekolwiek z proponowanych przeze mnie rozwiązań, lub (2) mam alternatywny pomysł, jak osiągnąć cel, jakim jest uzyskanie dokładnego wyjścia o wysokiej rozdzielczości w buforze?

Odpowiedz

0

Mam dokładnie ten sam problem.

Szybkie rozwiązanie polega na narysowaniu tekstu na mapie bitowej o 100% skali, a następnie przeskalowaniu bitmapy. To nie jest najlepsze rozwiązanie, ale może działać dla Ciebie.

Czy znalazłeś lepsze rozwiązania? jeśli tak, udostępnij je tutaj.

Zauważ, że ten problem występuje również, gdy narysujesz tekst w 100-metrowym pliku, a następnie przeskalujesz metawarunek do ekranu - uważam, że ma to coś wspólnego z funkcjami rysowania tekstu GDI, które nie są dostępne. t działa dobrze ze skalowaniem.

Roey

+0

Skalowanie mapy bitowej to handel jednym złem za drugiego. Wynikowy obraz byłby niewyraźny: po co zawracać sobie głowę wyjściami do obrazu o wysokiej rozdzielczości? Podejście metapliku również nie zadziałało - sądzę, że z powodu tych samych problemów z błędem zaokrąglania - wyniki były identycznie błędne. –

+0

Pomyślałem tylko o dwóch możliwych rozwiązaniach: (1) Stwórz bogatą w oknach edycję bogatą w edycję, powiększ ją i poproś o renderowanie do dowolnego kontekstu urządzenia, który w rzeczywistości nie jest oknem. To może być najlepszy sposób, ponieważ używa obsługiwanego interfejsu. (2) przechwyć funkcję GetDeviceCaps i spraw, by kłamała ona o LOGPIXELSX i LOGPIXELSY dla konkretnego kontekstu urządzenia, aby oszukać formant edycji edycyjnej do renderowania z pożądanym DPI. Ale oczywiście nie będzie to wspierane/nieudokumentowane. Nie miałem czasu zbadać żadnego z tych rozwiązań. Jeśli otrzymasz działające rozwiązanie, chciałbym o tym usłyszeć! –

+0

rozwiązanie (1): z mojego doświadczenia, próbując narysować tekst gdi (nie gdi +) na powierzchni, która nie jest powierzchnią ekranu, da ci złe wyniki, ponieważ wygładzanie czcionek nie zadziała (przez te dni zmagałem się z tym problemem). rozwiązanie (2): nie mam pojęcia, jak to zrobić :) Czy masz XP w tym polu? – Roey

0

Można mnożyć rozmiar punktem wszystkich tekstu w kontroli przez współczynnik 4 i oddać kontrolę na bitmapę, która jest 4 razy większe.

Jeśli sam wypełniasz kontrolę, będzie to całkiem proste. Jeśli obsługujesz dowolną zawartość wprowadzoną przez użytkownika, byłoby to znacznie więcej pracy i wymagałoby dodatkowego wysiłku, aby obsłużyć wszystko, co nie było tekstem (na przykład osadzone mapy bitowe).

0

Właśnie spędziłem dwa tygodnie na podobny problem. Potrzebowałem Rich Edit, który był skalowalny do edycji WYSISWG. Jak już odkryliśmy, formant edycji Edytor bogaty w okna nie obsługuje poprawnego skalowania za pomocą EM_FORMATRANGE, a odstępy między znakami nie zmieniają się między poziomami powiększenia i rozmiarami czcionek są skalowane tylko w dyskretnych krokach wielkości czcionki.

Ponieważ nie potrzebowałem dużych różnic w skali, rozwiązanie, na które się zdecydowałem, polegało na wykorzystaniu interfejsów do edycji tekstu bez okien z ITextServices w celu renderowania do wewnętrznej bitmapy ze stałą rozdzielczością. Następnie użyłem GDI +, aby ponownie porównać wewnętrzną mapę bitową do wymaganego rozmiaru ekranu z filtrem trójliniowym. Wyniki emulowały skalowalną bogatą edycję wystarczająco dobrze, o ile różnica skali nie była zbyt duża, była wystarczająco dobra dla moich potrzeb.

Po wypróbowaniu wielu różnych opcji jestem przekonany, że nie można uzyskać precyzyjnego skalowania za pomocą formantu edycji bogatego w okna. Możesz napisać własną kontrolę, która renderuje tekst. Musisz jednak mieć osobne wywołanie rysowania dla każdego fragmentu tekstu o innym stylu. Trzeba by było również obsłużyć wszystkie bogate edytowalne uchwyty dla ciebie, takie jak podświetlanie tekstu, umieszczanie kursora, obsługa myszy i klawiatury, analizowanie tekstu rtf itp. Najlepiej byłoby po prostu kupić komponent zewnętrzny w tym przypadku (nie mogłem znaleźć żadnych odpowiednich darmowych komponentów open source). Jeśli ktoś chce spróbować, wskażę odpowiednie punkty początkowe dla renderowania tekstu dla różnych interfejsów API.

  • GDI - TextOut nie ustawia poprawnie odstępu między znakami. Potrzebujesz GetCharacterPlacement i ExTextOut. Musisz także obliczyć skalowanie samodzielnie. Prawdopodobnie nie chcesz używać GDI
  • GDI + - DrawString obsługuje skalowanie poprawnie. GDI + jest rozsądną opcją
  • DirectWrite - Jeśli chcesz ograniczyć się do aktualizacji platformy Vista lub nowszej, DirectWrite jest najnowszym API tekstowym od Microsoft.

Również tutaj jest powiązanie opisujące sposób renderowania tekstu różni się między GDI i GDI +:

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

0

Spróbuj użyć EM_SETZOOM message pozwolić bogatej gamie edit kontrola samego wyjścia.

+0

Jestem zaznajomiony z tą wiadomością.Nie ma wpływu na wynik EM_FORMATRANGE. Jak zatem proponujesz przekierowanie tego powiększonego obrazu do innego miejsca niż okno interaktywne? (do czego był przeznaczony EM_SETZOOM) –

+0

@JamesJohnston, nigdy go nie wypróbowałem, a ponieważ o tym nie wspomniałeś, zakładałem, że wpłynie to na cały rendering. Mój błąd. –

Powiązane problemy