Apostol Rares Andrei 311CA

IMAGE EDITOR

    Pentru a rezolva proiectul, am definit doua structuri in care retin
informatii legate de imagini: inaltimea, latimea, valoarea maxima a culorilor,
matricea asociata si tipul pozei. Pentru pozele de tip PGM, am folosit
structura PGM_pic, iar pentru pozele PPM am folosit structura PPM_pic. In plus,
pentru pozele PPM, matricea este formata din structuri RGB, care retin valorile
pentru culorile rosu, verde si albastru.
    In memoria programului este alocata la un moment dat un singur tip de poza.

Operatiile implementate sunt:

1. LOAD <fisier>

    Daca se introduce comanda LOAD, poza din fisier se pastreaza in memorie.
Pentru a retine informatiile despre imagine, deschid fisierul in mod text si
citesc tipul pozei(P2, P3, P5 sau P6), dupa care inchid fisierul. In functie de
tipul pozei, programul se duce in una din functiile definite. Pentru pozele
greyscale ASCII, fisierul se redeschide text si se citeste headerul. Se aloca
o matrice si se citeste din fisier. Pentru pozele color functia este
asemanatoare, doar ca se aloca o matrice RGB si se citesc cele trei valori ale
culorilor una dupa alta. Pentru fisierele binare, se redeschide fisierul in mod
binar si se citeste matricea cu fread.
    In cazul in care exista comentarii intre magic word si dimensiunile
matricii, acestea se ignora, prin functia ignore_comments(am facut o cate o
functie pentru fiecare tip de fisier, binar sau text). Functia citeste doua
caractere din fisier, si verifica daca primul este '#'. Procesul se repeta pana
cand primul caracter citit este diferit de '#', si atunci se revine cu cursorul
cu doua poziti in urma.
    La intrarea in LOAD, in cazul in care este alocata o matrice inainte
aceasta se elibereaza. Deci daca operatia de LOAD esueaza, programul revine la
starea in care nicio matrice nu este incarcata in memorie.
    In plus, la LOAD se face si selectul default: sunt initializate variabilele
care retin matricea selectata(in cazul LOAD, toata matricea incarcata).

2. SELECT <x1> <y1> <x2> <y2>

    Inainte de a incepe comanda SELECT, am verificat daca a fost introdusa in
mod corespunzator: daca are 4 parametrii si daca acestia sunt numere. Am
verificat daca numerele sunt valide si daca se poate face selectia respectiva,
si in caz afirmativ am pus valorile lor in structura corespunzatoare pozei
alocate.

3. SELECT ALL

    Pentru comanda SELECT ALL, am verificat ce tip de poza este incarcata in
memorie si am actualizat informatiile cu privire la selectie: este selectata
intreaga inaltime si lungime a pozei.

4. HISTOGRAM <x> <y>

    Dupa ce am verificat daca comanda a fost introdusa in mod corespunzator,
am calculat numarul de aparitii al fiecarui pixel in poza si am retinut acest
numar intr-un vector de frecventa. Pentru a afla cate valori trebuie grupate
impreuna astfel incat sa rezulte un numar dat de binuri, am facut suma pentru
valorile care trebuiesc grupate si le-am pastrat in alt vector. Dupa aceea,
calculeaz numarul maxim de aparitii din noul vector si aplic formula data.

5. EQUALIZE

    Pentru EQUALIZE, folosesc aceeasi functie de la histograma pentru a calcula
numarul de aparitii al fiecarui pixel in matrice, dupa care aplic formula:
calculez suprafata imaginii, suma, si pun noua valoare a pixelului in matrice.

6. CROP

    CROP functioneaza asemanator pentru imaginile color si cele greyscale: se
aloca o matrice noua, pe dimensiunile selectiei, si se copiaza in aceasta
valorile din submatricea selectata. Se elibereaza matricea veche, se
actualizeaza dimensiunile si selectia, si matricea noua se duce in locul celei
vechi.

7. APPLY <PARAMETRU>

    Pentru APPLY, verific daca comanda a fost introdusa corespunzator si daca
parametrul este unul cunoscut. In functie de efectul dorit, kernelul se
initializeaza cu valorile potrivite. Pixelii care nu au suficienti vecini
pentru aplicare algoritmului (cei din margine), sunt ignorati: verific
daca parametrii pentru selectie se afla in margine, si daca sunt, ii mut
cu un pixel langa margine.
    Pentru aplicarea efectului, aloc o matrice noua, copiez in ea valorile din
poza originala, dupa care parcurg numai submatricea selectata. Fac pe rand
suma vecinilor pentru toate cele trei valori(R, G, B), si le pun in matricea
noua. Dupa aceea, copiez in submatricea selectata valorile noi ale pixelilor,
si eliberez matricea alocata.

8. SAVE <nume_fisier> |ascii|

    Pentru SAVE, verific daca apare parametrul ascii si ce tip de poza este
incarcata in memorie. Daca este prezent parametrul ascii, deschid un fisier
in mod text, scriu headerul, dupa care matricea. Daca nu apare parametrul
ascii, atunci deschid un fisier binar, scriu headerul, dupa care matricea,
cu fwrite.

9. EXIT

    La EXIT, verific daca a fost pastrata anterior cel putin o poza in memorie.
Daca nu a fost, atunci nu se poate iesi din program. Altfel, verific ce tip
de poza este incarcata in memorie, o eliberez, si ies din subprogram.

10. ROTATE <unghi>

    Algoritmul de rotate functioneaza asemanator pentru pozele greyscale si
cele color: se verifica daca selectia este patrata sau daca este selectata
toata imaginea. Daca unghiul este 0 sau +-360, atunci se afiseaza mesajul de
rotire, pentru ca aceste unghiuri nu afecteaza imaginea. Daca unghiul nu este
divizibil cu 90 atunci se afiseaza un mesaj si se iese din program.
    Daca unghiul este divizibil cu 90, atunci exista doua cazuri: > 0 sau < 0.
Pentru un unghi mai mic decat 0, nu mai este necesar niciun calcul, si se
apeleaza de cate ori este nevoie functia de rotire pentru -90 de grade.
    Subprogramul de rotate -90 functioneaza in felul urmator: se aloca o
matrice noua, cu dimensiunile submatricei selectate, si se copiaza in aceasta
matricea selectata. Pentru aceasta matrice, se calculeaza transpusa. Daca
este selectata intreaga imagine, atunci trebuie sa se faca un swap intre
dimensiuni, sa se realoce matricea pe noile dimensiuni si sa se actualizeze
variabilele de selectie. Daca nu este selectata toata imaginea, nu apare
aceasta problema. Cu transpusa calculata, se parcurg coloanele pe rand, se
pastreaza elementele intr-un vector si se pun inapoi in matrice in ordine
inversa. Dupa asta, se copiaza matricea rotita peste locul ei original.
    Daca unghiul este pozitiv, am observat ca se poate folosi functia de
rotate -90, deoarece un rotate de +90 de grade este egal cu 3 rotate-uri
de -90. De asemenea, am observat ca daca impart unghiul la 30 obtin numarul
de rotiri necesare (de exemplu, pentru 270: 270 / 30 = 9, sunt necesare
9 rotiri).
    Rotate este asemanator pentru imagini greyscale si color, singura diferenta
este ca pentru imaginile color se lucreaza cu 3 valori ale unui pixel.

Organizarea pe fisiere:

    In functions.c se gasesc functiile auxiliare, care verifica daca se pot
executa diverse operatii, daca comenziile au fost alocate corect, si functii
care executa pasi intermediari in rezolvare: spre exemplu calcularea
transpusei, pentru a fi utilizata in functia rotate. In commands.c se
gasesc functiile pentru executarea comenzilor. In structs.h am pus structurile
pentru imagini