Zaawansowane rysowanie tekstu w C#

06.02.2010 @ 18:44:47 by Rafał Kozik | C# .NET grafika

Pisząc różnego rodzaju aplikacje (i gry), chcielibyśmy czasami mieć większa możliwość dostosowania parametrów rysowanego tekstu niż tylko krój, rozmiar i kolor. W .NET jest to bardzo proste -- pokażę dzisiaj jak łatwo można to osiagnać za pomocą GraphicPath.


Freedoku w wersji do druku

18.09.2009 @ 09:35:41 by Rafał Kozik | C# freedoku

Plansze z freedoku można wydrukować, ale czy nadają się one do druku na ulotce, gazecie itp.? Nie bardzo. Wersja na stronie do druku jest specjalnie uproszczona (oszczędzanie tuszu / tonera) i drukowaniem zajmuje się tak naprawdę przeglądarka.

Potrzebowałem planszę do druku z 300 DPI, a to wymaga przygotowania grafiki w odpowiedniej rozdzielczości -- zwykłe przeskalowanie nie da wystarczająco dobrych rezultatów.

Napisałem program, który generuje plansze z freedoku dla zadanego DPI i boku planszy w cm, a efekt wyszedł całkiem pozytywny. Plansza o boku 7 x 7 cm przy 300 DPI wygląda tak:



Obrazek


Całość zaimplementowana w C#, przy okazji opiszę pewnie jakieś wskazówki odnośnie robienia podobnych rzeczy. A do czego mi potrzebne takie grafiki? W ciągu kilku tygodni powinna pojawić się na to pytanie odpowiedź ;).


Zdradzieckie DPI w plikach PNG

03.09.2009 @ 12:29:41 by Rafał Kozik | .NET C# grafika

Biblioteka GDI+ stara się być czasami sprytniejsza niż byśmy tego chcieli i podczas rysowania uwzględnia informację o DPI zawartą w pliku (jest to chunk pHYs), co czasami może przełożyć się na dziwne rezultaty. Jak dziwne? Weźmy jedną grafikę i narysujmy ją z DPI 72, 96 i 300, efekt jest taki:


Obrazek

Może się przez to okazać, że nasze narzędzia generujące grafiki będą dawać dziwne rezultaty. Na dodatek standardowo używane jest DPI z ustawień systemu (standardowo 96), które użytkownik naszego narzędzia może mieć zmienione.

Niektóre narzędzia przetwarzające obrazy zapisują błędnie informację o DPI, o czym przekonałem się parę dni temu, gdy 1/3 grafik testowych (które sam kiedyś tworzyłem) miała złe DPI.

Jak można temu zaradzić? Jako, że nas będą interesować tylko piksele, możemy zmienić DPI wczytanego obrazu za pomocą metody SetResolution i tak samo zrobić dla obrazu, który generujemy -- dzięki temu wszystkie będą miały takie samo DPI i problem powinien zniknąć.


Odtwarzanie dźwięku za pomocą MCI

07.08.2009 @ 19:18:24 by Rafał Kozik | C# WinAPI

Xion pisał ostatnio o odtwarzaniu dźwięku za pomocą PlaySound. Jak dla mnie, ta metoda ma jedną ogromną wadę -- nie pozwala na odtworzenie wielu dźwięków jednocześnie.

Okazuje się też, że dźwięk możemy odtwarzać za pomocą MCI (Media Control Interface). W MSDN można znaleźć szczegółowe informacje na temat użycia. W dalszej części prosty przykład, który potrafi coś odtworzyć.


Dwa nowe projekty

07.08.2009 @ 11:38:24 by Rafał Kozik | C# C++ programowanie

Powoli pracuję teraz nad dwoma projektami, o których jeszcze nie było wspominane. Czas najwyższy to zmienić.

GraphIt

GraphIt (zalecana wymowa 'po naszemu' to po prostu grafit ;)) jest biblioteką dla .NET wspierającą rysowanie różnego rodzaju grafów i diagramów. Będzie stanowiła część mojej pracy magisterskiej i docelowo będzie udostępniona na licencji LGPL. Z powodu kilku problemów technicznych powstaje wolniej niż się spodziewałem, ale powinno się to już zmienić. Mam nadzieję, że w przyszły weekend będę mógł pokazać screeny z jakiegoś prostego użycia.

Wombat Lite

Jestem w trakcie okrajania Wombata, żeby stał się trochę lżejszy i łatwiejszy w użyciu. Trochę rzeczy w oryginalnym projekcie było zrobionych nie do końca dobrze, brakowało też m.in. obsługi dźwięku, którą trzeba w końcu dodać. Przy okazji pracuję nad większym odseparowaniem rzeczy związanych z konkretnym systemem operacyjnym i renderer jest przenoszony na OpenGL. Biblioteka wciąż będzie zamknięta, ale możliwe, że niedługo pojawią się jakieś małe gierki oparte na tej bibliotece (ale za wcześnie jeszcze na szczegóły).


Extension methods w C#

04.06.2009 @ 20:20:42 by Rafał Kozik | C# .NET

W prawie każdym projekcie można znaleźć statyczną klasę/klasy pomocnicze, które zawierają operacje na jakiś danych, ale nie są obiektem w klasycznym sensie. Przykład takiej klasy:

static class Helper
{
	public static string SHA1(string text)
	{
		byte[] buffer = Encoding.UTF8.GetBytes(text);
		SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();

		string hash = BitConverter.ToString(sha1.ComputeHash(buffer));
		return hash.Replace("-", "");
	}
}

Używamy tego tak:

string sha1 = Helper.SHA1(password);

Jak zrobić, żeby pisać mniej kodu i było wygodniej i czytelniej? W C# 3.0 zostały wprowadzone Extension methods, które nam w tym pomogą.


Skróty w Visual C# 2008

04.05.2009 @ 20:54:49 by Rafał Kozik | C# narzędzia

Potrzebowałem przed chwilą znaleźć kilka skrótów w Visual C# 2008 i okazało się, że nie jest to wcale takie proste. Większość elementów menu nie ma pokazanych skrótów, mimo, że takie istnieją, a obsługa listy w opcjach jest uciążliwa.

Okazuje się jednak, że przyswojenie skrótów może być prostsze niż się wydaje. Wystarczy pobrać i wydrukować... plakat ze strony Microsoftu. Dostępne są też dla innych wersji i narzędzi.

Skróty znacznie przyspieszają pracę, dlatego warto poznać kolejną ich garść. Plakat wiszący obok monitora wydaje się być idealnym rozwiązaniem :)


Compo 3h

15.04.2009 @ 22:39:12 by Rafał Kozik | .NET C# gamedev warsztat programowanie

W poprzedni weekend na warsztacie zostało zorganizowane trzygodzinne compo.

Jeszcze nigdy nie brałem udziału w tak krótkim pisaniu gry na czas, ale postanowiłem, że zobaczę co z tego wyjdzie. Ostatecznie zająłem 2 miejsce i jestem z tego zadowolony.

Gra (oczywiście niedokończona ;)), którą pisałem była klonem crimson landa i wypadła nienajgorzej. Całkiem ciekawe wydają mi się szczegóły techniczne, bo jadąc do domu na święta nie miałem dostępu do swojego kodu i pisałem kompletnie od zera:

  • całość pisana w C# i GDI+ (standardowe rysowanie obiektem Graphics)
  • litery w 'intro' i 'outro' są zapisywane podczas preprocessingu do osobnych bitmap
  • podczas gry nie jest używana rotacja (która to byłaby dość wolna), ale podczas wczytywania danych generuję sporą ilość obróconych wersji robotów i pocisków
  • gdy robot jest niszczony, śmieci po nim pozostające zostają wkomponowane w bitmapę tła

Ciekawostką jest też to, że na procesorze C2D 1.8 GHz, użycie procesora według Menadżera zadań Windows nie przekracza 2%. Jak widać proste gry można spokojnie robić bez jakiejkowiek akceleracji ;)

Grę można zobaczyć tutaj.


Bitmapa o bezpośrednim dostępie do pikseli w C#

05.03.2009 @ 16:15:30 by Rafał Kozik | C# grafika

Kiedy w C# chcemy zmodyfikować zawartość bitmapy, możemy zrobić to na kilka sposobów. Pierwszym jest użycie metod GetPixel i SetPixel. Niestety ich wydajność pozostawia wiele do życzenia.

W większości tutoriali opisujących przetwarzanie bitmap, używa się metody Lock, aby dostać się do danych pikseli. Niestety metoda ta narzuca użycie unsafe w naszym kodzie, a poza tym brzydko wygląda.

Okazuje się, że jest jeszcze trzecia metoda, która jest rzadko opisywana -- stworzyć bitmapę na wcześniej przydzielonym obszarze pamięci. Dzięki temu mamy od razu dostęp do jej danych, bez potrzeby wcześniejszego jej blokowania. Taką bitmapę można używać normalnie do rysowania, można też utworzyć powiązany z nią Graphics, żeby po niej rysować. Ważne jest, żebyśmy zablokowali pamięć, której będzie używała taka bitmapa, żeby Garbage Collector jej nie przemieścił.

W dalszej części znajduje przykładowy kod, który robi prostą animację na takiej bitmapie o bezpośrednim dostępie.


Obrazek

Internet Explorer, png i gamma

26.02.2009 @ 23:46:22 by Rafał Kozik | webdev .NET C#

Kiedyś podczas testowania strony w IE okazało się, że pojawił się bardzo dziwny błąd -- obrazy zapisane w plikach png i plikach jpg miały inne odcienie.

Layout został pocięty na mniejsze części i w zależności od zawartości zapisywałem je w odpowiednim formacie (większość grafik przygotowuję w Paint.net). Niestety okazało się, że rezultaty są dziwne:

Obrazek

Bardzo prymitywnym rozwiązaniem było przerobienie wszystkiego na tylko jeden format, ale przez pewien czas się sprawdziło. Przyszedł jednak taki moment, że potrzebowałem nałożyć obraz z przezroczystym tłem (png) na główne tło (jpg) i trzeba było rozwiązać problem.

Jak się okazało, problemem jest chunk gAMA, który jest zapisywany przez Paint.net w plikach png. W GIMP-ie możemy po prostu go nie zapisać i wszystko będzie poprawnie. Nie wiem jednak jak jest w przypadku pozostałych programów graficznych. Chunk ten jest też dodawany gdy zapisujemy obraz w .NET metodą Bitmap.Save, której prawdopodobnie Paint.net używa.

Jeśli mamy już "felerne" pliki, to rozwiązanie jest bardzo proste -- wystarczy pobrać program TweakPNG, a w nim z plików png usunąć chunka gAMA. Zawsze można też otworzyć plik w GIMPie i zapisać bez niego ;)