HOWTO · Java

Recortar imagen en Java

Este artículo discutirá cómo recortar una imagen en Java, y para eso, usaremos la función de subimagen de la clase BufferedImage para recortar una imagen en Java.

En esta página

Recorta una parte rectangular de una imagen en Java con BufferedImage.getSubimage(x, y, width, height) y, después, escribe la imagen devuelta con ImageIO. El rectángulo comienza en su esquina superior izquierda (x, y); su ancho y su alto determinan qué parte de la imagen original se conserva.

Recortar una imagen con BufferedImage.getSubimage

BufferedImage representa una imagen cuyos píxeles pueden consultarse en memoria. Su método getSubimage devuelve una vista de una región rectangular de esa imagen. Los argumentos son x e y, las coordenadas de la esquina superior izquierda del rectángulo, seguidas de width y height. La imagen devuelta tiene las dimensiones solicitadas y comparte los datos de píxeles con la imagen original; por eso, usa una copia si necesitas que los cambios posteriores en una u otra sean independientes.

Leer una imagen y guardar el resultado recortado

Pasa como argumentos del programa la ruta de una imagen de entrada y una ruta de salida que termine en .png. Si no se proporcionan argumentos, el ejemplo crea una pequeña imagen PNG de muestra en un directorio temporal para mostrar el flujo completo sin necesitar otro archivo. Lee la imagen seleccionada con ImageIO, recorta el rectángulo y guarda el resultado como PNG. Ajusta las coordenadas del recorte para que se adapten a tu imagen.

Ejecuta este ejemplo autocontenido:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.imageio.ImageIO;

public class Main {
    public static void main(String[] args) {
        try {
            Path inputPath;
            Path outputPath;
            if (args.length == 2) {
                inputPath = Paths.get(args[0]);
                outputPath = Paths.get(args[1]);
            } else if (args.length == 0) {
                Path folder = Files.createTempDirectory("java-crop-");
                inputPath = folder.resolve("source.png");
                outputPath = folder.resolve("crop.png");

                BufferedImage sample = new BufferedImage(100, 80, BufferedImage.TYPE_INT_RGB);
                for (int y = 0; y < sample.getHeight(); y++) {
                    for (int x = 0; x < sample.getWidth(); x++) {
                        sample.setRGB(x, y, (x < 50) ? Color.BLUE.getRGB() : Color.ORANGE.getRGB());
                    }
                }
                ImageIO.write(sample, "png", inputPath.toFile());
            } else {
                System.out.println("Provide both an input path and an output path.");
                return;
            }

            if (!outputPath.getFileName().toString().toLowerCase().endsWith(".png")) {
                System.out.println("The output path must end in .png.");
                return;
            }

            BufferedImage source = ImageIO.read(inputPath.toFile());
            if (source == null) {
                System.out.println("The input format is not supported.");
                return;
            }

            int x = 20;
            int y = 15;
            int width = 40;
            int height = 30;
            if (x < 0 || y < 0 || width <= 0 || height <= 0
                    || x > source.getWidth() - width || y > source.getHeight() - height) {
                System.out.println("The crop rectangle must fit inside the input image.");
                return;
            }

            BufferedImage crop = source.getSubimage(x, y, width, height);
            boolean written = ImageIO.write(crop, "png", outputPath.toFile());
            if (written) {
                System.out.println("Saved crop: " + crop.getWidth() + "x" + crop.getHeight());
            } else {
                System.out.println("No PNG writer is available.");
            }
        } catch (IOException ex) {
            System.out.println("Image file operation failed: " + ex.getMessage());
        }
    }
}
Saved crop: 40x30

La imagen de origen seleccionada aparece junto al recorte resultante. Estas imágenes proporcionadas ilustran el efecto visible de recortar una imagen real.

Antes Después
Imagen original antes del recorte Imagen recortada que muestra la región seleccionada

Elegir las coordenadas y dimensiones del recorte

Las coordenadas parten de la esquina superior izquierda de la imagen de origen: x aumenta hacia la derecha e y hacia abajo. En el ejemplo, (20, 15) es el punto inicial del recorte, y 40 por 30 son sus dimensiones. Para una imagen de ancho W y alto H, elige valores no negativos para x e y, valores positivos para el ancho y el alto, y asegúrate de que x + width <= W e y + height <= H. Por ejemplo, un recorte que empieza en x = 20 y tiene 40 píxeles de ancho termina en la columna 59, así que la imagen de origen debe tener al menos 60 píxeles de ancho.

Gestionar entradas no válidas y errores habituales

ImageIO.read(File) puede lanzar IOException si no se puede leer un archivo. También puede devolver null si ningún lector registrado reconoce el formato de entrada; por eso, comprueba el resultado antes de llamar a getSubimage. El ejemplo captura los errores de las operaciones con archivos y comprueba si hay un escritor PNG disponible; ImageIO.write(RenderedImage, String, File) devuelve false cuando no puede escribir el formato solicitado.

Si el rectángulo de recorte queda fuera de los límites de la imagen de origen, o si su ancho o alto no es positivo, getSubimage lanza RasterFormatException; consulta la documentación de la API de BufferedImage.getSubimage. Valida las dimensiones antes de llamar al método, sobre todo si las coordenadas provienen de datos introducidos por el usuario. Para el ejemplo, proporciona una ubicación de salida en la que se pueda escribir y haz coincidir el nombre del formato PNG con la extensión .png.