/* ****************************************************** * * Martin Proks 25.1.2004 * License: GNU-GPL 2 nebo vyssi * * priklad.c * * Tento program ma za ukol vytvorit prikladovy png obrazek * jako 20% sedou plochu 100px x 100px s cernou carkou u prostred * * ****************************************************** */ #define _GNU_SOURCE /* kvuli funkci lrint z */ #include /* exit */ #include /* printf, ... */ #include /* hlavickovy soubor k funkcim z libpng */ #include /* lrint */ /* obrazek bude ve stupnich sedi a pak je bit depth = bit pixel */ /* BIT_PIXEL muze mit pro tento program hodnoty 4, 8, 16 */ #define BIT_PIXEL 16 /* WHITE = (2 mocneno na BIT_PIXEL) - 1 */ #define WHITE ((1 << BIT_PIXEL) - 1) #define BLACK 0 #define HEIGHT 100 #define WIDTH 100 #define FULL_BYTE 255 /* bits: 11111111 */ #define MS_BYTE 240 /* bits: 11110000 */ #define LS_BYTE 15 /* bits: 00001111 */ int main () { FILE *fp; register unsigned long int i, j; /* sizeof (typ pole) musi byt >= (BIT_PIXEL / 8), takze pro jistotu treba: */ unsigned long int rastr[HEIGHT][WIDTH]; /* Dale potrebujeme nektere promenne pro praci s png formatem: */ png_structp png_ptr = NULL; /* pro vnitrni pouziti libpng */ png_infop info_ptr = NULL; /* informacní struktura o png */ png_bytep p_row = NULL; /* jedna radka z obrazku, v podstate to predstavuje char * p_row */ png_text pngtext[1]; /* komentar k obrazku */ /* vytvorit rastrovou bitmapu v pameti: * pole rastr naplnime nejakou barvou, treba 20% sedou: */ for (i = 0; i < HEIGHT; i++) for (j = 0; j < WIDTH; j++) rastr[i][j] = (unsigned long int) lrint ((1 - 0.2) * WHITE); rastr[48][48] = BLACK; rastr[49][49] = BLACK; rastr[50][50] = BLACK; rastr[51][51] = BLACK; rastr[52][52] = BLACK; /* a jde se na PNG: */ /* Nejriíve je treba otevrit soubor pro binarni zapis: */ fp = fopen ("priklad.png", "wb"); if (fp == NULL) { printf ("chyba při otevírání/vytváření 'pokus.png', ošetřit ...\n"); exit (1); } /* pak vytvorit png vnitrni strukturu */ png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL); if (png_ptr == NULL) { printf ("Chybka za behu programu!\n"); fclose (fp); exit (1); } /* pak informacni strukturu */ info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { printf ("Chybka za behu programu!\n"); fclose (fp); png_destroy_write_struct (&png_ptr, png_infopp_NULL); exit (1); } /* odchytit vnitrni chyby png lib ... */ if (setjmp (png_jmpbuf (png_ptr))) { printf ("Chybka za behu programu!\n"); fclose (fp); png_destroy_write_struct (&png_ptr, &info_ptr); exit (1); } /* I/O inicializace ... */ png_init_io (png_ptr, fp); /* nastavit informace o obrazku do hlavicky. Vyska a sirka * musi byt mensi nez 2^31, barevná hloubka .... * Parametry jsou snad dostatecne samovysvetlujici. Snad jen * pripominka, v libpng 1.2.2 musí byt komprese a typ filtru * na DEFAULT jako v tomto prikladu na nasledujicich 3 radkach */ png_set_IHDR (png_ptr, info_ptr, WIDTH, HEIGHT, BIT_PIXEL, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Zapsat komentar */ pngtext[0].key = "Title"; pngtext[0].text = "Priblbly obrazek"; pngtext[0].compression = PNG_TEXT_COMPRESSION_NONE; # ifdef PNG_iTXt_SUPPORTED pngtext[0].lang = NULL; # endif png_set_text (png_ptr, info_ptr, pngtext, 1); /* Mno a konecne zapsat hlavicku */ png_write_info (png_ptr, info_ptr); /* Jeste jsme nenaalokovali radku p_row pro zapis obrazku. * Tady bude drobny problem, C umi alokovat pamat v byte, ale radka * by pri spatne konstelaci hvezd mohla pretect celych n byte o * par bit (napr. pri BIT_PIXEL == 1, 2, nebo 4 a WIDTH prvocislo). * To resi nasledujici konstrukce přes pom. prom. i */ if ((WIDTH * sizeof (png_byte) * BIT_PIXEL % 8) == 0) i = WIDTH * sizeof (png_byte) * BIT_PIXEL / 8; else i = (WIDTH * sizeof (png_byte) * BIT_PIXEL / 8) + 1; /* mno prima a ted konecne ta alokace a osetreni pripadne chyby */ p_row = malloc ((size_t) i); if (p_row == NULL) { printf ("Chybka za behu programu!\n"); fclose (fp); png_destroy_write_struct (&png_ptr, &info_ptr); return (1); } /* Mno a jde se zapisovat samotny obrazek hezky radku po radce */ for (i = 0; i < HEIGHT; i++) { for (j = 0; j < WIDTH; j++) { /* naplnit radku hezky pixel po pixelu: */ # if (BIT_PIXEL == 16) /* Nyni "sesoupneme" rastr[i][j] o jeden byte dolu */ p_row[2 * j] = (png_byte) ((rastr[i][j] >> 8) & FULL_BYTE); /* Pro druhy byte p_row neni potřeba nic posouvat, staci prenasobit */ p_row[2 * j + 1] = (png_byte) (rastr[i][j] & FULL_BYTE); # endif /* (BIT_PIXEL == 16) */ # if (BIT_PIXEL == 8) p_row[j] = (png_byte) rastr[i][j]; # endif /* (BIT_PIXEL == 8) */ # if (BIT_PIXEL == 4) { register unsigned long int k; k = j / 2; /* dva pixely v jedne bunce, tedy i index musi byt polovicni */ if ((j % 2) == 0) /* zbytek po deleni - test sude/liche */ { /* sude, tedy prvni pixel, horni pulka p_row[k]. * Nejdriv je potreba ji vynulovat pomoci nasobeni s LS_BYTE * a pak pripocist rastr[i][j] souplej o 4 nahoru */ p_row[k] = (png_byte) ((p_row[k] & LS_BYTE) | ((rastr[i][j] << 4) & MS_BYTE)); } else { /* liche, tedy druhy pixel, dolni pulka p_row[k]. * Nejdriv je potreba ji vynulovat pomoci nasobeni s MS_BYTE * a pak pripocist rastr[i][j] */ p_row[k] = (png_byte) ((p_row[k] & MS_BYTE) | (rastr[i][j] & LS_BYTE)); } } # endif /* (BIT_PIXEL == 4) */ } /* zapsat řádku */ png_write_row (png_ptr, p_row); } /* zakoncit png soubor */ png_write_end (png_ptr, info_ptr); /* uklid a odchod */ free (p_row); png_destroy_write_struct (&png_ptr, &info_ptr); fclose (fp); return (0); }