Android 使用Glide4.9 压缩并保存图片(jpg/png/gif)到本地


前言

项目中遇到,需要用户上传图片的场景。结果用户上传的、特别是拍摄后的图片,分辨率很大,长宽2000多3000甚至更高,一个图片5MB以上。 造成之后,从网络上加载这些图片,比较慢。
所以,不得不在上传前进行压缩后,再上传。


FileUtils 文件写入

/**
 * desc   : 
 * author : stone
 * email  : aa86799@163.com
 * time   : 2019/5/29 9:19
 */
public class FileUtils {
  
    //获取指定文件目录的内部文件(路径)
    public static File getAlbumStorageDir(Context context, String directory) {
        File file;
        //有sdcard
        if (TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)) {
            file = new File(Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES), directory);
        } else {
            file = new File(context.getCacheDir(), directory);
        }

        if (!file.mkdirs()) {
            LogUtils.e("ExtensionSignActivity", "Directory not created");
        }
        return file;
    }

	//保存 jpg/png的 Bitmap
    public static String saveBmp2Local(Context context, Bitmap bmp, String picName, boolean isPng) {
        // 声明文件对象
        File file = null;
        // 声明输出流
        FileOutputStream outStream = null;

        try {
            file = new File(getAlbumStorageDir(context, LFConfig.IMG_DIRECTORY_NAME), picName + (isPng ? ".png" : ".jpg"));

            // 获得输出流,如果文件中有内容,追加内容
            outStream = new FileOutputStream(file);
            bmp.compress(isPng ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.JPEG, 90, outStream);
        } catch (Exception e) {
            e.getStackTrace();
        } finally {
            try {
                if (outStream != null) {
                    outStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (file != null) {
            return file.getPath();
        }
        return null;
    }

   //保存gif。使用nio写入
    public static String saveGif2Local(Context context, ByteBuffer byteBuffer, String picName) throws FileNotFoundException {
        // 声明文件对象
        File file = null;
        // 声明输出流
        FileOutputStream outStream = null;
        FileChannel channel = null;
        try {
            file = new File(getAlbumStorageDir(context, LFConfig.IMG_DIRECTORY_NAME), picName + ".gif");

            // 获得输出流,如果文件中有内容,追加内容
            outStream = new FileOutputStream(file);
            channel = outStream.getChannel();
            //不能确定channel.write()能一次性写入buffer的所有数据
            //所以通过判断是否有余留循环写入
            while (byteBuffer.hasRemaining()) {
                channel.write(byteBuffer);
            }
        } catch (Exception e) {
            e.getStackTrace();
        } finally {
            try {
                if (outStream != null) {
                    outStream.close();
                }
                if (channel != null) {
                    channel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (file != null) {
            return file.getPath();
        }
        return null;
    }
}


Glide加载并压缩

结合rxjava#Obserable,在子线程中, 对图片路径做map变换。
用glide加载图片变换为 Bitmap 或 GifDrawable。
订阅后,进行压缩并保存到本地。
关于gif压缩,暂未考虑。

/**
 * 存储到本地
 * @param item      原始图片路径
 */
private void compressAndSaveItem(final String item) {
     String[] strArray = item.split("\\.");
     if (strArray.length > 0 && strArray[strArray.length - 1].toLowerCase().equals("gif")) {//判断后缀名是否是gif
         Observable.just(item)
                 .observeOn(Schedulers.io()) //整体运行行在子线程
                 .compose(RxJavaUtil.rxLife(PublishProductActivity.this)) //结合了rxlifecycle库
                 .map(s -> GlideApp.with(PublishProductActivity.this)
                         .asGif()
                         .load(s)
                         .fitCenter()
                         .submit()//原始分辨率
//                            .submit(720, 1080) //自定义分辨率
                         .get())
                 .subscribe(result -> {
                     int pointIndex = item.lastIndexOf(".");
                     int nameStartIndex = item.lastIndexOf("/") + 1;
                     int end;
                     if (pointIndex < nameStartIndex) {
                         end = item.length();
                     } else {
                         end = pointIndex;
                     }
                     String fileName = item.substring(nameStartIndex, end);

                     String path = FileUtils.saveGif2Local(PublishProductActivity.this,
                             result.getBuffer(),  fileName + "_copy");
                     /*
                      * 有了保存的压缩图片路径 path
                      * do other thing
                      */
                 }, error -> {
                     error.printStackTrace();
                 });
     } else {
         Observable.just(item)
                 .observeOn(Schedulers.io())//整体运行行在子线程
                 .compose(RxJavaUtil.rxLife(PublishProductActivity.this)) //结合了rxlifecycle库
                 .map(s -> GlideApp.with(PublishProductActivity.this)
                         .asBitmap()
                         .load(s)
                         .fitCenter()
                         .submit()//原始分辨率
//                            .submit(720, 1080) //自定义分辨率
                         .get())
                 .subscribe(result -> {
                     int pointIndex = item.lastIndexOf(".");
                     int nameStartIndex = item.lastIndexOf("/") + 1;
                     int end;
                     if (pointIndex < nameStartIndex) {
                         end = item.length();
                     } else {
                         end = pointIndex;
                     }
                     String fileName = item.substring(nameStartIndex, end);
					
					//缩放bitmap都为原宽高的1/2
                     Bitmap scaleBitmap = Bitmap.createScaledBitmap(result,
                             result.getWidth() / 2, result.getHeight() / 2, true);

                     String path = FileUtils.saveBmp2Local(PublishProductActivity.this, scaleBitmap
                             , fileName + "_copy",
                             strArray[strArray.length - 1].toLowerCase().equals("png"));
                     /*
                      * 有了保存的压缩图片路径 path
                      * do other thing
                      */
                 }, error -> {
                     error.printStackTrace();
                 });
     }

遇到了gif图片不显示的问题

太坑了,GifDrawable # getBuffer(),用nio保存的逻辑是没问题的。结果保存后的图片,无法展示了,貌似可能是Glide的bug,只能 删除掉 gif相关的代码,不使用glide处理了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要获取 GIF 图片的第一帧并保存到本地,可以使用 Glide 或者 BitmapFactory 进行处理,然后将 Bitmap 保存为图片文件。 使用 Glide: ```java Glide.with(context) .asBitmap() .load(gifUrl) .diskCacheStrategy(DiskCacheStrategy.DATA) .addListener(new RequestListener<Bitmap>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) { // 处理第一帧图片 saveBitmapToFile(resource, filePath); return false; } }) .submit(); ``` 使用 BitmapFactory: ```java // 获取 GIF 图片的字节数组 byte[] gifBytes = getGifBytes(gifUrl); if (gifBytes != null) { // 解码字节数组,获取第一帧图片 Bitmap bitmap = BitmapFactory.decodeByteArray(gifBytes, 0, gifBytes.length, null); // 处理第一帧图片 saveBitmapToFile(bitmap, filePath); } ``` 其中,`getGifBytes` 方法可以使用网络请求等方式获取 GIF 图片的字节数组,`saveBitmapToFile` 方法用于将 Bitmap 保存为图片文件: ```java public static void saveBitmapToFile(Bitmap bitmap, String filePath) { if (bitmap == null || TextUtils.isEmpty(filePath)) { return; } File file = new File(filePath); if (file.exists()) { file.delete(); } try { FileOutputStream fos = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } ``` 这里将 Bitmap 以 PNG 格式保存,可以根据需要修改为 JPG 等其他格式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值