问题:手机照片上传时,会发现ios手机上传竖拍照片会逆时针旋转90度,横拍照片无此问题;而Android不会出现这种现象。
原因:ios系统默认Orientation属性为1,与常规机器拍摄图片的Orientation属性不一致。
方案:读取文件Exif信息,获取Orientation属性,修改Orientation属性为0。
Orientation属性属性说明如下:
旋转角度 | 参数 |
0° | 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(); } } }