如何避免Image上传到服务器后发生转角度Rotation错误

在社区、论坛我们经常会上传一些图片啊、视频啊等多媒体文件到服务器,但有时候上传一些从相机里选择的图片会显示错误,图片翻转了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;
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值