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
edytujBezpośrednie tworzenie plików graficznych
edytujz użyciem basha
edytuj./a.out >h.pgm
Z poziomu c
edytujNajprostszym 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
- stb = stb_image.h: public domain C image loading library by Sean Barrett
gr
edytuj- https://github.com/sciapp/gr
- apt install libxt6 libxrender1 libxext6 libgl1-mesa-glx libqt5widgets5
make -C lib/gks GRDIR=/usr/local/gr make[1]: Entering directory '/home/a/gr/lib/gks' make -C ../.. Makedefs make[2]: Entering directory '/home/a/gr'
Building GR Framework --------------------- C: yes [cc (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0] C++: yes [c++ (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0] Python: no [not found] LaTeX: yes [version 3.141592653-2.6-1.40.22] dvipng: no [not found] Qt4: no [Qt4 API not found] Qt5: yes [version 5.15.3] Qt6: no [Qt6 API not found] wxWidgets: no [wx-config not found] GTK+: no [gtk+-2.0 not found] X11: yes [/usr/X11] Xft: no [disabled] Ghostscript: no [GS API not found] GLFW: yes [version 3.3.6] OpenGL: yes 0MQ: no [0MQ 3.x API not found] ffmpeg: yes [version 4.4.2-0ubuntu0.22.04.1] Cairo: yes [version 1.16.0] libtiff: yes [version 4.3.0] agg: no [agg not found]
dislin
edytuj- download 64 bit linux
- sudo apt install ./dislin-11.5.linux.i586_64.deb
- test instalacji
- google groups
cp -p -R /usr/local/dislin/examples $HOME cd $HOME/examples clink -c exa_c
- dlink
/******************************************************************/ /** G F 7 7 L I N K **/ /** **/ /** GF77LINK links Fortran 77 programs with the DISLIN library. **/ /** **/ /** Command: gf77link [option] [-r8] main **/ /** **/ /** option is an optional parameter that can have one of **/ /** the following values: **/ /** -c for compiling programs before linking **/ /** -r for running programs after linking **/ /** -a for compiling, linking and running programs. **/ /** **/ /** -r8 is an optional parameter for using the double **/ /** precision library of DISLIN. **/ /** **/ /** main is the name of the main program or may be in the **/ /** form 'main obj lib' where obj is a field of **/ /** object files and lib a field of library files. **/ /** Several files must be separated by blanks. **/ /** A file 'main' will be created after linking. **/ /** **/ /** Example: gf77link -a test mylib.a **/ /** Version: GFortran, Linux, Fortran 77 **/ /******************************************************************/
#include <stdio.h>
#include "dislin.h"
main()
{
disini ();
messag ("This is a test", 100, 100);
disfin ();
}
gcc exa_c.c -L$DISLIN -ldislin -lm
Dodatki
- sudo apt-get install xfonts-75dpi
- sudo apt-get install xfonts-100dpi
liblot
edytujBiblioteka libplot[4] służy do tworzenia grafiki 2D, zarówno wektorowej jak i rastrowej. Przykłady użycia w C: [5]
- libplot-dev
sudo apt install libplot-dev
Zobacz również:
pgplot
edytuj- ./makemake ~/Dokumenty/c/pgplot/pgplot5.2/pgplot linux f77_gcc
- make cpg
- ld -shared -o libcpgplot.so --whole-archive libcpgplot.a
- PGPLOT_DIR="/usr/local/pgplot/"; export PGPLOT_DIR
- C PGPLOT wrapper library = cpgplot
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
edytujGnuplot
edytujPotok
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
edytujPrzygotowanie pliku z danymi
edytujTen 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
edytujUruchom gnuplot:
gnuplot
i w linii komend wprowadź polecenie:
plot "data.txt"
W cudzysłowie jest nazwa pliku, może być poprzedzona ścieżką.
Plotutils
edytujPakiet Plotutils [7][8][9] korzysta z biblioteki libplot.
Obrazy utworzone z użyciem plotutils )( kod na stronie):
Instalacja
- sudo apt install plotutils
Przygotowanie plików z danymi
edytujint 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
edytujWykonanie 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
edytujGPU
edytujGPU shaders ( shader to program który działa na GPU)
- pixel shader (2D graphic)
- vertex (3D graphic)
- geometry ( 3D graphic)
- tessellation ( 3D graphic )
- compute ( GPGPU ) Moduły cieniujące obliczeniowe (ang. compute shaders) są to programy działające na GPU poza normalnym potokiem renderowania
GPGPU [13]
- OpenCL : stagnacja, słabe wsparcie dostawców
- CUDA : doskonałe narzędzia, powszechna wiedza, ale tylko sprzęt Nvidia
- Compute shaders: okropne narzędzia, skąpa wiedza, ale działa na wszystkich obecnych kartach graficznych
- Różnorodność API: Vulkan, DX12, Metal, WebGPU obiecujące, ale jeszcze nie gotowe
OpenGl
edytujCg
edytujCg czyli C dla grafiki
Główny program dla CPU jest napisany w C. Ten program otwiera i uruchamia program w Cg (dla GPU).[14][15]
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
edytujGtk
edytujPrzykł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
- ↑ Compute shader 101 by Raph Levien
- ↑ Cg Bumpmapping by Razvan Surdulescu at GameDev
- ↑ 15,0 15,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