W Win7 niektóre czcionki nie działają tak jak w Win2K / XP

Moje pytanie dotyczy tego, jak należy zmienić obsługę czcionek, aby działała poprawnie w systemie Windows 7. Jestem pewien, że założyłem o czymś, co było wcześniej ważne, ale nie jest już ważne. Ale nawet nie wiem, od czego zacząć szukać! Modlę się, żeby ktoś mógł pomóc! Oto szczegóły, które rozumiem (umieściłem to pytanie również na forum programistów Microsoft Windows, ale nie odpowiadają):

Tak, jestem za czasów (heck, wciąż piszę kod WIN32 w zwykłym C!) Mam 10-letnią bibliotekę DLL, którą napisałem, która naśladuje jeszcze starszą bibliotekę I / O ekranu DOS w obszarze roboczym okna. Nie trzeba dodawać, że pozwala to tylko na używanie czcionek o stałej szerokości. Gdy niektóre programy korzystające z biblioteki DLL zostały przeniesione do systemu Windows 7, pojawia się dziwne migotanie, które pojawia się, gdy używana jest czcionka TRUE TYPE o stałej szerokości (czcionki bitmapowe nadal działają idealnie.) Problem został namierzony aż do faktu że napisano jedną postaćExtTextOut jest szerszy niż powinien. Sprawdziłem pomiary na trzy różne sposoby (używającGetTextExtentPoint32 na łańcuchu 132 znaków i dzielenie przez 132, dzwoniącGetTextMetrics a nawet za pomocąGetCharABCWidths dla wszystkich 256 znaków) i wszyscy zgadzają się, że czcionka ma tę samą szerokość. AleExtTextOut renderuje prostokąt tła jeden lub dwa piksele szersze niż szerokość czcionki. Albo to, albo zaczyna tło renderujące piksel lub dwa na lewo od pozycji podanej w parametrach [nazywam to tak:ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL ).] I pamiętajcie, ten DOKŁADNY kod działał idealnie pod Windows 2000, Windows XP i, z czcionkami bitmapowymi w Windows 7 - ale już nie działa poprawnie z czcionkami True Type o stałej szerokości w Windows 7.

Dla każdego, kto nie rozumie tego, co muszę zrobić: spróbuj wyobrazić sobie pisanie jednego znaku na kwadrat na kawałku papieru milimetrowego. Każdy kwadrat używa tej samej czcionki, ale może mieć inny kolor pierwszego planu i / lub tła. używamTA_TOP|TA_LEFT wyrównanie tekstu, ponieważ jest to najprostszy i każde konsekwentnie stosowane wyrównanie powinno działać dla czcionki o stałej szerokości.

Widzę, że ExtTextOut emituje większy prostokąt tła niż podałem wRECT * parametr. Ponieważ dostarczany przeze mnie prostokąt jest tworzony na podstawie zgłoszonej wielkości czcionki, NIGDY nie powinno się to zdarzyć - i nigdy nie zdarzyło się to w systemie Windows XP i wcześniejszych, i nie występuje w przypadku czcionek bitmapowych (np. .FON) w systemie Windows 7, zarówno. Ale ZAWSZE dzieje się to z czcionkami TrueType o stałej szerokości w systemie Windows 7. Jest to z EXACT SAME EXECUTABLE działającym w Windows 2000, Windows XP i Windows 7 (32 i 64). Chociaż chciałbym po prostu powiedzieć, że Windows 7 ma błąd, Jestem bardziej skłonny uwierzyć, że pewne fundamentalne założenia, które zrobiłem na temat obsługi czcionek w systemie Windows, nie są już prawdziwe (po 20 latach pisania oprogramowania dla Windows).

Ale nie mam pojęcia, jak i gdzie odkryć, co to może być! Proszę, pomóżcie mi!

--- amm Poprawka ---

Wszystkim zainteresowanym udało mi się obejść to, co rozważam jako błąd - dopóki nie znajdę dokumentacji przeciwnej. Moje obejście składa się z dwóch zmian w mojej bibliotece:

Użyj rozmiaru zwróconego zGetTextExtentPoint32() „X” zamiast danychTEXTMETRICS.ZawieraćETO_CLIPPING flaga w ogóleExtTextOut() połączenia.

Wcześniej korzystałem ztmHeight+tmExternalLeading dla liczby pikseli między wierzchołkami kolejnych wierszy tekstu, jak jest to udokumentowane. Odkryłem, że wartość size.cy wraca zGetTextExtentPoint32() nie był taki sam i wydawał się bardziej dokładny. Najgorszym przykładem, jaki znalazłem, była czcionka OCRB typu prawdziwego. Oto, co zobaczyłem w debuggerze dla utworzonej przeze mnie czcionki OCRB (przy użyciu okna wyboru czcionek systemowych):

ocrbtm.tmHeight          = 11
ocrbtm.tmExternalLeading =  7

ocrbsize.cy = 11

Dlatego z jakiegoś powodu, którego jeszcze nie odkryłem, Windows ignoruje zewnętrzną wartość wiodącą zdefiniowaną dla czcionki OCRB. Użycie wartości rozmiaru zamiast TM powoduje, że tekst jest ładny, zgrabny, zapakowany, co właśnie chciałem.

TheETO_CLIPPING flaga nie powinna być dla mnie konieczna, ponieważ ustawiam prostokąt dokładnie do wymiarów pojedynczego znaku i użyciaETO_OPAQUE aby wypełnić tło (i nadpisać poprzednią zawartość komórki.) Ale bez flagi przycinania pojedynczy znak jest szerszy niż wskazywałby rozmiar, metryka tekstu lub szerokość ABC - przynajmniej tak jest w przypadku wszystkich dokumentacja, którą do tej pory znalazłem.

Wierzę, że problem HEIGHT istnieje od dłuższego czasu, ale reszta była niepotrzebna, dopóki nie uruchomiliśmy naszego oprogramowania pod Windows 7. Dołączam to do mojego pytania, aby sprawdzić, czy ktoś może wyjaśnić, czego oczywiście nie rozumiem.

- Poprawka 2 -

1: Cała dokumentacja, jaką mogę znaleźć, mówi taktmHeight+tmExternalLeading powinien tworzyć pojedyncze linie tekstu. Kropka. Ale to nie zawsze jest prawdą i nie mogę znaleźć dokumentacji wskazującej, w jaki sposób Windows określa różne wartości, które czasami są zwracane przezGetTextExtentPoint32().

2: pod Win7 (może Vista)ExtTextOut zaczęliśmy wypełniać trochę więcej tła niż powinno (dodając kilka dodatkowych pikseli w prawo), ale tylko wtedy, gdy wybrana jest czcionka typu prawdziwego. Robi to, nawet jeśli prostokąt jestpodwójnie oczekiwany rozmiar znaku (w obu wymiarach.) DPI / skalowanie może być czynnikiem, ale ponieważ mój system jest ustawiony na 100%, wydaje się, że system Windows ma problem ze współczynnikiem skalowania 1: 1 i wydaje się, że być błędem. Fakt, że dotyczy tylko czcionek typu prawdziwego, a nie bitmapowego (.FON), również wydaje się wykluczać skalowanie (chyba, że ​​istniejejest błąd w systemie skalowania), ponieważ Windows powinien próbować skalować cały tekst, a nie tylko część. Ponadto istnieje szare (ale zaznaczone) ustawienie „Użyj skalowania DPI stylu Windows XP” w oknie „Niestandardowe ustawienie DPI”. Wreszcie, cała ta sprawa może być wynikiem mojego działania pod motywem Windows Classic zamiast jednego z Aero lub innych natywnych motywów Win7.

- Poprawka 3 -

Po prostu wywołanie SetProcessDPIAware () nie ma wpływu na problem, który mam. Ponieważ mój problem występuje przy ustawieniu 100% DPI (skala 1: 1), jeśli mój problemjest Związane z DPI, to musiałem odkryć błąd w wirtualizacji DPI, ponieważ tak opisuje tę funkcję Microsoft:

Funkcja ta polega na udostępnianiu aplikacji „zwirtualizowanych” metryk systemu i elementów interfejsu użytkownika, tak jakby działała w 96 DPI. Następnie aplikacja wyświetla na powierzchni 96-DPI poza ekranem, a Menedżer Windows Desktop skaluje wynikowe okno aplikacji, aby dopasować ustawienie DPI.

Wszystkie moje ustawienia pokazują, że jestem w 100% skalowany, a przeglądanie ustawień niestandardowych wyraźnie pokazuje, że oznacza to 96 DPI. Jeśli więc wirtualizacja DPI z 96 DPI do 96 DPI nie działa dla moich czcionek True Type o stałej szerokości, to Windows ma problem, prawda? Czy istnieje funkcja, którą muszę zadzwonić (lub przestać dzwonić?), Aby wirtualizator DPI działał poprawnie?

Nadal nie jestem przekonany, że rzekomy problem skalowania ma tak samo dużo wspólnego z czcionką SIZE, jak początkowo sądziłem. To dlatego, że problem przejawia się wprostokąt tła być wypełnionymExtTextOut() zamiast emitowanego znaku tekstowego. Prostokąt tła zostaje nieco powiększony, gdy czcionka jest typu prawdziwego. Sprawdziłem również, czy ten problem występuje bez względu na to, czy używasz motywu Windows Classic, czy standardowego motywu Windows Aero. Teraz zbuduj uproszczony przykład, aby inni mogli z nim eksperymentować.

- Poprawka 4 -

Stworzyłem minimalny program demonstracyjny, który pokazuje, co widzę (i co robię). Projekt / źródło Visual Studio 2010 można pobrać zhttp://www.svalli.com/files/fwtt.7z - Celowo nie uwzględniłem plików wykonywalnych, ponieważ nie chcę ryzykować rozprzestrzeniania złośliwego oprogramowania. Program wybrał czcionkę o stałej szerokości, a następnie zapisuje dwie siatki znaków 5x5 do obszaru roboczego, jeden utworzony przy użyciuGetTextExtentPoint32 rozmiar i jeden za pomocąTEXTMETRIC rozmiar zgodnie z dokumentacją Microsoft. Siatki są w czarno-białym wzorze szachownicy z żółtym czerwonym znakiem wpisanym jako ostatni w środku, aby pokazać efekt nakładania się (możesz potrzebować narzędzia powiększenia, aby zobaczyć je wyraźnie). Program rysuje również ciąg, który zaczyna się od 5 X tuż poniżej siatkę, zaczynając od tego samego lewego przesunięcia, która ma być używana jako porównanie dla mojej metody umieszczania pojedynczych znaków (pasuję do ciągu). Menu pozwala na włączanie / wyłączanie przycinania wExtTextOut i wybór innych czcionek. Istnieje również opcja wiersza poleceńdpiaware (rozróżniana wielkość liter) powoduje wywołanie programuSetProcessDPIAware() kiedy się uruchamia, aby efekt tego połączenia mógł być również oceniony.

Dzięki temu nauczyłem się tegoExtTextOut wypełnia właściwy prostokąt tła, ale postać renderowana z nieprzezroczystym tłem może być szersza niż powinna być i może nawet nie zacząć się w miejscuExtTextOut kazano mi zacząć rysować! Powiedziałem „powinno być”, ponieważ odstępy między znakami, które kończę, są zgodne z tym, co otrzymuję, gdy mamExtTextOut renderuj cały ciąg. Nakładanie może najwyraźniej być po jednej lub obu stronach danego prostokąta, na przykład OCRB dodaje dodatkowy piksel zarówno po lewej, jak i prawej stronie komórki znakowej, podczas gdy inne czcionki typu prawdziwego, które sprawdziłem, dodają dwa piksele w prawo krawędź.

Naprawdę chcę to zrobić w „właściwy” sposób, ale nie mogę znaleźć żadnej dokumentacji, która pokazuje, co robię źle lub brakuje. Cóż, prawdopodobnie brakuje mi czegoś dla oprogramowania DPI Aware w skalach innych niż 100%, ale poza tym jestem po prostu zaskoczony.

- Poprawka 5 -

Nieco mniej zaskoczony ... problem jest spowodowany przez ClearType. Wyłączenie ClearType sprawiło, że wszystkie czcionki ponownie działały. Włączenie ClearType pod XP powoduje ten sam problem. Najwyraźniej ClearType może po cichu (dopóki ktoś nie powie mi, jak go wykryć) rozciągać znaki poziomo o kilka pikseli, aby zrobić miejsce na cieniowane piksele, które dodaje, aby wygładzić.

Czy wycinanie jest jedynym sposobem na rozwiązanie tego problemu?

- Poprawka 6 -

Częściowa odpowiedź na powyższe pytanie dotyczące wycinania: Podczas tworzenia nowej czcionki wykonuję teraz następujące czynności (w pseudo-kodzie):

CreateFontIndirect
SelectFont
GetTextMetrics
if( (tmPitchAndFamily & TMPF_TRUETYPE) && Win6.x or above )
   if( SystemParametersInfo( SPI_GETCLEARTYPE ) )
        lfQuality = NONANTIALIASED_QUALITY
        DeleteObject( font )
        CreateFontIndirect

Bez umożliwienia obcięcia tegoprawie zawsze działa z rozmiarami czcionek, których używam, chociaż znalazłem kilka, które wciąż renderują dodatkowy piksel po prawej (lub po lewej) komórki znaku. Na szczęście wydaje się, że są to darmowe czcionki znalezione w Internecie, więc ich ogólna jakość może być niższa niż standardy profesjonalnych odlewni czcionek.

Gdyby ktoś mógł znaleźć lepszą odpowiedź, naprawdę bymNAPRAWDĘ uwielbiam to słyszeć! Do tego czasu myślę, że to jest tak dobre, jak się da. Dziękuję, że przeczytałeś tak daleko!

questionAnswers(1)

yourAnswerToTheQuestion