• 获取图片Exif信息


    问题:手机照片上传时,会发现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();
    		}
        }
    }
    

      

  • 相关阅读:
    Creating a Simple Direct2D Application
    关于ssh加密方式的理解
    关于2147217913 从 char 数据类型到 datetime 数据类型的转换导致 datetime 值越界 的问题解决方法
    关于 win2003中ASP.Net 的edit configuration 无法使用的答疑
    vc 用ado访问Oracle数据库的代码示例
    手工移除vs6的VSS绑定
    关于:无法执行值从 char 到 char 的隐性转换,因为该值的排序规则因排序规则冲突而未能解决
    vs2003 无法进行调试的经历
    关于如何在VMware上安装Puppy Linux
    VB: DataGrid 的列可见问题
  • 原文地址:https://www.cnblogs.com/xieegai/p/8427618.html
Copyright © 2020-2023  润新知