Skip to content

Commit

Permalink
video stable
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasSevagen committed Feb 25, 2025
1 parent 82eab2f commit 61f127c
Show file tree
Hide file tree
Showing 2 changed files with 294 additions and 19 deletions.
298 changes: 286 additions & 12 deletions backend/src/main/java/fr/cgi/magneto/helper/SlideHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;
import javax.xml.namespace.QName;

import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFHyperlink;
import org.apache.poi.xslf.usermodel.XSLFPictureData;
import org.apache.poi.xslf.usermodel.XSLFPictureShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
Expand All @@ -24,7 +21,6 @@
import org.apache.poi.xslf.usermodel.XSLFTextRun;
import org.apache.poi.xslf.usermodel.XSLFTextShape;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS;
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
Expand All @@ -44,16 +40,10 @@
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.sl.usermodel.Hyperlink;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.PlaceholderDetails;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;

public class SlideHelper {
private static final int SLIDE_HEIGHT = 720;
Expand Down Expand Up @@ -301,6 +291,157 @@ public static XSLFPictureShape createAudio(XSLFSlide slide, byte[] audioData, St
}
}

public static XSLFPictureShape createVideo(XSLFSlide slide, byte[] videoData, String fileContentType) {
System.out.println("=== DÉBUT CRÉATION VIDÉO ===");
String extension = getExtensionFromContentType(fileContentType);
try {
// Générer un nom pour le fichier vidéo
String videoFileName = "video_" + System.currentTimeMillis() + "." + extension;
System.out.println("Nom fichier vidéo généré: " + videoFileName);

// Créer et stocker le fichier vidéo
XMLSlideShow ppt = slide.getSlideShow();
OPCPackage opcPackage = ppt.getPackage();
System.out.println("Package récupéré: " + opcPackage);

PackagePartName videoPartName = PackagingURIHelper.createPartName("/ppt/media/" + videoFileName);
System.out.println("Chemin vidéo créé: " + videoPartName);

PackagePart videoPart = opcPackage.createPart(videoPartName, fileContentType);
System.out.println("Partie vidéo créée: " + videoPart);

try (OutputStream out = videoPart.getOutputStream()) {
out.write(videoData);
System.out.println("Données vidéo écrites: " + videoData.length + " octets");
}

// Obtenir la partie du slide
PackagePart pp = slide.getPackagePart();
System.out.println("Partie du slide: " + pp);

// Créer deux relations vers le fichier vidéo
System.out.println("Création des relations...");
PackageRelationship prsEmbed = pp.addRelationship(
videoPart.getPartName(), TargetMode.INTERNAL,
"http://schemas.microsoft.com/office/2007/relationships/media");
System.out.println("Relation média créée: " + prsEmbed.getId() + " -> " + prsEmbed.getTargetURI());

PackageRelationship prsExec = pp.addRelationship(
videoPart.getPartName(), TargetMode.INTERNAL,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");
System.out.println("Relation vidéo créée: " + prsExec.getId() + " -> " + prsExec.getTargetURI());

// Créer une miniature de la vidéo
System.out.println("Création de la miniature...");
byte[] thumbnailData = getVideoThumbnail(videoData, extension);
System.out.println("Miniature générée: " + (thumbnailData != null ? thumbnailData.length : 0) + " octets");

XSLFPictureData snap = ppt.addPicture(thumbnailData, PictureType.PNG);
System.out.println("Image ajoutée au PPT: " + snap.getFileName());

// Positionner la miniature vidéo dans le slide
XSLFPictureShape pic = createAndPositionVideoThumbnail(slide, thumbnailData);
System.out.println("Forme image créée, ID: " + pic.getShapeId());

// Configurer les propriétés de l'image pour le média
System.out.println("Configuration du XML...");
CTPicture xpic = (CTPicture) pic.getXmlObject();
System.out.println("XML de l'image récupéré");

CTHyperlink link = xpic.getNvPicPr().getCNvPr().addNewHlinkClick();
link.setId("");
link.setAction("ppaction://media");
System.out.println("Lien hypertexte configuré: " + link.getAction());

// Ajouter les propriétés vidéo
CTApplicationNonVisualDrawingProps nvPr = xpic.getNvPicPr().getNvPr();
// Pour vidéo, utiliser videoFile au lieu de audioFile
nvPr.addNewVideoFile().setLink(prsExec.getId());
System.out.println("Propriété videoFile configurée avec ID: " + prsExec.getId());

// Ajouter l'extension média
CTExtension ext = nvPr.addNewExtLst().addNewExt();
ext.setUri("{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");
System.out.println("Extension ajoutée avec URI: " + ext.getUri());

// Configurer l'élément p14:media
String p14Ns = "http://schemas.microsoft.com/office/powerpoint/2010/main";
try (XmlCursor cur = ext.newCursor()) {
cur.toEndToken();
System.out.println("Curseur positionné à la fin de l'extension");
cur.beginElement(new QName(p14Ns, "media", "p14"));
System.out.println("Élément p14:media créé");
cur.insertNamespace("p14", p14Ns);
cur.insertNamespace("r", CORE_PROPERTIES_ECMA376_NS);
System.out.println("Namespaces p14 et r insérés");

System.out.println("Tentative d'insertion de l'attribut embed avec ID: " + prsEmbed.getId());
cur.insertAttributeWithValue(
new QName(CORE_PROPERTIES_ECMA376_NS, "embed"),
prsEmbed.getId());
System.out.println("Attribut embed inséré");
}

// S'assurer que le blipFill utilise le bon ID pour l'image
System.out.println("Vérification de la référence de l'image...");
String imageRelId = slide.getRelationId(snap);
if (imageRelId != null) {
xpic.getBlipFill().getBlip().setEmbed(imageRelId);
System.out.println("BlipFill configuré avec ID d'image: " + imageRelId);
} else {
System.out.println("Avertissement: Impossible de trouver la relation pour l'image");
}

// Ajouter la section timing - CRUCIAL
System.out.println("Ajout des informations de timing...");
CTSlide xslide = slide.getXmlObject();
CTTimeNodeList ctnl;

if (!xslide.isSetTiming()) {
System.out.println("Timing non défini, création...");
CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();
ctn.setId(1);
ctn.setDur(STTLTimeIndefinite.INDEFINITE);
ctn.setRestart(STTLTimeNodeRestartType.NEVER);
ctn.setNodeType(STTLTimeNodeType.TM_ROOT);
System.out.println("Timing root créé avec ID: 1");
ctnl = ctn.addNewChildTnLst();
System.out.println("Liste des nœuds enfants créée");
} else {
System.out.println("Timing déjà défini, récupération...");
ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();
}

// Pour vidéo, utiliser addNewVideo() au lieu de addNewAudio()
System.out.println("Ajout du nœud vidéo...");
CTTLCommonMediaNodeData cmedia = ctnl.addNewVideo().addNewCMediaNode();
cmedia.setVol(80000); // Garder le volume comme pour l'audio
System.out.println("Volume configuré: 80000");

CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();
ctn.setId(2);
ctn.setFill(STTLTimeNodeFillType.HOLD);
ctn.setDisplay(false);
System.out.println("Propriétés du nœud temporel configurées avec ID: 2");

ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);
System.out.println("Condition de démarrage ajoutée");

cmedia.addNewTgtEl().addNewSpTgt().setSpid(pic.getShapeId());
System.out.println("Cible du média configurée avec ID: " + pic.getShapeId());

// Afficher le XML pour le débogage
System.out.println("XML final du slide: " + xslide);

System.out.println("=== CRÉATION VIDÉO TERMINÉE AVEC SUCCÈS ===");
return pic;
} catch (Exception e) {
System.out.println("=== ERREUR LORS DE LA CRÉATION VIDÉO ===");
e.printStackTrace();
return null;
}
}

private static PictureType getPictureTypeFromContentType(String contentType) {
if (contentType == null) {
return PictureType.PNG;
Expand Down Expand Up @@ -414,14 +555,115 @@ private static byte[] getAudioIcon() {
}
}

private static XSLFPictureShape createAndPositionVideoThumbnail(XSLFSlide slide, byte[] thumbnailData) {
System.out.println("Création et positionnement de la miniature vidéo...");

XMLSlideShow ppt = slide.getSlideShow();
XSLFPictureData snap = ppt.addPicture(thumbnailData, PictureType.PNG);
System.out.println("Image ajoutée au PPT: " + snap.getFileName());

XSLFPictureShape pic = slide.createPicture(snap);
System.out.println("Forme image créée, ID: " + pic.getShapeId());

// Définir une taille adaptée pour la vidéo
int videoWidth = 640;
int videoHeight = 360; // Format 16:9 standard

// Calculer la position centrée
int x = (SLIDE_WIDTH - videoWidth) / 2; // Centre horizontal
int y = (SLIDE_HEIGHT - videoHeight) / 2; // Centre vertical

pic.setAnchor(new Rectangle(x, y, videoWidth, videoHeight));
System.out.println("Position de la miniature ajustée: x=" + x + ", y=" + y +
", width=" + videoWidth + ", height=" + videoHeight);

return pic;
}

private static byte[] getVideoThumbnail(byte[] videoData, String extension) {
try {
// Dans un cas réel, on extrairait une image de la vidéo ici
// Pour cet exemple, nous allons simplement créer une vignette générique

// Créer une image de 640x360 pixels (format 16:9)
BufferedImage image = new BufferedImage(640, 360, BufferedImage.TYPE_INT_RGB);

// Obtenir le contexte graphique
Graphics2D g2d = image.createGraphics();

// Activer l'antialiasing pour des bords plus lisses
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

// Remplir le fond avec un dégradé bleu foncé
g2d.setColor(new Color(20, 20, 50));
g2d.fillRect(0, 0, 640, 360);

// Dessiner un symbole de lecture au centre
g2d.setColor(new Color(255, 255, 255, 180));
int centerX = 640 / 2;
int centerY = 360 / 2;
int radius = 50;
g2d.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);

// Triangle de lecture
g2d.setColor(new Color(20, 20, 50));
int[] xPoints = { centerX - 15, centerX + 25, centerX - 15 };
int[] yPoints = { centerY - 25, centerY, centerY + 25 };
g2d.fillPolygon(xPoints, yPoints, 3);

// Ajouter le texte "VIDÉO"
g2d.setColor(Color.WHITE);
g2d.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 24));
java.awt.FontMetrics fm = g2d.getFontMetrics();
String text = "VIDÉO";
int textWidth = fm.stringWidth(text);
g2d.drawString(text, centerX - textWidth / 2, centerY + 80);

// Libérer les ressources
g2d.dispose();

// Convertir l'image en tableau de bytes (PNG)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
return baos.toByteArray();

} catch (IOException e) {
e.printStackTrace();
return getDefaultThumbnail();
}
}

private static byte[] getDefaultThumbnail() {
try {
// Créer une image simple par défaut
BufferedImage image = new BufferedImage(320, 180, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
g2d.setColor(Color.DARK_GRAY);
g2d.fillRect(0, 0, 320, 180);
g2d.setColor(Color.WHITE);
g2d.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 18));
g2d.drawString("Video Preview", 100, 90);
g2d.dispose();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return new byte[0];
}
}

private static String getExtensionFromContentType(String contentType) {
if (contentType == null) {
return null;
return "mp4"; // Par défaut général
}

String lowerContentType = contentType.toLowerCase();

// Types audio
switch (lowerContentType) {
// Types audio
case "audio/mpeg":
case "audio/mp3":
return "mp3";
Expand All @@ -433,8 +675,40 @@ private static String getExtensionFromContentType(String contentType) {
return "m4a";
case "audio/ogg":
return "ogg";

// Types vidéo
case "video/mp4":
return "mp4";
case "video/mpeg":
return "mpg";
case "video/x-ms-wmv":
return "wmv";
case "video/quicktime":
return "mov";
case "video/x-matroska":
return "mkv";
case "video/webm":
return "webm";
case "video/x-flv":
return "flv";
case "video/3gpp":
return "3gp";
case "video/avi":
case "video/x-msvideo":
return "avi";

default:
return null;
// Déterminer le type de média par préfixe
if (lowerContentType.startsWith("audio/")) {
System.out.println("Type audio non reconnu: " + contentType + ", utilisation de .mp3 par défaut");
return "mp3";
} else if (lowerContentType.startsWith("video/")) {
System.out.println("Type vidéo non reconnu: " + contentType + ", utilisation de .mp4 par défaut");
return "mp4";
} else {
System.out.println("Type de média non reconnu: " + contentType);
return null; // Retourner null pour les types non reconnus
}
}
}
}
Loading

0 comments on commit 61f127c

Please sign in to comment.