Staňte se programátorem: Napište si malý Photoshop

Bitmapový editor Paint.NET je napsaný v jazyku C#. Dnes vám ukážeme, jak snadno lze v tomto jazyku napsat základní fotografické efekty. Napište si s námi takový malý Photoshop.

Jedním z nejznámějších desktopových programů napsaných pro Microsoft .NET Framework je bitmapový editor Paint.NET. Ačkoliv se zatím svými možnostmi a schopnostmi nemůže rovnat s vyspělými grafickými editory, je jednou z vlajkových lodí této platformy, většina .NET vývojářů se totiž soustředí především na webové aplikace, ASP.NET aj.

Bitmapový editor s fotografickými efekty I.

Bitmapový editor bez množství nejrůznějších fotografických a kreativních filtrů by v těžké konkurenci nemohl obstát. Dnes vám tedy ukážeme, jak si v jazyku C# napsat filtr, který původní obrázek převede do odstínu šedi, přidá mu historický nádech pomocí sépiového efektu a převede jej do negativu. Kód si pak budete moci vyzkoušet v jednoduchém editoru, který obrázek s efektem bude umět i uložit.

Klepněte pro větší obrázek  Klepněte pro větší obrázek
Náš jednoduchý editor s třemi bitmapovými efekty

V dnešním projektu se tedy dozvíte, jakým způsobem lze manipulovat s jednotlivými pixely obrázku, jejichž změnou budete moci na bitmapě vytvářet grafické efekty. Nejprve vám vysvětlíme teorii a ukážeme několik jednoduchých grafických efektů. Příští týden pak přijde řada i na složitější algoritmy.

Úprava pixelů bitmapy standartním způsobem

K pixelům bitmapy, která je realizována třídou System.Drawing.Bitmap, můžete přistupovat pomocí metody GetPixel a SetPixel. Metoda GetPixel vrací instanci struktury System.Drawing.Color představující barvu pixelu ležící na určitých souřadnicích X,Y v bitmapě. K nastavení pixelu na určitou souřadnici lze pak použít metodu SetPixel.

Následující metoda nastaví pouze červený filtr bitmapy:

void NastavCervenou(Bitmap b)
{
  for (int x = 0; x< b.Width; x++)
  {
    for (int y = 0; y<b.Height; y++)
    {
      Color vybBarva = b.GetPixel(x,y);
      b.SetPixel(x,y, Color.FromArgb(vybBarva.R,0,0));
    }
  }
}

Kód tedy vlastně u každého pixelu obrázku v barevném modelu RGB ponechá pouze červený kanál a zelený a modrý nastaví na nulu. Jednoduše řečeno, výsledek bude vypadat jako zobrazení pouze červeného kanálu v kdejakém bitmapovém editoru.

Rychlejší úprava pixelů bitmapy pomocí unsafe kódu

Nevýhodou tohoto postupu je jeho pomalý výkon – metody SetPixel a GetPixel jsou časově poměrně náročné. Pro zrychlení manipulace s pixely budete muset pracovat přímo s pamětí pomocí unsafe (nezabezpečeného) kódu.

Například takto by vypadala předchozí metoda NastavCervenou za použití efektivnějšího unsafe kódu:

using System.Drawing.Imaging;
using System.Drawing;

. . .

unsafe Bitmap NastavCervenou(Bitmap b)
{
 
// Uzamkne v paměti data bitmapy tak, aby s nimi bylo možno pracovat.
 
BitmapData bd = b.LockBits(new Rectangle(0,0,b.Width,b.Height),
                             ImageLockMode.ReadWrite,
                             PixelFormat.Format32bppArgb);

  for (int y = 0; y< b.Height; y++)
  {
    // Vytvoří ukazatel na začátek y-té řádky bitmapy
    int* ukzt = (int*)((int)bd.Scan0 + y * bd.Stride);
    for (int x = 0; x <b.Width; x++)
    {
      // Vybere barvu pixelu
      Color c = Color.FromArgb(*ukzt);
      Color cervenyOdstin = Color.FromArgb(c.R,0,0);
      // Nastaví barvu pixelu
      *ukzt = cervenyOdstin.ToArgb();
      // Posune ukazatel na x-tý pixel v dané řádce
      ukzt++;
   
}
  }
 
b.UnlockBits(bd);
  return b;
}

Schválně si všimněte klíčového slova unsafe v deklaraci metody, které říká, že kód v této metodě budou používány ukazatele. Více o ukazatelích se dozvíte třeba na tomto webu.

K tomu, aby bylo možné ve Visual Studiu zkompilovat program obsahující unsafe kód, je nutné tuto vlastnost povolit v menu Project -> Project Options -> Debug.

Pro přístup k pixelum bitmapy je musíte uzamknout v paměti pomocí metody LockBits, která jako argument očekává instanci třídy Rectangle představující část bitmapy, jejíž data mají být uzamknuta, druhým argumentem je položka výčtového typu System.Drawing.Imaging.ImageLockMode, která nám definuje způsob, kterým můžete přistupovat k pixelům bitmapy.

Posledním argumentem je položka výčtového typu System.Drawing.Imaging.PixelFormat určující barevnou hloubku bitmapy. Následně cyklem projdete jednotlivé řádky bitmapy. Pozici prvního pixelu v y-tém řádku v bitmapy vypočítáte za použití vlastnosti Scan0 a Stride třídy BitmapData. Vlastnost Scan0 představuje počáteční pixel bitmapy a vlastnost Stride délku jedné řádky. Pro přesun na další pozici v řádce je nutné zvýšit ukazatel o hodnotu 1. Po dokončení úprav bitmapy, lze její data z paměti uvolnit pomocí metody UnLockBits.

A teď už slíbené fotografické filtry

Převod barev do odstínů šedi

Klepněte pro větší obrázek Klepněte pro větší obrázek
Převod do odstínů šedi a výsledný obrázek

Algoritmus s unsafe kódem může v C# vypadat třeba takto:

unsafe Bitmap SedaSkala(Bitmap b)
{
  BitmapData bd = b.LockBits(new Rectangle(0,0,b.Width,b.Height),
                            
ImageLockMode.ReadWrite,
                             PixelFormat.Format32bppArgb);

  for (int y = 0; y< b.Height; y++)
  {
    int* ukzt = (int*)((int)bd.Scan0 + y * bd.Stride);
    for (int x = 0; x <b.Width; x++)
    {
      Color c = Color.FromArgb(*ukzt);
      int seda = (int)(0.299 * c.R + 0.587 * c.G + 0.114 * c.B);
      Color sedaBarva = Color.FromArgb(seda,seda,seda);
      *ukzt = sedaBarva.ToArgb();
      ukzt++;
    }
  }
  b.UnlockBits(bd);
  return b;
}

Invertování barev

Klepněte pro větší obrázek  Klepněte pro větší obrázek  Klepněte pro větší obrázek  Klepněte pro větší obrázek
Negativ v několika podobách, efekty totiž můžete kombinovat, a výsledný obrázek

Algoritmus s unsafe kódem může v C# vypadat třeba takto:

unsafe Bitmap Invert(Bitmap b)
{
  BitmapData bd = b.LockBits(new Rectangle(0,0,b.Width,b.Height),
                                           ImageLockMode.ReadWrite,
                                           PixelFormat.Format32bppArgb);

  for (int y = 0; y< b.Height; y++)
  {
    int* ukzt = (int*)((int)bd.Scan0 + y * bd.Stride);
    for (int x = 0; x <b.Width; x++)
    {
      Color vybrBarva = Color.FromArgb(*ukzt);
      Color invBarva = Color.FromArgb(255-vybrBarva.R,
                                      255-vybrBarva.G,
                                      
255-vybrBarva.B);

      *ukzt = invBarva.ToArgb();
      ukzt++;
    }
  }
  b.UnlockBits(bd);
  return b;
}

Vytvoření sépiového nádechu

Klepněte pro větší obrázek  Klepněte pro větší obrázek
Nakonec nesmí chybět ještě sépiový efekt

Algoritmus s unsafe kódem může v C# vypadat třeba takto:

unsafe Bitmap Sepia(Bitmap b)
{
  BitmapData bd = b.LockBits(new Rectangle(0,0,b.Width,b.Height),
                                           ImageLockMode.ReadWrite,
                                           PixelFormat.Format32bppArgb);

  for (int y = 0; y< b.Height; y++)
  {
    int* ukzt = (int*)((int)bd.Scan0 + y * bd.Stride);
    for (int x = 0; x <b.Width; x++)
    {
      Color c = Color.FromArgb(*ukzt);
      int sepia = (int)(0.299 * c.R + 0.587 * c.G + 0.114 * c.B);
      int r = (int)((sepia > 206) ? 255 : sepia + 49);
      int g = (int)((sepia< 14) ? 0 : sepia - 14);
      int bl = (int)((sepia < 56) ? 0 : sepia - 56);
      Color sepiaColor = Color.FromArgb(r,g,bl);
      *ukzt = sepiaColor.ToArgb();
      ukzt++;
    }
  }
  b.UnlockBits(bd);
  return b;
}

Jak na složitější efekty? Přečtěte si příští článek

V tomto článku jsme vám ukázali, jakým způsobem lze manipulovat s pixely bitmapy za použití unsafe kódu. Příště vás seznámíme s pokročilejšími grafickými efekty.

Nakonec nesmí chybět ani slíbený spustitelný program a projekt.  K prvnímu budete potřebovat nainstalovaný novější Microsoft .NET Framework, pakliže si budete chtít projekt upravit a sestavit, budete potřebovat bezplatné vývojové prostředí Microsoft Visual C# 2008 Express Edition.

Máte zajímavý tip na drobnou aplikaci, kterou byste zde chtěli vidět? Neváhejte a napište nám váš nápad do diskuze pod článkem. 

Témata článku: Programování, Adobe Photoshop, Family, Kody

25 komentářů

Nejnovější komentáře

  • kvok 20. 8. 2008 14:50:06
    "Máte zajímavý tip na drobnou aplikaci, kterou byste zde chtěli vidět?...
  • jehoVista 19. 8. 2008 23:11:18
    imagemagick
  • jehoVista 19. 8. 2008 23:10:27
    Dva radkove komentare na 150 radek kodu? Kdyz ma slouzit vyuce?
Určitě si přečtěte

Operační systém běžným počítačům nedal Bill Gates, ale Gary Kildall

Operační systém běžným počítačům nedal Bill Gates, ale Gary Kildall

** Gary Kildall pochopil, že levné výpočetní čipy mohou posloužit jako univerzální počítače pro všechny ** Připravil pro ně proto první operační systém ** Později mu systém vyfoukl Microsoft a nazval ho MS DOS

23.  4.  2017 | Pavel Tronner | 52

Umělá inteligence je sice v plenkách, už teď ale přestáváme rozumět, jak vlastně funguje. To je problém

Umělá inteligence je sice v plenkách, už teď ale přestáváme rozumět, jak vlastně funguje. To je problém

** Už je to tady, lidé přestávají chápat počítače ** Systémy neuronových sítí začínají pracovat tak, že ani jejich tvůrci přesně neví, co se uvnitř děje ** Do budoucna to může být závažný problém

24.  4.  2017 | Jakub Čížek | 111

Před 35 lety měl premiéru legendární počítač ZX Spectrum. Připomeňte si „Gumáka“

Před 35 lety měl premiéru legendární počítač ZX Spectrum. Připomeňte si „Gumáka“

** Slavný osmibitový počítač Sinclair ZX Spectrum byl uveden právě před 35 lety ** Připomeňte si tento průkopnický počítač v tematických článcích ** Podívejte se, jak funguje dnes

23.  4.  2017 | Pavel Tronner | 13

Správný počítač má alespoň dva monitory. Anebo je to jinak?

Správný počítač má alespoň dva monitory. Anebo je to jinak?

** David si nedokáže představit práci bez dvou a více monitorů ** Kubovi naopak stačí jeden a ve více displejích se ztrácí ** Jaký přístup je lepší?

23.  4.  2017 | Jakub Čížek | 59

Český Google Překladač začal používat umělou inteligenci. Konec „drahoušků zákazníků“

Český Google Překladač začal používat umělou inteligenci. Konec „drahoušků zákazníků“

** Google ve svém překladači roky používal statistickou technologii ** Nyní zavádí strojové učení a neuronové sítě ** Rozdíl by měl být zvláště na větších textech patrný už nyní

20.  4.  2017 | Jakub Čížek | 31

Brno otevřelo největší českou dílnu pro bastlíře. Kladívka, vrtačky, 3D tiskárny, laserové řezačky. Je tu vše

Brno otevřelo největší českou dílnu pro bastlíře. Kladívka, vrtačky, 3D tiskárny, laserové řezačky. Je tu vše

** Máte nápad, ale chybí vám stroje a pořádná dílna? ** Chcete postavit ptačí budku, nebo krabičku pro Arduino? ** Brno otevřelo svůj FabLab – laboratoř pro bastlíře

19.  4.  2017 | Jakub Čížek | 31


Aktuální číslo časopisu Computer

První test AMD Ryzen

Velké testy: 22 powerbank a 8 bezdrátových setů

Radíme s koupí Wi-Fi routeru

Co dokáží inteligentní domy?