Tekst na elipsie / ścieżce np. Beziera w WinAPI

0

Jak można narysować np. za pomocą funkcji typu TextOut, DrawText (tylko taki przykład) tekst na elipsie / ścieżce ?

0

WinAPI daje co najwyżej możliwość obracać / ściskać / rozciągać tekst (transformacje afiniczne).

0

Hmmm, zadanie jest następujące narysuj tekst na okręgu. Mó kolega wspomniał, że można rysować literkę po literce obracając fonty. Jest jakieś inne, lepsze rozwiązanie tego problemu?

0

Bez użycia dodatkowych bibliotek nie.
Sposób ten ma wadę, może i nie istotną. Same literki nie będą odpowiednio wygięte np. pauza powinna zostać narysowana jako łuk...

"How to rotate text using WinAPI?"
http://ntcoder.com/bab/2008/02/14/how-to-rotate-text-using-winapi/
Przykład z użyciem MFC, ale bez MFC będzie podobnie. Najważniejsze to wypełnić odpowiednio LOGFONT, utworzyć czcionkę (CreateFontIndirect) i wybrać ją (SelectObject).

0

Ja bym zrobił tak. Narysował tekst na obrazku, a potem na ekranie narysował obrazek radialnie. Jeśli promień krzywizny jest duży w porównaniu do wysokości tekstu efekt powinien być całkiem dobry.
Rysowanie litera po literze też może być, ale trzeba się troszkę namęczyć dla fontów o różnej szerokości liter.

0
MarekR22 napisał(a)

Narysował tekst na obrazku, a potem na ekranie narysował obrazek radialnie. Jeśli promień krzywizny jest duży w porównaniu do wysokości tekstu efekt powinien być całkiem dobry.
Pomysł niezły. Ale tu by wypadało zastosować jakąś interpolację (lepszą niż nearrest neighbour), bo raczej wyjdzie brzydko, literki mają zwykle grubość około 1-2 piksele...

0

Panowie, ścieżki (paths) -> http://www.planetclegg.com/projects/WarpingTextToSplines.html W artykule mowa o GDI+, ale stare GDI także daje możliwość operowania na ścieżkach, więc nie powinno być problemu z przełożeniem tego.

0

Da się, trzeba tylko się zastanowić. Poniższy przykład rysuje tekst na ukrytej bitmapie, którą potem" zawija" na promieniu okręgu. Różnica długości promienia zewnętrznego i wewnętrznego jest równa wysokości tekstu.
Program nie jest w najprostszej wersji - implementuje bitmapy z bezpośrednim dostępem do pikseli, by być wydajnym, oraz rysuje na takowej bitmapie, zamiast bezpośrednio bazgrać po oknie, piksel po pikselu.

Tekst jest rozciągnięty na całym obwodzie okręgu.
Jeszcze kilka rzeczy jest tu do zoptymalizowania - np. ograniczenie pętli do pi/2.

#include <windows.h>
#include <tchar.h>
#define _USE_MATH_DEFINES
#include <math.h>
#define PI2 (M_PI*2)

void Draw(HWND hWnd)
{
	RECT rc;
	GetClientRect(hWnd, &rc);
	int zerox = rc.right/2;
	int zeroy = rc.bottom/2;

	BITMAPINFO bmi={0};
	bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 32;

	// HDC okna
	HDC hdc = GetDC(hWnd);
	// oblicz rozmiar tekstu w pikselach
	SIZE sizeText;
	LPTSTR pszText = TEXT("Jak można narysować np. za pomocą funkcji typu TextOut, DrawText (tylko taki przykład) tekst na elipsie / scieżce ? ");
	GetTextExtentPoint32(hdc,pszText,_tcslen(pszText), &sizeText);
	// bitmapa na tekst - z bezpośrednim dostępem do pikseli - CreateDIBSection
	bmi.bmiHeader.biWidth = sizeText.cx;
	bmi.bmiHeader.biHeight = -sizeText.cy;
	COLORREF *pixels;
	HDC hdcText = CreateCompatibleDC(hdc);
	HGDIOBJ hbmText = SelectObject(hdcText, CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&pixels, 0, 0));
	TextOut(hdcText, 0, 0, pszText, _tcslen(pszText));

	// rysuj pikselami na bitmapie zamiast po oknie, będzie wydajniej
	bmi.bmiHeader.biWidth  = rc.right;
	bmi.bmiHeader.biHeight = -rc.bottom;
	HDC hdcMem = CreateCompatibleDC(hdc);
	COLORREF *pixelsMem;
	HGDIOBJ hbmMem = SelectObject(hdcMem, CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&pixelsMem, 0, 0));
	// białe tło okna
	FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH));

	// obliczamy promień okręgu: połowa wysokości okna minus wysokość tekstu
	int r = zeroy - sizeText.cy;
	int x, y;

	static float offset; // animacja
	
	// optymizuj poza pętlą
	float textxScale = (sizeText.cx-1) / PI2;

	for (float angle=0.0f; angle<PI2; angle+=(M_PI/1024.0f)) // dokładność
	{
		// optymizuj poza pętlą
		float sinx = sin(angle);
		float cosy = cos(angle);
#if 1
		// draw inner circle (optional)
		x = (int)(sinx*(r-1));
		y = (int)(cosy*(r-1));
		SetPixelV(hdcMem, zerox+x, zeroy+y, RGB(255,0,0)); // todo pixelsMem[zerox+x + (zeroy+y)*rc.right];

		// draw outer circle (optional)
		x = (int)(sinx*(r+sizeText.cy));
		y = (int)(cosy*(r+sizeText.cy));
		SetPixelV(hdcMem, zerox+x, zeroy+y, RGB(0,255,0)); // todo
#endif
		for (int texty=0; texty<sizeText.cy; texty++)
		{
			// docelowe koordynaty
			x = (int)(sinx*(r+texty));
			y = (int)(cosy*(r+texty));

			// źródłowe koordynaty: y=texty; x=skaluj(angle na sizeText.cx)
			// 2pi   -> sizeText.cx-1
			// angle -> ?
			int textx = (int)((angle+offset) * textxScale);
			textx = textx % sizeText.cx;

#if 1 // tekst skierowany na zewnątrz okręgu
			COLORREF pixel = pixels[textx + texty*sizeText.cx];
			pixelsMem[zerox+x + (zeroy+y)*rc.right] = pixel;
#else // tekst skierowany do wewnątrz okręgu
			COLORREF pixel = pixels[(sizeText.cx-textx-1) + (sizeText.cy-texty-1)*sizeText.cx];
			pixelsMem[zerox+x + (zeroy+y)*rc.right] = pixel;
#endif
		}
	}

	// skopiuj obraz na okno
	BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY);

	DeleteObject(SelectObject(hdcText, hbmText));
	DeleteDC(hdcText);
	DeleteObject(SelectObject(hdcMem, hbmMem));
	DeleteDC(hdcMem);
	ReleaseDC(hWnd, hdc);

	offset += M_PI*(1.0f/180.0f); // jeżeli mamy animację
}

LRESULT __stdcall MyWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	switch (uMsg)
	{
		case WM_TIMER:
			Draw(hwnd);
			break;

		case WM_CLOSE:
			DestroyWindow(hwnd);
			break;
	}
	return 0;
}

extern "C" int main()
{
	MSG msg;
	HWND hwnd = CreateWindowEx(0, WC_DIALOG, TEXT("round text sample"),
		WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,0,0,0,0);

	if (hwnd)
	{
		Draw(hwnd);
		SetWindowLongPtr(hwnd, DWLP_DLGPROC, (LONG_PTR)MyWindowProc);
		SetTimer(hwnd, 1000, 50, 0);
		while (IsWindow(hwnd) && GetMessage(&msg,0,0,0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return 0;
}

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