Android图片压缩(包含拍照或从相册选取图片,PopupWindow的使用)

目前大部分智能手机拍照效果好,图片像素很高.但是在存储或传输图片的时候不太方便,需要首先将其进行压缩.
先看看效果图.
首界面 弹出PopupWindow选择拍照或从相册选取 压缩前后效果图对比
注意,最后一张图片显示的压缩前后两张图似乎没有太大区别,但事实上压缩前图片为1.6MB,压缩后只有141KB.(如有需要可以根据源代码自己对压缩后图片大小进行调整,我这里设置的是压缩后图片大小不超过200KB.压缩后的图片会保存在SD卡的PicCompress文件夹下)
完整的源代码以及下载链接我会在后面给出下载链接,下面我对程序用到的几个重要的函数进行简单说明.
首先是图片压缩函数.这里给出了两个压缩函数(两种方式的输入不一样,大家可以根据自己的需要进行选择),第一个函数是compressImage(String path, int size)

   /**
     * 压缩图片。
     * @param path  图片路径
     * @param size  压缩后图片最大尺寸(单位:KB)
     * @return 压缩后的图片
     * @throws IOException
     */
    public static Bitmap compressImage(String path, int size)
            throws IOException {
        Bitmap bitmap = null;
        // 取得图片
        InputStream is = new FileInputStream(path);
        BitmapFactory.Options options = new BitmapFactory.Options();
        // 这个参数代表,不为bitmap分配内存空间,只记录一些该图片的信息(例如图片大小),说白了就是为了内存优化
        options.inJustDecodeBounds = true;
        // 通过创建图片的方式,取得options的内容(这里就是利用了java的地址传递来赋值)
        BitmapFactory.decodeStream(is, null, options);
        // 关闭流
        is.close();
        // // 生成压缩的图片
        int i = 0;
        while (true) {
            // 这一步是根据要设置的大小,使宽和高都能满足
            if ((options.outWidth >> i <= size)
                    && (options.outHeight >> i <= size)) {
                // 重新取得流,注意:这里一定要再次加载,不能二次使用之前的流!
                is = new FileInputStream(path);
                // 这个参数表示 新生成的图片为原始图片的几分之一。
                options.inSampleSize = (int) Math.pow(2.0D, i);
                // 这里之前设置为了true,所以要改为false,否则就创建不出图片
                options.inJustDecodeBounds = false;
                options.inPreferredConfig = Config.ARGB_8888;
                // 同时设置才会有效
                options.inPurgeable = true;
                // 当系统内存不够时候图片自动被回收
                options.inInputShareable = true;
                // 创建Bitmap
                bitmap = BitmapFactory.decodeStream(is, null, options);
                break;
            }
            i += 1;
        }

        return bitmap;
    }
第二个函数是imageZoom(Bitmap bm, double maxSize)(最后选用的是这种方法)
  /**
     * 缩放图片到固定文件大小
     * @param bm  需要缩放的图片
     * @param maxSize   目标文件大小,单位:KB
     * @return
     */
    public static Bitmap imageZoom(Bitmap bm, double maxSize) {
        // 图片允许最大空间 单位:KB
        // 将bitmap放至数组中,意在bitmap的大小(与实际读取的原文件要大)
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] b = baos.toByteArray();
        // 将字节换成KB
        double mid = b.length / 1024;
        // 判断bitmap占用空间是否大于允许最大空间 如果大于则压缩 小于则不压缩
        if (mid > maxSize) {
            // 获取bitmap大小 是允许最大大小的多少倍
            double i = mid / maxSize;
            // 开始压缩 此处用到平方根 将宽带和高度压缩掉对应的平方根倍
            // 保持刻度和高度和原bitmap比率一致,压缩后也达到了最大大小占用空间的大小
            bm = zoomImage(bm, bm.getWidth() / Math.sqrt(i), bm.getHeight()
                    / Math.sqrt(i));
        }
        return bm;
    }
    /***
     * 图片的缩放方法
     * 
     * @param bgimage
     *            :源图片资源
     * @param newWidth
     *            :缩放后宽度
     * @param newHeight
     *            :缩放后高度
     * @return
     */
    public static Bitmap zoomImage(Bitmap bgimage, double newWidth,
            double newHeight) {
        // 获取这个图片的宽和高
        float width = bgimage.getWidth();
        float height = bgimage.getHeight();
        // 创建操作图片用的matrix对象
        Matrix matrix = new Matrix();
        // 计算宽高缩放率
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
                (int) height, matrix, true);
        return bitmap;
    }

还有一个重要的函数就是将Bitmap保存成图片的函数.本应用将系统时间设为图片名.最后要注意保存后通过广播对相册进行通知.

public static void saveImageToGallery(Context context, Bitmap bmp) {
        // 首先保存图片
        File appDir = new File(Environment.getExternalStorageDirectory(), "PicCompress");
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        Log.d("PICCOMPRESS","文件夹创建成功!");
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }      
        // 其次把文件插入到系统图库
        try {
            MediaStore.Images.Media.insertImage(context.getContentResolver(),
                    file.getAbsolutePath(), fileName, null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 最后通知图库更新
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" +file.getAbsolutePath())));
        Log.d("PICCOMPRESS","广播通知相册成功!");
    }

除此之外PopupWindow的使用也比较重要.PopupWindow整体比较美观,这里使用它就是让用户选择拍照获取图片还是直接从相册选取图片.初始化PopupWindow的方法如下:

private  void initPopWIndow(){
        popupWindow=new PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        View view= LayoutInflater.from(context).inflate(R.layout.popwindow_select_photo,null);

        TextView selectPhoto=(TextView)view.findViewById(R.id.selectPhoto);
        selectPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                startActivityForResult(Intent.createChooser(intent, "Pick any photo"), RESUEST_SELECT_PHOTO);
            }
        });
        TextView takePhoto=(TextView)view.findViewById(R.id.takePhoto);
        takePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                photoFile = bitMapIO.getFullFile();
                //polygonBean.setFileName(photoFile.toString());
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
                imageUri = Uri.fromFile(photoFile);
                startActivityForResult(intent, RESUEST_PHOTO);
            }
        });
        TextView cancel=(TextView)view.findViewById(R.id.cancel);
        cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupWindow.dismiss();
            }
        });

        popupWindow.setContentView(view);
        popupWindow.setFocusable(true);
        popupWindow.setOutsideTouchable(true);
        ColorDrawable colorDrawable = new ColorDrawable(Color.BLUE);
        popupWindow.setBackgroundDrawable(colorDrawable);
    }   

其他部分,比如布局文件什么的大家直接看源代码就好.注意要添加几项权限:

 <uses-permission android:name="android.permission.CAMERA"></uses-permission>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

下面是源代码的下载链接:点击这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值