images_typo.php 17,90 Kio
<?php
/**
* SPIP, Système de publication pour l'internet
*
* Copyright © avec tendresse depuis 2001
* Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James
*
* Ce programme est un logiciel libre distribué sous licence GNU/GPL.
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
// librairie de base du core
include_spip('inc/filtres_images_mini');
// Image typographique
// Fonctions pour l'arabe
function rtl_mb_ord($char) {
if (($c = ord($char)) < 216) {
return $c;
}
return 256 * rtl_mb_ord(substr($char, 0, -1)) + ord(substr($char, -1));
/* return (strlen($char) < 2) ?
ord($char) : 256 * mb_ord(substr($char, 0, -1))
+ ord(substr($char, -1));
*/
}
function rtl_reverse($mot, $rtl_global) {
$res = null;
$rtl_prec = $rtl_global;
$ponctuations = ['/', '-', '«', '»', '“', '”', ',', '.', ' ', ':', ';', '(', ')', '،', '؟', '?', '!', ' '];
foreach ($ponctuations as $ponct) {
$ponctuation[$ponct] = true;
}
for ($i = 0; $i < spip_strlen($mot); $i++) {
$lettre = spip_substr($mot, $i, 1);
$code = rtl_mb_ord($lettre);
# echo "<li>$lettre - $code";
if (($code >= 54928 && $code <= 56767) || ($code >= 15_707_294 && $code <= 15_711_164)) {
$rtl = true;
} else {
$rtl = false;
}
if (
$lettre == '٠' || $lettre == '١' || $lettre == '٢' || $lettre == '٣' || $lettre == '٤' || $lettre == '٥'
|| $lettre == '٦' || $lettre == '٧' || $lettre == '٨' || $lettre == '٩'
) {
$rtl = false;
}
if ($ponctuation[$lettre]) {
# le truc mega casse-gueule de l'inversion unicode:
# traiter le sens de placement en fonction de la lettre precedente
# (et non automatiquement le rtl_global)
$rtl = $rtl_prec;
if ($rtl) {
switch ($lettre) {
case '(':
$lettre = ')';
break;
case ')':
$lettre = '(';
break;
case '«':
$lettre = '»';
break;
case '»':
$lettre = '«';
break;
case '“':
$lettre = '”';
break;
case '”':
$lettre = '“';
break;
}
}
}
if ($rtl) {
$res = $lettre . $res;
} else {
$res = $res . $lettre;
}
$rtl_prec = $rtl;
}
return $res;
}
function rtl_visuel($texte, $rtl_global) {
// hebreu + arabe: 54928 => 56767
// hebreu + presentation A: 15707294 => 15710140
// arabe presentation: 15708336 => 15711164
# echo hexdec("efb7bc");
// premiere passe pour determiner s'il y a du rtl
// de facon a placer ponctuation et mettre les mots dans l'ordre
$arabic_letters = [
[
'ي', // lettre 0
'ﻱ', // isolee 1
'ﻳ', // debut 2
'ﻴ', // milieu 3
'ﻲ',
],
[
'ب', // lettre 0
'ﺏ', // isolee 1
'ﺑ', // debut 2
'ﺒ', // milieu 3
'ﺐ',
],
[
'ا', // lettre 0
'ا', // isolee 1
'ﺍ', // debut 2
'ﺍ', // milieu 3
'ﺎ',
],
[
'إ', // lettre 0
'إ', // isolee 1
'إ', // debut 2
'ﺈ', // milieu 3
'ﺈ',
],
[
'ل', // lettre 0
'ﻝ', // isolee 1
'ﻟ', // debut 2
'ﻠ', // milieu 3
'ﻞ',
],
[
'خ', // lettre 0
'ﺥ', // isolee 1
'ﺧ', // debut 2
'ﺨ', // milieu 3
'ﺦ',
],
[
'ج', // lettre 0
'ﺝ', // isolee 1
'ﺟ', // debut 2
'ﺠ', // milieu 3
'ﺞ',
],
[
'س', // lettre 0
'ﺱ', // isolee 1
'ﺳ', // debut 2
'ﺴ', // milieu 3
'ﺲ',
],
[
'ن', // lettre 0
'ﻥ', // isolee 1
'ﻧ', // debut 2
'ﻨ', // milieu 3
'ﻦ',
],
[
'ش', // lettre 0
'ﺵ', // isolee 1
'ﺷ', // debut 2
'ﺸ', // milieu 3
'ﺶ',
],
[
'ق', // lettre 0
'ﻕ', // isolee 1
'ﻗ', // debut 2
'ﻘ', // milieu 3
'ﻖ',
],
[
'ح', // lettre 0
'ﺡ', // isolee 1
'ﺣ', // debut 2
'ﺤ', // milieu 3
'ﺢ',
],
[
'م', // lettre 0
'ﻡ', // isolee 1
'ﻣ', // debut 2
'ﻤ', // milieu 3
'ﻢ',
],
[
'ر', // lettre 0
'ر', // isolee 1
'ﺭ', // debut 2
'ﺮ', // milieu 3
'ﺮ',
],
[
'ع', // lettre 0
'ع', // isolee 1
'ﻋ', // debut 2
'ﻌ', // milieu 3
'ﻊ',
],
[
'و', // lettre 0
'و', // isolee 1
'ﻭ', // debut 2
'ﻮ', // milieu 3
'ﻮ',
],
[
'ة', // lettre 0
'ة', // isolee 1
'ة', // debut 2
'ﺔ', // milieu 3
'ﺔ',
],
[
'ف', // lettre 0
'ﻑ', // isolee 1
'ﻓ', // debut 2
'ﻔ', // milieu 3
'ﻒ',
],
[
'ﻻ', // lettre 0
'ﻻ', // isolee 1
'ﻻ', // debut 2
'ﻼ', // milieu 3
'ﻼ',
],
[
'ح', // lettre 0
'ﺡ', // isolee 1
'ﺣ', // debut 2
'ﺤ', // milieu 3
'ﺢ',
],
[
'ت', // lettre 0
'ﺕ', // isolee 1
'ﺗ', // debut 2
'ﺘ', // milieu 3
'ﺖ',
],
[
'ض', // lettre 0
'ﺽ', // isolee 1
'ﺿ', // debut 2
'ﻀ', // milieu 3
'ﺾ',
],
[
'ك', // lettre 0
'ك', // isolee 1
'ﻛ', // debut 2
'ﻜ', // milieu 3
'ﻚ',
],
[
'ه', // lettre 0
'ﻩ', // isolee 1
'ﻫ', // debut 2
'ﻬ', // milieu 3
'ﻪ',
],
[
'ي', // lettre 0
'ي', // isolee 1
'ﻳ', // debut 2
'ﻴ', // milieu 3
'ﻲ',
],
[
'ئ', // lettre 0
'ﺉ', // isolee 1
'ﺋ', // debut 2
'ﺌ', // milieu 3
'ﺊ',
],
[
'ص', // lettre 0
'ﺹ', // isolee 1
'ﺻ', // debut 2
'ﺼ', // milieu 3
'ﺺ',
],
[
'ث', // lettre 0
'ﺙ', // isolee 1
'ﺛ', // debut 2
'ﺜ', // milieu 3
'ﺚ',
],
[
'ﻷ', // lettre 0
'ﻷ', // isolee 1
'ﻷ', // debut 2
'ﻸ', // milieu 3
'ﻸ',
],
[
'د', // lettre 0
'ﺩ', // isolee 1
'ﺩ', // debut 2
'ﺪ', // milieu 3
'ﺪ',
],
[
'ذ', // lettre 0
'ﺫ', // isolee 1
'ﺫ', // debut 2
'ﺬ', // milieu 3
'ﺬ',
],
[
'ط', // lettre 0
'ﻁ', // isolee 1
'ﻃ', // debut 2
'ﻄ', // milieu 3
'ﻂ',
],
[
'آ', // lettre 0
'آ', // isolee 1
'آ', // debut 2
'ﺂ', // milieu 3
'ﺂ',
],
[
'أ', // lettre 0
'أ', // isolee 1
'أ', // debut 2
'ﺄ', // milieu 3
'ﺄ',
],
[
'ؤ', // lettre 0
'ؤ', // isolee 1
'ؤ', // debut 2
'ﺆ', // milieu 3
'ﺆ',
],
[
'ز', // lettre 0
'ز', // isolee 1
'ز', // debut 2
'ﺰ', // milieu 3
'ﺰ',
],
[
'ظ', // lettre 0
'ظ', // isolee 1
'ﻇ', // debut 2
'ﻈ', // milieu 3
'ﻆ',
],
[
'غ', // lettre 0
'غ', // isolee 1
'ﻏ', // debut 2
'ﻐ', // milieu 3
'ﻎ',
],
[
'ى', // lettre 0
'ى', // isolee 1
'ﯨ', // debut 2
'ﯩ', // milieu 3
'ﻰ',
],
[
'پ', // lettre 0
'پ', // isolee 1
'ﭘ', // debut 2
'ﭙ', // milieu 3
'ﭗ',
],
[
'چ', // lettre 0
'چ', // isolee 1
'ﭼ', // debut 2
'ﭽ', // milieu 3
'ﭻ',
],
];
if (init_mb_string() and mb_regex_encoding() !== 'UTF-8') {
echo 'Attention: dans php.ini, il faut indiquer:<br /><strong>mbstring.internal_encoding = UTF-8</strong>';
}
$texte = explode(' ', $texte);
foreach ($texte as $mot) {
$res = '';
// Inserer des indicateurs de debut/fin
$mot = '^' . $mot . '^';
$mot = preg_replace(', ,u', ' ', $mot);
$mot = preg_replace(',«,u', '«', $mot);
$mot = preg_replace(',»,u', '»', $mot);
// ponctuations
$ponctuations = ['/', '-', '«', '»', '“', '”', ',', '.', ' ', ':', ';', '(', ')', '،', '؟', '?', '!', ' '];
foreach ($ponctuations as $ponct) {
$mot = str_replace("$ponct", "^$ponct^", $mot);
}
// lettres forcant coupure
$mot = preg_replace(',ا,u', 'ا^', $mot);
$mot = preg_replace(',د,u', 'د^', $mot);
$mot = preg_replace(',أ,u', 'أ^', $mot);
$mot = preg_replace(',إ,u', 'إ^', $mot);
$mot = preg_replace(',أ,u', 'أ^', $mot);
$mot = preg_replace(',ر,u', 'ر^', $mot);
$mot = preg_replace(',ذ,u', 'ذ^', $mot);
$mot = preg_replace(',ز,u', 'ز^', $mot);
$mot = preg_replace(',و,u', 'و^', $mot);
$mot = preg_replace(',و,u', 'و^', $mot);
$mot = preg_replace(',ؤ,u', 'ؤ^', $mot);
$mot = preg_replace(',ة,u', 'ة^', $mot);
// $mot = preg_replace(",ل,u", "^ل", $mot);
// $mot = preg_replace(",,", "^", $mot);
$mot = preg_replace(',٠,u', '^٠^', $mot);
$mot = preg_replace(',١,u', '^١^', $mot);
$mot = preg_replace(',٢,u', '^٢^', $mot);
$mot = preg_replace(',٣,u', '^٣^', $mot);
$mot = preg_replace(',٤,u', '^٤^', $mot);
$mot = preg_replace(',٥,u', '^٥^', $mot);
$mot = preg_replace(',٦,u', '^٦^', $mot);
$mot = preg_replace(',٧,u', '^٧^', $mot);
$mot = preg_replace(',٨,u', '^٨^', $mot);
$mot = preg_replace(',٩,u', '^٩^', $mot);
// Ligatures
$mot = preg_replace(',لا,u', 'ﻻ', $mot);
$mot = preg_replace(',لأ,u', 'ﻷ', $mot);
foreach ($arabic_letters as $a_l) {
$mot = preg_replace(',([^\^])' . $a_l[0] . '([^\^]),u', '\\1' . $a_l[3] . '\\2', $mot);
$mot = preg_replace(',\^' . $a_l[0] . '([^\^]),u', '^' . $a_l[2] . '\\1', $mot);
$mot = preg_replace(',([^\^])' . $a_l[0] . '\^,u', '\\1' . $a_l[4] . '^', $mot);
// il semble qu'il ne soit pas necessaire de remplacer
// la lettre isolee
// $mot = preg_replace(",\^".$a_l[0]."\^,u", "^".$a_l[1]."^", $mot);
}
$mot = preg_replace(',\^,u', '', $mot);
$res = $mot;
$res = rtl_reverse($mot, $rtl_global);
/*
$rtl = false;
for ($i = 0; $i < spip_strlen($mot); $i++) {
$lettre = spip_substr($mot, $i, 1);
$code = rtl_mb_ord($lettre);
if (($code >= 54928 && $code <= 56767) || ($code >= 15708336 && $code <= 15711164)) $rtl = true;
}
*/
if ($rtl_global) {
$retour = $res . ' ' . $retour;
} else {
$retour = $retour . ' ' . $res;
}
}
return $retour;
}
function printWordWrapped(
$image,
$top,
$left,
$maxWidth,
$font,
$couleur,
$text,
$textSize,
$align = 'left',
$hauteur_ligne = 0
) {
$line = null;
$retour = [];
static $memps = [];
$fontps = false;
// Normalisation du chemin de la police en chemin absolu (pour Windows cf https://bugs.php.net/bug.php?id=75656)
$font = realpath($font);
// imageftbbox exige un float, et settype aime le double pour php < 4.2.0
settype($textSize, 'double');
// calculer les couleurs ici, car fonctionnement different selon TTF ou PS
$black = imagecolorallocatealpha(
$image,
hexdec(substr($couleur, 0, 2)),
hexdec(substr($couleur, 2, 2)),
hexdec(substr($couleur, 4, 2)),
0
);
$grey2 = imagecolorallocatealpha(
$image,
hexdec(substr($couleur, 0, 2)),
hexdec(substr($couleur, 2, 2)),
hexdec(substr($couleur, 4, 2)),
127
);
$rtl_global = false;
for ($i = 0; $i < spip_strlen($text); $i++) {
$lettre = spip_substr($text, $i, 1);
$code = rtl_mb_ord($lettre);
if (($code >= 54928 && $code <= 56767) || ($code >= 15_707_294 && $code <= 15_711_164)) {
$rtl_global = true;
}
}
// split the text into an array of single words
$words = explode(' ', $text);
// les espaces
foreach ($words as $k => $v) {
$words[$k] = str_replace(['~'], [' '], $v);
}
if ($hauteur_ligne == 0) {
$lineHeight = floor($textSize * 1.3);
} else {
$lineHeight = $hauteur_ligne;
}
$dimensions_espace = imageftbbox($textSize, 0, $font, ' ', []);
if ($dimensions_espace[2] < 0) {
$dimensions_espace = imageftbbox($textSize, 0, $font, $line, []);
}
$largeur_espace = $dimensions_espace[2] - $dimensions_espace[0];
$retour['espace'] = $largeur_espace;
$line = '';
$lines = [];
while (count($words) > 0) {
$mot = $words[0];
if ($rtl_global) {
$mot = rtl_visuel($mot, $rtl_global);
}
$dimensions = imageftbbox($textSize, 0, $font, $line . ' ' . $mot, []);
$lineWidth = $dimensions[2] - $dimensions[0]; // get the length of this line, if the word is to be included
if ($lineWidth > $maxWidth) { // if this makes the text wider that anticipated
$lines[] = $line; // add the line to the others
$line = ''; // empty it (the word will be added outside the loop)
}
$line .= ' ' . $words[0]; // add the word to the current sentence
$words = array_slice($words, 1); // remove the word from the array
}
if ($line != '') {
$lines[] = $line;
} // add the last line to the others, if it isn't empty
$height = count($lines) * $lineHeight; // the height of all the lines total
// do the actual printing
$i = 0;
// Deux passes pour recuperer, d'abord, largeur_ligne
// necessaire pour alignement right et center
$largeur_max = 0;
foreach ($lines as $line) {
if ($rtl_global) {
$line = rtl_visuel($line, $rtl_global);
}
$dimensions = imageftbbox($textSize, 0, $font, $line, []);
$largeur_ligne = $dimensions[2] - $dimensions[0];
if ($largeur_ligne > $largeur_max) {
$largeur_max = $largeur_ligne;
}
}
foreach ($lines as $i => $line) {
if ($rtl_global) {
$line = rtl_visuel($line, $rtl_global);
}
$dimensions = imageftbbox($textSize, 0, $font, $line, []);
$largeur_ligne = $dimensions[2] - $dimensions[0];
if ($align == 'right') {
$left_pos = $largeur_max - $largeur_ligne;
} else {
if ($align == 'center') {
$left_pos = floor(($largeur_max - $largeur_ligne) / 2);
} else {
$left_pos = 0;
}
}
imagefttext($image, $textSize, 0, $left + $left_pos, $top + $lineHeight * $i, $black, $font, trim($line), []);
}
$retour['height'] = $height; # + round(0.3 * $hauteur_ligne);
$retour['width'] = $largeur_max;
return $retour;
}
//array imagefttext ( resource image, float size, float angle, int x, int y, int col, string font_file, string text [, array extrainfo] )
//array imagettftext ( resource image, float size, float angle, int x, int y, int color, string fontfile, string text )
function produire_image_typo() {
/*
arguments autorises:
$texte : le texte a transformer; attention: c'est toujours le premier argument, et c'est automatique dans les filtres
$couleur : la couleur du texte dans l'image - pas de dieze
$police: nom du fichier de la police (inclure terminaison)
$largeur: la largeur maximale de l'image ; attention, l'image retournee a une largeur inferieure, selon les limites reelles du texte
$hauteur_ligne: la hauteur de chaque ligne de texte si texte sur plusieurs lignes
(equivalent a "line-height")
$padding: forcer de l'espace autour du placement du texte; necessaire pour polices a la con qui "depassent" beaucoup de leur boite
$align: alignement left, right, center
*/
/**
* On définit les variables par défaut
*/
$variables_defaut = [
'align' => false,
'police' => '',
'largeur' => 0,
'hauteur_ligne' => 0,
'padding' => 0,
];
$variable = [];
// Recuperer les differents arguments
$variable = [];
$numargs = func_num_args();
$arg_list = func_get_args();
$texte = $arg_list[0];
for ($i = 1; $i < $numargs; $i++) {
if (($p = strpos($arg_list[$i], '=')) !== false) {
$nom_variable = substr($arg_list[$i], 0, $p);
$val_variable = substr($arg_list[$i], $p + 1);
$variable["$nom_variable"] = $val_variable;
}
}
$variable = [...$variables_defaut, ...$variable];
// Construire requete et nom fichier
$text = str_replace(' ', '~', $texte);
$text = preg_replace(",(\r|\n)+,ms", ' ', $text);
include_spip('inc/charsets');
$text = html2unicode(strip_tags($text));
if (strlen($text) == 0) {
return '';
}
$taille = $variable['taille'];
if ($taille < 1) {
$taille = 16;
}
if (isset($variable['couleur'])) {
$couleur = couleur_html_to_hex($variable['couleur']);
} else {
$couleur = '';
}
if (strlen($couleur) < 6) {
$couleur = '000000';
}
$alt = $texte;
$align = $variable['align'];
if (!$variable['align']) {
$align = 'left';
}
$police = $variable['police'];
if (strlen($police) < 2) {
$police = 'dustismo.ttf';
}
$largeur = $variable['largeur'];
if ($largeur < 5) {
$largeur = 600;
}
if ($variable['hauteur_ligne'] > 0) {
$hauteur_ligne = $variable['hauteur_ligne'];
} else {
$hauteur_ligne = 0;
}
if ($variable['padding'] > 0) {
$padding = $variable['padding'];
} else {
$padding = 0;
}
// Normalisation de la couleur pour ne pas produire 2 hash différents pour le nom du fichier cache
$string = "$text-$taille-" . strtoupper($couleur) . "-$align-$police-$largeur-$hauteur_ligne-$padding";
$query = md5($string);
$dossier = sous_repertoire(_DIR_VAR, 'cache-texte');
$fichier = "$dossier$query.png";
$flag_gd_typo = function_exists('imageftbbox')
&& function_exists('imageCreateTrueColor');
if (@file_exists($fichier)) {
$image = $fichier;
} else {
if (!$flag_gd_typo) {
return $texte;
}
$font = find_in_path('polices/' . $police);
if (!$font) {
spip_log(_T('fichier_introuvable', ['fichier' => $police]));
$font = find_in_path('polices/' . 'dustismo.ttf');
}
// Normalisation du chemin de la police en chemin absolu (pour Windows cf https://bugs.php.net/bug.php?id=75656)
$font = realpath($font);
$imgbidon = imageCreateTrueColor($largeur, 45);
$retour = printWordWrapped(
$imgbidon,
$taille + 5,
0,
$largeur,
$font,
$couleur,
$text,
$taille,
'left',
$hauteur_ligne
);
$hauteur = $retour['height'];
$largeur_reelle = $retour['width'];
$espace = $retour['espace'];
imagedestroy($imgbidon);
$im = imageCreateTrueColor($largeur_reelle - $espace + (2 * $padding), $hauteur + 5 + (2 * $padding));
imagealphablending($im, false);
imagesavealpha($im, true);
// Creation de quelques couleurs
$grey2 = imagecolorallocatealpha(
$im,
hexdec(substr($couleur, 0, 2)),
hexdec(substr($couleur, 2, 2)),
hexdec(substr($couleur, 4, 2)),
127
);
ImageFilledRectangle($im, 0, 0, $largeur_reelle + (2 * $padding), $hauteur + 5 + (2 * $padding), $grey2);
// Le texte a dessiner
printWordWrapped(
$im,
$taille + 5 + $padding,
$padding,
$largeur,
$font,
$couleur,
$text,
$taille,
$align,
$hauteur_ligne
);
// Utiliser imagepng() donnera un texte plus claire,
// compare a l'utilisation de la fonction imagejpeg()
_image_gd_output($im, ['fichier_dest' => $fichier, 'format_dest' => 'png']);
imagedestroy($im);
$image = $fichier;
}
$dimensions = spip_getimagesize($image);
$largeur = $dimensions[0];
$hauteur = $dimensions[1];
return inserer_attribut(
"<img src='$image' width='$largeur' height='$hauteur' style='width:" . $largeur . 'px;height:' . $hauteur . "px;' />",
'alt',
$alt
);
}