美文网首页Android常用功能
图片滤镜——GPUImage

图片滤镜——GPUImage

作者: 海晨忆 | 来源:发表于2019-05-23 18:13 被阅读45次

    个人博客:haichenyi.com。感谢关注

      GPUImage图片滤镜处理的第三方开源库,对照IOS版的GPUImage写的,部分功能尚未完善,目前也有很多种滤镜,常用的滤镜基本上都有,请先浏览一遍github上面的用法。

    依赖的库

    repositories {
        jcenter()
    }
    
    dependencies {
    //这个版本号2.x.x,具体的数字看,github官方说明
    //README.md下方Download后面的版本号
        implementation 'jp.co.cyberagent.android:gpuimage:2.x.x'
    }
    

    注意事项

    一、图片变形

      Android版目前没有IOS那么多类,那么多用法,我们用的最多的就是GPUImageView这个自定义view,继承的FrameLayout,并不是继承的ImageView,所以,它这里显示图片的时候,会有图片变形的问题。我的处理方法:

    1. 先用Glide获取图片的宽高
    2. 然后获取GPUImageView的LayoutParams,动态设置控件的宽高

    二、内存溢出

    1. 图片过大造成的内存溢出,压缩图片,推荐使用鲁班压缩
    2. 频繁使用GPUImage获取Bitmap的getBitmapWithFilterApplied()方法,造成Bitmap过多的内存泄漏,推荐用WeakReference(弱引用)标记Bitmap,GC自动回收
    3. 显示大图和缩略图,一般都是一个大图和多种添加滤镜后的效果图(这个是缩略图),这里缩略图再通过getBitmapWithFilterApplied获取之前,最好吧原图按照规则缩小之后再获取显示,这样也能尽可能的减少内存的占用,点击缩略图显示大的效果图的时候,并不是改变bitmap,是给gpuIamgeView对象设置你点击目标图使用滤镜即可,这样也可以避免内存过多的消耗

    三、滤镜添加

    1. 单一滤镜的添加
    //这里以添加黑白滤镜为例
    GPUImageView gpuImageView = findViewById(R.id.img);
    gpuImageView.setImage(bitmap);
    gpuImageView.setFilter(new GPUImageGrayscaleFilter());
    
    1. 组合滤镜的添加GPUImageFilterGroup
    GPUImageView gpuImageView = findViewById(R.id.img);
    gpuImageView.setImage(bitmap);
    GPUImageFilterGroup filterGroup = new GPUImageFilterGroup();
    //把你需要添加的滤镜放到GPUImageFilterGroup容器里面,
    //这里我添加了灰色滤镜,曝光度滤镜和饱和度滤镜理论上可以添加无数个
    filterGroup.add(new GPUImageGrayscaleFilter());
    filterGroup.add(new GPUImageExposureFilter());
    filterGroup.add(new GPUImageSaturationFilter());
    //把这个容器添加到GPUImageView
    gpuImageView.setFilter(filterGroup);
    
    1. 多张图片的滤镜
    //这里以GPUImageTwoInputFilter为例(可以加到组合滤镜里面),它有多个子类
    //我们这里用GPUImageChromaKeyBlendFilter为例
    //实现的效果是一个过渡效果,从原图过渡到目标图
    GPUImageView gpuImageView = findViewById(R.id.img);
    //设置原图
    gpuImageView.setImage(bitmap);
    //新建滤镜对象,并且把目标图设置给滤镜
    GPUImageChromaKeyBlendFilter keyBlendFilter = new GPUImageChromaKeyBlendFilter();
    //设置目标图
    keyBlendFilter.setBitmap(bitmap1);
    //平滑的过渡方法,改变参数的值即可
    keyBlendFilter.setSmoothing(progressFloat);
    //把滤镜设置给GPUImageView
    gpuImageView.setFilter(keyBlendFilter);
    

    四、微调(敏感度问题)

      只要构造方法,方法带参数的,都可以微调,这里微调的取值范围,Filter源码的类注释上面都有。如果,我们把seekBar的取值范围设置成类注释上面的范围,你滑动很小距离的seekBar,图片变化就会很大,所以,我们一般都是缩小范围再使用。

     //第一个参数seekBar是最大值,第二个参数是最小值,第三个参数是默认值,第四个参数是seekbar分几段
     //mapSeekBarBean.put(TYPE_SATURATION, new SeekBarBean(2, 0, 0.5f, 10));
     mapSeekBarBean.put(TYPE_SATURATION, new SeekBarBean(100, 0, 50f, 2));
     //mapSeekBarBean.put(TYPE_BRIGHTNESS, new SeekBarBean(1, -1, 0.5f, 10));
     mapSeekBarBean.put(TYPE_BRIGHTNESS, new SeekBarBean(100, 0, 50f, 2));
     //mapSeekBarBean.put(TYPE_EXPOSURE, new SeekBarBean(10, -10, 0.5f, 0));
     mapSeekBarBean.put(TYPE_EXPOSURE, new SeekBarBean(100, 0, 50f, 2));
     //mapSeekBarBean.put(TYPE_CONTRAST, new SeekBarBean(4, 0, 0.25f, 0));
     mapSeekBarBean.put(TYPE_CONTRAST, new SeekBarBean(100, 0, 25f, 2));
     mapSeekBarBean.put(TYPE_POSTERIZE, new SeekBarBean(256, 0, 100f, 3));
     //mapSeekBarBean.put(TYPE_HIGH_LIGHT_SHADOW, new SeekBarBean(1, 0, 0f, 0));
     mapSeekBarBean.put(TYPE_HIGH_LIGHT_SHADOW, new SeekBarBean(100, 0, 0f, 2));
     mapSeekBarBean.put(TYPE_SHARPEN, new SeekBarBean(100, 0, 50f, 3));
     //mapSeekBarBean.put(TYPE_GAMMA, new SeekBarBean(3, 0, 0.33f, 0));
     mapSeekBarBean.put(TYPE_GAMMA, new SeekBarBean(100, 0, 33f, 3));
     //mapSeekBarBean.put(TYPE_OPACITY, new SeekBarBean(1, 0, 1f, 0));
     mapSeekBarBean.put(TYPE_OPACITY, new SeekBarBean(100, 0, 100f, 2));
     //mapSeekBarBean.put(TYPE_VIBRANCE, new SeekBarBean(1, 0, 0f, 0));
     mapSeekBarBean.put(TYPE_VIBRANCE, new SeekBarBean(100, 0, 0f, 2));
    
    //这里是最终设置的值
    switch (entrySet.getKey()) {
                    case TYPE_SATURATION:
                        //最后面*2是范围(0,2)
                        float f1 = (entrySet.getValue().getProgress() / entrySet.getValue().getMax()) * 2;
                        filters.add(new GPUImageSaturationFilter(f1));
                        break;
                    case TYPE_BRIGHTNESS:
                        float f2 = entrySet.getValue().getProgress();
                        if (f2 == 50) {
                            f2 = 0f;
                        } else {
                            //后面的*0.7是范围(-1,1),以中间0为准,分成两部分(-1,0),(0,1)
                            //负数为变暗,正数为变亮,本应该*1
                            f2 = (float) (((f2 - 50) / 50) * 0.4);
                        }
                        filters.add(new GPUImageBrightnessFilter(f2));
                        break;
                    case TYPE_EXPOSURE:
                        float f3 = entrySet.getValue().getProgress();
                        if (f3 == 50) {
                            f3 = 0f;
                        } else {
                            //后面的*1是范围(-10,10),以中间0为准,分成两部分(-10,0),(0,10)
                            //负数为变暗,正数为变亮,本应该*10
                            f3 = ((f3 - 50) / 50) * 1;
                        }
                        filters.add(new GPUImageExposureFilter(f3));
                        break;
                    case TYPE_CONTRAST:
                        //最后面*4是范围(0,4)
                        float f4 = (entrySet.getValue().getProgress() / entrySet.getValue().getMax()) * 4;
                        filters.add(new GPUImageContrastFilter(f4));
                        break;
                    case TYPE_POSTERIZE:
                        filters.add(new GPUImagePosterizeFilter((int) entrySet.getValue().getProgress()));
                        break;
                    case TYPE_HIGH_LIGHT_SHADOW:
                        GPUImageHighlightShadowFilter highlightShadowFilter = new GPUImageHighlightShadowFilter();
                        float f9 = (entrySet.getValue().getProgress() / entrySet.getValue().getMax()) * 1;
                        highlightShadowFilter.setHighlights(1 - f9);
                        highlightShadowFilter.setShadows(f9);
                        filters.add(highlightShadowFilter);
                        break;
                    case TYPE_SHARPEN:
                        float f5 = entrySet.getValue().getProgress();
                        if (f5 == 50) {
                            f5 = 0f;
                        } else {
                            //后面的*4是范围(-4,4),以中间0为准,分成两部分(-4,0),(0,4)
                            //负数为变暗,正数为变亮,本应该*4
                            f5 = ((f5 - 50) / 50) * 4;
                        }
                        filters.add(new GPUImageSharpenFilter(f5));
                        break;
                    case TYPE_GAMMA:
                        //最后面*3是范围(0,3)
                        float f6 = (entrySet.getValue().getProgress() / entrySet.getValue().getMax()) * 3;
                        filters.add(new GPUImageGammaFilter(f6));
                        break;
                    case TYPE_OPACITY:
                        float f7 = (entrySet.getValue().getProgress() / entrySet.getValue().getMax()) * 1;
                        filters.add(new GPUImageOpacityFilter(f7));
                        break;
                    case TYPE_VIBRANCE:
                        float f8 = (entrySet.getValue().getProgress() / entrySet.getValue().getMax()) * 1;
                        filters.add(new GPUImageVibranceFilter(f8));
                        break;
                    default:
                }
    

    用法

      上面的注意事项里面已经说了简单的用法了,怎么获取滤镜后的图片呢?

    //这个方法是获取bitmap对象,至于怎么保存,那就是你自己做了
    gpuImageView.getGPUImage().getBitmapWithFilterApplied();
    
    //当然,库也提供了保存图片的方法:保存的文件夹名称,文件名字,回调方法
    gpuImageView.saveToPictures(folderName,fileName,OnPictureSavedListener)
    //其中回调方法里面返回的uri,不能直接传给File,会找不到路径,需要转换一下
    
    /**
         * 根据Uri获取文件的路径
         *
         * @param context    context
         * @param contentURI uri
         * @return 文件路径
         */
        public static String getRealPathFromURI(Context context, Uri contentURI) {
            String result;
            Cursor cursor = context.getContentResolver().query(contentURI,
                    new String[]{MediaStore.Images.ImageColumns.DATA},
                    null, null, null);
            if (cursor == null) {
                result = contentURI.getPath();
            } else {
                cursor.moveToFirst();
                int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                result = cursor.getString(index);
                cursor.close();
            }
            return result;
        }
    

    项目就不贴出来了。

    相关文章

      网友评论

        本文标题:图片滤镜——GPUImage

        本文链接:https://www.haomeiwen.com/subject/sigbzqtx.html