Programowanie w systemie UNIX/c grafika

Grafika na ekranie[edytuj]
- Grafika nie jest znormalizowana w C.
- Trzeba napisać kod.
- można korzystać z bibliotek lub programów graficznych ( gnuplot)
- rysowanie w terminalu:[1]
- Terminale wyświetlają znaki i nie obsługują rysowania grafiki pikselowej.
- Można korzystać z grafiki ASCII / UTF-8
Tworzenie plików graficznych[edytuj]
Bezpośrednie tworzenie plików graficznych[edytuj]
z użyciem basha[edytuj]
./a.out >h.pgm
Z poziomu c[edytuj]


Najprostszym przykładem rastrowego pliku graficznego jest plik PPM. Poniższy program pokazuje jak utworzyć plik w katalogu roboczym programu. Do zapisu:[2]
- nagłówka pliku używana jest funkcja fprintf, która zapisuje do plików binarnych lub tekstowych
- tablicy do pliku używana jest funkcja fwrite, która zapisuje do plików binarnych,
#include <stdio.h>
int main() {
const int dimx = 800;
const int dimy = 800;
int i, j;
FILE * fp = fopen("first.ppm", "wb"); /* b - tryb binarny */
fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);
for(j=0; j<dimy; ++j){
for(i=0; i<dimx; ++i){
static unsigned char color[3];
color[0]=i % 255; /* red */
color[1]=j % 255; /* green */
color[2]=(i*j) % 255; /* blue */
fwrite(color,1,3,fp);
}
}
fclose(fp);
return 0;
}
W powyższym przykładzie dostęp do danych jest sekwencyjny. Jeśli chcemy mieć swobodny dostęp do danych to:
- korzystać z funkcji: fsetpos, fgetpos oraz fseek,
- utworzyć tablicę (dla dużych plików dynamiczną), zapisać do niej wszystkie dane a następnie zapisać całą tablicę do pliku. Ten sposób jest prostszy i szybszy. Należy zwrócić uwagę, że do obliczania rozmiaru całej tablicy nie możemy użyć funkcji sizeof.
/*
How do I get the length of a dynamically allocated array in C? You can't. You have to pass the length as a parameter to your function.
https://stackoverflow.com/questions/5126353/get-the-length-of-dynamically-allocated-array-in-c
--------------
gcc p.c -Wall -lm
./a.out
ls -l *.ppm
*/
#include <stdio.h>
#include <string.h> // strncat
#include <stdlib.h> // malloc
#include <math.h> // log10
// color = RGB triplet = (thus three bytes per pixel) in the order red, green, then blue
// color = 3 bytes
// color component ( channel) = 1 byte = number from 0 to 255 = unsigned char
// size of virtual 2D array of pixels
// each piexel has a RGB color
int iWidth = 1000;
int iHeight ; //
// size of the dynamic 1D array
unsigned char * data;
size_t ColorSize = 3; // RGB = number of color components = channels
size_t ArrayLength; // number of 1D array's elements = ENumber = iWidth*iHeight*ColorSize
size_t ElementSize; // size of array's element in bytes
size_t ArraySize; // size of array in bytes = ElementSize*ArrayLength
size_t HeaderSize ; // size of the P6 file header in bytes
size_t FileSize; // = HeaderSize +ArraySize [bytes]
// --------------- save dynamic "A" array of uinsigned char to the binary ppm file ( P6 ) --------------------------------
int SaveArray2PPM (unsigned char A[], size_t ESize, size_t ALength, int k)
{
FILE *fp;
const unsigned int MaxColorComponentValue = 255; /* color component is coded from 0 to 255 ; it is 8 bit color file */
char name [100]; /* name of file */
snprintf(name, sizeof name, "%d", k); /* */
char *filename =strncat(name,".ppm", 4);
/* save image to the pgm file */
fp = fopen (filename, "wb"); /*create new file,give it a name and open it in binary mode */
if (fp == NULL)
{ printf("File open error");
return 1;}
else {
fprintf (fp, "P6\n%u %d\n%d\n", iWidth, iHeight, MaxColorComponentValue); /*write header to the file */
fwrite (A, ESize, ALength, fp); // write dynamic A array to the binary file in one step = fwrite (A , ESize, ALength, fp);
printf ("File %s saved. \n", filename);
fclose (fp);
return 0;}
}
int setup(){
iHeight = iWidth; // quadratic 2D array
// 1D array
ArrayLength = iWidth*iHeight*ColorSize;
ElementSize = sizeof(unsigned char);
ArraySize = ElementSize*ArrayLength ;
HeaderSize = 11 + (size_t) (log10(iHeight) +log10(iWidth));
FileSize = HeaderSize + ArraySize;
/* create dynamic 1D array for RGB colors */
data = malloc (ArraySize);
if (data == NULL ){
printf ( "Could not allocate memory for the array\n");
return 1;}
return 0;
}
void info(){
printf("ppm (P6) header size = %zu bytes\n", HeaderSize);
printf("Array Size = %zu bytes\n", ArraySize);
printf("PPM file size = %zu bytes\n", FileSize);
}
int end(){
printf (" allways free memory (deallocate ) to avoid memory leaks \n"); // https://en.wikipedia.org/wiki/C_dynamic_memory_allocation
free (data);
info();
return 0;
}
// ================================== main ============================================
int main (){
setup();
SaveArray2PPM(data, ElementSize, ArrayLength, 1);
end();
return 0;
}
Bardzo łatwo również utworzyć plik SVG[3]
/*
c console program based on :
cpp code by Claudio Rocchini
http://commons.wikimedia.org/wiki/File:Poincare_halfplane_eptagonal_hb.svg
http://validator.w3.org/
The uploaded document "circle.svg" was successfully checked as SVG 1.1.
This means that the resource in question identified itself as "SVG 1.1"
and that we successfully performed a formal validation using an SGML, HTML5 and/or XML
Parser(s) (depending on the markup language used).
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
const double PI = 3.1415926535897932384626433832795;
const int iXmax = 1000,
iYmax = 1000,
radius=100,
cx=200,
cy=200;
const char *black="#FFFFFF", /* hexadecimal number as a string for svg color*/
*white="#000000";
FILE * fp;
void draw_circle(FILE * FileP,int radius,int cx,int cy)
{
fprintf(FileP,"<circle cx=\"%f\" cy=\"%f\" r=\"%f\" style=\"stroke:%s; stroke-width:2; fill:%s\"/>\n",
cx,cy,radius,white,black);
}
void beginSVG(
int main(){
FILE * fp;
char *filename="circle.svg";
fp = fopen(filename,"w");
char *comment = "<!-- sample comment in SVG file \n can be multi-line -->";
fprintf(fp,
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
"%s \n "
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \n"
"\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
"<svg width=\"20cm\" height=\"20cm\" viewBox=\"0 0 %f %f \"\n"
" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
comment,iXmax,iYmax);
draw_circle(fp,radius,cx,cy);
fprintf(fp,"</svg>\n");
fclose(fp);
printf(" file %s saved \n",filename );
getchar();
return 0;
}
Biblioteki[edytuj]
- Gegl
- libgd
- freeimage
- ImageMagic
- GraphicsMagic
- OpenCV
- OpenImageIO
- Cairo
- MathGl
- plplot
- gmic : A small, portable, thread-safe and multi-threaded, image processing library libgmic
liblot[edytuj]
Biblioteka libplot[4] służy do tworzenia grafiki 2D, zarówno wektorowej jak i rastrowej. Przykłady użycia w C: [5]
pgplot[edytuj]
Przykład [6]
#include "cpgplot.h"
#include "math.h"
int main()
{
int i;
float xs[9], ys[9];
float xr[101], yr[101];
/* Compute numbers to be plotted. */
for (i=0; i<101; i++) {
xr[i] = 0.1*i;
yr[i] = xr[i]*xr[i]*exp(-xr[i]);
}
for (i=0; i<9; i++) {
xs[i] = i+1;
ys[i] = xs[i]*xs[i]*exp(-xs[i]);
}
/* Open graphics device. */
if (cpgopen("?") < 1)
return 1;
/* Define coordinate range of graph (0 < x < 10, 0 < y < 0.65),
and draw axes. */
cpgenv(0., 10., 0., 0.65, 0, 0);
/* Label the axes (note use of \\u and \\d for raising exponent). */
cpglab("x", "y", "PGPLOT Graph: y = x\\u2\\dexp(-x)");
/* Plot the line graph. */
cpgline(101, xr, yr);
/* Plot symbols at selected points. */
cpgpt(9, xs, ys, 18);
/* Close the graphics device */
cpgclos();
return 0;
}
Zewnętrzne programy[edytuj]
Gnuplot[edytuj]
Potok[edytuj]
#!/bin/bash
# http://mathr.co.uk/blog/
creal=0.258385930
cimag=0.00148483651
rot=34
den=$(echo "2^${rot}-1" | bc)
for i in $(seq 0 $((rot-1)))
do
num=$(echo "2^${i}" | bc)
./julia-exray "${creal}" "${cimag}" "${num}/${den}"
echo
echo
done > "${rot}.txt"
gnuplot <<EOF
set terminal png size 1024,1024
set output "${rot}.png"
plot [-0.2:1] [-0.2:1] "${rot}.txt" using 1:2:(column(-2)%8) with lines lc variable title "quadratic Julia set external rays at 2^k/(2^${rot}-1) for c = ${creal} + ${cimag} i"
EOF
Plik z danymi[edytuj]
Przygotowanie pliku z danymi[edytuj]
Ten program tworzy w swoim katalogu roboczym plik tekstowy data.txt zawierający dane w formacie, który akceptuje gnuplot. Zawiera nagłówek poprzedzony znakiem "#", który przy rysowaniu jest ignorowany, oraz 2 kolumny liczb rozdzielone spacjami.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i;
double x,y;
char *output_filename="data.txt";
FILE *output_file;
output_file = fopen(output_filename, "w");
if (output_file == NULL) {
fprintf(stderr, "Nie moge otworzyc %s\n", output_filename);
getchar();
return 1;
} else {
/* nagłówek */
fprintf(output_file,"%s %s %s \n","#","x","y");
y = 0.005;
x = 0.0;
/* 2 kolumny liczb rozdzielone spacjami */
fprintf(output_file,"% 6.2f % 6.2f \n",x,y);
for(i=0;i<5;++i) {
x += y;
/* 2 kolumny liczb rozdzielone spacjami */
fprintf(output_file,"% 6.2f % 6.2f \n",x,y);
}; /* for(i */
}; /* if ((output_file ... else */
fclose(output_file);
fprintf(stderr,"file saved");
getchar();
return 0;
}
Zawartość pliku wygląda następująco:
# x y 0.00 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.02 0.01 0.03 0.01
Rysowanie danych z pliku[edytuj]

Uruchom gnuplot:
gnuplot
i w linii komend wprowadź polecenie:
plot "data.txt"
W cudzysłowie jest nazwa pliku, może być poprzedzona ścieżką.
Plotutils[edytuj]
Pakiet Plotutils [7][8][9] korzysta z biblioteki libplot.
Obrazy utworzone z użyciem plotutils )( kod na stronie):
Przygotowanie plików z danymi[edytuj]
int SaveFiles(double A[Length][2], int p)
{
int p;
int i;
char name [30]; /* name of the file */
char *filename;
FILE * fp;
// save ray from A array to the text file
sprintf(name,"Ray%d", p); /* create name from number */
filename =strcat(name,".dat");
fp= fopen(filename,"wb"); /*create new file,give it a name and open it in binary mode */
fprintf(fp ,"%s %s %s \n","#","x","y");
for (i=0; i<Length ; ++i) fprintf(fp ,"% 1.12f % 1.12f \n",A[i][0],A[i][1]);
fclose(fp);
printf("file %s saved \n", filename);
return 0;
}
bezpieczniej :
char name [100]; /* name of file */
snprintf(name, sizeof name, "%d", k); /* */
char *filename =strncat(name,".ppm", 4);
Tworzenie grafiki[edytuj]
Wykonanie jednego rysunku z jednego pliku:
graph -T svg < inter.dat > inter.svg
Wykonanie jednego rysunku (do pliku all.png) z kilku plików z rozszerzeniem dat:
graph -T png *.dat> all.png
lub poprzez podanie nazw:
graph -T png Ray0.dat Ray1.dat Ray2.dat Ray3.dat > all.png
Standardowo każdy zbiór danych jest rysowany w innym stylu (ang. line mode), np. pierwszy w stylu nr 1, drugi w stylu nr 2 itd. Jeśli chcemy to wyłączyć to użyjemy opcji B (--toggle-auto-bump
) wyłączającej autoinkrementację:
graph -T png -B -m 1 *.dat> all.png
Operacje matrycowe[edytuj]
GPU[edytuj]
OpenGl[edytuj]
Cg[edytuj]
Cg czyli C dla grafiki
Główny program dla CPU jest napisany w C. Ten program otwiera i uruchamia program w Cg (dla GPU).[13][14]
Potrzebne oprogramowanie:
- edytor tekstu
- Cg Toolkit
- kompilator Cg (cgc.exe)
- Cg/CgFX biblioteki dla graficznego API (OpenGL lub Direct X)
- kompilator C, np. gcc
Etapy:
- Cg / GPU
- utworzenie kodu Cg w postaci osobnego pliku , np. Fragment.cg
- prekompilacja kodu Cg do assemblera specyficznego dla danego GPU i sterownika
- C / CPU
Biblioteki Cg dołączamy poprzez umieszczenie w programie napisanym w C następującego kodu:
#include <cg\cg.h> // Cg Header #include <cg\cggl.h> // Cg OpenGL Specific Header
GUI[edytuj]
Gtk[edytuj]
Przykładowy kod w języku C wyświetlający puste okienko:
#include <gtk/gtk.h>
int main(int argc, char* argv[])
{
GtkWidget* window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GTK+");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_widget_show(window);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return 0;
}
Qt[edytuj]
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label("Hello, world!");
label.show();
return app.exec();
}
Glut[edytuj]
#include<GL/glut.h>
void main(int argc, char**argv) {
glutInit(&argc, argv);
glutInitWindowPosition(100,100);
glutInitWindowSize(500,500);
glutCreateWindow(Hello World);
glutMainLoop();
}
Odnośniki[edytuj]
- ↑ unix.stackexchange question: how-to-draw-a-single-pixel-in-a-terminal
- ↑ PBMPAK is a collection of C routines for creating and reading Portable Bit Map files (PBM).
- ↑ Tworzenie pliku SVG - Claudio Rocchini
- ↑ libplot, a 2-D Vector Graphics Library
- ↑ Programowanie w c z użyciem biblioteki libplot
- ↑ PGPLOT Examples
- ↑ Pakiet Plotutils
- ↑ Fossies Dox: plotutils-2.6.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)
- ↑ Popularity contest statistics for plotutils
- ↑ Using GNU plotutils for your assignments by Luke Hutchison
- ↑ Plot coordinate pairs - rosettacode
- ↑ GSL example program
- ↑ Cg Bumpmapping by Razvan Surdulescu at GameDev
- ↑ 14,0 14,1 Lesson: 47 from NeHe Productions
- ↑ Cg & HLSL Shading Language FAQ by Fusion Industries
- ↑ cgui - a library for making graphical user interfaces (GUI) by Christer Sandberg
- ↑ 2D Graphics Using C in Linux by Anthoniraj Amalan
- ↑ Graphics.h in Linux for c/c++ 02/29/2012 ~ Mandeep Simak
- ↑ IUP is a multi-platform toolkit for building graphical user interfaces. It offers a simple API in three basic languages: C, Lua and LED.
- ↑ Graphics Programming in Linux