read libreria language example java image-processing groovy

libreria - read image java



¿Cómo rotar imágenes JPEG en base a los metadatos de orientación? (6)

Tengo un código de servidor que genera miniaturas cuando se carga una imagen. El problema es que cuando se tomó la imagen y se giró la cámara / dispositivo, las miniaturas se rotan, aunque las imágenes de tamaño completo se muestran con la orientación correcta en cualquier software de visualización de imágenes. Esto solo está sucediendo con jpgs.

Usando Vista previa en OSX, puedo ver que los jpgs tienen metadatos de orientación incrustados dentro. Cuando uso ImageTools (Grails Plugin) para generar una miniatura, los metadatos EXIF ​​no están en la miniatura, por lo que las miniaturas aparecen rotadas.

A través de conversaciones fuera de línea, aprendí que si bien es relativamente fácil leer los metadatos EXIF, no existe una manera fácil de escribirlo, por lo que los datos se pierden al generar una miniatura en formato jpg.

Entonces parece que tengo dos opciones:

  1. Use ImageMagick para generar las miniaturas. El inconveniente es que requiere más software instalado en nuestros servidores.
  2. Lea los datos de orientación EXIF ​​es código y gire la miniatura de forma adecuada.

¿Alguien sabe de alguna otra opción?


En base a las respuestas de Antoine Martin, creé una clase propia para corregir la orientación de una imagen jpeg dada (en mi caso como una secuencia de entrada) basada en la información exif de la imagen. Con su solución tuve el problema, que los colores de la imagen resultante estaban equivocados, por lo tanto, creé este. Para recuperar los metadatos de la imagen utilicé la biblioteca metadata-extractor .

Espero que ayude a algunas personas.

public class ImageOrientationUtil { /** * Checks the orientation of the image and corrects it if necessary. * <p>If the orientation of the image does not need to be corrected, no operation will be performed.</p> * @param inputStream * @return * @throws ImageProcessingException * @throws IOException * @throws MetadataException */ public static BufferedImage correctOrientation(InputStream inputStream) throws ImageProcessingException, IOException, MetadataException { Metadata metadata = ImageMetadataReader.readMetadata(inputStream); if(metadata != null) { if(metadata.containsDirectoryOfType(ExifIFD0Directory.class)) { // Get the current orientation of the image Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); int orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); // Create a buffered image from the input stream BufferedImage bimg = ImageIO.read(inputStream); // Get the current width and height of the image int[] imageSize = {bimg.getWidth(), bimg.getHeight()}; int width = imageSize[0]; int height = imageSize[1]; // Determine which correction is needed AffineTransform t = new AffineTransform(); switch(orientation) { case 1: // no correction necessary skip and return the image return bimg; case 2: // Flip X t.scale(-1.0, 1.0); t.translate(-width, 0); return transform(bimg, t); case 3: // PI rotation t.translate(width, height); t.rotate(Math.PI); return transform(bimg, t); case 4: // Flip Y t.scale(1.0, -1.0); t.translate(0, -height); return transform(bimg, t); case 5: // - PI/2 and Flip X t.rotate(-Math.PI / 2); t.scale(-1.0, 1.0); return transform(bimg, t); case 6: // -PI/2 and -width t.translate(height, 0); t.rotate(Math.PI / 2); return transform(bimg, t); case 7: // PI/2 and Flip t.scale(-1.0, 1.0); t.translate(height, 0); t.translate(0, width); t.rotate( 3 * Math.PI / 2); return transform(bimg, t); case 8: // PI / 2 t.translate(0, width); t.rotate( 3 * Math.PI / 2); return transform(bimg, t); } } } return null; } /** * Performs the tranformation * @param bimage * @param transform * @return * @throws IOException */ private static BufferedImage transform(BufferedImage bimage, AffineTransform transform) throws IOException { // Create an transformation operation AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BICUBIC); // Create an instance of the resulting image, with the same width, height and image type than the referenced one BufferedImage destinationImage = new BufferedImage( bimage.getWidth(), bimage.getHeight(), bimage.getType() ); op.filter(bimage, destinationImage); return destinationImage; } }


Esto se puede hacer sorprendentemente fácil utilizando la parte de la imagen de la biblioteca principal de JavaXT :

// Browsers today can''t handle images with Exif Orientation tag Image image = new Image(uploadedFilename); // Auto-rotate based on Exif Orientation tag, and remove all Exif tags image.rotate(); image.saveAs(permanentFilename);

¡Eso es!

He probado Apache Commons Imaging, pero fue un desastre. JavaXT es mucho más elegante.


Exif parece ser difícil de escribir debido a cosas patentadas en él. Sin embargo, puedes considerar otra opción

Lea el original, pero solo escriba la etiqueta de orientación en las miniaturas.

Apache Sanselan parece tener una buena colección de herramientas para hacerlo.

http://commons.apache.org/proper/commons-imaging/

Mire la clase ExifRewriter, por ejemplo.


La biblioteca Thumbnailator respeta las banderas de orientación EXIF. Para leer una imagen a tamaño completo con la orientación correcta:

BufferedImage image = Thumbnails.of(inputStream).scale(1).asBufferedImage();


Si desea rotar sus imágenes, le sugiero que use la biblioteca del extractor de metadatos http://code.google.com/p/metadata-extractor/ . Puede obtener la información de la imagen con el siguiente código:

// Inner class containing image information public static class ImageInformation { public final int orientation; public final int width; public final int height; public ImageInformation(int orientation, int width, int height) { this.orientation = orientation; this.width = width; this.height = height; } public String toString() { return String.format("%dx%d,%d", this.width, this.height, this.orientation); } } public static ImageInformation readImageInformation(File imageFile) throws IOException, MetadataException, ImageProcessingException { Metadata metadata = ImageMetadataReader.readMetadata(imageFile); Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); JpegDirectory jpegDirectory = metadata.getFirstDirectoryOfType(JpegDirectory.class); int orientation = 1; try { orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); } catch (MetadataException me) { logger.warn("Could not get orientation"); } int width = jpegDirectory.getImageWidth(); int height = jpegDirectory.getImageHeight(); return new ImageInformation(orientation, width, height); }

Luego, dada la orientación que recupera, puede rotar y / o voltear la imagen a la orientación correcta. La transformación Affine para la orientación EXIF ​​viene dada por el siguiente método:

// Look at http://chunter.tistory.com/143 for information public static AffineTransform getExifTransformation(ImageInformation info) { AffineTransform t = new AffineTransform(); switch (info.orientation) { case 1: break; case 2: // Flip X t.scale(-1.0, 1.0); t.translate(-info.width, 0); break; case 3: // PI rotation t.translate(info.width, info.height); t.rotate(Math.PI); break; case 4: // Flip Y t.scale(1.0, -1.0); t.translate(0, -info.height); break; case 5: // - PI/2 and Flip X t.rotate(-Math.PI / 2); t.scale(-1.0, 1.0); break; case 6: // -PI/2 and -width t.translate(info.height, 0); t.rotate(Math.PI / 2); break; case 7: // PI/2 and Flip t.scale(-1.0, 1.0); t.translate(-info.height, 0); t.translate(0, info.width); t.rotate( 3 * Math.PI / 2); break; case 8: // PI / 2 t.translate(0, info.width); t.rotate( 3 * Math.PI / 2); break; } return t; }

La rotación de la imagen se realizará mediante el siguiente método:

public static BufferedImage transformImage(BufferedImage image, AffineTransform transform) throws Exception { AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BICUBIC); BufferedImage destinationImage = op.createCompatibleDestImage(image, (image.getType() == BufferedImage.TYPE_BYTE_GRAY) ? image.getColorModel() : null ); Graphics2D g = destinationImage.createGraphics(); g.setBackground(Color.WHITE); g.clearRect(0, 0, destinationImage.getWidth(), destinationImage.getHeight()); destinationImage = op.filter(image, destinationImage); return destinationImage; }

En un entorno de servidor, no te olvides de ejecutar con -Djava.awt.headless=true


Si solo quieres que se vea bien. Simplemente puede agregar una "rotación" -PI / 2 (-90 grados), PI / 2 (90 grados), o PI (+180 grados) según sea necesario dependiendo de la ''orientación'' que ya haya extraído. El navegador o cualquier otro programa mostrará correctamente la imagen, ya que se habrá aplicado la orientación y eliminado los metadatos de la salida de la miniatura.