Manipulación de Imágenes BMP en Java: Duplicación y Procesamiento

Clasificado en Informática

Escrito el en español con un tamaño de 9,62 KB

Este documento explica el código Java para la manipulación de imágenes en formato BMP (Bitmap) de 24 bits, con un enfoque en la duplicación de imágenes. Se asume que la altura y la anchura de la imagen son múltiplos de 4 y menores que 127.

Clase ImagenBMP

La clase ImagenBMP proporciona métodos para leer, duplicar y guardar imágenes BMP.

Atributos

  • TAM_CABECERAS: Constante que define el tamaño de la cabecera de un archivo BMP (54 bytes).
  • cabecera: Array de bytes que almacena la cabecera de la imagen BMP.
  • nombre: String que representa el nombre del archivo de la imagen.
  • matriz: Matriz de objetos Pixel que representa la imagen original.
  • imagen: Objeto File que representa el archivo de la imagen.
  • matrizDoble: Matriz de objetos Pixel que representa la imagen duplicada.

Constructor ImagenBMP(String nomb)

Inicializa una nueva instancia de la clase ImagenBMP.

  • Recibe el nombre del archivo de imagen como parámetro.
  • Lee la cabecera y los datos de píxeles del archivo BMP.
  • Almacena la cabecera en el array cabecera.
  • Crea una matriz de objetos Pixel con las dimensiones especificadas en la cabecera.
  • Lee los bytes de datos de píxeles y los convierte en objetos Pixel, almacenándolos en la matriz matriz.
  • Maneja las excepciones FileNotFoundException e IOException.

Métodos

getAncho()

Devuelve el ancho de la imagen (número de columnas de la matriz).

getAlto()

Devuelve el alto de la imagen (número de filas de la matriz).

setImagen(String nom)

Establece el archivo de imagen a partir del nombre de archivo proporcionado.

  • Recibe el nombre del archivo como parámetro.
  • Crea un nuevo objeto File con el nombre de archivo dado.
duplicar()

Duplica el tamaño de la imagen almacenada en la matriz matriz.

  • Crea una nueva matriz matrizDoble con el doble de ancho y alto que la matriz original.
  • Copia cada píxel de la matriz original en cuatro posiciones adyacentes en la matriz matrizDoble, duplicando efectivamente la imagen.
  • Actualiza la cabecera para reflejar las nuevas dimensiones.
duplicar2()

Duplica el tamaño de la imagen utilizando un método alternativo más eficiente.

  • Crea una nueva matriz matrizDoble con el doble de ancho y alto que la matriz original.
  • Itera sobre cada píxel de la matriz matrizDoble y asigna el valor del píxel correspondiente de la matriz original, dividiendo los índices por 2.
volcarImagen(String nomFichero)

Guarda la imagen duplicada en un archivo BMP.

  • Recibe el nombre del archivo de salida como parámetro.
  • Crea un nuevo objeto FileOutputStream.
  • Crea una nueva cabecera cabeceraDoble con las dimensiones actualizadas.
  • Escribe la cabecera en el archivo de salida.
  • Escribe los datos de píxeles de la matriz matrizDoble en el archivo de salida.
  • Cierra el flujo de salida.
  • Maneja las excepciones FileNotFoundException e IOException.

Método main

El método main demuestra el uso de la clase ImagenBMP.

  • Crea una nueva instancia de ImagenBMP con el archivo "orig.bmp".
  • Llama al método duplicar2() para duplicar la imagen.
  • Llama al método volcarImagen() para guardar la imagen duplicada en el archivo "doble.bmp".

Código Completo


import java.io.*;

/**
 * Clase para duplicar imágenes BMP de 24 bits con altura y anchura múltiplo de 4 menor que 127.
 */
public class ImagenBMP {
    private static final int TAM_CABECERAS = 54;
    private byte cabecera[];
    private String nombre;
    private Pixel[][] matriz;
    private File imagen;
    private Pixel matrizDoble[][];

    public ImagenBMP(String nomb) {
        cabecera = new byte[TAM_CABECERAS];
        imagen = new File(nomb);
        try {
            FileInputStream in = new FileInputStream(imagen);
            int leido1 = 0;
            int leido2 = 0;
            int leido3 = 0;
            int i = 0;
            int j = 0;
            in.read(cabecera);
            matriz = new Pixel[cabecera[18]][cabecera[22]];
            while (i < matriz.length && j < matriz[0].length) {
                while (((leido1 = in.read()) != -1) && ((leido2 = in.read()) != -1) && ((leido3 = in.read()) != -1)
                        && j < matriz[0].length) {
                    Pixel nuevoPixel = new Pixel(((byte) leido1), ((byte) leido2), ((byte) leido3));
                    matriz[i][j] = nuevoPixel;
                    j++;
                }
                j = 0;
                i++;
                if ((leido1 != -1) && (leido2 != -1) && (leido3 != -1)) {

                    Pixel nuevoPixel = new Pixel(((byte) leido1), ((byte) leido2), ((byte) leido3));
                    matriz[i][j] = nuevoPixel;

                    j++;
                }
            }

            in.close();
        } catch (FileNotFoundException e) {
            System.out.println("No existe el fichero");
        } catch (IOException e) {
            System.out.println("Error E/S lectura");
        }

    }

    public int getAncho() {
        return matriz.length;
    }

    public int getAlto() {
        return matriz[0].length;
    }

    /**
     * Carga una imagen bmp del fichero de nombre dado.
     *
     * @param nom nombre del fichero a cargar
     */
    public void setImagen(String nom) {
        imagen = new File(nom);
    }

    /**
     * Duplica los datos de la imagen guardada.
     */
    public void duplicar() {
        int alto = getAncho() * 2;
        int ancho = getAlto() * 2;
        matrizDoble = new Pixel[alto][ancho];
        for (int i = 0; i < getAncho(); i++) {
            for (int j = 0; j < getAlto(); j++) {
                Pixel valor = matriz[i][j];
                for (int m = 0; m < getAncho(); m += 2) {
                    for (int n = 0; n < getAlto(); n += 2) {
                        matrizDoble[m][n] = valor;
                        matrizDoble[m + 1][n] = valor;
                        matrizDoble[m][n + 1] = valor;
                        matrizDoble[m + 1][n + 1] = valor;
                    }
                }
            }
        }
        byte cabeceraDoble[] = new byte[TAM_CABECERAS];
        cabeceraDoble[18] = ((byte) ancho);
        cabeceraDoble[22] = ((byte) alto);
    }

    public void duplicar2() {
        int ancho = getAncho() * 2;
        int alto = getAlto() * 2;
        matrizDoble = new Pixel[alto][ancho];
        for (int i = 0; i < alto; i++) {
            for (int j = 0; j < ancho; j++) {
                matrizDoble[i][j] = matriz[i / 2][j / 2];
            }
        }
    }

    /**
     * Guarda en un fichero de nombre dado los datos de la imagen.
     *
     * @param nomFichero nombre del fichero donde almacenar los datos de la imagen.
     */
    public void volcarImagen(String nomFichero) {
        try {
            byte cabeceraDoble[] = new byte[TAM_CABECERAS];
            FileOutputStream out = new FileOutputStream(nomFichero);
            for (int i = 0; i < cabecera.length; i++) {
                cabeceraDoble[i] = cabecera[i];
            }
            cabeceraDoble[18] = ((byte) (getAncho() * 2));
            cabeceraDoble[22] = ((byte) (getAlto() * 2));
            out.write(cabeceraDoble);
            for (int i = 0; i < getAlto() * 2; i++) {
                for (int j = 0; j < getAncho() * 2; j++) {
                    out.write(matrizDoble[i][j].getByte1());
                    out.write(matrizDoble[i][j].getByte2());
                    out.write(matrizDoble[i][j].getByte3());
                }
            }
            out.close();
        } catch (FileNotFoundException e) {
            System.out.println("No existe el fichero ");
        } catch (IOException e) {
            System.out.println("Error E/S escritura ");
        }
    }

    public static void main(String[] args) {
        ImagenBMP x = new ImagenBMP("orig.bmp");
        x.duplicar2();
        x.volcarImagen("doble.bmp");
    }

}

Clase Pixel

La clase Pixel, aunque no se muestra en el código proporcionado, se puede inferir que representa un píxel individual con tres componentes de color (rojo, verde y azul), cada uno almacenado como un byte. Probablemente, tendría métodos para obtener los valores de cada componente (getByte1(), getByte2(), getByte3()) y un constructor para crear un nuevo objeto Pixel a partir de tres bytes.

Ejemplo de la clase Pixel


public class Pixel {
    private byte byte1;
    private byte byte2;
    private byte byte3;

    public Pixel(byte byte1, byte byte2, byte byte3) {
        this.byte1 = byte1;
        this.byte2 = byte2;
        this.byte3 = byte3;
    }

    public byte getByte1() {
        return byte1;
    }

    public byte getByte2() {
        return byte2;
    }

    public byte getByte3() {
        return byte3;
    }
}

Entradas relacionadas: