14。打開FiltersListFragment.java并進行如下所示的修改。這里
>?FilterPack.getFilterPack()提供庫中可用過濾器的列表。
>在prepareThumbnail()方法中,過濾器被填充,并且每個縮略圖項目都被添加到ThumbnailsManager以處理它們。處理后的縮略圖將添加回thumbnailItemList,后者是RecyclerView的數(shù)據(jù)資源。
>縮略圖數(shù)據(jù)集準備就緒后,調(diào)用mAdapter.notifyDataSetChanged()來渲染列表。所有這些都是在后臺線程中完成的,因為圖像處理需要一段時間,我們不應該阻止主線程。
>每當選擇新過濾器時,FiltersListFragmentListener接口都會為主活動提供回調(diào)方法。
>?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.添加圖像編輯控件片段
現(xiàn)在我們將添加圖像控件片段來控制亮度,對比度和飽和度。
15。按照與上一步相同的步驟再創(chuàng)建一個名為EditImageFragment.java的片段。打開此片段fragment_edit_image.xml的布局文件,并執(zhí)行如下修改。
在這個布局中,我們將添加三個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值發(fā)生更改時,EditImageFragmentListener接口都會提供回調(diào)方法。
>在回調(diào)時,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.實現(xiàn)主界面(組合片段)
現(xiàn)在我們準備好了片段,讓我們看看如何將它們組合起來以實現(xiàn)我們的最終輸出。
17。打開主活動activity_main.xml和content_main.xml以及NonSwipeableViewPager和TabLayout的布局文件。
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并執(zhí)行如下所示的更改。
>調(diào)用System.loadLibrary(“NativeImageProcessor”)來初始化本機庫。
>?FiltersListFragment和EditImageFragments加到ViewPager在setupViewPager()方法。
>?onFilterSelected()當在被選擇的過濾器將被稱為FiltersListFragment。處理選定的過濾器,并顯示最終圖像imagePreview。
>?onBrightnessChanged(),onSaturationChanged()和onContrastChanged()方法將在EditImageFragments中的Seekbar值更改時調(diào)用。
>從工具欄中選擇“保存”選項后,最終圖像將保存到圖庫。
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那么好。在庫的下一個版本中,我將嘗試即興創(chuàng)建過濾器。
3。過濾器不適合所有類型的圖像。例如:具有白色背景的圖像看起來與不同的濾鏡幾乎相似。