BPC2E POČÍTAČOVÉ CVIČENÍ 1 Cílem je seznámit se s programováním binárních souborů, v případě tohoto cvičení pak s bitmapovými obrázky. Úloha A. Pro tuto úlohu je připraven zdrojový kódu programu k příkladu souboru bpc2e_c1a.c, kde je připravena kompletní úloha, která vygeneruje nekompresovaný bitmapový obrázek (viz obr. 1.1). Na začátku programu jsou kompletně připraveny potřebné hlavičky pro BMP soubory s plným 24bitovým rozlišení barev (RGB barvy po 8 bitech) bez komprese. Název položky bftype bfsize bfreserved1 bfreserved2 bfoffbits Tab 1.1. Definice proměnných struktury BITMAPFILEHEADER. Délka položky Význam Identifikátor formátu BMP. Aktuální verze formátu BMP zde obsahuje ASCII kód znaků "BM", tj. 0 42 a 0 4D. Celková velikost souboru s obrazovými údaji. Některé aplikace tuto položku ignorují a dosazují zde nulu. Rezerva pro pozdější použití. V současné verzi formátu BMP zde musí být uložena nulová hodnota. Rezerva pro pozdější použití. V současné verzi formátu BMP zde musí být uložena nulová hodnota. Posun struktury BITMAPFILEHEADER od začátku vlastních obrazových dat. Název položky Tab 1.2. Definice proměnných struktury BITMAPINFOHEADER. Délka položky Význam bisize Celková velikost datové struktury BITMAPINFOHEADER biwidth Šířku obrázku v pixelech biheight Výšku obrázku v pixelech biplanes Počet bitových rovin pro výstupní zařízení. V BMP vždy hodnota 1. Položka existuje z historických důvodů. Celkový počet bitů na pixel. Podle počtu barev zde mohou být bibitcount hodnoty 1, 4, 8 nebo 24 (to odpovídá postupně 2, 16, 256ti barvám popř. plnobarevnému režimu). bicompression Typ komprimační metody obrazových dat. Musí být nastavené na jednu z hodnot: 0 (BI_RGB), 1 (BI_RLE8) nebo 2 (BI_RLE4). bisizeimage Velikost obrazu v bytech. Pokud je bitmapa nekomprimovaná, může zde být nulová hodnota, protože ji je možno vypočítat z rozměrů obrázků a počtu bitů na pixel. bixpelspermete r biypelspermete r biclrused biclrimportant Horizontální rozlišení výstupního zařízení v pixelech na metr. Většina aplikací nemá potřebné informace o výstupním zařízení, a proto do této položky vkládá hodnotu 0. Vertikální rozlišení výstupního zařízení v pixelech na metr. Většina aplikací nemá potřebné informace o výstupním zařízení, a proto do této položky vkládá hodnotu 0. Celkový počet barev, které jsou použité v dané bitmapě. Jestliže je tato hodnota nastavena na nulu, bitmapa používá maximální počet barev. Počet barev, které jsou důležité pro vykreslení bitmapy. Pokud je tato hodnota nulová, jsou všechny barvy důležité. Tento údaj je používán při zobrazování na zařízeních, které mají omezený počet současně zobrazitelných barev. Pro definici parametrů obrázku v hlavičkách souboru jsou využity předdefinované struktury BITMAPFILEHEADER a BITMAPINFOHEADER z knihovny windows.h. Popis jednotlivých
proměnných těchto struktur je uveden v tabulkách 1.1 a 1.2. Jediný parametr obrázku, který je třeba nastavit je šířka a výška v pixelech pomocí maker WIDTH a HEIGHT: //size of picture definition #define WIDTH 512 #define HEIGHT 512 Ostatní položky struktur jsou již předdefinovány, pro BITMAPFILEHEADER: bmp_fh.bftype = 19778; // BITMAPFILEHEADER specification bmp_fh.bfsize = WIDTH * HEIGHT * 3 + 54; bmp_fh.bfreserved1 = 0; bmp_fh.bfreserved2 = 0; bmp_fh.bfoffbits = 54; i pro BITMAPINFOHEADER: bmp_ih.bisize = 40; // BITMAPINFOHEADER specification bmp_ih.biwidth = WIDTH; bmp_ih.biheight = HEIGHT; bmp_ih.biplanes = 1; bmp_ih.bibitcount = 24; bmp_ih.bicompression = 0; bmp_ih.bisizeimage = WIDTH * HEIGHT * 3; bmp_ih.bixpelspermeter = 0; bmp_ih.biypelspermeter = 0; bmp_ih.biclrused = 0; bmp_ih.biclrimportant = 0; Hlavičky jsou následně ve správném pořadí nahrány do souboru test.bmp.pomocí funkce fwrite(): fwrite(&bmp_fh, sizeof(bmp_fh), 1, fbmp); //write BITMAPFILEHEADER fwrite(&bmp_ih, sizeof(bmp_ih), 1, fbmp); //write BITMAPINFOHEADER V poslední části programu jsou ve dvou vnořených cyklech definovány barvy jednotlivých pixelů a nahrávány do souboru. Pixelová data jsou BMP dvacetičtyřbitovém souboru nahrávána v pořadí RGB (každá barva má 1 byte, a její úroveň od 0 do 255 jako unsigned char) a to postupně po řádcích od levého dolního rohu po pravý horní roh. Každý pixel je definován tripletem těchto úrovní pro červenou, zelenou a modrou složku barvy pixelu. Tento triplet je shrnut ve struktuře bmp_rgb typu RGBTRIPLE. Ve vnořených cyklech se postupně definují a ukládají opět pomocí funkce fwrite() jednotlivé pixely. V příkladu je vidět, že složka červené a modré je vždy nulová, zatímco úroveň zelené barvy je závislá na poloze pixelu. Výsledkem je tedy obrázek s měnící se úrovní zelené barvy od levého dolního rohu po pravý horní roh (viz. obr. 1.1), protože hodnota úrovně zelené barvy je přímo úměrně závislá na součtu indexů řádku a sloupce pro daný pixel: //part for bitmap content definition for(h = 0; h < HEIGHT; h++) //rows in bitmaps from bottom to top { for (v = 0; v < WIDTH; v++) //columns in bitmaps from left to right { bmp_rgb.rgbtred = 0x00; bmp_rgb.rgbtgreen = (h+v)%256; bmp_rgb.rgbtblue = 0x00; fwrite(&bmp_rgb, sizeof(bmp_rgb), 1, fbmp); Tzn., že všechny pixely, kde součet h+v je konstantní budou mít stejnou barvu. Pochopitelně je třeba omezit úroveň barvy na rozsah 0 až 255, což lze provést snadno operací zbytku po celočíselném dělení 256. Zkuste pro začátek vymyslet jiný vztah pro výpočet úrovně zelené barvy pixelu, např. při aplikaci bmp_rgb.rgbtgreen = (h+v)%256; bmp_rgb.rgbtblue = 0x00; fwrite(&bmp_rgb, sizeof(bmp_rgb), 1, fbmp);
Pokud například pro výpočet úrovně zelené úrovně použijte následující vztah: bmp_rgb.rgbtgreen = (cos(2*6.28*v/(1.0*width))+1)*127; získáte krásnou fotografii svislých trubek včetně jasového přechodu do stínu (viz. obr. 1.2). Zkuste zapřemýšlet proč? Nezapomeňte na přilinkování knihovny math.h. Vaším samostatným úkolem je upravit právě část kódu pro definici pixelů obrázku tak, aby výsledkem byl obrázek podle obr. 1.3. Hodnocení: 1,5 bodu. Obr. 1.1. Výsledný bitmapový obrázek podle vzoru z příkladu A. Obr. 1.2. Výsledný experimentální obrázek při aplikaci funkce kosinus.
Obr. 1.3. Požadovaný výsledný bitmapový obrázek pro příklad A. Úloha B. Zadáno cvičícím na začátku cvičení. Hodnocení: 1,5 bodu. Bonusová úloha Pro nadšené programátory i další zájemce je tu opět připravená bonusová úloha. V souboru TPR.bmp je uložen výřez terénního reliéfu jistého území v 256 úrovních šedi od černé definující nejnižší výškovou hladinu až po bílou definující nejvyšší výškovou hladinu. Cílem úlohy je sestavit program, který pro definovanou hladinu moře vygeneruje nový obrázek mapy souše a moře. Souše může být definována zelenou barvou, moře logicky modrou barvou. Číselným parametr hladiny moře v rozsahu 0 až 255 nechť je argumentem při spouštění programu. Parametrem může být také jméno výstupního BMP souboru. Terénní reliéf ve stupních šedi je na obrázku 1.4, příklad výsledné BMP mapy souše a moře je pro daný reliéf a hladinu moře 80 na obrázku 1.5. Obr. 1.4. Terénní reliéf v úrovních šedi.
Obr. 1.5. Vygenerovaná mapa souše a moře pro hladinu moře 80.