El otro día estaba haciendo un captcha para la página con las primitivas de dibujado de imágenes de PHP y al final me decidí por lo más lógico para que me sirva para un futuro: hacer una clase Image en PHP con todas las primitivas y hacer una clase CaptchaImage que herede de la clase Image.
De momento no voy a poner aquí el código porque está sin terminar, pero vamos, es tan sencillo como hacer una clase en PHP que tenga las funciones de dibujar dentro de ella y que sepa cargar imágenes desde archivos.
El problema me surgió cuando intenté posicionar texto de fuentes True Type rotado con un ángulo determinado, ya que al rotar dicho texto, las posiciones de X e Y así como el ancho y algo del contenido cambian.
Para esto, PHP tiene una función que se llama imagettfbbox(...) que dado un texto, el tamaño, el ángulo y la fuente, devuelve un array con las posiciones de todos sus puntos, es decir, las coordenadas (x,y) de las 4 posiciones de color azul que se muestran en la imagen:
Pero para poder posicionar ese texto dentro de la imagen, lo que necesitamos saber son las posiciones de los puntos naranjas. O, mejor aún, el ancho y el alto del cuadrado naranja y ya daremos nosotros la posición de la izquierda y de arriba para posicionar la caja completa.
Hay que tener en cuenta que las coordenadas que devuelve la función de PHP siempre se refieren a la caja de texto como si este estuviese horizontal, es decir, si rotamos el texto 180 grados, las coordenadas (6,7), por ejemplo, seguirían siendo la posición superior izquierda aunque visualmente estuviesen en la posición inferior derecha.
Mirando en la documentación de la función en cuestión, hay varias personas que han puesto sus funciones de posicionado, (bastante complicadas, por cierto). Pero las he probado y no van bien, sobre todo con texto rotado, que al fin y al cabo, es la cuestión de la función, así que me hice la mía:
function calculateTextBox($text,$fontFile,$fontSize,$fontAngle) {
$rect = imagettfbbox($fontSize,$fontAngle,$fontFile,$text);
$minX = min(array($rect[0],$rect[2],$rect[4],$rect[6]));
$maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6]));
$minY = min(array($rect[1],$rect[3],$rect[5],$rect[7]));
$maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7]));
return array(
“left” => abs($minX),
“top” => abs($minY),
“width” => $maxX – $minX,
“height” => $maxY – $minY,
“box” => $rect
);
}
$mystring = “Hello world!”;
$imgWidth = 300;
$imgHeight = 150;
$angle = 40;
$image = imagecreate($imgWidth,$imgHeight);
imagefill($image,0,0,imagecolorallocate($image,200,200,200));
$box = calculateTextBox($mystring,“./Verdana.ttf”,15,$angle);
$color = imagecolorallocate($image,0,0,0);
imagettftext($image,
15,
$angle,
$box["left"] + ($imgWidth / 2) – ($box["width"] / 2),
$box["top"] + ($imgHeight / 2) – ($box["height"] / 2),
$color,
“./Verdana.ttf”,
$mystring);
header(“Content-Type: image/x-png”);
imagepng($image);
imagedestroy($image);
La función calculateTextBox(...) calcula la caja real donde encaja el texto dado, con su alto y ancho además de las posiciones de izquierda y derecha (necesarias para un correcto posicionamiento).
Luego ya sólo es necesario crear una imagen y dibujar el texto centrado sabiendo lo que ocupa.
Yo esto lo tengo dentro de un par de clases de PHP que me solucionan bastante los problemas. En cuanto estén listas las pongo por aquí por si a alguien les sirven de ayuda.






No es por malmeter, pero… si asumimos que una buena práctica de programación consiste en no reinventar la rueda constantemente, ¿por qué existiendo esto http://framework.zend.com/manual/en/zend.captcha.html, querrías hacer todo este trabajo para implementar un captcha? Un saludo
Pues principalmente por aprender a hacerlo. Y sí, hay multitud de cosas hechas que puedes hacer, pero cuando no te gusta ninguna porque eres un tiquismiquis pues te haces la tuya propia, como muuuuuucha gente, ¿sino por qué tantos lenguajes de programación distintos, por ejemplo?