---
jupytext:
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
kernelspec:
  display_name: Python 3 (ipykernel)
  language: python
  name: python3
---

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "d6b46a0a95cd43ae80dbc181dc125671", "grade": false, "grade_id": "cell-10", "locked": true, "schema_version": 3, "solution": false, "task": false}}

# Semaine 8 : fichiers et flux de données

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "dc414efeceffd39f0262e39fbf550a1d", "grade": false, "grade_id": "cell-20", "locked": true, "schema_version": 3, "solution": false, "task": false}}

## <a name=Cours/>[Cours](cours.md)

- Cours : [flux de données](cours-flux.md)
- Cours : [fichiers](cours-fichiers.md)
- Cours : [état d'un fichier](cours-etat-fichier.md)
- Cours : [lecture et écriture dans des chaînes de caractères](cours-flux-chaines-de-caracteres.md)

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "dbf5500bedb753c425b378e4748347d6", "grade": false, "grade_id": "cell-30", "locked": true, "schema_version": 3, "solution": false, "task": false}}

## [TD : fichiers et images numériques](TD.md)

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "bf4d86ed29ba34ce66bdbc753d794093", "grade": false, "grade_id": "cell-40", "locked": true, "schema_version": 3, "solution": false, "task": false}}

## TP

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "6ff5819dcd18e689494acb0ba1af242e", "grade": false, "grade_id": "cell-49", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 0 : Jupyter : l'indentation

À faire chez vous!

- [Jupyter : l'indentation](00-jupyter-indentation.md)

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "9dd26fe469908352fac43de3f823d14a", "grade": false, "grade_id": "cell-50", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 1 : écrire dans un fichier - 20 minutes

+++

::::{hint} Rappels

-   Pour exécuter un programme, il faut d’abord avoir compilé le
    fichier `.cpp` avec la commande `clang++` puis lancer l’exécutable
    créé par la compilation. Consultez au besoin les instructions des
    TP précédents.
-   Pensez à organiser votre espace de travail et à ajuster la taille
    des caractères (avec <kbd>Ctrl</kbd>-<kbd>+</kbd> et
    <kbd>Ctrl</kbd>-<kbd>-</kbd>) pour avoir une vue confortable
    simultanée de tous les éléments requis : consignes, code,
    terminal.

    :::{figure} https://nicolas.thiery.name/Enseignement/Info111/media/screencast-espace-de-travail-compilation.gif
    Vidéo: organiser son espace de travail avec JupyterLab
    :::

::::

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "8124382c9ab91f1d2004315ed95e82c1", "grade": false, "grade_id": "cell-60", "locked": true, "schema_version": 3, "solution": false, "task": false}}

1.  Consultez le fichier [fichier-ecriture.cpp](fichier-ecriture.cpp).

2.  Essayez de deviner ce que fait ce programme.

3.  Exécutez ce programme.
    
4.  Trouvez le fichier `.txt` qui a été créé à l’exécution et l’ouvrir
    avec un éditeur de texte. Que contient-il?

5.  Copiez le contenu de [fichier-ecriture.cpp](fichier-ecriture.cpp)
    dans [fichier-ecriture-v2.cpp](fichier-ecriture-v2.cpp), et
    adaptez le pour qu’à l’exécution il écrive un fichier nommé
    `essai.txt` contenant le texte «17 fois 23 vaut» suivi de la
    valeur de ce nombre (valeur que le programme calcule par
    lui-même).

6.  Exécutez ce programme puis ouvrez le fichier `essai.txt` afin de
    vérifier son contenu.

7.  Lisez et essayez à nouveau dans le cours l'exemple de [lecture
    depuis le clavier](cours-flux.md) avec `cin`.

8.  En vous en inspirant, complétez le programme [cin.cpp](cin.cpp)
    pour que, à l’exécution, il demande à l’utilisateur d’entrer deux
    entiers, puis qu’il écrive un fichier nommé `multiplication.txt`
    contenant un texte similaire au fichier `essai.txt` de la question
    précédente, avec 17 et 23 remplacés respectivement par les deux
    entiers choisis par l’utilisateur.
    
    :::{note}
    
    Pour faire des affichages à l’écran et pour faire saisir des
    données depuis le clavier, il faut inclure la bibliothèque
    `iostream` en écrivant `#include <iostream>`. Pour lire et écrire
    dans un fichier de texte, il faut inclure la bibliothèque
    `fstream` en écrivant `#include <fstream>`

    :::

9.  Exécutez le programme puis ouvrez le fichier `multiplication.txt`
    pour vérifier son contenu.

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "cb2c18e19c408b69d4d8589c8f7649cd", "grade": false, "grade_id": "cell-70", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 2 : ouvrir le smiley - 5 minutes

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "5f1d313afad6f51ebf42d10eb2ea7a42", "grade": false, "grade_id": "cell-80", "locked": true, "schema_version": 3, "solution": false, "task": false}}

Le fichier [media/smiley.pbm](media/smiley.pbm) (dans le répertoire
`media` donc!) contient l’image en noir et blanc du TD.

1.  Ouvrez ce fichier d’abord avec un éditeur de texte. Depuis le
    navigateur de fichiers de JupyterLab: clic droit -> Ouvrir avec ->
    Éditeur.

2.  Ouvrez ce même fichier avec un logiciel de vision d’images. Pour
    cela, depuis Jupyter, vous pouvez utiliser la cellule ci-dessous :

```{code-cell}
from open_ppm import open_ppm                # importe la commande open_ppm fournie
im = open_ppm("media/smiley.pbm")            # charge l'image
im.resize((256*im.width // im.height, 256))  # affiche l'image avec une taille donnée
```

:::{admonition} Pour les curieux
:class: dropdown

Python et Jupyter ne savent pas manipuler nativement les fichiers aux
formats PBM, PGM ou PPM non compressés. La commande
`open_ppm('xxx.ppm')` fournie dans le fichier
[open_ppm.py](open_ppm.py) commence par utiliser l'utilitaire
`convert` de `ImageMagick` avec `convert xxx.ppm xxx.png` pour
convertir l'image en format PNG.

:::

Alternativement :
-   Sous Windows, vous pouvez utiliser l’application `irfanview`.
-   Sous Linux, vous pouvez utiliser l’application `xviewer` :
    utilisez «Control +» et «Control -» pour zoomer /
    dezoomer. Vous remarquerez que l’image est lissée / floutée. Allez
    dans le menu «Edit -> Preferences» et décochez «Smooth images when
    zoomed in» pour mieux voir les pixels.

### Exercice 3 : petit damier - 15 minutes

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "7a193c543e70cced08244a1a71520334", "grade": false, "grade_id": "cell-90", "locked": true, "schema_version": 3, "solution": false, "task": false}}

1.  Utilisez un éditeur de texte pour écrire à la main un **fichier
    texte** `damier.pbm` contenant une image au format PBM
    ([*Portable Bit Map*](http://fr.wikipedia.org/wiki/Portable_bitmap))
    de taille 10×10 représentant un damier :

    :::{image} media/damier_svg.png
    :width: 10%
    :alt: un damier
    :::

2.  Visualisez le résultat, par exemple avec :

```{code-cell}
from open_ppm import open_ppm
im = open_ppm("damier.pbm")
im.resize((256*im.width // im.height, 256))
```

(indications_images)=
:::{hint} Indications en cas d'erreur à la visualisation ou d'image incorrecte
:class: dropdown

- Vérifiez que le fichier existe, dans le répertoire `Semaine8`, avec
  le bon nom et la bonne extension (`.pbm`, `.pgm`, ou `.ppm` selon
  l'exercice).
- Ouvrez le fichier avec un éditeur de texte.
- Vérifiez l'entête de l'image:
    - la première ligne contient `P1` (format PBM), `P2` (format PGM)
      ou `P3` (format PPM);
    - la deuxième ligne (sans compter les lignes de commentaires
      commençant par `#`) contient deux entiers: le nombre $c$ de
      colonnes et le nombre $l$ de lignes;
    - pour les fichiers `pbm` ou `ppm`: la troisième ligne contient un
      entier $m$.
- Vérifiez que le reste du fichier consiste d'entiers séparés par des
  espaces ou des sauts de ligne:
  - format `pbm`: $cl$ entiers $0$ ou $1$;
  - format `pgm`: $cl$ entiers entre $0$ et $m$;
  - format `ppm`: $3cl$ entiers entre $0$ et $m$.
- Vérifiez que les valeurs sont adéquates.

:::

Tests automatiques :

```{code-cell}
assert im.size == (10, 10), "l'image n'est pas de taille 10×10"
```

```{code-cell}
import numpy as np
M = np.array(im, dtype=int)
assert np.all(M[1:,:] + M[:-1,:] == 1), "l'image n'est pas un damier horizontalement"
assert np.all(M[:,1:] + M[:,:-1] == 1), "l'image n'est pas un damier verticalement"
```

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "65237cca3ba3cf9fb579a874a7f3f6b1", "grade": false, "grade_id": "cell-100", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 4 : grand damier

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "792992fb2ce3f4d9bf342c4bee84e65a", "grade": false, "grade_id": "cell-110", "locked": true, "schema_version": 3, "solution": false, "task": false}}

Complétez le **programme C++** [damier.cpp](damier.cpp) qui, lorsqu’on
l’exécute, écrit un fichier image `damier-automatique.pbm` comme le
précédent, mais cette fois pour un damier 100x100.

Visualisez et vérifiez au fur et à mesure le résultat avec :

```{code-cell}
im = open_ppm("damier-automatique.pbm")
im.resize((512*im.width // im.height, 512))
```

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "8b8ba5a75745c14276324532d144a1fe", "grade": false, "grade_id": "cell-120", "locked": true, "schema_version": 3, "solution": false, "task": false}}

:::{hint} Indications

-   Vous pouvez vous inspirer de [fichier-ecriture.cpp](fichier-ecriture.cpp).
-   Commencez par un programme pour un damier 10×10 avant de passer à
    100×100.
-   L'exécution de votre programme devrait être instantanée ou
    presque. Si ce n'est pas le cas, interrompez le avec
    <kbd>Ctrl</kbd>-<kbd>C</kbd>.
-   Vérifiez la taille du fichier produit en tapant la commande suivante dans
    le terminal :
    ```
    ls -lh *.pbm
    ```
    Il devrait faire dans les 20 kilo octets (20K). Veillez à le
    supprimer s'il fait nettement plus que cela.
-   Si le fichier produit ne donne pas l’image attendue, ou si vous
    n'arrivez pas à le visualiser: reportez vous aux [indications de
    l'exercice précédent](#indications_images).
-   Si cela vous aide, vous pouvez aussi dans un premier temps
    afficher le texte produit à l’écran avec `cout`; puis écrivez le
    dans le fichier dans un deuxième temps.

:::

+++

Tests automatiques :

```{code-cell}
assert im.size == (100, 100), "l'image produite n'est pas de taille 100×100"
```

```{code-cell}
import numpy as np
M = np.array(im, dtype=int)
assert np.all(M[1:,:] + M[:-1,:] == 1), "l'image n'est pas un damier horizontalement"
assert np.all(M[:,1:] + M[:,:-1] == 1), "l'image n'est pas un damier verticalement"
```

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "fec81568499bca600d3cae6fb9dc41c0", "grade": false, "grade_id": "cell-130", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 5 : dégradé de gris

Pour créer une image avec des nuances de gris, il faut enregistrer un
fichier de texte au format PGM ([Portable Gray Map](http://fr.wikipedia.org/wiki/Portable_graymap)). Ce fichier doit
contenir des nombres entre 0 et une valeur maximale (au choix) qui
représenteront les différentes nuances de gris.

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "3175edfdcd2ba6f573443ce9504466dd", "grade": false, "grade_id": "cell-140", "locked": true, "schema_version": 3, "solution": false, "task": false}}

1.  Écrivez à la main, dans un éditeur de texte, un fichier
    `essai.pgm` représentant une image de taille 10×10 contenant
    différentes nuances de gris de votre choix. Vérifiez au fur et à
    mesure le résultat avec :

```{code-cell}
im = open_ppm("essai.pgm")
im.resize((256*im.width // im.height, 256))
```

Tests automatiques :

```{code-cell}
assert im.size == (10, 10), "l'image produite n'est pas de taille 10×10"
```

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "65f16b8b10337cf30c2a8273bd57ff79", "grade": false, "grade_id": "cell-150", "locked": true, "schema_version": 3, "solution": false, "task": false}}

2.  Implantez un programme [degrade.cpp](degrade.cpp) qui écrit un
    fichier contenant une image `degrade.pgm` de taille 128x128, avec
    un dégradé de gris comme celui-ci :

    :::{image} media/degrade.png
    :width: 20%
    :alt: un dégradé de gris
    :::

```{code-cell}
im = open_ppm("degrade.pgm")
im.resize((256*im.width // im.height, 256))
```

Tests automatiques :

```{code-cell}
assert im.size == (128, 128), "l'image produite n'est pas de taille 128×128"
```

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "4f500798eefc2a87622c29ef17e57230", "grade": false, "grade_id": "cell-160", "locked": true, "schema_version": 3, "solution": false, "task": false}}

3.  Répétez, avec une image de taille 100×100

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "9c9224e94d136176282b95357c8edd88", "grade": false, "grade_id": "cell-170", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 6 : inversion d’image

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "f3fa5bea0ea3429d63f52fd66e7d3369", "grade": false, "grade_id": "cell-180", "locked": true, "schema_version": 3, "solution": false, "task": false}}

Implantez un programme [videoInverse.cpp](videoInverse.cpp)
qui lit un fichier contenant une image au format
PGM (par exemple le fichier `media/image.pgm` fourni), et écrit un fichier
contenant la même image en vidéo inverse (clair remplacé par sombre et
réciproquement).

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "2a4cc77ee0d0dcd169aad954bff7fd0a", "grade": false, "grade_id": "cell-190", "locked": true, "schema_version": 3, "solution": false, "task": false}}

:::{hint} Indication Implantez une fonction

``` c++
    /** Image en vidéo inverse
     * @param image1: le nom du fichier contenant l'image à lire
     * @param image2: le nom du fichier pour l'image à écrire
     **/
    void videoInverse(string image1, string image2);
```
:::

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "8e4c6932227912a0021029a54216d0ec", "grade": false, "grade_id": "cell-200", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 7 : dégradé circulaire de rouge ♣

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "a4badd45d2e8d7c755437d2bcc49f9bc", "grade": false, "grade_id": "cell-210", "locked": true, "schema_version": 3, "solution": false, "task": false}}

1.  Implantez un programme [degrade-circulaire.cpp](degrade-circulaire.cpp)
    qui écrit un fichier contenant une image `degrade-circulaire.ppm`
    au format PPM de taille 255×255, avec
    un dégradé circulaire de rouge:  

    :::{image} media/degrade-circulaire.png
    :width: 20%
    :alt: un dégradé circulaire
    :::

2.  Répétez, avec une image de taille 100×100.