问题:手机照片上传时,会发现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();
}
}
}
浙公网安备 33010602011771号