Jak dostosować wielkość czcionki na canvasie do wymiarów bitmapy

0

Witajcie,

Mam taki dość nietypowy problem. Tworzę plik jpg z poziomu kodu mniej więcej w taki sposób:

procedure TForm1.Button1Click(Sender: TObject);
var
  bmp: TBitmap;
  jpg: TJPEGImage;
begin
  bmp := TBitmap.Create;
  jpg := TJPEGImage.Create;
  try
    bmp.Width := 6;
    bmp.Height := 8;
    bmp.Canvas.Font.Name:='Verdana';
    bmp.Canvas.TextOut(0,0,'A');
    jpg.Assign(bmp);
    jpg.SaveToFile('C:\a_6x8.jpg');
  finally
    jpg.Free;
    bmp.Free;
  end;
end;

Sęk w tym, że jeśli zrobię to tak jak teraz to literka A jest ucięta. Potrzebowałbym jakiś sprytny sposób aby tą literkę A wysterować w taki sposób aby jej rozmiar dobrać do wielkości podanych w bmp.width i bmp.height. Efekt jaki chciałbym uzyskać jest w załączniku. Potrzebuję taką operację wykonać dla wielu różnych czcionek i rozmiarów. Cała funkcjonalność jest częścią większego projektu gdzie parametrami wejściowymi będzie znak, czcionka i wymiary bitmapy. Ja potrzebowałbym teraz taki kod, który w zależności od wymiarów i czcionki tak rozciągnie znak aby by on rozciągnięty do wskazanych wymiarów. Nie może być czegoś takiego, że ktoś poda wymiar np 100x100, a w środku będzie tylko malutka literka. Efekt ma być taki, że litera ma być 100x100 px.

0

Nie znam i nie znalazłem jakiegoś szybkiego rozwiązania, ale zawsze możesz namalować dużą literę (np. na 200px wysokości) na większym obszarze, przyciąć ją i za pomocą Canvas.StretchDraw namalować, już w konkretnym Rect; Do wyznaczenia rozmiarów litery (mniej więcej) możesz skorzystać z funkcji Windows.DrawText i flagi DT_CALCRECT; Ale może ktoś inny zna jakiś sposób na solidne i niezawodne mierzenie tekstu, przed jego narysowaniem;

Ogólnie to standardowe fonty sprawiają dużo problemów, a metody klasy TCanvas często źle obliczają wymiary tekstu.

0

użyj CreateFontIndirect - możesz tam podać wprost wysokość i szerokość fonta. Oczywiście przy czcionce ze zmienną szerokością musisz najpierw sprawdzić ile będzie zajmował cały napis przy danej szerokości a potem przeskalować szerokość fonta wg wymaganej szerokości. Wysokość jak ustalisz taka będzie.

0

abrakadaber napis to tylko jedna literka lub cyfra i niestety nie zadziałało tak jak bym chciał. Jak podałem wymiary to mi obciął albo z dołu albo z boku.
furious programming - spróbuję pokombinować dam znać czy mi się udało.

0

To co podałem daje bardzo duży nakład pracy, bo trzeba sporo operacji wykonać, aby dobrze wymierzyć literkę; Tyle że nic sensowniejszego i przede wszystkim działającego zawsze poprawnie nie znalazłem i to mnie dziwi; Nawet fukncje WinAPI źle mierzą wysokość znaków (a razem z nimi metody klasy TCanvas), więc trzeba to jakoś obejść;

Podczas pracy nad moim labelkiem zdarzały się przypadki, gdzie wysokość była mierzona dobrze, ale szerokość słów już nie; Głównie jeśli chodzi o font pogrubiony - metoda TextWidth zwracała zbyt małą szerokość, przez co słowa prawie nachodziły na siebie; Dlatego też w nowym projekcie używam całkiem customowych fontów, przez co problemy z pomiarami się skończyły.

0
furious programming napisał(a):

... zdarzały się przypadki, gdzie wysokość była mierzona dobrze, ale szerokość słów już nie ...
Możesz poprzeć to twierdzenie fragmentem kodu?

0

To nie jest twierdzenie, a realny problem, zauważony w Delphi7 - pisałem swój label i taki problem napotkałem przy testach różnych fontów; Pisałem o tym od pierwszego posta w tym wątku: http://4programmers.net/Forum/Off-Topic/Oceny_i_recenzje/239916-tfuriouslabel_-_etykieta_formatowana_znacznikami_html:

Wady:

(...)

  • występuje problem z niektórymi fontami i rysowaniem podkreślonych linków o takich fontach - z tego co wybadałem nie jest to problem kodu komponentu, a metody TCanvas.TextHeight, która czasem źle oblicza wysokość pogrubionego lub podkreślonego tekstu), co negatywnie wpływa na rysowanie słów; W nowszych środowiskach niż Delphi7 być może zostało to poprawione;

Złe mierzenie wysokości tekstu objawiało się tym, że słowa o pogrubionym stylu były rysowane piksel/dwa piksele niżej, niż tekst ze stylem standardowym; W niektórych fontach (głównie Ubuntu) był problem z mierzeniem szerokości słów o stylu pogrubionym lub pochylonym; Objawiało się to tym, że dwa słowa - ze stylem standardowym i drugie z pogrubionym - rysowane były ze zbyt małą przerwą, a nawet bez odstępu; Taki defekt zauważyłem wilokrotnie podczas dziesiątek testów i nie znalazłem winy w moim kodzie; Dlatego też napisałem o tym w dedykowanym komponentowi wątku;

Sprawdzałem dokładnie i wielokrotnie poprawność działania tokenizera, wrzucając dane ze wszystkich tokenów do pliku tekstowego; Jeżeli pogrubione słowo było źle malowane na kanwie, patrzyłem do pliku z logami i faktycznie token posiadał złą wartość szerokości słowa (ze złą wysokością było tak samo); A szerokość słowa zawsze była obliczana po ustawieniu stylu i metodą TCanvas.TextWidth; Dlatego też tokenizer działał poprawnie, mechanizm rysujący słowa także, więc jedynym winnym były metody TCanvas.TextHeigh i TCanvas.TextWidth, które de facto korzystają z API Windowsa; Pod Lazarusem tego problemu nie było, a przynajmniej w testach się nie ujawnił;

Z resztą funkcja DrawText z modułu Windows także jest wadliwa; Przeprowadziłem testy na mierzeniu obszaru za pomocą flagi DT_CALCRECT i obszar wyliczany był źle; Dla samej literki A szerokość była dobra, ale z góry i z dołu były niepotrzebne odstępy, więc obszar był źle wyznaczany; Następnie sprawdziłem z sekwencją Aj, aby także sprawić na innych literach; Tu znowu był problem, po pusta przestrzeń była u góry, a dół literki j był ucięty;

Tak więc kodu nie ujawnię, bo kod labelka nie jest otwarty; Sam sprawdź to zobaczysz (a może i nie); Z resztą metoda TCanvas.TextHeight chyba żadnego fonta nie zmierzy według faktycznych rozmiarów liter i dobrze, bo nie do tego ma służyć; Znaki są różne, mają różną szerokość, różną wysokość i różny offset od góry, a pomimo tego wysokość wszystkich znaków określa jako taką samą - Canvas.TextHeight(',') = Canvas.TextHeight('|');

PS: W wątku dotyczącym mojego labelka jest program testowy - spróbuj wywalić parser i zaobserwować ten defekt.

1 użytkowników online, w tym zalogowanych: 0, gości: 1