一步步带你实现Android图片处理库gpuimage的配置、使用、封装、多效果集于一身(eg:灰度滤镜+鱼眼效果)

官网:https://github.com/cats-oss/android-gpuimage

以下以灰色滤镜、鱼眼效果(变形,看腰和海面)、饱和度 为例,进行讲解,效果图如下:

图一:原图,刚进去的界面,没有任何操作,可以优化黑色,一开始隐藏,进行图片处理时再显示;

图二:灰色滤镜  ;   图三:鱼眼效果  ;    图四:灰色+鱼眼

第二排:饱和度,注意看进度条,图片可以随进度条变化(不会传GIF)

                                                                                                                                      

 

                                                             

 

步骤: 

注:我的项目是AndroidX的,视图绑定使用了dataBinding,不需要的话,直接忽略,布局时按照自己的来;需要的话,在使用视图绑定的build.gradle里面添加如下代码:

android {
    dataBinding {
        enabled = true
    }
***************
}

 

一.添加依赖(在用到的模块)

implementation 'jp.co.cyberagent.android:gpuimage:2.0.4'

 

二.封装图片处理库gpuimage方法,工具类GPUImageUtil,包含单一效果处理方法、多效果集处理方法(同一张照片需要多个效果)

package com.example.module_utils.utils;

import android.graphics.Bitmap;

import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.filter.GPUImageBulgeDistortionFilter;
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
import jp.co.cyberagent.android.gpuimage.filter.GPUImageGrayscaleFilter;
import jp.co.cyberagent.android.gpuimage.filter.GPUImageSaturationFilter;

/**
 * 图片处理
 *
 * @author mcl 2020.6.2
 */
public class GPUImageUtil {
    private static GPUImageFilter mGPUImageFilter;

    private static int progress;

    /**
     * 获取过滤器(还有其它很多的方法:高斯模糊、锐化等到,以下之列出三个,其它的自行补充)
     *
     * @param GPUFlag 选择滤镜类型
     * @return 滤镜
     */
    public static GPUImageFilter getGPUImageFilter(int GPUFlag) {
        switch (GPUFlag) {
            //灰色滤镜
            case 1:
                mGPUImageFilter = new GPUImageGrayscaleFilter();
                break;

            //鱼眼效果
            case 2:
                mGPUImageFilter = new GPUImageBulgeDistortionFilter();
                break;

            //饱和度
            case 3:
                mGPUImageFilter = new GPUImageSaturationFilter(progress);
                break;

            default:
                break;
        }

        return mGPUImageFilter;
    }

    /**
     * 处理图片
     *
     * @param mGPUImage
     * @param mBitmap    原图
     * @param filterType 选择滤镜类型
     * @return 返回处理好后的图片
     */
    public static Bitmap getGPUImage(GPUImage mGPUImage, Bitmap mBitmap, int filterType) {
        mGPUImage.setImage(mBitmap);
        mGPUImage.setFilter(getGPUImageFilter(filterType));
        mBitmap = mGPUImage.getBitmapWithFilterApplied();
        return mBitmap;
    }

    /**
     * 多种效果集处理照片(eg:灰度+鱼眼)(目前想到比较笨的方法,有改进时再发出来)
     * @param mGPUImage
     * @param mBitmap 原图
     * @param filterTypes 选择滤镜类型集
     * @return
     */
    public static Bitmap getGPUImages(GPUImage mGPUImage, Bitmap mBitmap, int[] filterTypes){
        Bitmap bitmap=mBitmap;
        if (filterTypes!=null && filterTypes.length>0){
            //循环处理照片,是基于上一次的处理结果照片上再次处理。eg:先灰度滤镜,再鱼眼效果
            for (int i=0;i<filterTypes.length;i++){
                mGPUImage.setImage(bitmap);
                mGPUImage.setFilter(getGPUImageFilter(filterTypes[i]));
                bitmap = mGPUImage.getBitmapWithFilterApplied();
            }
        }
        return bitmap;
    }

    /**
     * 在一些图像处理方法中用得的值,eg:饱和度、亮度
     *
     * @param progress 赋值
     */
    public static void progressValue(int progress) {
        GPUImageUtil.progress = progress;
    }

}

 

三.GpuImageActivity

public class GpuImageActivity extends AppCompatActivity {
    private ActivityGpuImageBinding mBinding;
    private GPUImage mGpuImage;
    private Bitmap mBitmap;
    private int[] filterTypes=new int[]{1,2};//图片处理效果集,先固定是灰色+鱼眼,可修改得更人性化一些,手动选择效果集

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_gpu_image);
        mBinding.setActivity(this);
        initView();
    }

    private void initView() {
        mGpuImage = new GPUImage(this);
        mBitmap = BitmapFactory.decodeResource(this.getResources(), R.mipmap.ye);
        mBinding.ivGpuImageOriginal.setImageBitmap(mBitmap);


        mBinding.sbGpuImage.setMax(10);//进度条最大值
        mBinding.sbGpuImage.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                GPUImageUtil.progressValue(progress);
                mBinding.ivGpuImageTransform.setImage(GPUImageUtil.getGPUImage(mGpuImage, mBitmap, 3));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }

    /**
     * 灰色滤镜(点击事件)
     *
     * @param view
     */
    public void clickGrayScale(View view) {
        mBinding.ivGpuImageTransform.setImage(GPUImageUtil.getGPUImage(mGpuImage, mBitmap, 1));
    }

    /**
     * 鱼眼效果(点击事件)
     *
     * @param view
     */
    public void clickBulgeDistortion(View view) {
        mBinding.ivGpuImageTransform.setImage(GPUImageUtil.getGPUImage(mGpuImage, mBitmap, 2));
    }

    /**
     * 灰色滤镜+鱼眼效果(点击事件)
     * @param view
     */
    public void clickGrayBulge(View view){
        mBinding.ivGpuImageTransform.setImage(GPUImageUtil.getGPUImages(mGpuImage, mBitmap, filterTypes));
    }

}

 

四. 布局activity_gpu_image.xml,布局用到了dataBinding,如果不熟悉dataBinding的,按照自己的来布局即可,jp.co.cyberagent.android.gpuimage.GPUImageView控件用来显示处理后的图片,其它的随意。

注:android:scaleType="fitXY"是为了让图片充满控件

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="activity"
            type="com.example.module_login.ui.activity.GpuImageActivity" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.activity.GpuImageActivity">

        <ImageView
            android:id="@+id/iv_gpuImage_original"
            android:layout_width="@dimen/dp_200"
            android:layout_height="@dimen/dp_200"
            android:layout_marginTop="@dimen/dp_20"
            android:scaleType="fitXY"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <SeekBar
            android:id="@+id/sb_gpuImage"
            android:layout_width="@dimen/dp_0"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dp_20"
            app:layout_constraintLeft_toLeftOf="@id/iv_gpuImage_original"
            app:layout_constraintRight_toRightOf="@id/iv_gpuImage_original"
            app:layout_constraintTop_toBottomOf="@id/iv_gpuImage_original" />


        <Button
            android:id="@+id/bt_gpuImage_grayScale"
            android:layout_width="@dimen/dp_0"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dp_40"
            android:onClick="@{activity.clickGrayScale}"
            android:text="@string/login_Grayscale"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@+id/bt_gpuImage_bulgeDistortion"
            app:layout_constraintTop_toBottomOf="@id/sb_gpuImage" />

        <Button
            android:id="@+id/bt_gpuImage_bulgeDistortion"
            android:layout_width="@dimen/dp_0"
            android:layout_height="wrap_content"
            android:onClick="@{activity.clickBulgeDistortion}"
            android:text="@string/login_BulgeDistortion"
            app:layout_constraintRight_toLeftOf="@+id/bt_gpuImage_grayBulge"
            app:layout_constraintBottom_toBottomOf="@id/bt_gpuImage_grayScale"
            app:layout_constraintLeft_toRightOf="@id/bt_gpuImage_grayScale"
            app:layout_constraintTop_toTopOf="@id/bt_gpuImage_grayScale" />

        <Button
            android:id="@+id/bt_gpuImage_grayBulge"
            android:layout_width="@dimen/dp_0"
            android:layout_height="wrap_content"
            android:text="@string/login_grayBulge"
            android:onClick="@{activity.clickGrayBulge}"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintBottom_toBottomOf="@id/bt_gpuImage_bulgeDistortion"
            app:layout_constraintLeft_toRightOf="@+id/bt_gpuImage_bulgeDistortion"
            app:layout_constraintTop_toTopOf="@id/bt_gpuImage_bulgeDistortion" />


        <jp.co.cyberagent.android.gpuimage.GPUImageView
            android:id="@+id/iv_gpuImage_transform"
            android:layout_width="@dimen/dp_200"
            android:layout_height="@dimen/dp_200"
            android:layout_marginBottom="@dimen/dp_20"
            app:gpuimage_show_loading="false"
            app:gpuimage_surface_type="surface_view"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent" />


    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

到此就完成了,有不对的地方,多包含。在这篇文章中,学到最有用的是"多效果集处理方法"(名字好拗口,自己瞎取的)。一开始写的时候,我没有想到这个功能的,第一遍写完了,在检查全文有没有错误时,突发奇想,能不能把"多个效果"集合在同一张照片上面呢?然后就折腾起来,怎么封装更加合理。完成之后重新编辑文章。如果有更好的"多效果集处理方法",麻烦评论区告诉我一下,小女子感激不尽!

 

6.12补充:

经好心人(在评论区)的提点(感恩),gpuimage自带"GPUImageFilterGroup组合滤镜",经实践之后,前面笨笨的方法效果跟它是一样的,现在贴一下方法:

/**
     * 组合滤镜(eg:灰度+鱼眼)(GPUImageFilterGroup)
     *
     * @param mGPUImage
     * @param mBitmap     原图
     * @param filterTypes 组合滤镜集
     * @return
     */
    public static Bitmap getFPUImagesGroup(GPUImage mGPUImage, Bitmap mBitmap, int[] filterTypes) {
        mGPUImage.setImage(mBitmap);
        GPUImageFilterGroup gpuImageFilterGroup = new GPUImageFilterGroup();
        if (filterTypes != null && filterTypes.length > 0) {
            for (int i = 0; i < filterTypes.length; i++) {
                gpuImageFilterGroup.addFilter(getGPUImageFilter(filterTypes[i]));
            }
        }
        mGPUImage.setFilter(gpuImageFilterGroup);
        mBitmap = mGPUImage.getBitmapWithFilterApplied();

        return mBitmap;
    }

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
当然,我可以为你生成一个关于Android RxJava + Retrofit + MVP网络框架封装的完整项目配置的博客。以下是一个示例: 标题:Android RxJava + Retrofit + MVP网络框架封装:完整项目配置 正文: 在Android开发中,使用RxJava、Retrofit和MVP进行网络请求的框架封装是非常常见和实用的。本文将向你展示如何将它们结合起来,以实现一个完整的网络请求框架。 首先,确保你的Android项目中已经引入了RxJava、Retrofit和MVP的相关依赖。在项目的build.gradle文件中添加以下依赖: ```groovy dependencies { // RxJava implementation 'io.reactivex.rxjava2:rxjava:2.2.21' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' // Retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' // MVP implementation 'com.hannesdorfmann.mosby3:mvp:3.2.0' } ``` 接下来,我们将按照以下步骤完成完整的项目配置: 1. 创建网络请求接口 在你的项目中创建一个接口,用于定义网络请求的方法。例如,创建一个名为ApiService的接口,其中包含一个获取数据的方法。 ```java public interface ApiService { @GET("api/endpoint") Observable<ResponseData> getData(); } ``` 2. 创建网络请求管理类 创建一个名为ApiManager的类,用于管理网络请求。在这个类中,你可以初始化Retrofit,并提供一个方法来执行具体的网络请求。 ```java public class ApiManager { private static final String BASE_URL = "http://your-api-base-url.com/"; private ApiService apiService; public ApiManager() { Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); apiService = retrofit.create(ApiService.class); } public Observable<ResponseData> getData() { return apiService.getData() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } } ``` 3. 创建Presenter层 在MVP架构中,Presenter层负责处理业务逻辑和数据操作。创建一个名为MainPresenter的类,并在其中调用ApiManager执行网络请求。 ```java public class MainPresenter { private MainView mainView; private ApiManager apiManager; public MainPresenter(MainView mainView) { this.mainView = mainView; apiManager = new ApiManager(); } public void fetchData() { apiManager.getData() .subscribe(new Observer<ResponseData>() { @Override public void onSubscribe(Disposable d) { // 可选的订阅回调 } @Override public void onNext(ResponseData responseData) { // 处理请求成功的数据 mainView.showData(responseData); } @Override public void onError(Throwable e) { // 处理请求失败的情况 mainView.showError(e.getMessage()); } @Override public void onComplete() { // 请求完成,可选的回调 } }); } } ``` 4. 创建View层 在MVP架构中,View层负责展示数据和处理用户交互。创建一个名为MainActivity的类,并实现MainView接口。 ```java public class MainActivity extends AppCompatActivity implements MainView { private MainPresenter mainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainPresenter = new MainPresenter(this); mainPresenter.fetchData(); } @Override public void showData(ResponseData responseData) { // 展示数据到UI上 } @Override public void showError(String errorMessage) { // 展示错误信息到UI上 } } ``` 通过以上步骤,你就完成了Android使用RxJava、Retrofit和MVP进行网络请求的框架封装。根据你的实际需求,你可以进一步添加其他功能和模块来完善你的项目。 希望本文对你有所帮助!如果有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值