reklama

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

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?
reklama
Určitě si přečtěte

Microsoft: Zbavte se už konečně zastaralých a děravých Windows 7

Microsoft: Zbavte se už konečně zastaralých a děravých Windows 7

** Microsoft pomalu začíná kritizovat svůj nejpopulárnější OS ** Chce konečně dostat podniky na Desítky ** Bezpečnostní podpora Sedmiček vydrží ještě necelé tři roky

17.  1.  2017 | Jakub Čížek | 405

Český státní blacklist už funguje. Ministerstvo financí se pochlubilo s detaily

Český státní blacklist už funguje. Ministerstvo financí se pochlubilo s detaily

** Dva týdny po Novém roce zajím zeje prázdnotou ** Ministerstvo vydalo metodický pokyn ** Takhle to bude fungovat v praxi

16.  1.  2017 | Jakub Čížek | 49

8 produktů, o kterých byste neřekli, že nesou značku Apple

8 produktů, o kterých byste neřekli, že nesou značku Apple

** Věděli jste, že Apple vyvinul celkem 45 modelů tiskáren? ** ** Monitor na výšku, plotter nebo herní konzole - to vše měl Apple ve své nabídce ** Většinu z těchto produktů pohřbil Steve Jobs

19.  1.  2017 | Stanislav Janů | 38

Opera Neon: Takto prý bude vypadat prohlížeč budoucnosti. Chcete to?

Opera Neon: Takto prý bude vypadat prohlížeč budoucnosti. Chcete to?

** Opera představila Neon ** Koncepci prohlížeče budoucnosti ** Připomíná Chrome OS

16.  1.  2017 | Jakub Čížek | 35


Aktuální číslo časopisu Computer

99 nejlepších programů pro váš počítač

Zvykejte si na umělou inteligenci

Velké testy PC zdrojů a gamepadů

Alternativní zdroje energie

reklama
reklama