在社区、论坛我们经常会上传一些图片啊、视频啊等多媒体文件到服务器,但有时候上传一些从相机里选择的图片会显示错误,图片翻转了90度。。虽然对于程序员来说,偶尔动一下脖子歪着看问题也不大~但对于用户来说,这是一个很严重的问题。
那原因是什么呢,明明在相册里的图片好好的,一上传到服务器就歪呢。经过分析,就是在相片的Rotation没有设置好,需要在上传之前再调整一次。
那要怎么做呢-->1.根据相册返回的uri,重新生成一张一样的图片 -> 2.对图片的Rotation进行修改 -> 3.根据新图片的绝对路径获取相应的contentUri -> 4.上传图片
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.photo);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//打开多媒体Document 也可以使用ACIONT_GET_CONTENT 但官方建议4.4以上都是用Document
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(DOCUMENTS_UI_POLICY, DOCUMENTS_UI_POLICY_SEC);
intent.setType("image/*");
startActivityForResult(intent, 2);
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if (requestCode == 2) {
if (resultCode == Activity.RESULT_CANCELED) {
return;
}
//当返回的resultCode = OK时,通过getData获取图片的Uri
Uri result = (data == null || resultCode != Activity.RESULT_OK ? null : data.getData());
if (result != null) {
String absPath = getImagePathFromUri(getBaseContext(), result);
//获取文件的扩展名,假如没有则返回null
String fileExtension = getFileExtension(absPath);
//getExternalFilesDir:获取到 SDCard/Android/data/你的应用的包名/files/ 目录
String newFilePath = getBaseContext().getExternalFilesDir(Environment.DIRECTORY_DCIM) + File.separator + System.currentTimeMillis() + "." +fileExtension;
result = getRightRotationUri(getBaseContext(), result, absPath, newFilePath);
}
}
}
public String getImagePathFromUri(Context context, Uri uri){
//因为是从ACTION_OPEN_DOCUMENT打开,所以要调用DocumentsContract.getDocumentId获取Uri的id
String id = DocumentsContract.getDocumentId(uri);
String[] split = id.split(":");
String[] args = new String[]{split[1]};
//通过ContentProvider.getContentResolver()通过id查询当前图片信息
String selection = MediaStore.Images.Media._ID + "= ?";
String pro = MediaStore.Images.Media.DATA;
String[] projection = new String[]{ pro };
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, args, null);
if (cursor != null) {
cursor.moveToFirst();
//寻找DATA的队列并获取图片的AbsolutePath
int index = cursor.getColumnIndexOrThrow(pro);
try {
String imagePath = cursor.getString(index);
if (imagePath != null) {
return imagePath;
}
}catch (Exception e){
e.printStackTrace();
}
finally {
cursor.close();
}
}
return null;
}
public String getFileExtension(String filePath) {
if (filePath == null) {
return null;
}
int docIndex = filePath.lastIndexOf(".");
if (docIndex != -1) {
return filePath.substring(docIndex + 1, filePath.length());
}
return null;
}
public Uri getRightRotationUri(Context context, Uri uri, String filePath, String fileName){
String fileExtension = getFileExtension(filePath);
//getMimeTypeFromExtension直接使用的根据扩展名获取mimetype
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
if (mimeType != null) {
mimeType = mimeType.split("/")[0];
}
if (Objects.equals(mimeType, "image")) {
//假如不是gif文件,对相片进行Rotation处理。
if (Objects.equals(fileExtension, "gif")) {
return uri;
}
try{
//根据原图片的uri,重新生成一张压缩过的同样图片
Bitmap bitmap = getBitmapFromUri(context, uri);
if (bitmap == null) {
return uri;
}
int degrees = getImageDegrees(filePath);
bitmap = rotation(bitmap, degrees);
return getCacheBitmapUri(context, bitmap, fileName, fileExtension);
}catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
public Bitmap getBitmapFromUri(Context context, Uri uri) throws IOException{
//通过contentProvider,获取图片在数据库的数据流
InputStream inputStream = context.getContentResolver().openInputStream(uri);
BitmapFactory.Options options = new BitmapFactory.Options();
// inJustDecodeBounds值设为true那么将不返回实际的bitmap,也不给其分配内存空间这样就避免内存溢出了。但是允许我们查询图片的信息
options.inJustDecodeBounds = true;
//是否采用抖动解码,true的话会在色带上采用随机噪声色来填充,目的是让这张图显示效果更好,色带不那么明显
options.inDither = true;
//表示图片解码时使用的颜色模式,也就是图片中每个像素颜色的表示方式(ARGB_8888 图片中每个像素用四个字节(32位)存储,Alpha,R,G,B四个通道每个通道用8位表示)
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
BitmapFactory.decodeStream(inputStream, null, options);
if (inputStream != null) {
inputStream.close();
}
int originWidth = options.outWidth;
int originHeight = options.outHeight;
if (originWidth == -1 || originHeight == -1) {
return null;
}
float h = 1920f;
float w = 1080f;
int b = 1; //b=1表示不缩放
//如果宽度大的话根据宽度固定大小缩放
if (originWidth > originHeight && originWidth > w) {
b = (int) (originWidth / w);
}
//如果高度高的话根据宽度固定大小缩放
else if (originWidth < originHeight && originHeight > h) {
b = (int) (originHeight / h);
}
if (b <= 0) {
b = 1;
}
BitmapFactory.Options bitOptions = new BitmapFactory.Options();
bitOptions.inSampleSize = b; //设置压缩比例
bitOptions.inDither = true;
bitOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
inputStream = context.getContentResolver().openInputStream(uri);
//为了避免OOM,在decodeStream之前对图片进行压缩
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, bitOptions);
if(inputStream != null) {
inputStream.close();
}
return compressImage(bitmap);
}
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();//重置baos即清空baos
//第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差 ,第三个参数:保存压缩后的数据的流
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
options -= 10;//每次都减少10
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
return bitmap;
}
public int getImageDegrees(String filePath) {
int d = 0;
try {
// 从指定路径下读取图片,并获取其EXIF信息
/*Android开发中,在对图片进行展示、编辑、发送等操作时经常会涉及Exif的操作,Android中操作Exif主要是通过ExifInterface.
*ExifInterface看上去是一个接口,其实是一个类,位于Android.media.ExifInterface的位置。
*进入ExifInterface类,发现方法很少,主要就是三个方面:读取、写入、缩略图。
*/
ExifInterface exifInterface = new ExifInterface(filePath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
d = ExifInterface.ORIENTATION_ROTATE_90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
d = ExifInterface.ORIENTATION_ROTATE_180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
d = ExifInterface.ORIENTATION_ROTATE_270;
break;
}
}catch (Exception e) {
e.printStackTrace();
}
return d;
}
public Bitmap rotation(Bitmap bitmap, int degrees){
Bitmap returnBitmap = null;
Matrix matrix = new Matrix();
// 根据旋转角度,生成旋转矩阵
matrix.postRotate(degrees);
try {
// 将原始图片按照旋转矩阵进行旋转,并得到新的图片
returnBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}catch (Exception e) {
e.printStackTrace();
}
if (returnBitmap == null) {
returnBitmap = bitmap;
}
if (bitmap != returnBitmap) {
bitmap.recycle();
}
return returnBitmap;
}
public Uri getCacheBitmapUri(Context context, Bitmap bitmap, String fileName, String fileExtension){
File cacheFile = new File(fileName);
if (cacheFile.exists()) {
cacheFile.delete();
}
try {
FileOutputStream os = new FileOutputStream(cacheFile);
if ("jpg".equalsIgnoreCase(fileExtension) || "jpeg".equalsIgnoreCase(fileExtension)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
}else if ("png".equalsIgnoreCase(fileExtension)) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
}else if ("webp".equalsIgnoreCase(fileExtension)) {
bitmap.compress(Bitmap.CompressFormat.WEBP, 100, os);
}else {
bitmap.compress(Bitmap.CompressFormat.JPEG,100, os);
}
os.flush();
os.close();
}catch (Exception e) {
e.printStackTrace();
}
return getImageContentUri(context, cacheFile);
}
public Uri getImageContentUri(Context context, File imageFile) {
String filePath = imageFile.getAbsolutePath();
Uri contentUri;
Uri mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = context.getContentResolver().query(mediaUri,
new String[] { MediaStore.Images.Media._ID }, MediaStore.Images.Media.DATA + "=? ",
new String[] { filePath }, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
contentUri = Uri.withAppendedPath(mediaUri, "" + id);
} else {
//通过FileProvider把我们的file转化为content://uri了,详细参考:https://blog.csdn.net/soslinken/article/details/70145354
contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", imageFile);
}
cursor.close();
} else {
contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", imageFile);
}
return contentUri;
}