Android图片压缩上传(整体压缩VS单张压缩)

Posted 亮亮在江湖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android图片压缩上传(整体压缩VS单张压缩)相关的知识,希望对你有一定的参考价值。

最近的项目中图片上传时遇到了anr的情况,下面看一下bugly上的错误

 主要说的是图片上传多张时先进行压缩,此时压缩超时,上报anr,针对这种情况采取了遍历图片集合单张上传,接下来会逐一介绍整体上传和单张上传的代码部分,下面两张gif图是展示单张和整体上传的效果。

                        单张压缩上传                                                               整体压缩上传

da  

 首先项目中添加所需要的依赖,图片选择器采用的是matisse,像朋友圈一样多张图片选择器,加载图片框架采用的是glide,网络框架是retrofit。

 implementation 'com.zhihu.android:matisse:0.5.3-beta3'
 implementation 'com.github.bumptech.glide:glide:4.9.0'
 implementation 'com.squareup.retrofit2:retrofit:2.1.0'

先来说一下整体压缩的主要代码,点击整体压缩按钮跳转到图片选择器页面,最多可以上传9张图片,其中uploadSumImg代表已上传的图片数量,最多设置为
.maxSelectablePerMediaType(9 - uploadSumImg, 1)

public void openPic() 
        if (uploadSumImg < 9) 
            Matisse.from(MoreUploadActivity.this)
                    .choose(MimeType.ofImage(), false)
                    .countable(true)
                    .capture(true)
                    .captureStrategy(new CaptureStrategy(true, BuildConfig.APPLICATION_ID+".fileprovider"))
                    .maxSelectablePerMediaType(9 - uploadSumImg, 1)
                    .gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
                    .addFilter((new util.GifSizeFilter(0, 0, 10 * Filter.K * Filter.K)))
                    .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
                    .thumbnailScale(0.85f)
                    .theme(R.style.Matisse_Dracula)//主题  暗色主题
                    .imageEngine(new GlideEngine())
                    .showSingleMediaType(true)
                    .maxOriginalSize(10)
                    .autoHideToolbarOnSingleTap(true)
                    .forResult(23);
        
    

选择完对应的图片确定后回调事件获取本地图片路径集合

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) 
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 23 && resultCode == RESULT_OK && data != null) 
            List<String> pathList = Matisse.obtainPathResult(data);
            List<Uri> uriList = Matisse.obtainResult(data);
            util.LoadingDialog.showDialog(this);
            if (uriList.size() > 0) 
                new Handler().postDelayed(() -> handleImage(uriList,pathList), 200);
            
        
    
    /**
     * 处理要添加的图片
     */
    private void handleImage(List<Uri> list, List<String> pathList) 
        String path = null;
        images.clear();
        for (int i = 0; i < list.size(); i++) 
            Uri uri = list.get(i);
            //根据不同的uri进行不同的解析
            if (DocumentsContract.isDocumentUri(this, uri)) 
                String docId = DocumentsContract.getDocumentId(uri);
                if ("com.android.providers.media.documents".equals(uri.getAuthority())) 
                    String id = docId.split(":")[1];
                    String selection = MediaStore.Images.Media._ID + "=" + id;
                    path = util.BusinessUtils.getImagePath(this,MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
                 else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) 
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
                    path = util.BusinessUtils.getImagePath(this,contentUri, null);
                
             else if ("content".equalsIgnoreCase(uri.getScheme())) 
                path = util.FileUtil.getFilePathFromURI(this, uri);
             else if ("file".equalsIgnoreCase(uri.getScheme())) 
                path = uri.getPath();
            
            images.add(new UploadImageBean(pathList.get(i), path));
        
        if (images.size() > 0) 
            uploadPicture(images);
        
    

此时将获取到的图片循环压缩,先尺寸压缩再进行质量压缩

public static String getCompressImage(String srcPath, int maxSize, String outputName) 
            BitmapFactory.Options newOpts = new BitmapFactory.Options();
            //开始读入图片,此时把options.inJustDecodeBounds 设回true了
            newOpts.inJustDecodeBounds = true;
            //此时返回bm为空
            Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);

            newOpts.inJustDecodeBounds = false;
            int w = newOpts.outWidth;
            int h = newOpts.outHeight;
            //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
            DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
            int hh,ww;
            if (getFileSize(new File(srcPath)) / 1024 > maxSize) 
                if (w >= 3000 && h >= 3000) 
                    if(w>=h)
                        hh = 2500;
                        ww = 2501;
                    else 
                        hh = 2500;
                        ww = 2500;
                    
                 else 
                    hh = dm.heightPixels;
                    ww = dm.widthPixels;
                
             else 
                hh = h;
                ww = w;
            
    //        float hh = 800f;//这里设置高度为800f
    //        float ww = 480f;//这里设置宽度为480f
            //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
            int be = 1;//be=1表示不缩放
            if (w > h && w > ww) //如果宽度大的话根据宽度固定大小缩放
                be =Math.round ((float) newOpts.outWidth / ww);
             else if (w < h && h > hh) //如果高度高的话根据宽度固定大小缩放
                be = Math.round((float) newOpts.outHeight / hh);
            
            if (be <= 0)
                be = 1;
            newOpts.inSampleSize = be;//设置缩放比例
            //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
            bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
            int degree = readPictureDegree(srcPath);
            bitmap = rotateBitmap(bitmap, degree);
            bitmap = qualityCompressImage(bitmap, maxSize);//压缩好比例大小后再进行质量压缩

            String path = saveBitmap(outputName,bitmap);
            if(bitmap!=null)
                bitmap.recycle();
            
            return path;
        

调用上传接口,获取到后台返回的图片集合,设置成功后绘制在页面

//图片上传
        Call<ResponseImgBean> uploadResultCall = RetrofitBuild.getAnInterface().uploadImage(parts);
        uploadResultCall.enqueue(new Callback<ResponseImgBean>() 
            @Override
            public void onResponse(Call<ResponseImgBean> call, Response<ResponseImgBean> response) 
                util.LoadingDialog.dismissDialog();
                if(response.body().isSuccess())
                    List<String> urls = response.body().getData();
                    List<ImageBean> beans = new ArrayList<>();
                    for(int i = 0;i<urls.size();i++)
                        ImageBean bean = new ImageBean();
                        File file ;
                        if (images.get(i).isGif()) 
                            file = new File(images.get(i).getRealPath());
                         else 
                            file = new File(Environment.getExternalStorageDirectory(), "boxCompress" + i + ".jpg");
                        
                        List<Integer> size = util.BitmapUtils.getImageSize(file.getAbsolutePath());
                        bean.setUrl(urls.get(i));
                        bean.setWidth(size.get(0));
                        bean.setHeight(size.get(1));
                        if(!images.get(i).isGif()&&file.exists())
                            file.delete();
                        
                        beans.add(bean);
                    

                    if (beans.size() != images.size()) 
                        Toast.makeText(MoreUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
                        return;
                     else 
                        for (int i = 0; i < beans.size(); i++) 
                            beans.get(i).setPath(images.get(i).getUriPath());
                        
                    
                    imageEditor.addImage(beans);
                    images.clear();
                 else 
                    Toast.makeText(MoreUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
                
            

            @Override
            public void onFailure(Call<ResponseImgBean> call, Throwable t) 
                Toast.makeText(MoreUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
                util.LoadingDialog.dismissDialog();
            
        );
    

第二种采取单张压缩上传,用同样的方式获取到本地图片的路径集合,然后采用单独压缩

//图片压缩
    private void checkImage()
        UploadImageBean uploadImageBean = imageList.get(0);
        if (uploadImageBean.isGif()) 
            uploadPicture(uploadImageBean.getRealPath());
         else 
            util.ImageCompressTask compressTask = new util.ImageCompressTask(new util.ImageCompressTask.CompressListener() 
                @Override
                public void Success(String imagePath) 
                    uploadPicture(imagePath);
                
            );
            compressTask.execute(uploadImageBean.getUriPath(), "boxCompress" + 0 + ".jpg");
        
    


public static class ImageCompressTask extends AsyncTask<String, Integer, String> 
        private final CompressListener compressListener;
        public ImageCompressTask(CompressListener listener)
            compressListener = listener;
        
        @Override
        protected String doInBackground(String... strings) 
            String imagePath = strings[0];
            String outputName = strings[1];
            return BitmapUtils.getCompressImage(imagePath, 1024, outputName);
        

        @Override
        protected void onPostExecute(String path) 
            if(compressListener != null)
                compressListener.Success(path);
            
        

        public static interface CompressListener 
            void Success(String imagePath);
        
    

最后调用图片上传接口,

//图片上传
    private void uploadPicture(String path) 
        List<MultipartBody.Part> parts = new ArrayList<>();
        File file = new File(path);
        RequestBody fileRQ = RequestBody.create(MediaType.parse("image/*"), file);
        MultipartBody.Part part = MultipartBody.Part.createFormData("files", file.getName(), fileRQ);
        parts.add(part);

        Call<ResponseImgBean> uploadResultCall = RetrofitBuild.getAnInterface().uploadImage(parts);
        uploadResultCall.enqueue(new Callback<ResponseImgBean>() 
            @Override
            public void onResponse(Call<ResponseImgBean> call, Response<ResponseImgBean> response) 
                if(response.body().isSuccess())
                    List<String> urls = response.body().getData();
                    List<ImageBean> beans = new ArrayList<>();
                    ImageBean bean = new ImageBean();
                    File file;
                    if (imageList.get(0).isGif()) 
                        file = new File(imageList.get(0).getRealPath());
                     else 
                        file = new File(Environment.getExternalStorageDirectory(), "boxCompress" + 0 + ".jpg");
                    
                    List<Integer> size = util.BitmapUtils.getImageSize(file.getAbsolutePath());
                    bean.setUrl(urls.get(0));
                    bean.setWidth(size.get(0));
                    bean.setHeight(size.get(1));
                    if (!imageList.get(0).isGif() && file.exists()) 
                        file.delete();
                    
                    beans.add(bean);
                    imageList.remove(0);

                    if(beans != null)
                        beans.get(0).setPath(images.get(0).getUriPath());
                        imageEditor.addImage(beans);
                    
                    images.remove(0);
                    if (imageList.size() == 0) 
                        util.LoadingDialog.dismissDialog();
                     else 
                        checkImage();
                    
                 else 
                    util.LoadingDialog.dismissDialog();
                    Toast.makeText(SingleUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
                
            

            @Override
            public void onFailure(Call<ResponseImgBean> call, Throwable t) 
                Toast.makeText(SingleUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
                imageList.remove(0);
                images.remove(0);
                if(imageList.size()>0) 
                    checkImage();
                else
                    util.LoadingDialog.dismissDialog();
                
            
        );
    

imageList为要上传的图片集合,每一张图片上传成功后移除调首位置的图片imageList.remove(0);
 

如果移除不是最后一个,那么重新调用图片压缩上传,直到最后结束。

 if (imageList.size() == 0) 
       util.LoadingDialog.dismissDialog();
   else 
          checkImage();
    

到这里图片的两种压缩上传方式也讲完了,希望本文对有需要的同学帮助,欢迎讨论。最后附上本文的demo  代码下载

以上是关于Android图片压缩上传(整体压缩VS单张压缩)的主要内容,如果未能解决你的问题,请参考以下文章

Android图片压缩上传(整体压缩VS单张压缩)

JS—图片压缩上传(单张)

uni-app 图片上传压缩方法 拍照图片过大

多张图片上传并压缩

base64文件转MultipartFile文件

微信小程序压缩图片并上传到服务器(拿去即用)