Android建筑图像过滤器,如Instagram(2)

14。打开FiltersListFragment.java并进行如下所示的修改。这里

FilterPack.getFilterPack()提供库中可用过滤器的列表。

>prepareThumbnail()方法中,过滤器被填充,并且每个缩略图项目都被添加到ThumbnailsManager以处理它们。处理后的缩略图将添加回thumbnailItemList,后者是RecyclerView的数据资源。

>缩略图数据集准备就绪后,调用mAdapter.notifyDataSetChanged()来渲染列表。所有这些都是在后台线程中完成的,因为图像处理需要一段时间,我们不应该阻止主线程。

>每当选择新过滤器时,FiltersListFragmentListener接口都会为主活动提供回调方法。

MainActivity中将对所选图像过滤器的实际处理进行处理。

FiltersListFragment.java

packageinfo.androidhive.imagefilters;

importandroid.graphics.Bitmap;

importandroid.os.Bundle;

importandroid.support.v4.app.Fragment;

importandroid.support.v7.widget.DefaultItemAnimator;

importandroid.support.v7.widget.LinearLayoutManager;

importandroid.support.v7.widget.RecyclerView;

importandroid.util.Log;

importandroid.util.TypedValue;

importandroid.view.LayoutInflater;

importandroid.view.View;

importandroid.view.ViewGroup;

importcom.zomato.photofilters.FilterPack;

importcom.zomato.photofilters.imageprocessors.Filter;

importcom.zomato.photofilters.utils.ThumbnailItem;

importcom.zomato.photofilters.utils.ThumbnailsManager;

importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;

importbutterknife.BindView;

importbutterknife.ButterKnife;

importinfo.androidhive.imagefilters.utils.BitmapUtils;

importinfo.androidhive.imagefilters.utils.SpacesItemDecoration;

publicclassFiltersListFragment extendsFragment implementsThumbnailsAdapter.ThumbnailsAdapterListener {

    @BindView(R.id.recycler_view)

    RecyclerView recyclerView;

    ThumbnailsAdapter mAdapter;

    List thumbnailItemList;

    FiltersListFragmentListener listener;

    publicvoidsetListener(FiltersListFragmentListener listener) {

        this.listener = listener;

    }

    publicFiltersListFragment() {

        // Required empty public constructor

    }

    @Override

    publicvoidonCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

    }

    @Override

    publicView onCreateView(LayoutInflater inflater, ViewGroup container,

                             Bundle savedInstanceState) {

        // Inflate the layout for this fragment

        View view = inflater.inflate(R.layout.fragment_filters_list, container, false);

        ButterKnife.bind(this, view);

        thumbnailItemList = newArrayList<>();

        mAdapter = newThumbnailsAdapter(getActivity(), thumbnailItemList, this);

        RecyclerView.LayoutManager mLayoutManager = newLinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);

        recyclerView.setLayoutManager(mLayoutManager);

        recyclerView.setItemAnimator(newDefaultItemAnimator());

        intspace = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,

                getResources().getDisplayMetrics());

        recyclerView.addItemDecoration(newSpacesItemDecoration(space));

        recyclerView.setAdapter(mAdapter);

        prepareThumbnail(null);

        returnview;

    }

    /**

     * Renders thumbnails in horizontal list

     * loads default image from Assets if passed param is null

     *

     * @param bitmap

     */

    publicvoidprepareThumbnail(finalBitmap bitmap) {

        Runnable r = newRunnable() {

            publicvoidrun() {

                Bitmap thumbImage;

                if(bitmap == null) {

                    thumbImage = BitmapUtils.getBitmapFromAssets(getActivity(), MainActivity.IMAGE_NAME, 100, 100);

                } else{

                    thumbImage = Bitmap.createScaledBitmap(bitmap, 100, 100, false);

                }

                if(thumbImage == null)

                    return;

                ThumbnailsManager.clearThumbs();

                thumbnailItemList.clear();

                // add normal bitmap first

                ThumbnailItem thumbnailItem = newThumbnailItem();

                thumbnailItem.image = thumbImage;

                thumbnailItem.filterName = getString(R.string.filter_normal);

                ThumbnailsManager.addThumb(thumbnailItem);

                List filters = FilterPack.getFilterPack(getActivity());

                for(Filter filter : filters) {

                    ThumbnailItem tI = newThumbnailItem();

                    tI.image = thumbImage;

                    tI.filter = filter;

                    tI.filterName = filter.getName();

                    ThumbnailsManager.addThumb(tI);

                }

                thumbnailItemList.addAll(ThumbnailsManager.processThumbs(getActivity()));

                getActivity().runOnUiThread(newRunnable() {

                    @Override

                    publicvoidrun() {

                        mAdapter.notifyDataSetChanged();

                    }

                });

            }

        };

        newThread(r).start();

    }

    @Override

    publicvoidonFilterSelected(Filter filter) {

        if(listener != null)

            listener.onFilterSelected(filter);

    }

    publicinterfaceFiltersListFragmentListener {

        voidonFilterSelected(Filter filter);

    }

}

7.添加图像编辑控件片段

现在我们将添加图像控件片段来控制亮度对比度饱和度

15。按照与上一步相同的步骤再创建一个名为EditImageFragment.java的片段。打开此片段fragment_edit_image.xml的布局文件,并执行如下修改。

在这个布局中,我们将添加三个SeekBar小部件来控制图像亮度,对比度和饱和度。

fragment_edit_image.xml

http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:gravity="center_vertical"

    android:orientation="vertical"

    android:paddingLeft="@dimen/margin_horizontal"

    android:paddingRight="@dimen/margin_horizontal"

    tools:context="info.androidhive.imagefilters.EditImageFragment">

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal"

        android:paddingBottom="@dimen/padding_10"

        android:paddingTop="@dimen/padding_10">

            android:layout_width="@dimen/lbl_edit_image_control"

            android:layout_height="wrap_content"

            android:text="@string/lbl_brightness"/>

            android:id="@+id/seekbar_brightness"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="1"/>

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal"

        android:paddingBottom="@dimen/padding_10"

        android:paddingTop="@dimen/padding_10">

            android:layout_width="@dimen/lbl_edit_image_control"

            android:layout_height="wrap_content"

            android:text="@string/lbl_contrast"/>

            android:id="@+id/seekbar_contrast"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="1"/>

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal"

        android:paddingBottom="@dimen/padding_10"

        android:paddingTop="@dimen/padding_10">

            android:layout_width="@dimen/lbl_edit_image_control"

            android:layout_height="wrap_content"

            android:text="@string/lbl_saturation"/>

            android:id="@+id/seekbar_saturation"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="1"/>

16。打开EditImageFragment.java并进行如下修改。

>onCreateView方法中,Seekbar小部件使用初始值和最大值进行初始化。对于亮度,值可以在-100 / +100之间。在对比度饱和度采取浮动值。

>每当Seekbar值发生更改时,EditImageFragmentListener接口都会提供回调方法。

>在回调时,MainActivity再次处理亮度对比度饱和度

EditImageFragment.java

packageinfo.androidhive.imagefilters;

importandroid.os.Bundle;

importandroid.support.v4.app.Fragment;

importandroid.util.Log;

importandroid.view.LayoutInflater;

importandroid.view.View;

importandroid.view.ViewGroup;

importandroid.widget.SeekBar;

importbutterknife.BindView;

importbutterknife.ButterKnife;

publicclassEditImageFragment extendsFragment implementsSeekBar.OnSeekBarChangeListener {

    privateEditImageFragmentListener listener;

    @BindView(R.id.seekbar_brightness)

    SeekBar seekBarBrightness;

    @BindView(R.id.seekbar_contrast)

    SeekBar seekBarContrast;

    @BindView(R.id.seekbar_saturation)

    SeekBar seekBarSaturation;

    publicvoidsetListener(EditImageFragmentListener listener) {

        this.listener = listener;

    }

    publicEditImageFragment() {

        // Required empty public constructor

    }

    @Override

    publicvoidonCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

    }

    @Override

    publicView onCreateView(LayoutInflater inflater, ViewGroup container,

                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_edit_image, container, false);

        ButterKnife.bind(this, view);

        // keeping brightness value b/w -100 / +100

        seekBarBrightness.setMax(200);

        seekBarBrightness.setProgress(100);

        // keeping contrast value b/w 1.0 - 3.0

        seekBarContrast.setMax(20);

        seekBarContrast.setProgress(0);

        // keeping saturation value b/w 0.0 - 3.0

        seekBarSaturation.setMax(30);

        seekBarSaturation.setProgress(10);

        seekBarBrightness.setOnSeekBarChangeListener(this);

        seekBarContrast.setOnSeekBarChangeListener(this);

        seekBarSaturation.setOnSeekBarChangeListener(this);

        returnview;

    }

    @Override

    publicvoidonProgressChanged(SeekBar seekBar, intprogress, booleanb) {

        if(listener != null) {

            if(seekBar.getId() == R.id.seekbar_brightness) {

                // brightness values are b/w -100 to +100

                listener.onBrightnessChanged(progress - 100);

            }

            if(seekBar.getId() == R.id.seekbar_contrast) {

                // converting int value to float

                // contrast values are b/w 1.0f - 3.0f

                // progress = progress > 10 ? progress : 10;

                progress += 10;

                floatfloatVal = .10f * progress;

                listener.onContrastChanged(floatVal);

            }

            if(seekBar.getId() == R.id.seekbar_saturation) {

                // converting int value to float

                // saturation values are b/w 0.0f - 3.0f

                floatfloatVal = .10f * progress;

                listener.onSaturationChanged(floatVal);

            }

        }

    }

    @Override

    publicvoidonStartTrackingTouch(SeekBar seekBar) {

        if(listener != null)

            listener.onEditStarted();

    }

    @Override

    publicvoidonStopTrackingTouch(SeekBar seekBar) {

        if(listener != null)

            listener.onEditCompleted();

    }

    publicvoidresetControls() {

        seekBarBrightness.setProgress(100);

        seekBarContrast.setProgress(0);

        seekBarSaturation.setProgress(10);

    }

    publicinterfaceEditImageFragmentListener {

        voidonBrightnessChanged(intbrightness);

        voidonSaturationChanged(floatsaturation);

        voidonContrastChanged(floatcontrast);

        voidonEditStarted();

        voidonEditCompleted();

    }

}

8.实现主界面(组合片段)

现在我们准备好了片段,让我们看看如何将它们组合起来以实现我们的最终输出。

17。打开主活动activity_main.xmlcontent_main.xml以及NonSwipeableViewPagerTabLayout的布局文件。

activity_main.xml中

http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context="info.androidhive.imagefilters.MainActivity">

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:theme="@style/AppTheme.AppBarOverlay">

            android:id="@+id/toolbar"

            android:layout_width="match_parent"

            android:layout_height="?attr/actionBarSize"

            android:background="@android:color/white"

            app:popupTheme="@style/AppTheme.PopupOverlay"/>

content_main.xml

http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@android:color/white"

    android:orientation="vertical"

    app:layout_behavior="@string/appbar_scrolling_view_behavior"

    tools:context="info.androidhive.imagefilters.MainActivity"

    tools:showIn="@layout/activity_main">

        android:id="@+id/image_preview"

        android:layout_width="match_parent"

        android:layout_height="360dp"

        android:scaleType="centerCrop"/>

        android:id="@+id/viewpager"

        android:layout_width="match_parent"

        android:layout_height="120dp"

        android:layout_above="@+id/tabs"

        android:layout_below="@+id/image_preview"

        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

        android:id="@+id/tabs"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true"

        app:tabGravity="fill"

        app:tabMode="fixed"/>

18。打开MainActivity.java并执行如下所示的更改。

>调用System.loadLibrary(“NativeImageProcessor”)来初始化本机库。

FiltersListFragmentEditImageFragments加到ViewPager在setupViewPager()方法。

onFilterSelected()当在被选择的过滤器将被称为FiltersListFragment。处理选定的过滤器,并显示最终图像imagePreview

onBrightnessChanged()onSaturationChanged()onContrastChanged()方法将在EditImageFragments中的Seekbar值更改时调用。

>从工具栏中选择“保存”选项后,最终图像将保存到图库。

MainActivity.java

packageinfo.androidhive.imagefilters;

importandroid.Manifest;

importandroid.content.Intent;

importandroid.graphics.Bitmap;

importandroid.net.Uri;

importandroid.os.Bundle;

importandroid.support.design.widget.CoordinatorLayout;

importandroid.support.design.widget.Snackbar;

importandroid.support.design.widget.TabLayout;

importandroid.support.v4.app.Fragment;

importandroid.support.v4.app.FragmentManager;

importandroid.support.v4.app.FragmentPagerAdapter;

importandroid.support.v4.view.ViewPager;

importandroid.support.v7.app.AppCompatActivity;

importandroid.support.v7.widget.Toolbar;

importandroid.text.TextUtils;

importandroid.util.Log;

importandroid.view.Menu;

importandroid.view.MenuItem;

importandroid.view.View;

importandroid.widget.ImageView;

importandroid.widget.Toast;

importcom.karumi.dexter.Dexter;

importcom.karumi.dexter.MultiplePermissionsReport;

importcom.karumi.dexter.PermissionToken;

importcom.karumi.dexter.listener.PermissionRequest;

importcom.karumi.dexter.listener.multi.MultiplePermissionsListener;

importcom.zomato.photofilters.imageprocessors.Filter;

importcom.zomato.photofilters.imageprocessors.subfilters.BrightnessSubFilter;

importcom.zomato.photofilters.imageprocessors.subfilters.ContrastSubFilter;

importcom.zomato.photofilters.imageprocessors.subfilters.SaturationSubfilter;

importjava.util.ArrayList;

importjava.util.List;

importbutterknife.BindView;

importbutterknife.ButterKnife;

importinfo.androidhive.imagefilters.utils.BitmapUtils;

publicclassMainActivity extendsAppCompatActivity implementsFiltersListFragment.FiltersListFragmentListener, EditImageFragment.EditImageFragmentListener {

    privatestaticfinalString TAG = MainActivity.class.getSimpleName();

    publicstaticfinalString IMAGE_NAME = "dog.jpg";

    publicstaticfinalintSELECT_GALLERY_IMAGE = 101;

    @BindView(R.id.image_preview)

    ImageView imagePreview;

    @BindView(R.id.tabs)

    TabLayout tabLayout;

    @BindView(R.id.viewpager)

    ViewPager viewPager;

    @BindView(R.id.coordinator_layout)

    CoordinatorLayout coordinatorLayout;

    Bitmap originalImage;

    // to backup image with filter applied

    Bitmap filteredImage;

    // the final image after applying

    // brightness, saturation, contrast

    Bitmap finalImage;

    FiltersListFragment filtersListFragment;

    EditImageFragment editImageFragment;

    // modified image values

    intbrightnessFinal = 0;

    floatsaturationFinal = 1.0f;

    floatcontrastFinal = 1.0f;

    // load native image filters library

    static{

        System.loadLibrary("NativeImageProcessor");

    }

    @Override

    protectedvoidonCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);

        Toolbar toolbar = findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        getSupportActionBar().setTitle(getString(R.string.activity_title_main));

        loadImage();

        setupViewPager(viewPager);

        tabLayout.setupWithViewPager(viewPager);

    }

    privatevoidsetupViewPager(ViewPager viewPager) {

        ViewPagerAdapter adapter = newViewPagerAdapter(getSupportFragmentManager());

        // adding filter list fragment

        filtersListFragment = newFiltersListFragment();

        filtersListFragment.setListener(this);

        // adding edit image fragment

        editImageFragment = newEditImageFragment();

        editImageFragment.setListener(this);

        adapter.addFragment(filtersListFragment, getString(R.string.tab_filters));

        adapter.addFragment(editImageFragment, getString(R.string.tab_edit));

        viewPager.setAdapter(adapter);

    }

    @Override

    publicvoidonFilterSelected(Filter filter) {

        // reset image controls

        resetControls();

        // applying the selected filter

        filteredImage = originalImage.copy(Bitmap.Config.ARGB_8888, true);

        // preview filtered image

        imagePreview.setImageBitmap(filter.processFilter(filteredImage));

        finalImage = filteredImage.copy(Bitmap.Config.ARGB_8888, true);

    }

    @Override

    publicvoidonBrightnessChanged(finalintbrightness) {

        brightnessFinal = brightness;

        Filter myFilter = newFilter();

        myFilter.addSubFilter(newBrightnessSubFilter(brightness));

        imagePreview.setImageBitmap(myFilter.processFilter(finalImage.copy(Bitmap.Config.ARGB_8888, true)));

    }

    @Override

    publicvoidonSaturationChanged(finalfloatsaturation) {

        saturationFinal = saturation;

        Filter myFilter = newFilter();

        myFilter.addSubFilter(newSaturationSubfilter(saturation));

        imagePreview.setImageBitmap(myFilter.processFilter(finalImage.copy(Bitmap.Config.ARGB_8888, true)));

    }

    @Override

    publicvoidonContrastChanged(finalfloatcontrast) {

        contrastFinal = contrast;

        Filter myFilter = newFilter();

        myFilter.addSubFilter(newContrastSubFilter(contrast));

        imagePreview.setImageBitmap(myFilter.processFilter(finalImage.copy(Bitmap.Config.ARGB_8888, true)));

    }

    @Override

    publicvoidonEditStarted() {

    }

    @Override

    publicvoidonEditCompleted() {

        // once the editing is done i.e seekbar is drag is completed,

        // apply the values on to filtered image

        finalBitmap bitmap = filteredImage.copy(Bitmap.Config.ARGB_8888, true);

        Filter myFilter = newFilter();

        myFilter.addSubFilter(newBrightnessSubFilter(brightnessFinal));

        myFilter.addSubFilter(newContrastSubFilter(contrastFinal));

        myFilter.addSubFilter(newSaturationSubfilter(saturationFinal));

        finalImage = myFilter.processFilter(bitmap);

    }

    /**

     * Resets image edit controls to normal when new filter

     * is selected

     */

    privatevoidresetControls() {

        if(editImageFragment != null) {

            editImageFragment.resetControls();

        }

        brightnessFinal = 0;

        saturationFinal = 1.0f;

        contrastFinal = 1.0f;

    }

    classViewPagerAdapter extendsFragmentPagerAdapter {

        privatefinalList mFragmentList = newArrayList<>();

        privatefinalList mFragmentTitleList = newArrayList<>();

        publicViewPagerAdapter(FragmentManager manager) {

            super(manager);

        }

        @Override

        publicFragment getItem(intposition) {

            returnmFragmentList.get(position);

        }

        @Override

        publicintgetCount() {

            returnmFragmentList.size();

        }

        publicvoidaddFragment(Fragment fragment, String title) {

            mFragmentList.add(fragment);

            mFragmentTitleList.add(title);

        }

        @Override

        publicCharSequence getPageTitle(intposition) {

            returnmFragmentTitleList.get(position);

        }

    }

    // load the default image from assets on app launch

    privatevoidloadImage() {

        originalImage = BitmapUtils.getBitmapFromAssets(this, IMAGE_NAME, 300, 300);

        filteredImage = originalImage.copy(Bitmap.Config.ARGB_8888, true);

        finalImage = originalImage.copy(Bitmap.Config.ARGB_8888, true);

        imagePreview.setImageBitmap(originalImage);

    }

    @Override

    publicbooleanonCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.menu_main, menu);

        returntrue;

    }

    @Override

    publicbooleanonOptionsItemSelected(MenuItem item) {

        intid = item.getItemId();

        if(id == R.id.action_open) {

            openImageFromGallery();

            returntrue;

        }

        if(id == R.id.action_save) {

            saveImageToGallery();

            returntrue;

        }

        returnsuper.onOptionsItemSelected(item);

    }

    @Override

    protectedvoidonActivityResult(intrequestCode, intresultCode, Intent data) {

        if(resultCode == RESULT_OK && requestCode == SELECT_GALLERY_IMAGE) {

            Bitmap bitmap = BitmapUtils.getBitmapFromGallery(this, data.getData(), 800, 800);

            // clear bitmap memory

            originalImage.recycle();

            finalImage.recycle();

            finalImage.recycle();

            originalImage = bitmap.copy(Bitmap.Config.ARGB_8888, true);

            filteredImage = originalImage.copy(Bitmap.Config.ARGB_8888, true);

            finalImage = originalImage.copy(Bitmap.Config.ARGB_8888, true);

            imagePreview.setImageBitmap(originalImage);

            bitmap.recycle();

            // render selected image thumbnails

            filtersListFragment.prepareThumbnail(originalImage);

        }

    }

    privatevoidopenImageFromGallery() {

        Dexter.withActivity(this).withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)

                .withListener(newMultiplePermissionsListener() {

                    @Override

                    publicvoidonPermissionsChecked(MultiplePermissionsReport report) {

                        if(report.areAllPermissionsGranted()) {

                            Intent intent = newIntent(Intent.ACTION_PICK);

                            intent.setType("image/*");

                            startActivityForResult(intent, SELECT_GALLERY_IMAGE);

                        } else{

                            Toast.makeText(getApplicationContext(), "Permissions are not granted!", Toast.LENGTH_SHORT).show();

                        }

                    }

                    @Override

                    publicvoidonPermissionRationaleShouldBeShown(List permissions, PermissionToken token) {

                        token.continuePermissionRequest();

                    }

                }).check();

    }

    /*

    * saves image to camera gallery

    * */

    privatevoidsaveImageToGallery() {

        Dexter.withActivity(this).withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)

                .withListener(newMultiplePermissionsListener() {

                    @Override

                    publicvoidonPermissionsChecked(MultiplePermissionsReport report) {

                        if(report.areAllPermissionsGranted()) {

                            finalString path = BitmapUtils.insertImage(getContentResolver(), finalImage, System.currentTimeMillis() + "_profile.jpg", null);

                            if(!TextUtils.isEmpty(path)) {

                                Snackbar snackbar = Snackbar

                                        .make(coordinatorLayout, "Image saved to gallery!", Snackbar.LENGTH_LONG)

                                        .setAction("OPEN", newView.OnClickListener() {

                                            @Override

                                            publicvoidonClick(View view) {

                                                openImage(path);

                                            }

                                        });

                                snackbar.show();

                            } else{

                                Snackbar snackbar = Snackbar

                                        .make(coordinatorLayout, "Unable to save image!", Snackbar.LENGTH_LONG);

                                snackbar.show();

                            }

                        } else{

                            Toast.makeText(getApplicationContext(), "Permissions are not granted!", Toast.LENGTH_SHORT).show();

                        }

                    }

                    @Override

                    publicvoidonPermissionRationaleShouldBeShown(List permissions, PermissionToken token) {

                        token.continuePermissionRequest();

                    }

                }).check();

    }

    // opening image in default image viewer app

    privatevoidopenImage(String path) {

        Intent intent = newIntent();

        intent.setAction(Intent.ACTION_VIEW);

        intent.setDataAndType(Uri.parse(path), "image/*");

        startActivity(intent);

    }

}

运行应用程序并测试一次。您应该看到文章中显示的漂亮界面。您可以从列表中应用不同的滤镜,并可以控制亮度,饱和度和对比度。

已知的问题

1。当前图像控件更改图像控件时,亮度,对比度和饱和度不平滑。这是由于SeekBar值更改时递归处理/复制位图。改进必须在原生水平上完成。

2。过滤器不像Instagram那么好。在库的下一个版本中,我将尝试即兴创建过滤器。

3。过滤器不适合所有类型的图像。例如:具有白色背景的图像看起来与不同的滤镜几乎相似。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容