Introduction
This article all about developing real-life mobile applications in Xamarin.Android with the help of a hashing algorithm that will be used for detecting duplicate images from any mobile device with 100% accuracy. Today, I will show you how to build an app that will help you on a daily basis for finding duplicate images from your phone.
This article all about developing real-life mobile applications in Xamarin.Android with the help of a hashing algorithm that will be used for detecting duplicate images from any mobile device with 100% accuracy. Today, I will show you how to build an app that will help you on a daily basis for finding duplicate images from your phone.
Why This App?
Nowadays, every person has social media apps like WhatsApp, Facebook Messenger, and Instagram. It's common to receive images from contacts but sometimes you may receive the same image from many friends. However, it is very difficult to see images from the gallery one by one and try to find duplicate images to clean your data and storage. Duplicate data is very harmful when you have low memory storage. Under consideration of this problem, I planned to build a duplicate finder that finds the duplicate images for you so you only need to press the delete button if you want to delete them. In this post, I will teach you how to build this app exactly with all frontend and backend-coding. So, let get started In the initial stage, we need all the images of references that we have on our phone. Moreover, put these references to a list of string and implement an algorithm on these references to get hashing of every item. After getting hashing, we will use LINQ to find similar hashes with their references and put these to a new List of string with namedListOfduplicates. The steps given below are required to be followed in order to create a Duplicate Image Detector app in Xamarin.Android, using Visual Studio. Prerequisites You will be required to install all of these Nuget Packages to build this app.- Xamarin.Android.Support.v7.AppCompat
- Xamarin.Android.Support.Design
- Xamarin.Android.Support.v7.CardView
- Xamarin.Android.Support.v7.RecyclerView
Step 1 - Create an Android Project Create your Android solution in Visual Studio or Xamarin Studio. Select Android and from the list, choose Android Blank App. Give it a name, like DuplicateImageDetector.(ProjectName: DuplicateImageDetector) Step 2 - Install Nuget Packages After creating a blank project, first, add all of the above-mentioned NuGet packages to this project by right-clicking on References and select manage NuGet packages. Step 3 - User Interface of Application Open Solution Explorer-> Project Name-> Resources-> Layout-> activity_main.axml. Open this main layout file and add the following code. In the layout, we will need the two buttons and RecyclerView holder. (File Name: activity_main.axml , Folder Name: Layout)- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout 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"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:minWidth="25px"
- android:minHeight="25px">
- <Button
- android:id="@+id/btnChoose"
- android:text="Check Duplicate Images"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <Button
- android:id="@+id/btnDelete"
- android:text="Delete Duplicate Images"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <android.support.v7.widget.RecyclerView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/reycyclerViewImages" />
- </LinearLayout>
Step 4 - Add Item Layout Next, add a new layout by going to Solution Explorer-> Project Name-> Resources-> Layout. Right-click to add a new item, select Layout, and give it a name, such as ItemLayout.axml. Open this layout file and add the following code. (Folder Name: Layout , File Name: ItemLayout.axml)- <?xml version="1.0" encoding="utf-8"?>
- <android.support.v7.widget.CardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:card_view="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="200dp"
- android:layout_margin="6dp"
- card_view:cardUseCompatPadding="true"
- card_view:cardElevation="4dp"
- >
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/imageitem"/>
- </android.support.v7.widget.CardView>
Step 5 - Add File Detail and Image Holder Class Add two new classes with name FileDetails.cs and ImageHolder.cs by right-clicking on project, Add New Class, and replace the following code:- public class FileInfo
- {
- public string Name { get; set; }
- public string Hash { get; set; }
- }
- public class ImageHolder
- {
- public string ImagePath { get; set; }
- }
Step 6 - Writing the Adapter Class After completing the layout, let’s start writing the adapter class to render the data. The RecyclerView adapter is the same as ListView but the override methods are different. Select Add -> New Item-> Class. Give it a name like CustomAdapter.cs and write the following code with appropriate namespaces. (File Name: CustomAdapter.cs)- public class CustomAdapter : Android.Support.V7.Widget.RecyclerView.Adapter
- {
- private List<ImageHolder> mValues = new List<ImageHolder>();
- public CustomAdapter(List<ImageHolder> list)
- {
- mValues = list;
- }
- public override int ItemCount => mValues.Count;
-
- public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
- {
-
- ViewHolderTicket nView = holder as ViewHolderTicket;
- nView.mItem = mValues[position];
-
- File imgFile = new File(mValues[position].ImagePath);
- if (imgFile.Exists())
- {
- Bitmap myBitmap = BitmapFactory.DecodeFile(imgFile.AbsolutePath);
-
- nView._imageView.SetImageBitmap(myBitmap);
- }
- }
-
- public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
- {
- View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ItemLayout, parent, false);
- ImageView imageView = view.FindViewById<ImageView>(Resource.Id.imageitem);
-
- ViewHolderTicket vh = new ViewHolderTicket(view)
- {
- _imageView = imageView,
- };
- return vh;
- }
- public void UpdateImages()
- {
- mValues.Clear();
- }
- }
- public class ViewHolderTicket : RecyclerView.ViewHolder
- {
- public ImageView _imageView { get; set; }
- public ImageHolder mItem;
- public ViewHolderTicket(View view) : base(view)
- {
- _imageView = view.FindViewById<ImageView>(Resource.Id.imageitem);
- }
- }
Step 7 - Main Activity Lastly, go to Solution Explorer-> Project Name-> MainActivity and add the following code to the main activity with the appropriate namespaces. (FileName: MainActivity)- public class MainActivity : AppCompatActivity
- {
- List<ImageHolder> ToDelete;
- CustomAdapter _adapter;
- private Button btnChoose, btnDelete;
- private RecyclerView recyclerView;
- protected override void OnCreate(Bundle savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
-
- // Set our view from the "main" layout resource
- SetContentView(Resource.Layout.activity_main);
- recyclerView = FindViewById<RecyclerView>(Resource.Id.reycyclerViewImages);
- btnChoose = FindViewById<Button>(Resource.Id.btnChoose);
- btnDelete = FindViewById<Button>(Resource.Id.btnDelete);
-
- //Events
- btnChoose.Click += delegate
- {
- double totalSize = 0;
- var fileLists = AllImage();
- //int totalFiles = fileLists.Count;
- List<FileInfo> finalInfo = new List<FileInfo>();
-
- ToDelete = new List<ImageHolder>();
-
- foreach (var item in fileLists)
- {
- using (var fs = new FileStream(item, FileMode.Open, FileAccess.Read))
- {
- finalInfo.Add(new FileInfo()
- {
- Name = item,
- Hash = BitConverter.ToString(SHA1.Create().ComputeHash(fs)),
- });
- }
- }
-
- //group by file hash code
- var similarList = finalInfo.GroupBy(f => f.Hash)
- .Select(g => new { Hash = g.Key, Files = g.Select(z => z.Name).ToList() });
- var somevar = similarList.SelectMany(f => f.Files.Skip(1)).ToList();
- List<ImageHolder> secondList = new List<ImageHolder>();
- foreach (var item in somevar)
- {
- secondList.Add(new ImageHolder { ImagePath = item });
- }
- ToDelete.AddRange(secondList);
- var layoutManager = new LinearLayoutManager(this);
- recyclerView.SetLayoutManager(layoutManager);
- _adapter = new CustomAdapter(ToDelete);
- recyclerView.SetAdapter(_adapter);
- if (ToDelete.Count > 0)
- {
- foreach (var item in ToDelete)
- {
- FileInfo fi = new FileInfo(item.ImagePath);
- totalSize += fi.Length;
- }
- btnDelete.Text = "Delete Size " + Math.Round((totalSize / 1000000), 2).ToString() + " MB";
- }
- Toast.MakeText(this, "Total No of Duplicate Images " + ToDelete.Count, ToastLength.Long).Show();
- };
-
- btnDelete.Click += delegate
- {
- if(ToDelete.Count > 0)
- {
- foreach (var file in ToDelete)
- {
- var imgFile = new Java.IO.File(file.ImagePath);
- if (imgFile.Exists())
- {
- imgFile.Delete();
- }
- }
- _adapter.UpdateImages();
- }
- else
- {
- Toast.MakeText(this, "Images not found for deleting.", ToastLength.Short).Show();
- }
- };
- }
-
- private List<string> AllImage()
- {
- List<string> AllImages = new List<string>();
-
- Android.Net.Uri uri;
- ICursor cursor;
- int column_index_data;
- string absolutePathOfImage = null;
- uri = Android.Provider.MediaStore.Images.Media.ExternalContentUri;
- string[] projection = { MediaStore.MediaColumns.Data, MediaStore.Images.Media.InterfaceConsts.BucketDisplayName };
- cursor = ApplicationContext.ContentResolver.Query(uri, projection, null, null,null);
- column_index_data = cursor.GetColumnIndexOrThrow(MediaStore.MediaColumns.Data);
- while (cursor.MoveToNext())
- {
- absolutePathOfImage = cursor.GetString(column_index_data);
- AllImages.Add(absolutePathOfImage);
- }
- //Toast.MakeText(this, "Number of Images " + AllImages.Count, ToastLength.Short).Show();
- return AllImages;
- }
- }
Step 9 - Permissions From Device We need permission from the device because we shall be using the device’s READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE. Please add External Storage permission to your AndroidManifest.xml.Let's open Solution Explorer-> Properties-> AndroidManifest and let's add the code inside application tags. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Nowadays, every person has social media apps like WhatsApp, Facebook Messenger, and Instagram. It's common to receive images from contacts but sometimes you may receive the same image from many friends. However, it is very difficult to see images from the gallery one by one and try to find duplicate images to clean your data and storage.
Duplicate data is very harmful when you have low memory storage. Under consideration of this problem, I planned to build a duplicate finder that finds the duplicate images for you so you only need to press the delete button if you want to delete them.
In this post, I will teach you how to build this app exactly with all frontend and backend-coding. So, let get started
In the initial stage, we need all the images of references that we have on our phone. Moreover, put these references to a list of string and implement an algorithm on these references to get hashing of every item. After getting hashing, we will use LINQ to find similar hashes with their references and put these to a new List of string with named
ListOfduplicates.
The steps given below are required to be followed in order to create a Duplicate Image Detector app in Xamarin.Android, using Visual Studio.
Prerequisites
You will be required to install all of these Nuget Packages to build this app.
- Xamarin.Android.Support.v7.AppCompat
- Xamarin.Android.Support.Design
- Xamarin.Android.Support.v7.CardView
- Xamarin.Android.Support.v7.RecyclerView
Step 1 - Create an Android Project
Create your Android solution in Visual Studio or Xamarin Studio. Select Android and from the list, choose Android Blank App. Give it a name, like DuplicateImageDetector.
(ProjectName: DuplicateImageDetector)
Step 2 - Install Nuget Packages
After creating a blank project, first, add all of the above-mentioned NuGet packages to this project by right-clicking on References and select manage NuGet packages.
Step 3 - User Interface of Application
Open Solution Explorer-> Project Name-> Resources-> Layout-> activity_main.axml. Open this main layout file and add the following code. In the layout, we will need the two buttons and RecyclerView holder.
(File Name: activity_main.axml , Folder Name: Layout)
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout 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"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:minWidth="25px"
- android:minHeight="25px">
- <Button
- android:id="@+id/btnChoose"
- android:text="Check Duplicate Images"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <Button
- android:id="@+id/btnDelete"
- android:text="Delete Duplicate Images"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <android.support.v7.widget.RecyclerView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/reycyclerViewImages" />
- </LinearLayout>
Step 4 - Add Item Layout
Next, add a new layout by going to Solution Explorer-> Project Name-> Resources-> Layout. Right-click to add a new item, select Layout, and give it a name, such as ItemLayout.axml. Open this layout file and add the following code.
(Folder Name: Layout , File Name: ItemLayout.axml)
- <?xml version="1.0" encoding="utf-8"?>
- <android.support.v7.widget.CardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:card_view="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="200dp"
- android:layout_margin="6dp"
- card_view:cardUseCompatPadding="true"
- card_view:cardElevation="4dp"
- >
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/imageitem"/>
- </android.support.v7.widget.CardView>
Step 5 - Add File Detail and Image Holder Class
Add two new classes with name FileDetails.cs and ImageHolder.cs by right-clicking on project, Add New Class, and replace the following code:
- public class FileInfo
- {
- public string Name { get; set; }
- public string Hash { get; set; }
- }
- public class ImageHolder
- {
- public string ImagePath { get; set; }
- }
Step 6 - Writing the Adapter Class
After completing the layout, let’s start writing the adapter class to render the data. The RecyclerView adapter is the same as ListView but the override methods are different. Select Add -> New Item-> Class. Give it a name like CustomAdapter.cs and write the following code with appropriate namespaces.
(File Name: CustomAdapter.cs)
- public class CustomAdapter : Android.Support.V7.Widget.RecyclerView.Adapter
- {
- private List<ImageHolder> mValues = new List<ImageHolder>();
- public CustomAdapter(List<ImageHolder> list)
- {
- mValues = list;
- }
- public override int ItemCount => mValues.Count;
- public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
- {
- ViewHolderTicket nView = holder as ViewHolderTicket;
- nView.mItem = mValues[position];
- File imgFile = new File(mValues[position].ImagePath);
- if (imgFile.Exists())
- {
- Bitmap myBitmap = BitmapFactory.DecodeFile(imgFile.AbsolutePath);
- nView._imageView.SetImageBitmap(myBitmap);
- }
- }
- public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
- {
- View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ItemLayout, parent, false);
- ImageView imageView = view.FindViewById<ImageView>(Resource.Id.imageitem);
- ViewHolderTicket vh = new ViewHolderTicket(view)
- {
- _imageView = imageView,
- };
- return vh;
- }
- public void UpdateImages()
- {
- mValues.Clear();
- }
- }
- public class ViewHolderTicket : RecyclerView.ViewHolder
- {
- public ImageView _imageView { get; set; }
- public ImageHolder mItem;
- public ViewHolderTicket(View view) : base(view)
- {
- _imageView = view.FindViewById<ImageView>(Resource.Id.imageitem);
- }
- }
Step 7 - Main Activity
Lastly, go to Solution Explorer-> Project Name-> MainActivity and add the following code to the main activity with the appropriate namespaces.
(FileName: MainActivity)
- public class MainActivity : AppCompatActivity
- {
- List<ImageHolder> ToDelete;
- CustomAdapter _adapter;
- private Button btnChoose, btnDelete;
- private RecyclerView recyclerView;
- protected override void OnCreate(Bundle savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
- // Set our view from the "main" layout resource
- SetContentView(Resource.Layout.activity_main);
- recyclerView = FindViewById<RecyclerView>(Resource.Id.reycyclerViewImages);
- btnChoose = FindViewById<Button>(Resource.Id.btnChoose);
- btnDelete = FindViewById<Button>(Resource.Id.btnDelete);
- //Events
- btnChoose.Click += delegate
- {
- double totalSize = 0;
- var fileLists = AllImage();
- //int totalFiles = fileLists.Count;
- List<FileInfo> finalInfo = new List<FileInfo>();
- ToDelete = new List<ImageHolder>();
- foreach (var item in fileLists)
- {
- using (var fs = new FileStream(item, FileMode.Open, FileAccess.Read))
- {
- finalInfo.Add(new FileInfo()
- {
- Name = item,
- Hash = BitConverter.ToString(SHA1.Create().ComputeHash(fs)),
- });
- }
- }
- //group by file hash code
- var similarList = finalInfo.GroupBy(f => f.Hash)
- .Select(g => new { Hash = g.Key, Files = g.Select(z => z.Name).ToList() });
- var somevar = similarList.SelectMany(f => f.Files.Skip(1)).ToList();
- List<ImageHolder> secondList = new List<ImageHolder>();
- foreach (var item in somevar)
- {
- secondList.Add(new ImageHolder { ImagePath = item });
- }
- ToDelete.AddRange(secondList);
- var layoutManager = new LinearLayoutManager(this);
- recyclerView.SetLayoutManager(layoutManager);
- _adapter = new CustomAdapter(ToDelete);
- recyclerView.SetAdapter(_adapter);
- if (ToDelete.Count > 0)
- {
- foreach (var item in ToDelete)
- {
- FileInfo fi = new FileInfo(item.ImagePath);
- totalSize += fi.Length;
- }
- btnDelete.Text = "Delete Size " + Math.Round((totalSize / 1000000), 2).ToString() + " MB";
- }
- Toast.MakeText(this, "Total No of Duplicate Images " + ToDelete.Count, ToastLength.Long).Show();
- };
- btnDelete.Click += delegate
- {
- if(ToDelete.Count > 0)
- {
- foreach (var file in ToDelete)
- {
- var imgFile = new Java.IO.File(file.ImagePath);
- if (imgFile.Exists())
- {
- imgFile.Delete();
- }
- }
- _adapter.UpdateImages();
- }
- else
- {
- Toast.MakeText(this, "Images not found for deleting.", ToastLength.Short).Show();
- }
- };
- }
- private List<string> AllImage()
- {
- List<string> AllImages = new List<string>();
- Android.Net.Uri uri;
- ICursor cursor;
- int column_index_data;
- string absolutePathOfImage = null;
- uri = Android.Provider.MediaStore.Images.Media.ExternalContentUri;
- string[] projection = { MediaStore.MediaColumns.Data, MediaStore.Images.Media.InterfaceConsts.BucketDisplayName };
- cursor = ApplicationContext.ContentResolver.Query(uri, projection, null, null,null);
- column_index_data = cursor.GetColumnIndexOrThrow(MediaStore.MediaColumns.Data);
- while (cursor.MoveToNext())
- {
- absolutePathOfImage = cursor.GetString(column_index_data);
- AllImages.Add(absolutePathOfImage);
- }
- //Toast.MakeText(this, "Number of Images " + AllImages.Count, ToastLength.Short).Show();
- return AllImages;
- }
- }
Step 9 - Permissions From Device
We need permission from the device because we shall be using the device’s READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE. Please add External Storage permission to your AndroidManifest.xml.Let's open Solution Explorer-> Properties-> AndroidManifest and let's add the code inside application tags.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Summary
This was the process of creating a Duplicate Image Detector app in Xamarin.Android, using Visual Studio. Please share your comments and feedback.
This was the process of creating a Duplicate Image Detector app in Xamarin.Android, using Visual Studio. Please share your comments and feedback.
0 Comments:
Post a Comment