Un poster sur base des images d’une vidéo

Fabriquer une affiche faite de photogrammes d’un film est un classique de l’art numérique et du code en Processing. Voici une méthode parmi d’autres pour obtenir ce résultat.

Variables de configuration

Le script nécessite un fichier vidéo (mp4, avi, etc.) supporté par la librairie "vidéo" de Processing.
La variable "source" contient le nom du fichier vidéo associé.
La variable "marges" détermine le nombre de pixels pour la marge, en 72 dpi. 28 pixels équivalent 1 centimètre.
La variable "nbx" quand à elle définit le nombre d’images en largeur. Le script calcule à partir de ce chiffre et de la hauteur des images vidéos le nombre d’images qui composeront le poster.
Le script produit un pdf A3 avec des images capturés à intervalles réguliers.

Attention : les images sont écrites dans le pdf à leur définition d’origine (720 par 576 par exemple). Il peut en résulter un pdf très lourd. Il est souvent nécessaire de réduire la taille du fichier en recalculant la résolution du fichier via un utilitaire comme acrobat.

Le code

import processing.pdf.*;
import processing.video.*;

Movie mov;
PGraphicsPDF pdf;
PFont mapolice;

// variables de personnalisation
String source="lefilm.mp4";
String titre="Nomdufilm, année";
int marges=56; // marges du pdf en pixel - 72 dpi
int nbx=20; // nombre d'image sur l'axe x, influence le nombre d'image final

// variables du script (ne pas changer)
float saut;
float timeline=0;
float x=marges;
float y=marges;
float largeur, hauteur;
int compteur=1;

void setup() {
 size(842, 1191); // A3 vertical
 background(255);
  pdf = (PGraphicsPDF)beginRecord(PDF, "poster.pdf");

 mapolice = createFont("Courier", 14);
 textFont(mapolice);
 textAlign(CENTER, CENTER);

 mov = new Movie(this, source);
 mov.play();
 mov.jump(0);
 while (!mov.available()) {
   println("wait for movie");
 }
 mov.read();

 // calculer le nombre d'images demandées en fonction du nombre d'images demandées en largeur
 // et de l'espace disponible en hauteur
 largeur=(width-(marges*2))/nbx; // largeur de l'image sur base du nombre d'images demandées
 hauteur=((mov.height*1.0)/(mov.width*1.0))*largeur; // hauteur sur base de la largeur

 int nby=int((height-(marges*3))/hauteur); // nombre de rangs sur base de la hauteur d'image

 saut=(mov.duration())/(nbx*nby); // déplacement en seconde entre deux images
 println("fichier source : " + source);
 println("durée : " + mov.duration());
 println("temps entre chaque image : " + saut);
 println("taille des images : " + largeur+" / "+hauteur);
 println("Nombre d'images : "+ (nbx*nby));

 mov.play();
 while (timeline <= mov.duration()) {
   mov.jump(timeline);
   if (mov.available()) {
     // la hauteur de l'image est en proportion de la largeur
     mov.read();
     image(mov, x, y, largeur, hauteur);

     x+=largeur;
     if (x > width-(marges*2)) {
       x=marges;
       y+=hauteur;
     }
     print(compteur+", ");
     compteur++;
     timeline +=saut;
   }
 }
 // placer le titre
 fill(0);
 text(titre, width/2, height-(marges*1.5));
 endRecord();
 println("fini");
 exit();
}