Android按键事件及手势事件(三)实战项目:仿美图秀秀的抠图

2023-02-20  本文已影响0人  古早味蛋糕

一、简介:
抠图神器,就是从一幅图片中抠出用户想要的某块区域。就像在花店里卖花,先适当修剪花束,再配上一些包装,看起来就很漂亮,不愁用户不喜欢。如何从现有图片抠出指定区域着实是一门学问,抠大还是抠小还得调整合适的角度,全凭用户两根灵活的手指头
1、需求描述
前段时间主打图片美颜的美图秀秀大受欢迎,甚至火到了国外。美图的修图功能如此强大,离不开专业的图片加工技术,抠图便是其中重要的一项。点击美图秀秀首页的图片美化按钮,到相册中选择一张图片,就打开了图片加工界面,在界面底部左滑拉出抠图按钮并点击,再选择下方的形状按钮,此时图片中央出现一个方框,这个方框就是待抠的目标区域。
2、功能分析
抠图工具通过对图像进行平移、缩放、旋转等操作把图像的某个区域抠下来。抠图工具要提供打开图片和保存图片两种操作,其中打开图片支持从手机相册选取待加工的原始图片、保存图片支持把抠出来的图像保存到存储卡。
打开原始图片后,工具界面进入抠图模式,主界面上没有任何控制按钮,抠哪块区域完全靠手势操作。需要实现的手势处理有以下5种。
● 挪动高亮区域的手势:点击高亮区域内部,再滑动手势,即可将该区域拖曳至指定位置。
● 调整高亮区域边界的手势:点击高亮区域边界,再滑动手势,即可将边界拉至指定位置。
● 挪动图片的手势:点击高亮区域外部(阴影部分),然后滑动手势,即可将整张图片拖曳至指定位置。
● 缩放图片的手势:两只手指同时按压屏幕,然后一起往中心点靠拢或彼此远离中心点,即可实现图片的缩小和放大操作。
● 旋转图片的手势:两个手指同时按压屏幕,然后围绕中心点一起顺时针或逆时针转动,即可实现图片的旋转操作。
下面是自定义的美图视图中关于缩放与旋转手势的判断代码:完整代码MeituView

if (mListener != null) {
       // 上次两个触摸点之间的距离
      float preWholeDistance = PointUtil.distance(mFirstLastPos, mSecondLastPos);
      // 当前两个触摸点之间的距离
      float nowWholeDistance = PointUtil.distance(firstP, secondP);
      // 主要点在前后两次落点之间的距离
     float primaryDistance = PointUtil.distance(firstP, mFirstLastPos);
     // 次要点在前后两次落点之间的距离
     float secondaryDistance = PointUtil.distance(secondP, mSecondLastPos);
     if (Math.abs(nowWholeDistance - preWholeDistance) >
                            (float) Math.sqrt(2) / 2.0f * (primaryDistance + secondaryDistance)) {
             // 倾向于在原始线段的相同方向上移动,则判作缩放图像
             // 触发图像变更监听器的缩放图像动作
             mListener.onImageScale(nowWholeDistance / preWholeDistance);
     } else { // 倾向于在原始线段的垂直方向上移动,则判作旋转图像
              // 计算上次触摸事件的旋转角度
              int preDegree = PointUtil.degree(mFirstLastPos, mSecondLastPos);
               // 计算本次触摸事件的旋转角度
              int nowDegree = PointUtil.degree(firstP, secondP);
              // 触发图像变更监听器的旋转图像动作
              mListener.onImageRotate(nowDegree - preDegree);
     }

根据落点坐标与矩形边界的相对位置,决定本次拖曳动作的类型的代码如下:完整代码MeituView

// 根据落点坐标与矩形边界的相对位置,决定本次拖曳动作的类型
private int getDragMode(float x, float y) {
    int left = mRect.left;
    int top = mRect.top;
    int right = mRect.left + mRect.right;
    int bottom = mRect.top + mRect.bottom;
    if (Math.abs(x - left) <= mInterval && Math.abs(y - top) <= mInterval) {
        return DRAG_LEFT_TOP; // 拖动矩形边界的左上角
    } else if (Math.abs(x - right) <= mInterval && Math.abs(y - top) <= mInterval) {
        return DRAG_RIGHT_TOP; // 拖动矩形边界的右上角
    } else if (Math.abs(x - left) <= mInterval && Math.abs(y - bottom) <= mInterval) {
        return DRAG_LEFT_BOTTOM; // 拖动矩形边界的左下角
    } else if (Math.abs(x - right) <= mInterval && Math.abs(y - bottom) <= mInterval) {
        return DRAG_RIGHT_BOTTOM; // 拖动矩形边界的右下角
    } else if (Math.abs(x - left) <= mInterval && y > top + mInterval && y < bottom - mInterval) {
        return DRAG_LEFT; // 拖动矩形边界的左边缘
    } else if (Math.abs(x - right) <= mInterval && y > top + mInterval && y < bottom - mInterval) {
        return DRAG_RIGHT; // 拖动矩形边界的右边缘
    } else if (Math.abs(y - top) <= mInterval && x > left + mInterval && x < right - mInterval) {
        return DRAG_TOP; // 拖动矩形边界的上边缘
    } else if (Math.abs(y - bottom) <= mInterval && x > left + mInterval && x < right - mInterval) {
        return DRAG_BOTTOM; // 拖动矩形边界的下边缘
    } else if (x > left + mInterval && x < right - mInterval
            && y > top + mInterval && y < bottom - mInterval) {
        return DRAG_WHOLE; // 拖动整个矩形边界框
    } else if (x + mInterval < left || x - mInterval > right || y + mInterval < top || y - mInterval > bottom) {
        return IMAGE_TRANSLATE; // 平移图像
    } else {
        return DRAG_NONE; // 无拖曳动作
    }
}

其中需要实现内容获取动作的意图,然后进行保存抠取图片,部分代码:完整代码MeituActivity

// 在选中菜单项时调用
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.menu_file_open) { // 点击了“打开文件”
        // 创建一个内容获取动作的意图(准备跳到系统相册)
        Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);
        albumIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选
        albumIntent.setType("image/*"); // 类型为图像
        startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册
    } else if (item.getItemId() == R.id.menu_file_save) { // 点击了“保存文件”
        Bitmap bitmap = mv_content.getCropBitmap(); // 获取美图视图处理后的位图
        // 生成图片文件的保存路径
        String path = String.format("%s/%s.jpg",
                getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),
                DateUtil.getNowDateTime());
        BitmapUtil.saveImage(path, bitmap); // 把位图保存为图片文件
        BitmapUtil.notifyPhotoAlbum(this, path); // 通知相册来了张新图片
        Toast.makeText(this, "已保存抠好的图片 "+path, Toast.LENGTH_SHORT).show();
    }
    return super.onOptionsItemSelected(item);
}

二、效果展示
1、打开抠图App,点击右上角的三点图标,弹出读写图片文件的菜单,如图【读写图片文件的菜单】所示


读写图片文件的菜单.png

2、选择菜单项“打开图片”,打开待加工的图片文件,初始界面如图【原始图片】所示。


原始图片.png
3、接着拖动原始图片与高亮区域,并适当放大移动图片,使白兔灯位于高亮区域中间部,如图【抠图裁剪过程】全部手势调整结束,点击保存图片。
抠图裁剪过程.png
3、完成抠图打开相册查看效果如图【抠图裁剪完成后】所示。
抠图裁剪完成后.png
上一篇下一篇

猜你喜欢

热点阅读