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

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

问题描述

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



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



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



因此,我似乎有两个选择:


  1. 使用ImageMagick生成缩略图。缺点是它需要在我们的服务器上安装更多的软件。

  2. 阅读EXIF方向数据是代码并适当地旋转缩略图。

有没有人知道其他选项? 如果你想旋转你的图片,我建议使用元数据提取器库 http://code.google.com/p/metadata -extractor / 。您可以使用以下代码获取图像信息:

  // //包含图像信息的内部类
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) ; (File imageFile)抛出IOException,MetadataException,ImageProcessingException {
元数据元数据= ImageMetadataReader.readMetadata(imageFile){
}
}


public static ImageInformation readImageInformation ;
目录目录= metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
JpegDirectory jpegDirectory = metadata.getFirstDirectoryOfType(JpegDirectory.class);

int orientation = 1;
尝试{
orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
} catch(MetadataException me){
logger.warn(Could not get orientation);
}
int width = jpegDirectory.getImageWidth();
int height = jpegDirectory.getImageHeight();

返回新的ImageInformation(orientation,width,height);
}

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

  //查看http://chunter.tistory。 com / 143获取信息
public static AffineTransform getExifTransformation(ImageInformation info){

AffineTransform t = new AffineTransform();

switch(info.orientation){
案例1:
break;
案例2://翻转X
t.scale(-1.0,1.0);
t.translate(-info.width,0);
休息;
案例3:// PI旋转
t.translate(info.width,info.height);
t.rotate(Math.PI);
休息;
案例4://翻转Y
t.scale(1.0,-1.0);
t.translate(0,-info.height);
休息;
case 5:// - PI / 2和Flip X
t.rotate(-Math.PI / 2);
t.scale(-1.0,1.0);
休息;
案例6:// -PI / 2和-width
t.translate(info.height,0);
t.rotate(Math.PI / 2);
休息;
案例7:// PI / 2和翻转
t.scale(-1.0,1.0);
t.translate(-info.height,0);
t.translate(0,info.width);
t.rotate(3 * Math.PI / 2);
休息;
case 8:// PI / 2
t.translate(0,info.width);
t.rotate(3 * Math.PI / 2);
休息;
}

return t;

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

  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;

$ / code>

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


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.

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.

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. Use ImageMagick to generate the thumbnails. The downside is it requires installed more software on our servers.
  2. Read the EXIF Orientation data is code and rotate the thumbnail appropriately.

Does anyone know of any other options?

解决方案

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

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

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

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

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