Inici > Programació, Web > Clase PHP para tratar imágenes (rotar, redimensionar, añadir marcas de agua..)

Clase PHP para tratar imágenes (rotar, redimensionar, añadir marcas de agua..)

dissabte, 16 d'abril de 2011 Imprimir

Actualizado: Tanto la clase como este post han sido actualizados a fecha 14 de enero de 2012.

Hace ya un tiempo publiqué (en inglés) un Componente para el tratamiento de imágenes en CakePHP. Hoy me he pasado un rato actualizándolo y aprovechando he decidido publicar una entrada con los cambios.

Aunque la he modificado considerablemente, he procurado no modificar el funcionamiento de ésta. Aquí vienen los cambios:

  • He eliminado el uso del método obsoleto mime_content_type.
  • Ahora utilizo la clase Exception para tratar los errores.
  • He añadido el método “flip” para hacer espejo de la imagen.
  • He limpiado el código y he arreglado algún que otro fallo.
  • Ahora las transparencias funcionan correctamente.

Podéis descargar el proyecto desde GibHub:

https://github.com/elboletaire/Watimage/archives/master

Si queréis utilizar la clase desde CakePHP simplemente tenéis que descomentar la primera línea de la clase, donde dice //Component extends Object, y utilizarlo como un componente cualquiera.

Aplicando marcas de agua

$wm = new Watermark();
$wm->setImage('test.png');
$wm->setWatermark(array('file' => 'watermark.png', 'position' => 'top right'));
$wm->applyWatermark();
if ( !$wm->generate('test1.png') ) {
	// handle error...
	print_r($wm->errors);
}

Redimensionando

$wm = new Watermark('test.png');
$wm->resize(array('type' => 'resizecrop', 'size' => array(400, 200)));
if ( !$wm->generate('test2.png') ) {
	// handle error...
	print_r($wm->errors);
}

Rotando

$wm = new Watermark('test.png');
$wm->rotate(90);
if ( !$wm->generate('test3.png') ) {
	// handle error...
	print_r($wm->errors);
}

Guardando en otros formatos

$wm = new Watermark('test.png');
if ( !$wm->generate('test4.jpg') ) {
	// handle error...
	print_r($wm->errors);
}

Espejo

$wm = new Watermark('test.png');
$wm->flip('vertical');
if ( !$wm->generate('test5.png') ) {
	// handle error...
	print_r($wm->errors);
}

Todo junto

$wm = new Watermark('test.png', 'watermark.png');
$wm->resize(array('type' => 'resizecrop', 'size' => 400));
$wm->flip('horizontal');
$wm->rotate(90);
$wm->applyWatermark();
if ( !$wm->generate('test6.png') ) {
	// handle error...
	print_r($wm->errors);
}

Gracias a los comentarios de Francisco he podido arreglar la clase para que trate correctamente las transparencias.

Si véis cualquier fallo hacédmelo saber o haced un fork en github directamente!

  1. Jacin
    dimecres, 20 d'abril de 2011 a les 09:05 | #1

    Hola.

    ¿Es posible adaptar la marca de agua según el tamaño de la imagen?

    Me explico mi marca de agua tiene 900×900 y hay imagenes que son mas pequeñas y quería que se adaptara, por ejemplo una imagen de 200×200 la marca de agua debería tener 200×200 para que quedara bien. He probado a redimensionar la marca de agua cada vez que se suba una imagen al servidor pero es engorroso tener que ir después eliminando las imagenes que no sirven.

    ¿Hay alguna instrucción que adapte la marca de agua automaticamente a las medidas de la imagen?

    Muchas gracias.

  2. Edjarris
    dilluns, 2 de maig de 2011 a les 14:52 | #2

    Si señor, el script va de lujo. Muchas gracias por compartirlo. El único problema que me he encontrado es que en imágenes gif/png con canal alpha la transparencia se convierte en color negro. Si encuentro alguna solución se lo comentaré.
    Gracias de nuevo y saludos,

    • dilluns, 2 de maig de 2011 a les 15:35 | #3

      Vaya.. eso es un tema que en teoría funcionaba bien pero que me debo haber cargado al “mejorar” la clase. Miraré a ver si puedo arreglarlo cuando tenga tiempo.. aunque si encuentras solución antes compártelo por aquí como bien has dicho! 😀

  3. diumenge, 8 de maig de 2011 a les 14:35 | #4

    Ei @Jacin , perdona pero no había visto tu comentario hasta hoy mismo.

    Puedes indicar que el tamaño del watermark sea “full” y te lo pondrá ocupando el 100% de la imagen 😉

  4. diumenge, 8 de maig de 2011 a les 14:51 | #5

    Gracias @Booletaire

  5. Edjarris
    dimecres, 11 de maig de 2011 a les 12:47 | #6

    Hola Booletaire,

    Estoy usando tu código como componente de cakephp y tengo un pequeño problema que no acabo de entender. Cuando subo una imagen por ejemplo de 400kb , desde el controlador llamo a la función imgWater y el fichero final con la marca de agua incrustada aumenta el tamaño a 2Mb (el fichero watermark.png solo ocupa 3kb y la foto 400kb) .

    function imgWater ($foto = null){
    $this->Watermark->setImage(‘./img/ ‘.$foto);
    $this->Watermark->setWatermark(array(‘file’ => ‘./img/watermark.png’, ‘position’ => ‘center’));
    $this->Watermark->applyWatermark();
    if ( !$this->Watermark->generate(‘./img/w_’.$foto) ) {
    // handle error…
    print_r($this->Watermark->errors);
    }

    No hace mucho que empecé así que seguro que es culpa mía ^^. Si ves algo raro por lo que me pueda estar pasando este aumento de tamaño estaría muy agradecido.

    Saludos,

  6. dimecres, 11 de maig de 2011 a les 14:20 | #7

    Si has ejecutado el ejemplo que hay en github verás que el tamaño de las imágenes se reduce en todos los ejemplos, pero sí que es cierto que hay ocasiones en que el tamaño puede aumentar (lo he visto en contadas ocasiones).

    Para evitar que aumente mucho el tamaño puedes provar a reducir la calidad de las imágenes a 70 o menos. En el componente que había hasta ahora en GitHub no hay manera de regular la calidad a no ser que modifiques manualmente el valor de la variable privada “quality” a lo que quieras.

    Ahora mismo estoy haciendo un commit de una pequeña modificación del componente para poder setear la calidad fácilmente:

    $this->Watermark->setImage(‘imagen.jpg’);
    $this->Watermark->setQuality(70);
    $this->Watermark->etc…

    también puedes setearla directamente desde setImage:
    $this->Watermark->setImage(array(‘file’ => ‘imagen.jpg’, ‘quality’ => 70));
    $this->Watermark->etc…

    Espero que te sirva 😉

    Edito: Si estabas exportando a png acabo de descubrir que, por fallo mío, estaba calculando mal la calidad de salida del png y por eso debe estar aumentando tanto el tamaño. También lo he arreglado y puedes descargar los cambios desde github.

    https://github.com/elboletaire/Watimage

  7. Edjarris
    dimecres, 11 de maig de 2011 a les 21:11 | #8

    Buenas noches Booletaire,

    Primero de todo agradecerte la rapidez y el esfuerzo :). Me he bajado la versión de github y he estado haciendo pruebas pero parece que el error persiste. Las imágenes problemáticas son de una cámara digital Sony dsc-w320 en formato jpg, el watermark era png y continua disparando el tamaño en la imagen final a pesar de ir jugando con el nuevo método (setQuality()).Con todas las imágenes que he probado funciona a la perfección, menos con las de esta dichosa cámara. He probado con la imagen maldita aplicarle el watermark en formato gif por si era la combinación de jpg/png y nada lo mismo >2Mb.

    Aquí va lo más curioso de todo abro la maldita imagen con el fireworks, sin aplicarle nada la guardo y entonces funciona perfecto me deja la imagen de salida de 166kb.

    Otra cosa curiosa es que en las propiedades de la imagen de la sony sale 72ppp pero en la imagen de salida ha aumentado a 96ppp. Si que esto podría producir que la imagen aumentara de tamaño pero he hecho lo mismo con imágenes que si funcionan y pasa exactamente lo mismo la imagen inicial tiene una resolución de 72ppp y la final 96ppp y queda reducida.

    Continuo investigando por donde puede venir el problema y si tengo alguna pista más te lo comentaré.

    Saludos y gracias por todo ^^

  8. Edjarris
    dijous, 12 de maig de 2011 a les 11:32 | #9

    Hola de nuevo Booletaire,

    Ya encontré el bug!!! El problema es si la extensión de la imagen es en mayúsculas parece que no le aplica la compresión ^^. Lo descubrí porque con otra cámara digital también me pasaba y me di cuenta de que la mayoría cámaras lo guardan en mayúsculas. Renombre el fichero y funciono a la perfección. Por eso cuando guarde la “imagen” sin aplicar ninguna compresión con el fireworks le cambio la extensión a minúsculas y funciono. Seguramente hay alguna manera más elegante pero de momento lo he solucionado en la función setImage convirtiendo el contenido de $image a minúsculas. Es posible que en entornos Linux y si el uploader lo sube en mayúsculas pudiera dar algún problema, pero de memento funciona ahora solo queda mejorarlo :).

    public function setImage($file)
    {
    $file = strtolower($file); //lo paso a minusculas

    try
    {

    Saludos,
    Ed.

  9. dijous, 12 de maig de 2011 a les 20:02 | #10

    Buah chico, me acabas de dejar flipado xDD

    Podrías mandarme una de esas fotos a través de algún enlace? De este modo podría intentar ver cómo evitar que pase eso.. porque he estado probando con imágenes mías y no he tenido ningún problema :\

    Vete con cuidado con lo que has hecho porque en Linux y Mac no debería funcionar, ya que al pasar la extensión a minúsculas en el método setImage la imagen no cargará (ya que en Linux y Mac se distinguen mayúsculas y minúsculas).

  10. divendres, 20 de maig de 2011 a les 09:12 | #11

    Booletaire!!!! muchas gracias por tu aporte. como consigo que la watermark se redimensione deacuerdo con el nuevo tamaña de la imagen. ésto lo ha preguntado alguien antes pero no entiendo bien como hacerlo.!!

    otra vez gracias!

  11. divendres, 20 de maig de 2011 a les 09:38 | #12

    Pues por ahora tendrás que calcularlo tú mismo a manopla… por cada imagen tendrás que obtener el tamaño y calcular el tamaño de la marca de agua.

    Tengo en mente añadir esta funcionalidad a la clase para poder hacerlo con un único parámetro, pero por falta de tiempo todavía no he podido hacerlo.

    Salud y gracias por el comentario.

  12. divendres, 8 de juliol de 2011 a les 23:10 | #13

    Ahí va, @Luis Miguel , te entendí mal la pregunta. Eso es lo que pasa cuando uno contesta preguntas recién levantado…

    Para hacer que la marca de agua ocupe el 100% de la imagen simplemente tienes que poner el parámetro ‘size’ del watermark a ‘full’:

    $this->Watermark->setWatermark(array('file' => 'fichero.png', 'size' => 'full'));

  13. Borja
    dissabte, 12 de novembre de 2011 a les 10:56 | #14

    Buenas booleataire,
    de primeras agradecerte la clase, funciona muy bien, el unico inconveniente ya lo pusieron arriba y es que la marca de agua no respeta las transparencias en imagenes gif/png.
    ¿Hay algun avance en cuanto este tema?, no soy muy dado a la edicion de imagen mediante PHP sinó ya hubiese echado una mano =)

  14. Borja
    dissabte, 12 de novembre de 2011 a les 11:00 | #15

    Borja :
    Buenas booleataire,
    de primeras agradecerte la clase, funciona muy bien, el unico inconveniente ya lo pusieron arriba y es que la marca de agua no respeta las transparencias en imagenes gif/png.
    ¿Hay algun avance en cuanto este tema?, no soy muy dado a la edicion de imagen mediante PHP sinó ya hubiese echado una mano =)

    Mil disculpas y fallo mio ^^ no le habia metido suficiente transparencia a la imagen como para que se notase el efecto, gracias de nuevo 😀

  15. Borja
    dissabte, 12 de novembre de 2011 a les 11:11 | #16

    Sigo haciendo prubas ^^

    Con una imagen de unos 3000px de ancho y 1000px de alto y un peso de unos 750Kb me ha saltado un error el propio PHP.

    Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 13056 bytes)

    He estado leyendo y es por falta de memoria (Evidentemente algo tenia que ver) pero no doy con la solucion, ¿alguien con un problema similar?

  16. dissabte, 12 de novembre de 2011 a les 11:14 | #17

    Tienes que ampliar la memoria permitida para PHP. Para ello puedes modificar directamente tu php.ini, buscar “memory_limit” y ampliarlo a 256MB por ejemplo.

    Otra cosa que puedes hacer es modificarlo directamente desde tu php, con ini_set:

    < ?php ini_set('memory_limit', '256MB');

  17. dilluns, 26 de desembre de 2011 a les 12:55 | #18

    Hola buenas tardes:
    Ante todo agradecerte la genial clase que has preparado. Enhorabuena.
    Ahora mi duda: tengo una imagen PNG que, al aplicarle un resize o resizecrop, el fondo me lo pone negro, ¿de qué puede ser?
    Investigué algo pero me quedé en la función handleTransparentImage() que no logro entender bien del todo.

  18. dilluns, 26 de desembre de 2011 a les 13:02 | #19

    Es un tema que debería de repasar porque ya se quejan anteriormente en los comentarios y seguramente sea debido a algun fallo por mi parte. La verdad es que el tema de las transparencias con las librerías GD es bastante tocapelotas…

    De todos modos, si lo que quieres es hacer resize, con la versión antigua de la clase recuerdo que al redimensionar no se perdía la transparencia. Si te animas puedes echar un vistazo a la versión anterior:

    https://github.com/elboletaire/Watimage/blob/b526bda2a1fdd4d13023cdcc5bbf26a0afa259df/watermark.php

    Y tratar de modificar la nueva tú mismo 😀 A mi la verdad es que me gustaría dedicarle tiempo, pero ahora mismo me es imposible.. quizás pasado fin de año pueda dedicarle algún día pero tampoco prometo nada.

  19. dilluns, 26 de desembre de 2011 a les 18:00 | #20

    Gracias @Booletaire, voy a investigar a ver si te puedo echar una mano.
    Googleando encontré esto: http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/
    A ver si apartir de ahí puedo averiguar algo 😉

    @Booletaire

  20. divendres, 30 de desembre de 2011 a les 12:44 | #21

    Buenos días de nuevo, os dejo buena noticia antes de finales de año y para comenzar bien 2012.
    He conseguido que subiendo ficheros PNG me mantenga la transparencia con sólo sustituir todas las llamadas “imagecreatetruecolor” del método “resize” por “imagecreate”. Ej:

    if ( !$dest_image = imagecreatetruecolor($new_x, $new_y) )

    por:

    if ( !$dest_image = imagecreate($new_x, $new_y) )

    Eso sí, si pudiérais hacer pruebas me sentiría más realizado 😉

    @Booletaire

  21. dilluns, 9 de gener de 2012 a les 11:09 | #22

    Rectifico, con los ficheros JPG/JPEG no dejaba bien los colores, entonces hice unas mejoras.
    Hice un Pull rquest en github 😉

  22. dilluns, 9 de gener de 2012 a les 11:45 | #23

    Ou yeah! 😀 Cómo mola ver que la gente se implica (se ve poco a menudo). Esta semana la tengo súper liada pero si encuentro un hueco lo testeo y acepto el pull request 😉

    Salu2 y muchas gracias por colaborar!

  23. dissabte, 14 de gener de 2012 a les 18:04 | #24

    Francisco, gracias a tu ayuda he podido arreglar todos los errores relacionados con las transparencias (o al menos eso parece).

    Si bajas el nuevo código cuidado con el nombre de la clase que lo he cambiado de Watermark a Watimage.

    https://github.com/elboletaire/Watimage

    Saludos y gracias de nuevo por tu ayuda!

  24. diumenge, 15 de gener de 2012 a les 09:11 | #25

    De nada, para eso estamos 😉

  25. dilluns, 14 de maig de 2012 a les 12:41 | #26

    Hola,

    estoy intentando utilizar el componente dentro de cakephp 2.0.5 y nada mas agregarlo al controller me surgen 2 warnings:

    – First argument is expected to be a valid callback,

    lo cual he solucionado modificando

    class WatimageComponent extends Object

    al inicio del componente por

    class WatimageComponent extends Component

    Pero el otro warning:

    – Object of class ComponentCollection could not be converted to string

    que hace referencia a las lineas 123 y 126 de watimage.php, concretamente estas íneas tienen el código:
    “if ( file_exists($file) )”
    y
    “throw new Exception(‘File “‘ . $file . ‘” does not exist’);”

    respectivamente, no consigo solventarlo.

    Si alguien sabe como evitar dichos warnings…

    Gracias,

    Ernesto

  26. dilluns, 14 de maig de 2012 a les 14:41 | #27

    El primer warning es debido al cambio de versión de CakePHP… yo todavía no me he puesto con CakePHP 2.X (cosas del trabajo…), así que ni siquiera lo sabía xD Pero gracias por el comentario, trataré de especificarlo en el post.

    El segundo error está relacionado con el primero. Dado que no he podido verificar la clase con CakePHP 2 puede que dé más errores… Pero puedes hacer una cosa: en lugar de utilizar la clase como componente puedes utilizarla como “Vendor”… al caso, no hay gran diferencia… y puede que solucione tu problema, ya que parece más bien un problema de diseño (por el cambio al “Extend” que has hecho deduzco que han cambiado un poco el diseño de la aplicación de la versión 1 a la 2).

  27. dimarts, 15 de maig de 2012 a les 09:51 | #28

    Hola Booletaire,

    como “vendor” ya no aparecen los warnings.

    Por si a alguien le viene bien:
    La clase se declara:

    class Watimage extends Object

    y el objeto se instancia/utiliza en el controlador de la siguiente forma:

    App::import(‘Vendor’, ‘Watimage’);
    $watimage = new Watimage();
    $watimage->setImage(‘img/test.png’);

    Gracias por tan pronta contestación y, evidentemente, gracias por compartir un trabajo tan bueno.

    Saludos,

    Ernesto.

  28. dimarts, 15 de maig de 2012 a les 10:05 | #29

    Si la utilizas como vendor creo que debería de ser:

    class Watimage {

    a secas, ya que el “extends Object” es para utilizarlo como componente en CakePHP v. 1.3 y anteriores.

    De nada en cuanto a la contestación, y un placer compartir mis conocimientos con el mundo. Ojalá todo el mundo hiciera igual! :)

  29. divendres, 5 d'octubre de 2012 a les 14:13 | #30

    Esta es definitivamente mas completa que el timthumb.php que solía usar, gracias.

  30. dimecres, 24 d'octubre de 2012 a les 13:06 | #31

    Hola,
    estupenda clase.

    Mi problema es que cuando aplica el watermark, deja un borde negro en el lateral inferior y derecho.
    El watermark está definido para la posicion => ‘center center’ y size => ‘25%’

    Saludos
    Luis

  31. Elí Daván Palma
    dimarts, 27 d'agost de 2013 a les 18:37 | #32

    Se puede agregar un espacio blanco a una imagen?

    en la parte inferior por ejemplo

  32. divendres, 30 d'agost de 2013 a les 11:31 | #33

    Gracias Kalvin!

    Luis, lamento no haber contestado antes (sí, ha pasado casi un año). La verdad es que no dispongo del tiempo libre que me gustaría ni para poder ayudaros ni para poder hacer mejoras con la clase.

    Elí , hace tiempo que tengo en mente sacar una nueva versión de la clase que permita trastear con el objeto de imagen antes de generarla. Es decir, que en lugar de trabajar internamente con la imagen, lo devuelva como valor y podamos modificar dicha variable:

    // genreamos un resize con watimage
    $image = $this->Watermark->resize(array(...));
    // añadimos caracteres directamente con GD
    imagechar($image, 1, 0, 0, 'ola ke ase', imagecolorallocate($image, 0, 0, 0));

    Desgraciadamente, como le comentaba a Luis, la verdad es que no dispongo de tiempo para hacerlo así que por ahora tendrás que crearte una función (o clase) que genere dicho espacio blanco en las imágenes (a partir del fichero resultante tratado con watimage).

  33. divendres, 27 de desembre de 2013 a les 16:04 | #34

    Buenas tardes, estaba mirando tu código la verdad es muy practico y facil de implementar pero tengo el siguiente problema. Por lo que veo las imágenes tienen que estar cargadas en el servidor y si yo quisiera redimensionarlas antes de subirlas dado que pesan mucho el codigo no anda si le digo que tome la ruta temporal. o al menos no puede darle las directivas correctas.

  34. divendres, 10 de gener de 2014 a les 11:33 | #35

    Hola @Mauro , me parece que hay algo que se te escapa.

    Efectivamente las imágenes tienen que estar cargadas en el servidor, este sistema no funciona si intentamos pasarle una imagen temporal, pero OJO, que esa imagen esté ubicada en el directorio temporal no significa que esa imagen no esté ocupando espacio, así que no veo qué problema te puede traer el guardar la imagen antes de tratarla.

    Por otro lado, es totalmente recomendable conservar la imagen subida por el usuario, así que más motivo para trabajar sobre una imagen guardada previamente.

    En github ya hay alguien que comentó algo parecido: https://github.com/elboletaire/Watimage/issues/2

  35. dimarts, 15 de setembre de 2015 a les 20:01 | #36

    Me alegra comunicaros a todos los usuarios que utilicéis Watimage de que podéis descargar la última versión en la que llevo trebajando el último medio año.

    Ha sido re-escrita desde cero separando toda la lógica (revisada) en distintas clases y además tiene muchos más métodos para tratar las imágenes así como efectos y mucho más.

    Y todo con chaining, que le aporta una gran comodidad a la hora de trabajar con imágenes mediante PHP.

    Echadle ya un vistazo en GitHub :_D !!!

    http://github.com/elboletaire/Watimage

Comentaris tancats.