Un exemple de mauvais caviardage

Un exemple de mauvais caviardage

Dans l'un des cas que j'ai traité récemment, j'ai été confronté à un document pdf dans lequel une partie du texte avait été caviardée. Voici ce à quoi le document ressemblait :

caviardage.

Les métadonnées indiquaient que le fichier était issu de Word. Il semblerait donc que la personne en charge du caviardage avait simplement ajouté des carrés noirs au-dessus du texte qu'il voulait cacher, avant d'enregistrer le fichier en pdf directement avec Word.

Ça n'est pas du tout la bonne manière de procéder. En effet, il suffit d'ouvrir le document avec Inkscape pour voir que les carrés noirs sont des objets :

inkscape

Pour voir le texte dans son intégralité, il suffit de supprimer ces objets :

inkscape

Selon moi, pour vraiment cacher une partie du contenu, il aurait fallu deux étapes de plus. Dans un premier temps, il aurait fallu convertir le pdf dans un format de fichier réellement graphique (png ou jpg par exemple). Et dans un second temps, il aurait fallu le reconvertir en pdf.

Dataviz des prénoms masculins les plus donnés en France

J'ai fait une petite vidéo qui montre les prénoms masculins les plus donnés en France par année (de 1900 à 2017) et par département.

Je me suis appuyé sur les données de l'Insee et sur cette carte.

Voici rapidement les étapes du processus :

  • Modification de la carte pour :
    • la simplifier en supprimant tout ce qui ne m'était pas utile,
    • qu'elle intègre les prénoms,
    • qu'elle puisse être facilement modifiable,
    • qu'elle tienne compte des départements avant 1968,
  • Intégration des données dans une base de données sqlite pour qu'elles soient facilement interrogeables en python,
  • Création d'un script en python qui :
    • attribue une couleur à chaque prénom,
    • interroge la base de données,
    • pour chaque année, modifie et enregistre le fichier svg
  • Conversion des fichiers svg en png,
  • Création de la vidéo avec iMovie.

Et voilà.

Matrice 8x8 sans fil avec un teensy et un ESP8266

Matrice 8x8 sans fil avec un teensy et un ESP8266

Il y a quelques années, j'avais acheté un teensy et une matrice 8x8. J'avais également quelques ESP8266 et un module AMS1117. Tout cela devait me permettre de créer un afficheur sans fil contrôlable depuis un navigateur.

J'ai sorti mon fer à souder et j'ai assemblé le tout de la manière suivante : teensy wiring

Il ne restait plus qu'à coder mon idée d'afficheur sans fil dans l'IDE arduino.

C'est ce que j'ai fait en utilisant le phénomène de la persistance rétinienne. Il n'y a, en effet, jamais plus d'une led allumée à la fois, mais elles changent tellement rapidement que l'œil ne voit pas de clignotement :

void matrix_disp(int x, int y) {
  digitalWrite(row[x], HIGH); // on
  digitalWrite(col[y], LOW);
  digitalWrite(col[y], HIGH); // off
  digitalWrite(row[x], LOW);
}
void matrix_draw(bool m[8][8]) {
  elapsedMillis time;
  while (time < timer) {
    for (int x = 0; x < 8; x++) {
      for (int y = 0; y < 8; y++) {
        if (m[x][y] == true) matrix_disp(x, y);
      }
    }
  }
}

Après avoir réussi à faire une interface web (minimaliste) et à faire défiler un texte sur la matrice, j'ai ajouté la possibilité d'afficher l'heure, grâce au protocole NTP :

time_t ntp_gettime() {
  if (TIMEDEBUG == 1) DEBUG_SERIAL.println("ntp_gettime");
  unsigned long timestamp = 0;
  byte ntp_request[48];
  for (int i = 0; i < 48; i++) {
    ntp_request[i] = 0x00;
  }
  ntp_request[0] = 0xE3;   // LI, Version, Mode
  ntp_request[1] = 0;      // Stratum, or type of clock
  ntp_request[2] = 10;     // Polling Interval
  ntp_request[3] = 0xEC;   // Peer Clock Precision
  wifi_buffclr();
  WIFI_SERIAL.println("AT+CIPSTART=1,\"UDP\",\"fr.pool.ntp.org\",123,123");
  delay(1);
  if (WIFI_SERIAL.find("OK")) {
    wifi_buffclr();
    WIFI_SERIAL.println("AT+CIPSEND=1,48");
    delay(1);
    if (WIFI_SERIAL.find(">")) {
      wifi_buffclr();
      for (int i = 0; i < 48; i++) {
        WIFI_SERIAL.print((char)ntp_request[i]);
      }
      delay(1);
      if (WIFI_SERIAL.find("SEND OK")) {
        wifi_buffclr();
        delay(1);
        if (WIFI_SERIAL.find("+IPD,1,48:")) {
          byte result[4] = {0, 0, 0, 0};
          byte nul[32];
          WIFI_SERIAL.readBytes(nul, 32);
          WIFI_SERIAL.readBytes(result, 4);
          timestamp = 0;
          timestamp += result[0] << 24;
          timestamp += result[1] << 16;
          timestamp += result[2] << 8;
          timestamp += result[3];
          timestamp -= 2208988800; // adjusting for epoch
          timestamp += 7200;       // adjusting for GMT + 2
          timestamp += 9;          // adjusting for display delay
          if (TIMEDEBUG == 1) DEBUG_SERIAL.println(timestamp);
        }
      }
    }
  }
  wifi_buffclr();
  WIFI_SERIAL.println("AT+CIPCLOSE=1");
  delay(250);
  wifi_buffclr();
  return timestamp;
}

mais aussi le cours du bitcoin, grace à l'API coindesk :

String btc_getprice() {
  if (BTCDEBUG == 1 ) DEBUG_SERIAL.println("btc_getprice");
  String price = "0";
  String get = "GET /v1/bpi/currentprice.json HTTP/1.1\r\nHost: api.coindesk.com\r\nConnection: close\r\n";
  wifi_buffclr();
  WIFI_SERIAL.println("AT+CIPSTART=2,\"TCP\",\"api.coindesk.com\",80");
  delay(1);
  if (WIFI_SERIAL.find("OK")) {
    wifi_buffclr();
    WIFI_SERIAL.println("AT+CIPSEND=2,85");
    delay(1);
    if (WIFI_SERIAL.find(">")) {
      wifi_buffclr();
      WIFI_SERIAL.println(get);
      delay(1);
      if (WIFI_SERIAL.find("SEND OK")) {
        wifi_buffclr();
        if (WIFI_SERIAL.find("+IPD,2,") and WIFI_SERIAL.find("EUR") and WIFI_SERIAL.find("rate_float\":")) {
          price = WIFI_SERIAL.readString();
          price = price.substring(0, price.indexOf("}"));
          if (BTCDEBUG == 1 ) DEBUG_SERIAL.println("price : " + price);
          wifi_buffclr();
        }
      }
    }
  }
  WIFI_SERIAL.println("AT+CIPCLOSE=2");
  delay(250);
  wifi_buffclr();
  return price;
}

À partir de là, on peut afficher ce qu'on souhaite...

Au final, j'ai environ 1550 lignes de codes, dont l'essentiel (~1000) pour la police 5x8 :

const bool alpha[][8][5] = {
  { { 0, 0, 0, 0, 0, }, // SP 32
    { 0, 0, 0, 0, 0, },
    { 0, 0, 0, 0, 0, },
    { 0, 0, 0, 0, 0, },
    { 0, 0, 0, 0, 0, },
    { 0, 0, 0, 0, 0, },
    { 0, 0, 0, 0, 0, },
    { 0, 0, 0, 0, 0, }
  },
[...]
  { { 0, 0, 0, 0, 0, }, // a 97
    { 0, 0, 0, 0, 0, },
    { 1, 1, 1, 0, 0, },
    { 0, 0, 0, 1, 0, },
    { 0, 1, 1, 1, 0, },
    { 1, 0, 0, 1, 0, },
    { 0, 1, 1, 0, 0, },
    { 0, 0, 0, 0, 0, }
  },
  { { 1, 0, 0, 0, 0, }, // b 98
    { 1, 0, 0, 0, 0, },
    { 1, 1, 1, 0, 0, },
    { 1, 0, 0, 1, 0, },
    { 1, 0, 0, 1, 0, },
    { 1, 0, 0, 1, 0, },
    { 1, 1, 1, 0, 0, },
    { 0, 0, 0, 0, 0, }
  },
[...]
}

C'était un projet assez fun à réaliser.

Je peux maintenant dire quand il ne faut pas me déranger quand je travaille :

Mes sources sont sur github.