<!--info
title: Programming Exam
start: 2021-02-19 14:00:00
stop: 2021-02-19 18:00:00
language: C++
type: upload
-->
# Esame MDP del 19/02/2021
## Esercizio 1
<!--begin
name: PPM-Load
files: [process_ppm.cpp]
topic: PPM
level: 2
points: 7
-->
Una software house sta realizzando una app per dispositivi mobili che deve trasmettere dati in formato JSON. Uno dei campi richiesti è però una piccola immagine a colori RGB e JSON non supporta la trasmissione di dati binari. Per questo motivo la software house decide di utilizzare un semplice encoding Base64. L’immagine viene compressa a piani separati con l’algoritmo PackBits e poi ogni piano così compresso viene codificato in Base64. Le informazioni vengono passate come campi di un dizionario JSON. Ad esempio:
```json
{
"width": 6,
"height": 6,
"red": "3f+A",
"green": "/gD+//4A/v/+AP7//gD+//4A/v/+AP7/gA==",
"blue": "3QCA"
}
```
In questo esempio è codificata un'immagine con tre colonne rosse (255,0,0) e tre gialle (255,255,0), come in tabella:
| r | r | r | g | g | g |
|---|---|---|---|---|---|
| **r** | **r** | **r** | **g** | **g** | **g** |
| **r** | **r** | **r** | **g** | **g** | **g** |
| **r** | **r** | **r** | **g** | **g** | **g** |
| **r** | **r** | **r** | **g** | **g** | **g** |
| **r** | **r** | **r** | **g** | **g** | **g** |
quindi i piani colore contengono (i valori sono mostrati qui in esadecimale e c'è uno spazio più grande tra una riga e l'altra, solo per chiarezza):
```
R: FF,FF,FF,FF,FF,FF, FF,FF,FF,FF,FF,FF, FF,FF,FF,FF,FF,FF,
FF,FF,FF,FF,FF,FF, FF,FF,FF,FF,FF,FF, FF,FF,FF,FF,FF,FF
G: 00,00,00,FF,FF,FF, 00,00,00,FF,FF,FF, 00,00,00,FF,FF,FF,
00,00,00,FF,FF,FF, 00,00,00,FF,FF,FF, 00,00,00,FF,FF,FF
B: 00,00,00,00,00,00, 00,00,00,00,00,00, 00,00,00,00,00,00,
00,00,00,00,00,00, 00,00,00,00,00,00, 00,00,00,00,00,00
```
Dopo la codifica PackBits:
```
R: DD,FF,80
G: FE,00,FE,FF,FE,00,FE,FF,FE,00,FE,FF,FE,00,FE,FF,FE,00,FE,FF,FE,00,FE,FF,80
B: DD,00,80
```
Dopo l'encoding in Base64:
```
R: 3f+A
G: /gD+//4A/v/+AP7//gD+//4A/v/+AP7/gA==
B: 3QCA
```
Nel file `process_ppm.cpp` implementare la funzione corrispondente alla seguente dichiarazione:
```c++
bool LoadPPM(const std::string& filename, mat<vec3b>& img);
```
La funzione deve caricare un'immagine a colori nel formato PPM, seguendo le specifiche allegate. Se la lettura va a buon fine la funzione ritorna `true`, altrimenti ritorna `false`. L'implementazione della classe `mat` e della classe `vec3b` sono disponibili nei file `mat.h`, `ppm.h` e `ppm.cpp`.
Sono dati a titolo di esempio i file `test.ppm` e `facolta.ppm`.
<!--end-->
## Esercizio 2
<!--begin
name: PPM-Split
files: [process_ppm.cpp]
topic: PPM
level: 2
points: 5
-->
Sempre nel file `process_ppm.cpp` implementare la procedura corrispondente alla seguente dichiarazione:
```c++
void SplitRGB(const mat<vec3b>& img, mat<uint8_t>& img_r, mat<uint8_t>& img_g, mat<uint8_t>& img_b);
```
La procedura deve separare la matrice di valori RGB `img` in tre matrici (`img_r`, `img_g`, e `img_b`) ognuna contenente un solo piano colore, R, G, e B.
## Esercizio 3
<!--begin
name: PackBits
files: [compress.cpp]
topic: PackBits
level: 2
points: 8
-->
Nel file `compress.cpp` implementare la procedura corrispondente alla seguente dichiarazione:
```c++
void PackBitsEncode(const mat<uint8_t>& img, vector<uint8_t>& encoded);
```
che applica l'algoritmo PackBits ad un piano colore, `img`, salvando il risultato in un vettore di `uint8_t`.
Come visto a lezione, PackBits è uno schema di compressione veloce e semplice senza perdita di dati per la codifica dei dati in run-length.
Il flusso di dati PackBits è costituito da pacchetti con un'intestazione da un byte seguita da uno o più byte di dati compressi.
Nella tabella seguente è riportata l'associazione tra il valore del byte di intestazione, `L`, e i byte dei dati.
|header (L) |byte di dati che seguono l'header |
|-------------|--------------------------------------|
|da 0 a 127 | (L+1) byte letterali di dati (copia) |
|da 129 a 255 | un byte di dati, ripetuto (257-L) volte nell'output decompresso (run)|
|128| End of data marker (EOD)|
L'algoritmo deve scorrere l'input e per ogni sequenza di byte uguali emettere una run, altrimenti una copia per le sequenze prive di ripetizioni e al termine dei dati un EOD.
<!--end-->
## Esercizio 4
<!--begin
name: Base64
files: [compress.cpp]
topic: Base64
level: 2
points: 8
-->
Sempre nel file `compress.cpp` implementare la funzione corrispondente alla seguente dichiarazione:
```c++
std::string Base64Encode(const vector<uint8_t>& v);
```
che applica ad una sequenza `v` l'encoding Base64 e ritorna la stringa risultante.
Si ricorda che il Base64 è un sistema di codifica che consente la traduzione di dati binari in stringhe di testo ASCII, rappresentando i dati sulla base di 64 caratteri ASCII diversi. L'algoritmo che effettua la conversione suddivide l'input in gruppi di tre byte da cui si ottengono quattro sottogruppi da 6 bit, i quali possono quindi contenere valori da 0 a 63. Ogni possibile valore viene convertito in un carattere ASCII secondo la seguente tabella:
| Valore | ASCII | Valore | ASCII | Valore | ASCII | Valore | ASCII |
|:-------:|:------:|:-------:|:------:|:-------:|:------:|:-------:|:------:|
| 0 | A | 16 | Q | 32 | g | 48 | w |
| 1 | B | 17 | R | 33 | h | 49 | x |
| 2 | C | 18 | S | 34 | i | 50 | y |
| 3 | D | 19 | T | 35 | j | 51 | z |
| 4 | E | 20 | U | 36 | k | 52 | 0 |
| 5 | F | 21 | V | 37 | l | 53 | 1 |
| 6 | G | 22 | W | 38 | m | 54 | 2 |
| 7 | H | 23 | X | 39 | n | 55 | 3 |
| 8 | I | 24 | Y | 40 | o | 56 | 4 |
| 9 | J | 25 | Z | 41 | p | 57 | 5 |
| 10 | K | 26 | a | 42 | q | 58 | 6 |
| 11 | L | 27 | b | 43 | r | 59 | 7 |
| 12 | M | 28 | c | 44 | s | 60 | 8 |
| 13 | N | 29 | d | 45 | t | 61 | 9 |
| 14 | O | 30 | e | 46 | u | 62 | + |
| 15 | P | 31 | f | 47 | v | 63 | / |
Invece che implementare il padding standard del Base64, è sufficiente aggiungere byte uguali a 128 in fondo al vettore, in modo che la lunghezza sia un multiplo di 3 e quindi si ottengano sempre gruppi completi di 3 byte.
<!--end-->
## Esercizio 5
<!--begin
name: JSON
files: [compress.cpp]
topic: JSON
level: 2
points: 5
-->
Sempre nel file `compress.cpp` implementare la funzione corrispondente alla seguente dichiarazione:
```c++
string JSON(const std::string& filename);
```
che data un'immagine RGB in formato PPM costruisce e ritorna la stringa in formato JSON come richiesto dalla software house.
<!--end-->