php

Poner marca de agua a imágenes con PHP

En este post voy a explicar y demostrar cómo se pueden poner marcas de agua con PHP utilizando las funciones de la librería GD.

Vamos a ver cómo poner la marca de agua en distintas posiciones (arriba a la izquierda, arriba a la derecha, centrada horizontal y verticalmente) y cómo modificar la opacidad de la marca de agua.

Marca de agua colocada con PHP y GD

En la imagen de arriba se puede notar que he colocado una marca de agua de una “terminal” sobre una captura de código C (es sobre el post de generar números aleatorios con C).

He elegido estas dos imágenes porque el dueño soy yo, así que no pueden existir reclamaciones de derechos de autor y esas cosas que dan pereza.

Nota: recuerda que hace tiempo publiqué WaterPy, una aplicación similar pero escrita en Python.

Probar ejemplos y ver código completo

A lo largo del tutorial explicaré las partes más importantes del código y ahorraré las repetitivas. Por ello es que he puesto todo el código actualizado en GitHub.

Funciones y explicación de las mismas

Primero debemos cargar la imagen; en este caso fueron imágenes PNG así que usamos la función llamada imagecreatefrompng; si fuera jpeg sería imagecreatefromjpeg. Ambas funciones reciben la ruta de la imagen,

Cuando tenemos una referencia al recurso de la imagen podemos obtener algunos datos de ella, por ejemplo la altura o anchura.

La función que realmente hace el trabajo de poner la marca de agua es imagecopy, pues pone una imagen encima de otra en determinadas posiciones.

Marca de agua en la parte superior izquierda

Marca de agua esquina superior izquierda

Veamos un ejemplo que coloca la marca de agua en la esquina superior izquierda, es decir, al “inicio” de la imagen:

<?php
/**
 * Ejemplos de cómo poner marcas de agua con PHP y GD
 * 
 * @author parzibyte
 */$rutaImagenOriginal = __DIR__ . "/codigo.png";
$rutaMarcaDeAgua = __DIR__ . "/marca.png";

$original = imagecreatefrompng($rutaImagenOriginal);
$marcaDeAgua = imagecreatefrompng($rutaMarcaDeAgua);

# En dónde poner la marca de agua sobre la original
$xOriginal = 0;
$yOriginal = 0;
# Desde dónde comenzar a cortar la marca de agua (si son 0, se comienza desde el inicio)
$xMarcaDeAgua = 0;
$yMarcaDeAgua = 0;
# Hasta dónde poner la marca de agua sobre la original
$alturaMarcaDeAgua = imagesy($marcaDeAgua) - $yMarcaDeAgua;
$anchuraMarcaDeAgua = imagesx($marcaDeAgua) - $xMarcaDeAgua;
imagecopy($original, $marcaDeAgua, $xOriginal, $yOriginal, $xMarcaDeAgua, $yMarcaDeAgua, $anchuraMarcaDeAgua, $alturaMarcaDeAgua);

# Imprimir y liberar recursos
header('Content-Type: image/png');
imagepng($original);
imagedestroy($original);
imagedestroy($marcaDeAgua);

Cuando llamamos a imagecopy la imagen se copia, pero no se guarda ni se muestra. Para mostrarla directamente en el navegador enviamos un encabezado indicando el tipo de imagen y llamamos a imagepng con un único argumento: el recurso de la imagen.

Para liberar los recursos tanto de la marca de agua como de la imagen a la que se le pone la marca de agua se llama a imagedestroy.

Se supone que deberían liberarse automáticamente al salir del script pero no siempre se llamarán al final del script; por eso es una buena práctica liberar lo tomado.

La sintaxis de imagecopy

Al principio es un poco difícil de comprender, pero yo te explico los argumentos en el orden que se mandan a imagecopy:

  • Imagen de destino obtenida con una función de imagecreatefrom*: Es la imagen sobre la cual se pone la marca de agua
  • Imagen fuente: recurso de imagen que se va a poner sobre la imagen de destino. Es la marca de agua
  • Posición x de inicio en donde se coloca la marca de agua sobre la imagen de destino: por ejemplo, si es 0 se pondrá hasta la izquierda. Si es 100 se pondrá 100 pixeles alejado de la izquierda y así sucesivamente.
  • Posición y de inicio: lo mismo que x pero ahora sobre Y.
  • Posición x de marca de agua: desde dónde comenzar a “cortar” la marca de agua. Si es 0 se empieza desde el inicio, si es, por ejemplo, 100, se cortará la marca de agua desde 100 pixeles en X.
  • Posición y de marca de agua: lo mismo que la posición anterior pero en y. En resumen, si quieres la imagen completa simplemente pon este y el anterior en 0.
  • Anchura de la imagen que se sobrepone: la anchura de la marca de agua
  • Altura de la imagen que se sobrepone: la altura de la marca de agua. Estos dos últimos se obtienen de imagesy e imagesx.

Centrar marca de agua

Marca de agua centrada – PHP y GD

Sabiendo lo anterior podemos jugar un poco con las matemáticas y las medidas de las imágenes para centrar completamente la marca de agua, tanto vertical como horizontalmente. El siguiente código ejemplifica cómo:

<?php
/**
 * Ejemplos de cómo poner marcas de agua con PHP y GD
 * 
 * @author parzibyte
 */$rutaImagenOriginal = __DIR__ . "/codigo.png";
$rutaMarcaDeAgua = __DIR__ . "/marca.png";

$original = imagecreatefrompng($rutaImagenOriginal);
$marcaDeAgua = imagecreatefrompng($rutaMarcaDeAgua);

# Como vamos a centrar  necesitamos sacar antes las anchuras y alturas
$anchuraOriginal = imagesx($original);
$alturaOriginal = imagesy($original);
$alturaMarcaDeAgua = imagesy($marcaDeAgua);
$anchuraMarcaDeAgua = imagesx($marcaDeAgua);
# En dónde poner la marca de agua sobre la original
$centroHorizontalDeOriginal = floor($anchuraOriginal / 2);
$centroHorizontalDeMarcaDeAgua = floor($anchuraMarcaDeAgua / 2);
$centroVerticalDeOriginal = floor($alturaOriginal / 2);
$centroVerticalDeMarcaDeAgua = floor($alturaMarcaDeAgua / 2);
$centroHorizontal = $centroHorizontalDeOriginal - $centroHorizontalDeMarcaDeAgua;
$centroVertical = $centroVerticalDeOriginal - $centroVerticalDeMarcaDeAgua;

$xOriginal = $centroHorizontal;
$yOriginal = $centroVertical;
# Desde dónde comenzar a cortar la marca de agua (si son 0, se comienza desde el inicio)
$xMarcaDeAgua = 0;
$yMarcaDeAgua = 0;
# Hasta dónde poner la marca de agua sobre la original
$alturaMarcaDeAgua = $alturaMarcaDeAgua - $yMarcaDeAgua;
$anchuraMarcaDeAgua = $anchuraMarcaDeAgua - $xMarcaDeAgua;
imagecopy($original, $marcaDeAgua, $xOriginal, $yOriginal, $xMarcaDeAgua, $yMarcaDeAgua, $anchuraMarcaDeAgua, $alturaMarcaDeAgua);

# Imprimir y liberar recursos
header('Content-Type: image/png');
imagepng($original);
imagedestroy($original);
imagedestroy($marcaDeAgua);

Para centrar se saca el punto medio de la imagen y el punto medio de la marca de agua, después de eso se hace una resta y se redondea hacia abajo.

Guardar imagen con marca de agua en lugar de mostrarla

Si se desea guardar la imagen en el disco duro para su futuro procesamiento solamente se debe pasar un segundo parámetro a imagepng: la ruta de la imagen (recuerda que el primer parámetro es el recurso de imagen)

<?php
$resultado = imagepng($original, "marcada.png");

Cambiar opacidad de marca de agua

Si queremos podemos cambiar la opacidad de la marca de agua para que se vea un poco transparente.

Cambiar transparencia de marca de agua – PHP y GD

Para ello usamos la función imagecopymerge que funciona exactamente igual que imagecopy pero recibe un parámetro adicional: un entero que indica el porcentaje de opacidad.

<?php
# Usar imagecopymerge en lugar de imagecopy
# La diferencia es que al final se indica el porcentaje
imagecopymerge($original, $marcaDeAgua, $xOriginal, $yOriginal, $xMarcaDeAgua, $yMarcaDeAgua, $anchuraMarcaDeAgua, $alturaMarcaDeAgua, $porcentajeOpacidad);

Todo se comportará de la misma manera pero la marca de agua estará transparente. Entre menor sea el número, la marca de agua será más transparente.

Marca de agua en distintas posiciones

Es totalmente posible colocar la marca de agua sobre la imagen en distintas posiciones, simplemente hay que llamar varias veces a imagecopy o imagecopymerge con distintos parámetros.

Al final, al llamar a imagepng se obtendrá el resultado de todas las imágenes copiadas.

Otro tipo de imágenes

En el ejemplo utilizamos únicamente imágenes PNG pero se pueden utilizar otro tipo de imágenes, por ejemplo JPG, BMP, etcétera.

Para esto existen las funciones imagecreatefromjpeg y todas ellas que se pueden ver en el manual oficial.

Cuando trabajes con imágenes y las muestres directamente en el navegador recuerda establecer el encabezado a la forma correcta, por ejemplo image/jpeg.

De la misma manera, no siempre vas a llamar a imagepng, puedes llamar a otras dependiendo del formato de tus imágenes.

Conclusión

Por si no lo leíste, puedes ver los ejemplos en GitHub y probar lo que hicimos en mi sitio web. Al inicio del post dejé los enlaces.

Puedes hacer que una imagen se envíe a través de un formulario y se ponga la marca de agua, por ejemplo. Las posibilidades son infinitas y todo depende de lo que necesidades.

Lee más sobre PHP aquí.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

2 días hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

1 semana hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

1 semana hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

1 semana hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

1 semana hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

1 semana hace

Esta web usa cookies.