¿Como usar la libreria GD? [PHP]

Iniciado por Castg!, 1 Marzo 2010, 04:42 AM

0 Miembros y 1 Visitante están viendo este tema.

Castg!

Hola, con esta guía voy a tratar de explicarles como trabajar con las funciones más utilizadas de la librería GD para obtener unas atractivas imagenes dinamicas.

Para entender perfectamente esta librería, les viene muy bien leer los siguientes apuntes (si no lo tienen muy claro):


También, estas funciones otorgan las propiedades de la imagen:

Código (php) [Seleccionar]
imagesx($im); //devuelve el ancho de la imagen
imagesy($im); //devuelve el alto de la imagen
getimagesize($direccion);


La función getimagesize devuelve un array con los datos de la imagen. Por ejemplo, aplicándolo a la imagen http://blog.nuestroclima.com/wp-content/uploads/2007/08/imagen_satelital_hires.jpg devuelve:
Array
(
   [0] => 4096       Ancho
   [1] => 4096       Altura
   [2] => 2
   [3] => width="4096" height="4096"
   [bits] => 8
   [channels] => 3
   [mime] => image/jpeg
)

Para descargar fuentes, aca en el foro hay una buena recopilación.


Perfecto, empecemos. Para crear una imagen se utilizan estos siguientes:

Para crear desde un archivo sea en tu servidor o en uno externo:
Código (php) [Seleccionar]
$im = imagecreatefrompng("dirección"); //para imágenes png
$im = imagecreatefromgif("dirección"); //para imagenes gif
$im = imagecreatefromjpeg("dirección"); //para imagenes jpg y jpeg

Si se carga una imagen con transparencias, para conservarlas, hace falta agregar estas dos lineas despues de crearla.
Código (php) [Seleccionar]
imagealphablending($im, true);
imagesavealpha($im, true);


Ahora, para crear una imagen de cero basta con las funciones:

Código (php) [Seleccionar]
$im = imagecreate($ancho, $alto);
//para imagenes con una paleta de colores,
//osea, no tan buena calidad del color.
//
//
$im = imagecreatetruecolor($ancho, $alto);
//para imagenes con un color real, esta es la más usada...

Bueno, ya utilizando estas funciones habremos creado la imagen. No se olviden que siempre se tiene que asignar el valor reslutante de esta fuincion a una nueva variable (no hace falta que sea nueva ¬¬ jajaj).




Datos a tener en cuenta:


Antes de seguir, tiene que quedarles algo claro fundamental mente, y es la visualizacion de la imagen y la DESTRUCCION de la misma. Por qué destruir? Porque sino queda guardada la imagen en la memoria RAM del servidor y eso no es muy agradable. Entonces, para visualizarla basta con agregar el header correspondiente para el tipo:
Código (php) [Seleccionar]
header("Content-type: image/".$imagenextension.);
Y para imprimir la imagen se usa el comando "image" seguido del tipo de imagen. por ejemplo para una imagen png:
Código (php) [Seleccionar]
imagepng($im);
Seguido de esta función le va:
Código (php) [Seleccionar]
imagedestroy($im);




Contenido de las imagenes:


Ahora que tenemos la imagen, vamos a darle el contenido. Para ellos se puede dibujar lineas, puntos, rectángulos (solo el borde) o rectángulos rellenos (no de dulce de leche!! ;D), así como los rectángulos, elipses y polígonos indicando cantidad de puntos y posición de los mismos. También se pueden crear colores de toda la gamma RGB con o sin transparencia. Se puede agregar texto de fuentes por defecto de la librería o fuentes del tipo "True Type", "Free  type" y "PostScript" importándolas de un enlace externo. Primeramente vamos por partes y comenzamos por el principio, los colores ;D.


Colores:


Para las creaciones de colores tenemos dos funciones y un verso sin esfuerzo.
Código (php) [Seleccionar]
$nombreDelColor = imagecolorallocate($r, $g, $b);
$nombreDelColor = imagecolorallocatealpha($r, $g, $b, $valorAlfa);




Por ejemplo podemos crear el color rojo, el amarillo y el violeta:
Código (php) [Seleccionar]
$rojo = imagecolorallocate(255, 0, 0);
$amarillo = imagecolorallocate(255, 255, 0);
$violeta = imagecolorallocate(0, 255, 255);

Y si se quiere agregar opacidad a uno de estos colores:
Código (php) [Seleccionar]
$azul = imagecolorallocate(0, 0, 255, 50); //ahí tenemos un 50% de opacidad...



Además de crear colores, se puede tomar el color de un píxel determinado de una imagen determinada con la función imagecolorat();, su sintaxis es
Código (php) [Seleccionar]
imagecolorat($im, $x, $y);
Código (php) [Seleccionar]
//por ejemplo en la imagen utilizada es una rápida que encontré por internet de un "mundo"
$im = imagecreatefromjpeg("http://www.hyparion.com/web/diccionari/dics/astronomia/imatges/tierra.jpg");
$color = imagecolorat($im, 100, 100);

Ahora, acá se nos complica un poco. La variable "color" recibe el valor de 9146518 y decimos: "Qué carajo!?". Bueno, para que ese es un valor que para nosotros trabajarlo como rgba (Red Green Blue Alpha, osea, rojo verde azul y transparencia). Para "convertirlo" a ese (rgba) o hexadecimal tenemos las posibilidades de:
Código (php) [Seleccionar]

//esto se cumple una vez realizado el proceso anterior...
//automático para rgba, el más fácil y practico de todos!
$color = imagecolorsforindex($im, $color);
/*este devuelve un array con los valores:
Array
(
   [red] => 255
   [green] => 0
   [blue] => 0
   [alpha] => 0
)
*/
//
//
//este es simple, se le da un formato y devuelve el valor del color en hexadecimal.
$hex = sprintf("%06X", $color); //devuelve FF0000
//
//
//manualmente para rgba, el más complicado de entender y es lo
//mismo que la función imagecolorsforindex() pero igualmente se los explico...
$colores = array();
$colores['red'] = ($color >> 16) & 0xFF;
$colores['green'] = ($color >> 8) & 0xFF;
$colores['blue'] = $color & 0xFF;
$colores['alpha'] = ($color >> 24) & 0xFF;

Ahora paso a explicar esas cosas raras que nos da php.net sin decirnos que es ¬¬.
Los caracteres ">>" cumplen el rol de operador y recibe el nombre de operador bitwise. Lo que hace este operador es correr determinadas veces la posición del valor indicado en binario. Osea, la variable $color toma un píxel de color rojo puro (a puro me refiero a rgb(255,0,0)) el valor retornado va a ser igual a: 16711680 :o mientras que el valor en rgb es 255. Entonces, diciéndole que me corra 16 lugares los bits de 16711680 me va a dar como resultado un numero decimal igual a 255. Ahora, si no colocamos el 0xFF en el valor del rojo, nos damos cuenta que no hay diferencia, pero cuando tratamos valores rgba, el 0xFF delimita la cantidad de bits para cada valor. Es como decir, para cada valor (rgb) corresponden 8 bits (por eso siempre los corremos para que queden los 8 primeros bits) en cambio, para el valor de alpha le corresponden solo 7 bits, pero como lo corremos 24 lugares quedando solo 7 bits (es como un substring a una cadena de 7 caracteres, aunque le indiques 8, siempre devuelve 7). Se entendió esto? Bueno, sigamos que apenas vamos por los colores!!!

Fondo:

Una cosa muy molesta de la libreria gd, es el color de fondo que por defecto lo pone negro. para eso esta la funcion imagefill() que rellena la imagen desde donde se le indique con el color establecido. Su sintaxis es:
Código (php) [Seleccionar]
imagefill($im, $x, $y, $color)
Para que rellene por completo la imagen, los valores de $x,$y son igual a 0,0.




Trazados:

Puntos:


Ahora que tenemos los colores, vamos a dibujar. Primero vamos a empezar por un punto, que aunque sea de solo un píxel, es muy útil como para un ejemplo, un captcha. No hace falta demásiada explicación, dibuja un píxel en x,y del color $color
Código (php) [Seleccionar]
imagesetpixel($im, $x, $y, $color); //$color es igual a el resultado de la función imagecolorallocate()

Líneas:

Para poder dibujar una linea, se indica el x,y de inicio y el x,y de final:
Código (php) [Seleccionar]
imageline($im, $xInicio, $yInicio, $xFin, $yFin, $color);
Por ejemplo si $im es una imagen de color real de 100x100 y con fondo blanco (ya va a llegar esa parte) podría realizar esto:



Con esto:
Código (php) [Seleccionar]
$im = imagecreatetruecolor(100, 100);
$color = imagecolorallocate($im, 0,0,0);
imageline($im, 10, 35, 76, 85, $color);





Poligonos, rectángulos y elipses:[/b]

Una vez entendido esto! nos vamos con los polígonos, primero lo primero! el rectángulo
para dibujar un rectángulo se puede dibujar solo su contorno (el borde va a medir 1px) o el rectángulo relleno de color (filled).
Sinceramente la sintaxis es idéntica a la de imageline además, son iguales entre si, solo el borde, o relleno.
Código (php) [Seleccionar]
imagefilledrectangle($im, $xInicio, $yInicio, $xFin, $yFin, $color);
imagerectangle($im, $xInicio, $yInicio, $xFin, $yFin, $color);

Para el elipse, circulo u ovalo (cambia según los valores dados), al igual que el rectángulo y el polígono que lo vamos a ver posteriormente, se puede solo el borde o relleno. su sintaxis es:
Código (php) [Seleccionar]
imageellipse($im, $centroX, $centroY, $ancho, $altura, $color);
imagefilledellipse($im, $centroX, $centroY, $ancho, $altura, $color);

Donde $centroX,Y son la posición del punto medio del elipse.
Bueno, para el polígono, se complica otra vez un poco. En la sintaxis del polígono:
Código (php) [Seleccionar]
imagepolygon($im, $puntosArray, $cantidadPuntos, $color);
imagefilledpolygon($im, $puntosArray, $cantidadPuntos, $color);

La variable $puntosArray es un array, porque no le puse ese nombre al pedo xD jajaja. La estructura del array tiene que ser, cada dos valores corresponden a los valores x,y de un punto, osea:
Código (php) [Seleccionar]
$puntosArray= array (
/*
x  y  */
10, 10,  //punto 1
15, 26,  //punto 2
50, 36,  //punto 3
68, 10   //punto 4, este ultimo numero va sin coma al final!!
);

En realidad no es tan complicado :P. y para $cantidadPuntos, lógicamente se indica la cantidad de los puntos. pero para no contarlos, basta con un:
Código (php) [Seleccionar]
$cantidadPuntos = count($puntosArray) / 2;
Y listo. Ahora, el resultado de esta función es una imagen parecida a esta:







Agregar textos:


Ya terminamos con las formás y esas cosas. Ahora vamos por el texto. Para escribir en una imagen se puede utilizar las fuentes que trae por defecto la librería gd o fuentes del "True type", "Free type" o "PostScript Type1". La sintaxis para las postscript se ponen un poco jodidas, además, no conozco las fuentes del tipo postscript. Así que paso a explicar principalmente el imagestring(), además de escribir horizontalmente, también esta la función imagestringup() que escribe verticalmente:
Código (php) [Seleccionar]
imagestring($im, $fuente, $x, $y, $cadenaTexto, $color);
imagestringup($im, $fuente, $x, $y, $cadenaTexto, $color);

Para la variable $fuente se puede usar los números del 1 al 6. Los ejemplos serian:



Fijense como a partir del numero 5 se repite el tipo de fuente. El problema de imagestring es que tienen el tamaño de fuente fija.

Con funciones donde se indica una fuente externa, se puede indicar el ángulo del texto (ahora lo van a entender) y el tamaño de la fuente. Yo les voy a explicar nomás imagettftext y sus derivados.

Primero van a necesitar un archivo del tipo ttf y conocer su link xD, puede estar en el mismo directorio o en uno externo, pero como cualquier cosa, recomiendo que este en tu mismo servidor para que no haya problemás. Yo por ejemplo voy a usar la fuente Hemi Head la cual es utilizada por el foro.
Antes que nada, la sintaxis de esta función es:
Código (php) [Seleccionar]
$fuente = "hemihead.ttf";
imagettftext($im, $tamanio, $ángulo, $x, $y, $color, $fuente, $texto)

La variable fuente indica donde se encuentra el archivo de la fuente.
Por ejemplo este código,
Código (php) [Seleccionar]
<?php
header
("Content-type: image/png");
$im imagecreatetruecolor(100100);
$color imagecolorallocate($im255255255);
$fuente "HEMIHEAD.TTF";
imagettftext($im1501520$color$fuente"Castg!");
imagepng($im);
imagedestroy($im);
?>

Da como resultado esta imagen:



Ahora, si yo cambio el ángulo que en caso anterior es 0 por 315:
Código (php) [Seleccionar]
imagettftext($im, 15, 315, 15, 20, $color, $fuente, "Castg!");
Da como resultado:







Centrar textos:



Una gran necesidad al momento de usar textos en la librería gd, es el tema de centrar el texto. Acá es donde entra en acción la matemática. piensen, primeramente vamos a necesitar conocer el tamaño que ocupa el texto. Para una fuente utilizada  con imagestring() se utilizan las funciones:
Código (php) [Seleccionar]
imagefontheight($fuente);
imagefontwidth($fuente);

Estas funciones devuelven la altura y el ancho en píxeles respectivamente de un carácter de la fuente especificada. como devuelve las propiedades de un solo carácter (es el mismo valor para cualquier carácter) hay que multiplicar los valores obtenidos por la cantidad de caracteres implementados. Entonces podemos hacer algo así:
Código (php) [Seleccionar]
$fuente = 1;
$cantidadCaracteres = strlen($texto);
$textoAltura = imagefontheight($fuente) * $cantidadCaracteres;
$textoAncho = imagefontwidth($fuente) * $cantidadCaracteres;

Y listo!, pero eso es nomás para las fuentes por defecto, ahora si se quiere con una fuente que usamos en imagettftext, tenemos la función imagettfbbox, su sintaxis:
Código (php) [Seleccionar]
imagettfbbox($tamanio, $ángulo, $fuente, $texto);
El resultado de esta función es un array con 8 puntos:


0 esquina inferior izquierda, posición X

1 esquina inferior izquierda, posición Y

2 esquina inferior derecha, posición X

3 esquina inferior derecha, posición Y

4 esquina superior derecha, posición X

5 esquina superior derecha, posición Y

6 esquina superior izquierda, posición X

7 esquina superior izquierda, posición Y

Los datos que nosotros necesitamos son, abajo a la derecha y cumplirán el rol de x = ancho y y = altura.

Ahora que tenemos el valor que ocupa el texto tenemos que averiguar cual tiene que ser la posición del texto en la imagen. Cuando usamos una de las funciones para agregar texto, las posiciones x,y que indicamos van a ser las de arriba a la izquierda, por eso no podemos simplemente indicarle el centro de la imagen. Por eso, tenemos que restarle las medidas del texto a las medidas de la imagen. Obviamente hay que hacer ancho de la imagen - (menos) ancho del texto y alto imagen - alto texto. El resultado de estas operaciones dividido dos ( / 2) va a ser la posición x,y que le vamos a asignar al texto. Esto quedaría más o menos así:
Código (php) [Seleccionar]
<?php
header
("Content-type: image/png");
$im imagecreatetruecolor(100100);
$color imagecolorallocate($im255255255);
$fuente "HEMIHEAD.TTF";
$cajaTexto imagettfbbox(150$fuente"Castg!");
$xCentrado = (imagesx($im) - $cajaTexto[2]) / 2;
$yCentrado = (imagesy($im) - $cajaTexto[3]) / 2;
imagettftext($im150$xCentrado$yCentrado$color$fuente"Castg!");
imagepng($im);
imagedestroy($im);
?>

Entonces podemos observar que el texto quedo centrado:



Entonces terminamos con suerte la implementacion del texto en imagenes.




Redimensionar:

Una de las otras herramientas que nos da GD es la posibilidad de redimensionar y copiar imagenes.
Para redimensionar lo único que se hace es copiar una imagen a otra indicándole desde donde copiar y pegar, y que tamaño se quiere. Además, tenemos dos funciones una que redimensiona como el paint( osea como que faltan píxeles), es imagecopyresize(). Y otra que rredimensiona suavizando los valores de los píxeles. Esa función es:
Código (php) [Seleccionar]
imagecopyresampled($im_original, $im_detino, $x_destino, $y_destino, $x_original, $y_original, $ancho_destino, $alto_destino, $ancho_orginal, $alto_orginal);
Donde los x,y son desde donde se quiere copiar la imagen, y los de destino son desde donde se quiere ubicar la imagen.
Si yo tengo esta imagen:



Y quiero que mida la mitad como esto:



Tengo que hacer esto:
Código (php) [Seleccionar]
<?php
header
("Content-type: image/jpg");
$im_original imagecreatefromjpeg("http://www.foroswebgratis.com/fotos/1/3/9/3/5//595440elhacker.jpg");
$im_destino imagecreatetruecolor(imagesx($im_original) / ,imagesy($im_original) / );
$blanco imagecolorallocate($im_destino255255255);
imagefill($im_destino00$blanco);
imagecopyresampled($im_destino$im_original0000imagesx($im_destino), imagesy($im_destino), imagesx($im_original), imagesy($im_original));
imagejpeg($im_destino);
imagedestroy($im_destino);
imagedestroy($im_original);
?>

Y listo. por ultimo dejo claro que con imagecopyresize() permite copiar partes dentro de una misma imagen...




Bueno, esto les tiene que alcanzar para tener bastante claro las funciones más usadas con esta librería. Cualquier duda, error, mal entendido o cualquier cosa, comenten acá en este foro o si no quieren, me pueden mandar un mensaje personal o como ultimo recurso, mandarme un email. Mi dirección esta en el perfil (por ahora xD). espero que esto les sirva y se entienda, trate de ser lo más expresivo posible. un saludo grande a todos!

~ Yoya ~

Muy bien hecho, ya sabia que esas firmitas con Data Minnig usaban GD xD, te falto, una guiita para verificar si esta instalado o si no las formas de instalarlo en linux y en window, en linux seria mas facir porque estan en los repositorios.
Mi madre me dijo que estoy destinado a ser pobre toda la vida.
Engineering is the art of balancing the benefits and drawbacks of any approach.

Castg!

tenes razon yoya, ahora estoy haciendo funciones de ruido, saturacion, desaturacion, agregar brillo, contraste, degradados y todo eso. voy a hacer unas minilibs de CastGD! y dicho sea el paso hago eso que decis. ahora estoy ocupado pensando en los calculos del rgb. aunque sean 3 numeros, tienen toda una ciencia detras... Saludos!

cristiangq

Estoy teniendo el siguiente problema y la verdad que me esta rompiendo la cabeza.
Resulta que necesito que suban una imagen de cualquier tipo. Luego en base a esa imagen crear una nueva imagen png con fondo transparente. Lo del fondo transparente es porque solo necesito tomar un circulo interno de la imagen que subieron no necesito que la imagen sea cuadrada como la subieron. Espero que me hayan entendido

Castg!

a ver, podrias subir unas fotos de ejemplo? la de entrada y la de salida porfavor ;)

cristiangq

Aqui te muestro como deberia ser.
en un principio a travez de un formulario suben una foto como esta

y yo la tengo que guardar en el servidor asi


Espero que puedas ayudarme :)

Castg!

una medida exacta del circulo, o dinamico? se ve dificil dinamico, pero voy a ver que puedo hacer con el circulo con medidas fijas. ya se me va ocurriendo como,

Castg!

bueno, la termine! jeje. yo te doy un par de ejemplos, que se adaptan a cada imagen, pero trata de jugar con los valores y podes obtener muchos resultados:

Inicial:



Resulatados:






Función:

Código (php) [Seleccionar]
function recortar($imagen, $centroX, $centroY, $ancho, $altura) {
$flotaImage = imagecreatetruecolor(imagesx($imagen), imagesy($imagen));
$naranja = imagecolorallocate($flotaImage, 255, 127, 0);
imagefilledellipse($flotaImage, $centroX, $centroY, $ancho, $altura, $naranja);
$finalImage = imagecreatetruecolor(imagesx($imagen), imagesy($imagen));
imagealphablending($finalImage,false);
$fondoFinal = imagecolorallocatealpha($finalImage, 0, 0, 0, 127);
imagefilledrectangle($finalImage , 0 , 0 ,imagesx($finalImage), imagesy($finalImage) , $fondoFinal);
imagealphablending($finalImage,true);
$xImage = imagesx($imagen);
$yImage = imagesy($imagen);
for($y=0;$y<$yImage;$y++) {
for($x=0;$x<$xImage;$x++) {
$rgb = imagecolorat($flotaImage, $x, $y);
if($rgb==$naranja) {
$rgb = imagecolorat($imagen, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$color = imagecolorallocate($flotaImage,  $r,  $g,  $b);
imagesetpixel($finalImage, $x, $y, $color);
}
}
}
imagesavealpha($finalImage,true);
return $finalImage;
imagedestroy($flotaImage);
}


Archivo que yo use para los ejemplos:

Código (php) [Seleccionar]
/*Funcion anterior...*/

$imagen = imagecreatefromjpeg("http://weblog.evasee.com/wp-content/uploads/2008/05/evasee-bender-smoking-3310.jpg");
switch ($_GET['mode']){
case 1:
default:
$centroX = imagesx($imagen) / 2;
$centroY = imagesy($imagen) / 2;
$ancho = imagesx($imagen);
$altura = imagesy($imagen);
break;
case 2:
$centroX = 0;
$centroY = 0;
$ancho = imagesx($imagen);
$altura = imagesy($imagen);
break;
case 3:
$centroX = imagesx($imagen) / 2;
$centroY = imagesy($imagen) / 2;
$ancho = imagesx($imagen) * 2;
$altura = imagesy($imagen);
break;
case 4:
$centroX = imagesx($imagen) / 2;
$centroY = imagesy($imagen) / 2;
$ancho = (imagesx($imagen)<imagesy($imagen)) ? imagesx($imagen) : imagesy($imagen);
$altura = (imagesx($imagen)<imagesy($imagen)) ? imagesx($imagen) : imagesy($imagen);
break;
}
$imagen = recortar($imagen, $centroX, $centroY, $ancho, $altura);
header("Content-type: image/png");
imagepng($imagen);
imagedestroy($imagen);



bueno, espero que este resultado sea el que necesites. la trasparencia creo que quedobien. un saludo grande ;)

дٳŦ٭

Excelente tutorial, muchas gracias por compartirlo.  ;)


Con sangre andaluza :)


cristiangq

:o :o :o :o :o
Realmente Fantastica
Justo lo que intentaba hacer.
Gracias y aplausos para vos
  ;-) ;-) ;-)