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

Odpowiedz Nowy wątek
2014-12-24 02:08
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.

edytowany 1x, ostatnio: woolfik, 2014-12-24 02:11

Pozostało 580 znaków

2014-12-24 02:43
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.


edytowany 1x, ostatnio: furious programming, 2014-12-24 02:44

Pozostało 580 znaków

2014-12-24 11:49
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.


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.

Pozostało 580 znaków

2014-12-24 13:01
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.

Pozostało 580 znaków

2014-12-24 15:02
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.


Pozostało 580 znaków

2014-12-24 18:18
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?


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

2014-12-24 19:22
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_irecenzje/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.


edytowany 2x, ostatnio: furious programming, 2014-12-24 19:24
Faktycznie u mnie ten sam efekt, że literka A ma u góry kilka pikseli odstępu. - woolfik 2014-12-24 19:59
Zobacz sobie na innych znakach - albo za dużo, albo za mało; Nie wiem dlaczego, ale trzeba pokombinować jeszcze, bo jeśli znajdzie się niezawodny sposób na mierzenie tekstu, to i mój label pod Delphi poprawię; - furious programming 2014-12-24 20:58
A nie da się z pliku z fontem wyciągnąć danych o offsetach i szerokościach/wysokościach liter? - babubabu 2014-12-24 21:28
Trzeba by zaglądnąć do specyfikacji konkretnych formatów, ale nie wiem jak są zbudowane i w jaki sposób system z nich korzysta; - furious programming 2014-12-24 21:56
Może google wie :P - babubabu 2014-12-24 22:23
Google podsunął mi funkcję DrawText i flagę DT_CALCRECT ;) - furious programming 2014-12-24 22:37

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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