如何根据方向元数据旋转 JPEG 图像? [英] How to rotate JPEG images based on the orientation metadata?

查看:24
本文介绍了如何根据方向元数据旋转 JPEG 图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些服务器代码可以在上传图像时生成缩略图.问题是,当拍摄图像并旋转相机/设备时,缩略图也会旋转,即使全尺寸图像本身在任何图像查看软件中都以正确的方向显示.这只发生在 jpg 上.

I have some server code that is generating thumbnails when an image is uploaded. The issue is that when the image was taken and the camera/device was rotated, the thumbnails are rotated, even though the full size images themselves are displayed in the correct orientation in any image viewing software. This is only happening with jpgs.

在 OSX 上使用预览,我可以看到 jpg 中嵌入了方向元数据.当我使用 ImageTools(Grails 插件)生成缩略图时,EXIF 元数据不在缩略图中,这就是缩略图出现旋转的原因.

Using Preview on OSX, I can see that jpgs have orientation metadata embedded within. When I use ImageTools (Grails Plugin) to generate a thumbnail, the EXIF metadata is not in the thumbnail, which is why the thumbnails appear rotated.

通过离线对话,我了解到虽然读取EXIF元数据相对容易,但编写它却没有简单的方法,这就是为什么生成jpg缩略图时数据丢失的原因.

Via offline conversations, I have learned that while it is relatively easy to read EXIF metadata, there is no easy way to write it, which is why the data is lost when generating a jpg thumbnail.

所以看来我有两个选择:

So it seems I have two options:

  1. 使用 ImageMagick 生成缩略图.缺点是它需要在我们的服务器上安装更多软件.
  2. 读取 EXIF 方向数据代码并适当旋转缩略图.

有人知道其他选择吗?

推荐答案

如果您想旋转图像,我建议使用元数据提取器库 http://code.google.com/p/metadata-extractor/.可以通过以下代码获取图片信息:

If you want to rotate your images, I would suggest to use the metadata extractor library http://code.google.com/p/metadata-extractor/. You can get the image information with the following code:

// 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);
}

然后根据您检索的方向,您可以将图像旋转和/或翻转到正确的方向.EXIF 方向的仿射变换由以下方法给出:

Then given the orientation you retrieve, you can rotate and/or flip the image to the right orientation. The Affine transform for the EXIF orientation is given by the following method:

// 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;
}

图像的旋转将通过以下方法完成:

The rotation of the image would be done by the following method:

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;
}

在服务器环境中,不要忘记使用 -Djava.awt.headless=true

In a server environment, don't forget to run with -Djava.awt.headless=true

这篇关于如何根据方向元数据旋转 JPEG 图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆