open("$tmp/cv.docx", ZipArchive::CREATE); $zip->addFromString('word/document.xml', ''); $zip->addFromString('word/media/image1.png', logo(400, 400)); $zip->addFromString('word/media/image2.jpeg', portrait(600, 760)); $zip->addFromString('word/media/image3.jpeg', portrait(900, 120)); $zip->addFromString('word/media/image4.png', portrait(40, 50, 'png')); $zip->close(); [$l, $h, $type] = dimensions(Photo::extraire("$tmp/cv.docx", 'docx')); verifier('Word : le portrait est retenu, pas le logo ni le bandeau', $type === IMAGETYPE_JPEG && abs($l / max($h, 1) - 600 / 760) < 0.02); verifier('Word : photo réduite à 480 px au plus', max($l, $h) === 480); $zip = new ZipArchive(); $zip->open("$tmp/sans.docx", ZipArchive::CREATE); $zip->addFromString('word/document.xml', ''); $zip->addFromString('word/media/image1.png', logo(400, 400)); $zip->close(); verifier('Word sans photo : rien n\'est retenu', Photo::extraire("$tmp/sans.docx", 'docx') === null); // --- PDF : image JPEG $jpeg = portrait(300, 380); $pdf = "%PDF-1.4\n1 0 obj\n<< /Type /XObject /Subtype /Image /Width 300 /Height 380 /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length " . strlen($jpeg) . " >>\nstream\n" . $jpeg . "\nendstream\nendobj\n%%EOF"; file_put_contents("$tmp/jpeg.pdf", $pdf); [$l, $h] = dimensions(Photo::extraire("$tmp/jpeg.pdf", 'pdf')); verifier('PDF : image JPEG retrouvée', $l === 300 && $h === 380); // --- PDF : image compressée sans perte, avec et sans prédicteur $img = imagecreatefromstring(portrait(200, 240)); $brut = ''; $filtre = ''; for ($y = 0; $y < 240; $y++) { $ligne = ''; for ($x = 0; $x < 200; $x++) { $c = imagecolorat($img, $x, $y); $ligne .= chr(($c >> 16) & 255) . chr(($c >> 8) & 255) . chr($c & 255); } $brut .= $ligne; $filtre .= "\0" . $ligne; } $objet = static fn (string $donnees, string $plus = ''): string => "%PDF-1.4\n4 0 obj\n<< /Subtype /Image /Width 200 /Height 240 /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /FlateDecode $plus/Length 9 0 R >>\nstream\r\n" . $donnees . "\r\nendstream\nendobj\n%%EOF"; file_put_contents("$tmp/flate.pdf", $objet(gzcompress($brut))); [$l, $h] = dimensions(Photo::extraire("$tmp/flate.pdf", 'pdf')); verifier('PDF : image sans perte retrouvée, longueur indirecte', $l === 200 && $h === 240); file_put_contents("$tmp/predicteur.pdf", $objet(gzcompress($filtre), '/DecodeParms << /Predictor 15 /Colors 3 /Columns 200 >> ')); [$l, $h] = dimensions(Photo::extraire("$tmp/predicteur.pdf", 'pdf')); verifier('PDF : image sans perte avec prédicteur retrouvée', $l === 200 && $h === 240); file_put_contents("$tmp/texte.pdf", "%PDF-1.4\n1 0 obj\n<< /Length 20 >>\nstream\nBT (Bonjour) Tj ET\nendstream\nendobj\n%%EOF"); verifier('PDF sans image : rien n\'est retenu', Photo::extraire("$tmp/texte.pdf", 'pdf') === null); file_put_contents("$tmp/casse.pdf", "%PDF-1.4 << /Subtype /Image /Width 300 /Height 300 /Filter /DCTDecode >> stream\nceci n'est pas une image"); verifier('PDF endommagé : aucune erreur', Photo::extraire("$tmp/casse.pdf", 'pdf') === null); verifier('format sans image (txt) : rien', Photo::extraire(__FILE__, 'txt') === null); // --- Normalisation [$l, $h, $type] = dimensions(Photo::normaliser(portrait(1200, 800, 'png'))); verifier('chargement manuel : PNG converti en JPEG réduit', $type === IMAGETYPE_JPEG && $l === 480 && $h === 320); verifier('fichier qui n\'est pas une image : refusé', Photo::normaliser(' 0 ? 1 : 0);