xieegai

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

问题:手机照片上传时,会发现ios手机上传竖拍照片会逆时针旋转90度,横拍照片无此问题;而Android不会出现这种现象。

原因:ios系统默认Orientation属性为1,与常规机器拍摄图片的Orientation属性不一致。

方案:读取文件Exif信息,获取Orientation属性,修改Orientation属性为0。

Orientation属性属性说明如下:

旋转角度 参数
1
顺时针90° 6
逆时针90° 8
180° 3

读取Exif信息:

(依赖:metadata-extractor-2.10.1.jar,xmpcore-5.1.2.jar)

package img;

import java.io.*;
import java.util.Collection;
import java.util.Iterator;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.*;
import com.drew.metadata.exif.ExifIFD0Directory;

/**
 * 获取图片exif信息
 * @date 2018年1月30日 下午8:29:32
 * @see http://blog.csdn.net/z69183787/article/details/50320821
 * @see http://blog.csdn.net/linlzk/article/details/48652635
 * @see http://blog.csdn.net/itsonglin/article/details/46405313
 */
public class CatchEXIF {
    public static void main(String[] args) throws Exception {  
        File file = new File("D:\\test\\test\\UNADJUSTEDNONRAW_thumb_b.jpg"); 
        Metadata metadata = ImageMetadataReader.readMetadata(file);
        /*旧版本
        Directory directory = metadata.getDirectory(ExifIFD0Directory.class);  
        JpegDirectory jpegDirectory = (JpegDirectory)metadata.getDirectory(JpegDirectory.class); */
        Iterable<Directory> directories = metadata.getDirectories();
        Iterator<Directory> iterator = directories.iterator();
        while (iterator.hasNext()) {
            Directory exif = iterator.next();
            int orientation = -1;
            if (exif.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
                System.out.println("*********************************************************");
                orientation = exif.getInt(ExifIFD0Directory.TAG_ORIENTATION);
                System.out.println(orientation);
                String description = exif.getDescription(ExifIFD0Directory.TAG_ORIENTATION);
                System.out.println(description);
                System.out.println("*********************************************************");
            }
            
            Collection<Tag> tags = exif.getTags();
            for (Tag tag : tags) {
                System.out.println(tag);
            }
        }
    } 
}

更改Exif信息:

package img;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.media.jai.PlanarImage;
import com.alibaba.simpleimage.ImageFormat;
import com.alibaba.simpleimage.ImageWrapper;
import com.alibaba.simpleimage.SimpleImageException;
import com.alibaba.simpleimage.render.CropParameter;
import com.alibaba.simpleimage.render.WriteParameter;
import com.alibaba.simpleimage.util.ImageCropHelper;
import com.alibaba.simpleimage.util.ImageWriteHelper;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifImageDirectory;

/**
 * 测试  获取图片旋转信息并处理
 * 图片旋转和剪切
 * @date 2018年1月30日 下午6:48:30
 */
public class CatchEXIF2 {
	
	public static void main(String[] args) throws Exception {
		// 输入输出文件路径/文件
		String src = "D:\\test\\微信图片_20180130193655.jpg";
		String dest = "D:\\test\\teswwwwt.jpg";
		File srcFile = new File(src);
		File destFile = new File(dest);
		// 将输入文件转换为字节数组
		byte[] bytes = getByte(srcFile);
		// 构造输入输出字节流
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		ByteArrayInputStream is = new ByteArrayInputStream(bytes);
		
		/*处理图片*/
		// 判断是否旋转并纠正
		BufferedImage bufferedImage = getExifAndTurn(bytes);
		// 缩放和剪切
		zoomAndCut(bufferedImage, os, 400, 400);
		
		// 将字节输出流写到输出文件路径下
		writeFile(os, destFile);
		os.close();
		is.close();
	}
	
	/**
     * 获取图片信息,并判断是否要做旋转操作
     * (ios图片可能会发生旋转现象)
     * @param is
     */
    public static BufferedImage getExifAndTurn(byte[] bytes){
    	ByteArrayInputStream is = null;
    	ByteArrayInputStream its = null;
    	BufferedImage result = null;
		try {
			is = new ByteArrayInputStream(bytes);
			Metadata metadata = ImageMetadataReader.readMetadata(is);
			Iterable<Directory> directories = metadata.getDirectories();
			Iterator<Directory> iterator = directories.iterator();
			int orientation = 0;
			int angel = 360;
			while (iterator.hasNext()) {
				Directory exif = iterator.next();
				// 获取图片旋转信息
				if (exif.containsTag(ExifImageDirectory.TAG_ORIENTATION)) {
					String description = exif.getDescription(ExifImageDirectory.TAG_ORIENTATION);
					orientation = getOrientation(description);
				}
			}
			
			if(orientation == 0 || orientation == 1) {  
	        	angel = 360;  
	        }  
	        else if(orientation == 3) {  
	        	angel = 180;  
	        }  
	        else if(orientation == 6) {  
	        	angel = 90;  
	        }  
	        else if(orientation == 8) {  
	        	angel = 270;  
	        }  
			
			its = new ByteArrayInputStream(bytes);
			result = ImageIO.read(its);
			// 旋转
			if(angel != 360){
				result = turn(result, angel);
			}
		} catch (ImageProcessingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				its.close();
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}
    
    /**
     * 获取图片旋转标志
     * @param description 图片旋转描述信息
     * @return
     */
    public static int getOrientation(String description) {  
        int orientation = 0;  
        if ("Top, left side (Horizontal / normal)".equalsIgnoreCase(description)) {  
        	orientation = 1;  
        } else if ("Top, right side (Mirror horizontal)".equalsIgnoreCase(description)) {  
        	orientation = 2;  
        } else if ("Bottom, right side (Rotate 180)".equalsIgnoreCase(description)) {  
        	orientation = 3;  
        } else if ("Bottom, left side (Mirror vertical)".equalsIgnoreCase(description)) {  
        	orientation = 4;  
        } else if ("Left side, top (Mirror horizontal and rotate 270 CW)".equalsIgnoreCase(description)) {  
        	orientation = 5;  
        } else if ("Right side, top (Rotate 90 CW)".equalsIgnoreCase(description)) {  
        	orientation = 6;  
        } else if ("Right side, bottom (Mirror horizontal and rotate 90 CW)".equalsIgnoreCase(description)) {  
        	orientation = 7;  
        } else if ("Left side, bottom (Rotate 270 CW)".equalsIgnoreCase(description)) {  
        	orientation = 8;  
        }  
        return  orientation;  
    }  
    
    /**
     * 图片旋转
     * @param degree 旋转角度
     */
    public static BufferedImage turn(BufferedImage bi, int degree) {
    	BufferedImage result = null;
    	try {
    		int swidth = 0; // 旋转后的宽度
            int sheight = 0; // 旋转后的高度
            int x; // 原点横坐标
            int y; // 原点纵坐标

            // 处理角度--确定旋转弧度
            degree = degree % 360;
            if (degree < 0) {
                degree = 360 + degree;// 将角度转换到0-360度之间
            }
            double theta = Math.toRadians(degree);// 将角度转为弧度

            // 确定旋转后的宽和高
            if (degree == 180 || degree == 0 || degree == 360) {
                swidth = bi.getWidth();
                sheight = bi.getHeight();
            } else if (degree == 90 || degree == 270) {
                sheight = bi.getWidth();
                swidth = bi.getHeight();
            } else {
                swidth = (int) (Math.sqrt(bi.getWidth() * bi.getWidth() + bi.getHeight() * bi.getHeight()));
                sheight = (int) (Math.sqrt(bi.getWidth() * bi.getWidth() + bi.getHeight() * bi.getHeight()));
            }
            // 确定原点坐标
            x = (swidth / 2) - (bi.getWidth() / 2);
            y = (sheight / 2) - (bi.getHeight() / 2);

            result = new BufferedImage(swidth, sheight, bi.getType());
            // 设置图片背景颜色
            Graphics2D gs = (Graphics2D) result.getGraphics();
            gs.setColor(Color.white);
            gs.fillRect(0, 0, swidth, sheight);// 以给定颜色绘制旋转后图片的背景

            AffineTransform at = new AffineTransform();
            at.rotate(theta, swidth / 2, sheight / 2);// 旋转图象
            at.translate(x, y);
            AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
            result = op.filter(bi, result);
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return result;
    }
    
    
    /**
     * 将file文件转为字节数组
     * @param file
     */
    public static byte[] getByte(File file){
    	byte[] bytes = null;
    	try {
			FileInputStream fis = new FileInputStream(file);
			bytes = new byte[fis.available()];
			fis.read(bytes);
			fis.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
    	return bytes;
    }
  
    /**
     * 将字节流写到指定文件
     * @param os
     * @param file
     */
    public static void writeFile(ByteArrayOutputStream os, File file){
    	FileOutputStream fos = null;
    	try {
    		byte[] bytes = os.toByteArray();
    		if (file.exists()) {
				file.delete();
			}
			fos = new FileOutputStream(file);
			fos.write(bytes);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
    }

    /**
     * 先等比例缩放,小边缩放至指定长度后, 大边直接裁剪指指定长度
     * @param bufferedImage
     * @param os
     * @param width
     * @param height
     */
    public static void zoomAndCut(BufferedImage bufferedImage, OutputStream os, Integer width, Integer height) {
		try {
			int w = bufferedImage.getWidth();
	    	int h = bufferedImage.getHeight();
	    	// 获取缩放比例
	    	double wRatio = 1.0 * width / w;
	    	double hRatio = 1.0 * height / h;
	    	double ratio = Math.max(wRatio, hRatio);
	    	// 缩放
	    	AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);
	    	bufferedImage = ato.filter(bufferedImage, null);
	    	// 对象转换
	    	ImageWrapper imageWrapper = new ImageWrapper(bufferedImage);
	    	
	    	// 获得裁剪偏移量
	    	int w2 = imageWrapper.getWidth();
	    	int h2 = imageWrapper.getHeight();
	    	float x = (w2 - width) / 2.0f;
	    	float y = (h2 - height) / 2.0f;
	    	// 裁剪参数   如果图片宽和高都小于目标图片则处理
	    	CropParameter cropParameter = new CropParameter(x, y, width, height);
	    	if (x < 0 && y < 0) {
	    		cropParameter = new CropParameter(0, 0, width, height);
			}
	    	PlanarImage crop = ImageCropHelper.crop(imageWrapper.getAsPlanarImage(), cropParameter);
	    	imageWrapper = new ImageWrapper(crop);
	    	// 写文件
	    	ImageWriteHelper.write(imageWrapper, os, ImageFormat.getImageFormat("jpg"), new WriteParameter());
	    	os.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SimpleImageException e) {
			e.printStackTrace();
		}
    }
}

  

 

posted on 2018-02-07 17:22  xieegai  阅读(511)  评论(0编辑  收藏  举报