4. Reto 4. Movimientos

4.2. Importar imágenes

Hasta ahora, hemos creado dibujos hechos a partir de las formas que creamos con p5.js. Pero con p5.js podemos importar imágenes en formato jpg o png y usarlas para incluirlas en nuestros programas, pudiendo hacer composiciones más complejas.

Para poder trabajar con imágenes necesariamente tendremos que trabajar en línea, con el servidor FTP de la UOC, dado que por seguridad los navegadores no permiten la carga de archivos de manera local.

Para ello, crearemos una carpeta nueva a la que llamaremos img, donde guardaremos las imágenes que usemos.

Organizando el espacio del servidor

Vamos a ver cuál será la estructura que tenemos que tener en el servidor:

Dentro de la carpeta js tendremos los dos archivos que ya teníamos, el p5.min.js y el sketch.js.

Dentro de la carpeta img guardaremos las imágenes que vienen como ejemplo en el libro, disponibles para bajarla desde http://p5js.org/learn/books/media.zip.

Para poder usar una imagen, tendremos que hacer tres pasos previos:

  1. Copiar la imagen en la carpeta donde tenemos nuestro código.
  2. Crear una variable que almacene la imagen.
  3. Cargar la imagen con la función loadImage().

¿Cómo hacemos estos tres pasos?

El primer paso ya lo hemos hecho. Para tener nuestros ficheros muy organizados, hemos almacenado las imágenes en una carpeta que se llama img, pero veremos que no influye a la hora de hacer nuestros programas.

El segundo y tercer pasos los veremos en este ejemplo:

var img;   // Definimos una variable para almacenar la imagen
function preload() {   // Añadimos una nueva función que nos 
                       // carga la imagen
  img = loadImage("img/lunar.jpg");
}
function setup() {
  createCanvas(480, 120);
}
function draw() {
  image(img, 0, 0); // Dibuja la imagen
}

La función preload() se usa para cargar la imagen antes de ejecutar el código. De hecho, si existe esta función, la función setup() esperará a ejecutarse a que la función preload() haya finalizado (y por lo tanto, a que todas las imágenes estén cargadas).

El resultado, si ejecutamos este programa, será este:

Podéis ver este ejemplo funcionando en https://cv.uoc.edu/~ccasadom/PDA/html.

Este ejemplo se corresponde con el ejemplo 7-1 del libro (atención al cambio que se ha hecho en el código –en color rosa– especificando el directorio donde está la imagen almacenada).

Para dibujar la imagen hemos usado la función image() que tiene esta sintaxis:

image(img, x, y, [width], [height])

image(img, dx, dy, dWidth, dHeight, sx, sy, [sWidth], [sHeight])

La primera es fácil; x e y indican la posición del canvas donde se pondrá la imagen (corresponde con la esquina superior izquierda de la imagen) y width y height el ancho y la altura. Si no indicamos estos dos datos, entonces usará las medidas originales.

La segunda es más compleja; dx y dy indican la posición de la imagen en el canvas, dWidth y dHeight, el tamaño de la imagen en el canvas, sx y sy a partir de qué posición de la imagen mostraremos y sWitdth y sHeight el tamaño que cogeremos de la imagen. Si sWitdth y sHeight son más pequeños que dWidth y dHeight el trozo de imagen que se muestre se hará más grande y, en caso contrario, más pequeño.

En el ejemplo 7-2 se hacen dos cosas. Por un lado, se cargan dos imágenes. Por otra, a la hora de dibujarlas se usan diferentes efectos:

image(img1, -120, 0);

Esto hace que la imagen que se carga lo haga 120 píxeles fuera del canvas. El resultado es este:

Hemos recortado la imagen por la izquierda.

Ahora añadimos otra vez la misma imagen, pero cambiando la posición x (130 píxeles a la derecha) y recortándola (nos quedamos solo con 240 píxeles de anchura y 120 de altura).

image(img1, -120, 0);
image(img1, 130, 0, 240, 120);

Este es el resultado:

En el primer caso, como no hemos indicado el tamaño, ha intentado poner toda la imagen. Y ha salido la parte que cabía en el canvas. En el segundo caso, hemos indicado el tamaño donde se tenía que encajar la imagen y la imagen se ha adaptado a la medida disponible.

Ahora añadimos la segunda imagen:

image(img1, -120, 0);
image(img1, 130, 0, 240, 120);
image(img2, 300, 0, 240, 120);

Y este es el resultado:

Fijaos en que las imágenes se ponen encima unas de otras. La última en dibujarse es la que estará más arriba.

Podéis ver este ejemplo funcionando en https://cv.uoc.edu/~ccasadom/PDA/r5e2.html.

En el ejemplo 7-3 el tamaño de la imagen varía según el movimiento del ratón:

image(img, 0, 0, mouseX * 2, mouseY * 2);

En este ejemplo se puede ver cómo la imagen se adapta al tamaño que hemos dado a la función image().

Podéis ver este ejemplo en la dirección https://cv.uoc.edu/~ccasadom/PDA/r5e3.html.

En los ejemplos 7-4 y 7-5 lo que tenemos son dos imágenes, una en formato gif y la otra en formato png, que tienen transparencia. El código es el mismo en los dos casos, lo único que cambia es la imagen. Podéis ver estos dos ejemplos en las siguientes direcciones:

Cuando tenemos imágenes gif o png con transparencia, podemos poner la imagen con transparencia por encima de cualquier dibujo (sea otra imagen, sea un dibujo generado por nosotros mediante código) y en los lugares donde la imagen sea transparente, se verá la imagen que tenemos por debajo.

El ejemplo 7-6 carga una imagen en formato svg. Se puede ver funcionando en esta dirección https://cv.uoc.edu/~ccasadom/PDA/r5e6.html.

Finalmente, los ejemplos 7-7 y 7-8 están hechos para explicar que hay que cargar las imágenes y esperar que carguen antes de mostrarlas. El ejemplo 7-7 es una copia del ejemplo 7-1, pero en este caso no se espera la carga de la imagen. En consecuencia, la imagen no aparece en pantalla porque se intenta pintar antes de estar cargada. Hay una pequeña «trampa», pues en el setup() se llama a la función noLoop() para que la función draw() no se repita, con lo cual solo se hará una vez. Cuidado, podría ser que nos interesara un código donde draw() no se repitiera; por lo tanto, no se puede considerar una trampa de verdad.

Este ejemplo se puede ver funcionando en https://cv.uoc.edu/~ccasadom/PDA/r5e7.html.

El ejemplo 7-8 propone otra solución a la cuestión de la carga de la imagen. Lo que se hace es añadir un nuevo parámetro a la función loadImage() donde se indica a qué función habrá que llamar una vez se haya acabado la carga de la imagen.

Este ejemplo se puede ver funcionando en https://cv.uoc.edu/~ccasadom/PDA/r5e8.html.