Android App开发实战项目之模仿美图秀秀的抠图工具(附源码和演示视频 简单易懂 可直接使用)

简介: Android App开发实战项目之模仿美图秀秀的抠图工具(附源码和演示视频 简单易懂 可直接使用)

需要图片集和源码请点赞关注收藏后评论区留言~~~

所谓抠图神器,就是从一副图片中扣出用户想要的某块区域

一、需求描述

美图的修图功能如此强大,离不开专业的图片加工技术,抠图便是其中重要的一项功能。在App界面底部点击抠图按钮,再选择下方的形状按钮就会出现等待抠图的目标区域,然后通过手指触摸挪动方框,也可两指并用缩放或者旋转方框,调整方框大小以及角度后,再点击右下角的三点按钮,选择弹出菜单中的存为贴纸,就可以在贴纸功能中查看已经扣好的图片。

示意图如下

 

二、功能分析

抠图工具通过对图像进行平移,缩放,旋转等操作把图像的某个区域扣下来,抠图工具要提供打工图片和保存图片两种操作,其中打开图片支持从手机相册选取待加工的原始图片,保存图片支持把抠出来的图像保存到存储卡

打开原始图片后 工具界面进入抠图模式 主界面上没有任何控制按钮,抠哪个区域完全靠手势操作 需要实现的手势处理有以下五种

1:挪动高亮区域的手势

2:调整高亮区域边界的手势

3:挪动图片的手势

4:缩放图片的手势

5:旋转图片的手势

三、效果展示

演示视频如下

美图秀秀

点击右上角的三角按钮 可以打开和保存图片

下面用我们熟知的足坛巨星C罗举例

 

可以对图像进行放缩 旋转等操作

四、代码

java类

package com.example.event;
import com.example.event.util.BitmapUtil;
import com.example.event.util.DateUtil;
import com.example.event.widget.BitmapView;
import com.example.event.widget.MeituView;
import com.example.event.widget.MeituView.ImageChangetListener;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
public class MeituActivity extends Activity implements ImageChangetListener {
    private final static String TAG = "MeituActivity";
    private int CHOOSE_CODE = 3; // 只在相册挑选图片的请求码
    private MeituView mv_content; // 声明一个美图视图对象
    private BitmapView bv_content; // 声明一个位图视图对象
    private TextView tv_hint; // 声明一个文本视图对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    private void initView() {
        Toolbar tl_head = findViewById(R.id.tl_head);
        tl_head.setTitle("抠图工具");
        setSupportActionBar(tl_head); // 替换系统自带的ActionBar
        // 设置工具栏左侧导航图标的点击监听器
        tl_head.setNavigationOnClickListener(view -> finish());
        mv_content = findViewById(R.id.mv_content);
        mv_content.setImageChangetListener(this); // 设置美图视图的图像变更监听器
        bv_content = findViewById(R.id.bv_content);
        bv_content.setDrawingCacheEnabled(true); // 开启位图视图的绘图缓存
        tv_hint = findViewById(R.id.tv_hint);
    }
    private void setSupportActionBar(Toolbar tl_head) {
    }
    // 刷新图像展示
    private void refreshImage(boolean is_first) {
        Bitmap bitmap = bv_content.getDrawingCache(); // 从绘图缓存获取位图对象
        mv_content.setOrigBitmap(bitmap); // 设置美图视图的原始位图
        if (is_first) { // 首次打开
            int left = bitmap.getWidth() / 4;
            int top = bitmap.getHeight() / 4;
            // 设置美图视图的位图边界
            mv_content.setBitmapRect(new Rect(left, top, left * 2, top * 2));
        } else { // 非首次打开
            // 设置美图视图的位图边界
            mv_content.setBitmapRect(mv_content.getBitmapRect());
        }
    }
    // 在图片平移时触发
    @Override
    public void onImageTraslate(int offsetX, int offsetY, boolean bReset) {
        bv_content.setOffset(offsetX, offsetY, bReset); // 设置位图视图的偏移距离
        refreshImage(false); // 刷新图像展示
    }
    // 在图片缩放时触发
    @Override
    public void onImageScale(float ratio) {
        bv_content.setScaleRatio(ratio, false); // 设置位图视图的缩放比率
        refreshImage(false); // 刷新图像展示
    }
    // 在图片旋转时触发
    @Override
    public void onImageRotate(int degree) {
        bv_content.setRotateDegree(degree, false); // 设置位图视图的旋转角度
        refreshImage(false); // 刷新图像展示
    }
    // 在图片点击时触发
    @Override
    public void onImageClick() {}
    // 在图片长按时触发
    @Override
    public void onImageLongClick() {}
    // 在创建选项菜单时调用
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_meitu, menu);
        return true;
    }
    // 在选中菜单项时调用
    @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);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) { // 从相册返回
            if (intent.getData() != null) { // 从相册选择一张照片
                Uri uri = intent.getData(); // 获得已选择照片的路径对象
                // 根据指定图片的uri,获得自动缩小后的位图对象
                Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, uri);
                bv_content.setImageBitmap(bitmap); // 设置位图视图的位图对象
                refreshImage(true); // 刷新图像展示
                tv_hint.setVisibility(View.GONE);
            }
        }
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/tl_head"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/blue_light"
        app:navigationIcon="@drawable/icon_back" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
        <com.example.event.widget.BitmapView
            android:id="@+id/bv_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            android:scaleType="centerCrop" />
        <com.example.event.widget.MeituView
            android:id="@+id/mv_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <TextView
            android:id="@+id/tv_hint"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="请点击右上角的三点图标,先打开图片文件,再开始抠图操作"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </RelativeLayout>
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
17天前
|
监控 安全 开发者
山东布谷科技:关于直播源码|语音源码|一对一直播源码提交App Store的流程及重构经验
分享提交直播源码,一对一直播源码,语音源码到Appstore的重构经验!
|
19天前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码服务器环境配置及app功能
一对一直播源码阿里云服务器环境配置及要求
|
15天前
|
机器人
布谷直播App系统源码开发之后台管理功能详解
直播系统开发搭建管理后台功能详解!
|
24天前
|
NoSQL PHP Redis
布谷语音app源码服务器环境配置及技术开发语言
布谷语音app源码服务器环境配置及技术语言研发。。
|
2月前
|
测试技术
基于LangChain手工测试用例转App自动化测试生成工具
在传统App自动化测试中,测试工程师需手动将功能测试用例转化为自动化用例。市面上多数产品通过录制操作生成测试用例,但可维护性差。本文探讨了利用大模型直接生成自动化测试用例的可能性,介绍了如何使用LangChain将功能测试用例转换为App自动化测试用例,大幅节省人力与资源。通过封装App底层工具并与大模型结合,记录执行步骤并生成自动化测试代码,最终实现高效自动化的测试流程。
|
2月前
仿SOUL社交友附近人婚恋约仿陌陌APP网站源码
仿SOUL社交友附近人婚恋约仿陌陌APP网站源码
51 0
仿SOUL社交友附近人婚恋约仿陌陌APP网站源码
|
3月前
|
存储 BI Android开发
全开源仿第八区H5APP封装打包分发系统源码
全开源仿第八区H5APP封装打包分发系统源码
141 4
|
3月前
【Azure App Service】如何来停止 App Service 的高级工具站点 Kudu ?
【Azure App Service】如何来停止 App Service 的高级工具站点 Kudu ?
|
3月前
|
XML 安全 Java
App安全检测实践基础——工具
App安全检测实践基础——工具
94 0
|
3月前
|
开发工具 数据安全/隐私保护 git
【Azure 应用服务】登录App Service 高级工具 Kudu站点的 Basic Auth 方式
【Azure 应用服务】登录App Service 高级工具 Kudu站点的 Basic Auth 方式