Slideshow option in the Phimpme Android Application

The Phimpme Android application along with all the basic features for viewing and sharing images also has some interesting functions, for example, the ability to view all the images at once using the slideshow option. The users can also manage the time duration for which a particular photo will be displayed before switching on to the next image. In this post, we will be discussing how we have achieved this functionality in the Phimpme Android application.

Step 1

First, we have to provide the user with an option to enter the time duration for which they want to view a particular photo. For this, we have made use of the themed dialog box which will take the input from the user and then we will be converting the time entered by them into milliseconds. This can be done by using the following code snippet.

dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.ok).toUpperCase(), new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
       String value= editTextTimeInterval.getText().toString();
       if(!"".equals(value))
       {
           slideshow=true;
           int intValue = Integer.parseInt(value);
           SLIDE_SHOW_INTERVAL = intValue * 1000;

Step 2

For changing the photo at a particular duration of time, we need to make use of the Runnable interface in Java, which uses a method run() to execute the tasks. To use it, we have to create a Handler object and initialize it. This can be done using the following lines of the code.

private Handler handler;
handler = new Handler();

After this, we have to define and initialize our Runnable object which will be used later to change the picture. The code snippet for initializing the runnable object is given below.

Runnable slideShowRunnable = new Runnable() {
   @Override
   public void run() {
       try{
           mViewPager.scrollToPosition((getAlbum().getCurrentMediaIndex() + 1) % getAlbum().getMedia().size());
       }
       catch (Exception e) {
           e.printStackTrace();
       }
       finally{
           handler.postDelayed(this, SLIDE_SHOW_INTERVAL);
       }

As the run() method gets executed, the scrollToPosition function of the ViewPager class gets called which changes the position of the image displayed to the next image available.

Step 3

To call the runnable object we created in the second step, we have to use the postDelayed function of the Handler class which takes in a Runnable object and the time in milliseconds as the parameter. The code snippet for this is provided below.

handler.postDelayed(this, SLIDE_SHOW_INTERVAL);

Please note that we have also included the above line of code in the finally block after each successful run of the method because as the slideshow starts, we will have to call this function to scroll to the new position after every finite provided duration.

This is how we have achieved the Slideshow functionality in the Phimpme Android application. To get the full source code for this implementation, please check out the Phimpme Android GitHub repository listed in the resources section below.

Resources

  1. GitHub – Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
  2. Android Developer Guide – Handler class – https://developer.android.com/reference/android/os/Handler.html
  3. StackOverflow – Runnable in Java – https://stackoverflow.com/questions/13327571/in-a-simple-to-understand-explanation-what-is-runnable-in-java
  4. StackOverflow – Image Slideshow in Android – https://stackoverflow.com/questions/2995145/image-slideshow-example-in-android

 

Compressing Albums in the Phimpme Android Application

The Phimpme Android application comes in with all the functionalities ranging from viewing images to taking photos, editing pictures  and sharing them with the world from within a single application without having to switch to or install other social media apps on your mobile phone. Apart from these basic functionalities, the Phimpme Android app also comes with additional features to enhance user experience like the ability to compress the whole album with a large number of photos so that it becomes easier to share them. In this post, I will be explaining how we achieved this functionality to compress the Albums.

Step 1

The first thing we need to do before compressing an album is to get all the paths of the images in that album and store it in an ArrayList<String> so that it can be used later for the compression process. This can be done using the code snippet provided below, it stores all the paths of the file in a particular folder whose name ends with .jpg

path = new ArrayList<>();
File folder = new File(getAlbums().getSelectedAlbum(0).getPath() + "/");
File[] fpath = folder.listFiles();
for(int i = 0; i < fpath.length; i++){
   if(fpath[i].getPath().endsWith(".jpg") ){
       path.add(fpath[i].getPath());
   }
}

Step 2

Since the compression is a heavy task, we can make use of an AsyncTask to run the task on the background thread so that the user experience is not at all hampered. In the onPreExecute method of the AsyncTask, we need to display the Notification that the compression of the particular album has started, for this we have made use of the Notification handler class that we have created in the Phimpme Android application to ease the process of displaying the notification and to avoid repetition of codes. The onPreExecute method of the AsyncTask is given below.

@Override
protected void onPreExecute() {
   super.onPreExecute();
   NotificationHandler.make(R.string.folder, R.string.zip_fol, R.drawable.ic_archive_black_24dp );
}

Step 3

On the doInBackground method of the AsyncTask, we run the process to compress the files one by one. For this we will make use of the ZipEntry class which is used to represent a zip file entry in Android/Java. First we will create a File with the .zip extension.  After this, we will make use of an object of the class ZipOutputStream as depicted in the code snippet provided below.

BufferedInputStream origin = null; 
FileOutputStream dest = new FileOutputStream(_zipFile); 
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); 
byte data[] = new byte[BUFFER];

After initializing the ZipOutPutStream object, we will put the zip entries in it by using the putNextEntry function of the class. To create a Zip entry of a file, we need to make use of for loop to generate the object of type ZipEntry and after that by using the putNextEntry function of the class, we will put the entries one by one as depicted in the code snippet given below.

for (int i = 0; i < path.size(); i++) {
FileInputStream fi = new FileInputStream(path.get(i));
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(path.get(i).substring(path.get(i).lastIndexOf("/") + 1));
out.putNextEntry(entry);

While preparing the Zip file, we will update the progress of the compression operation by making use of the Notification handler class.

This is how we have implemented the feature to compress the Albums in the Phimpme Android Application. To get the full source code for the same, please check the Phimpme Android GitHub repository listed on the resources below.

Resources

  1. StackOverflow – Compressing Files in Android – https://stackoverflow.com/questions/25562262/how-to-compress-files-into-zip-folder-in-android
  2. Blog – Compressing Files in Android programmatically – http://stacktips.com/tutorials/android/how-to-programmatically-zip-and-unzip-file-in-android
  3. GitHub – Phimpme Android Repository – https://github.com/fossasia/phimpme-android/

Shortcuts in the Phimpme Android Application

The Phimpme Android application comes with a great functionality of capturing moments, editing them, and sharing it with the world using various social media or cloud platforms integrated into the application. Sometimes, the user may want to directly go to a particular section of the application without having to go to the home activity all the time. We have solved this issue using the App shortcuts option which is provided on Android versions greater than 7.0 Nougat. When the user long clicks on the icon of the application, it provides us with multiple options to choose which activity or section we would like to go to as depicted in the screenshot below.

In this post, I will be explaining how we have achieved this functionality in the Phimpme Android application.

Step 1

In the Phimpme app, we have three main sections named Camera, Gallery and Accounts and we have added these three options in the app shortcut menu. To do this, first of all, we need to add a meta data to the main activity in the AndroidManifest.xml file. To do this, search for the activity which contains “android.intent.action.MAIN” and add the following line of code in the activity tag.

<meta-data android:name="android.app.shortcuts"
  android:resource="@xml/shortcuts" />

Step 2

Now after we have configured the manifest file, we need to create shortcuts.xml file in the resources folder which will contain the information about our app shortcuts along with the intent action to go to a particular activity.

After creating the xml file, add the following line of code.

<shortcuts xmlns:tools="http://schemas.android.com/tools"
  xmlns:android="http://schemas.android.com/apk/res/android">

Now after this we have to create a shortcut tag and define the id of our shortcut and should add the icon to it which will be displayed to the user along with the shortcut text as depicted in the screenshot above. This can be done using the following line of code.

android:shortcutId="camera"
android:enabled="true"
android:icon="@drawable/ic_camera_alt_black_24dp"
android:shortcutShortLabel="@string/camera_short"
android:shortcutLongLabel="@string/camera_long"
android:shortcutDisabledMessage="@string/camera_short"

Now after this, we have to define the action which we want to perform when the user clicks on a particular app shortcut. To do this, create an intent tag and add the following lines of code in it.

<intent
  android:action="android.media.action.IMAGE_CAPTURE_SECURE"
  android:targetPackage="org.fossasia.phimpme"
  android:targetClass="org.fossasia.phimpme.opencamera.Camera.CameraActivity" />
<categories android:name="android.intent.category.DEFAULT" />

The above code sets the action type as Image capture and defines the package name of the application. The above code is used to open the Camera activity of the Phimpme Application from the shortcut menu. In the similar fashion as described above, we have implemented the option to open up the Gallery and Accounts section of our application by just modifying the action name of the shortcut.

This is how we have implemented the App shortcut functionality in the Phimpme app. To get the full source code of the Shortcuts.xml file, please refer to the Phimpme Android repository.

Resources

  1. Android Developer’s Guide – App shortcuts – https://developer.android.com/guide/topics/ui/shortcuts.html
  2. GitHub – Google Sample Project to depict the usage of app shortcuts – https://github.com/googlesamples/android-AppShortcuts
  3. Blog – Using app shortcuts in Android 7.0 – http://www.brevitysoftware.com/blog/how-to-use-app-shortcuts-in-android-7-1-nougat/
  4. GitHub – Phimpme Android repository – https://github.com/fossasia/phimpme-android/

Using RecyclerView Instead Of ViewPager For Gallery

Phimpme is an Image app that provide camera, editing ,sharing options and a gallery section. The Gallery section allows us to view large number of images that are locally available in the users device. Generally developers used viewpager to swipe the horizontal images although we are also using viewPager but the problem is it is taking more time to load large size images and that disturb the user smooth experience. After so much research I came to new solution. So in this post, I will be explaining how to use recyclerview to view gallery images instead of viewPager.

Let’s get started

Make sure you have Recyclerview support in your dependencies in build.gradle. As recyclerView required an adapter and viewHolder to set data in recyclerView. So I will be explaining about adapter.

ViewHolder for RecyclerView

public static class ViewHolder extends RecyclerView.ViewHolder {
  ImageView imageView;
  LinearLayout linearLayout;

  public ViewHolder(View itemView) {
      super(itemView);
      imageView = new ImageView(context);
      linearLayout = (LinearLayout) itemView.findViewById(R.id.layout);
      WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
      Display display = wm.getDefaultDisplay();
      Point size = new Point();
      display.getSize(size);
      int width = size.x;
      int height = size.y;
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
              width, height);
      imageView.setLayoutParams(params);
      imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
      linearLayout.addView(imageView);
  }
}

Right now the imageView is adjusting according to device screen size so that it will be compatible with all devices.

I am passing the width and height in LayoutParams to parent of imageview i.e in our case linearlayout is parentView.

Adapter for RecyclerView

public ImageAdapter(ArrayList<Media> media) {
  this.media = media;
}

@Override
public ImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.unit_image_pager, null, false);

  return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
  Glide.with(getContext())
          .load(media.get(position).getUri())
          .diskCacheStrategy(DiskCacheStrategy.SOURCE)
          .thumbnail(0.5f)
          .into(holder.imageView);
  holder.imageView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
          basicCallBack.callBack(0,null);
      }
  });
}

MediaList is an arrray of media that contains the list of images with URI that will help to load images. I am using Glide to load images you can use any library to load images. Adapter helps to load data in recyclerView.

Now set viewPager where you require to scroll images horizontally

@Nullable @BindView(R.id.photos_pager)
RecyclerView mRecylerPager;
mRecylerPager.setLayoutManager(linearLayoutManager);
mRecylerPager.setHasFixedSize(true);
mRecylerPager.setLongClickable(true);

Our recycler view is ready now the most important part is to set things onPageChangeListner. For example : In Phimpme we are getting path of current position image to show in image description so to update the value we are writing that codde in onPageChangeListner and to update the toolbar.

mViewPager.setOnPageChangeListener(new PagerRecyclerView.OnPageChangeListener() {
  @Override
  public void onPageChanged(int oldPosition, int position) {
      getAlbum().setCurrentPhotoIndex(position);
      toolbar.setTitle((position + 1) + " " + getString(R.string.of) + " " + size_all);
      invalidateOptionsMenu();
      pathForDescription = getAlbum().getMedia().get(position).getPath();
  }
});

To scroll to the given position we require to set the position to recyclerView and it can be done by the following code

mViewPager.scrollToPosition(getCurrentPsotion());

This is how I implemented the recyclerView instead of ViewPager to load gallery images faster as compare to ViewPager.

RecyclerView in Phimpme to load gallery Images

Resources:     

 

Real Time Upload Progress in Phimpme Android

The Phimpme Android application along with a wonderful gallery, edit image and camera section comes in with an option to share the images to different connected accounts. For sharing the images to different accounts, we have made use of different SDK’s provided to help users to share the images to multiple accounts at once without having to install other applications on their devices. When the user connects the account and shares the image to any account, we display a snackbar at the bottom that the upload has started and then we display the progress of the uploads in the notification panel as depicted in the screenshot below.

In this tutorial, I will be explaining how we achieved this feature of displaying the upload progress in the Phimpme Android application using a Notification handler class.

Step 1

The first thing we need to do is to create an AsyncTask that will be handling the upload progress and the notification handling in the background without affecting the main UI of the application. This can be done using the upload progress class which is a subclass of the AsyncTask class as depicted below.

private class UploadProgress extends AsyncTask<Void, Integer, Void> {
}

The AsyncTask overrides three methods which are onPreExecute, doInBackground and onPostExecute methods. In the onPreExecute method we will make the uploading notification visible to the user via the Notification handler class.

Step 2

After this, we need to create a notification handler class which will be handling the uploads progress. We will be needing four methods inside of the Notification handler class to :

  1. Make the app notification in the notification panel.
  2. To update the progress of the upload.
  3. To display the upload failed progress.
  4. To display the upload passed progress.

The notification display can be made using the following lines of code below:

mNotifyManager = (NotificationManager) ActivitySwitchHelper.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(ActivitySwitchHelper.getContext());
mBuilder.setContentTitle(ActivitySwitchHelper.getContext().getString(R.string.upload_progress))
      .setContentText(ActivitySwitchHelper.getContext().getString(R.string.progress))
      .setSmallIcon(R.drawable.ic_cloud_upload_black_24dp)
      .setOngoing(true);
mBuilder.setProgress(0, 0, true);
// Issues the notification
mNotifyManager.notify(id, mBuilder.build());

The above code makes use of the Android’s NotificationManager class to get the notification service and sets the title and the upload image which is to be displayed to the user at the time of image uploads.

Now we need to update the notification after every each second to display the real time upload progress to the user. This can be done by using the upload progress method which takes in total file size and the amount of data uploaded as a parameter.

public static void updateProgress(int uploaded, int total, int percent){
  mBuilder.setProgress(total, uploaded, false);
  mBuilder.setContentTitle(ActivitySwitchHelper.getContext().getString(R.string.upload_progress)+" ("+Integer.toString(percent)+"%)");
  // Issues the notification
  mNotifyManager.notify(id, mBuilder.build());

The above updating process can be done in the doInBackground task of the AsyncTask described in step 1.

Step 3

After the upload has completed, the onPostExecute method will be executed and in that we need to make display the status whether the upload passed or failed and we need to set the onProgress value of the notification to be false so that user can remove the notification. This can be done using the following line of code below:

mBuilder.setContentText(ActivitySwitchHelper.getContext().getString(R.string.upload_done))
      // Removes the progress bar
      .setProgress(0,0,false)
      .setContentTitle(ActivitySwitchHelper.getContext().getString(R.string.upload_complete))
      .setOngoing(false);
mNotifyManager.notify(0, mBuilder.build());
mNotifyManager.cancel(id);

This is how we have created and made use of the Notification handler class in the Phimpme Application to display the upload progress in the application. To get the full source code for implementing the uploads to multiple accounts and to display the notification, please refer to the Phimpme Android GitHub repository.

Resources

  1. Google Developer’s Guide – Notification Handling – https://developer.android.com/guide/topics/ui/notifiers/notifications.html
  2. Google Developer’s Guide – AsyncTask in Android – https://developer.android.com/reference/android/os/AsyncTask.html
  3. StackOverflow – Notification Handling – https://stackoverflow.com/questions/31063920/how-to-program-android-notification
  4. GitHub – Phimpme Android Repository – https://github.com/fossasia/phimpme-android/

Handle Large Size Images in Phimpme

Phimpme is an image app which provides custom camera, sharing features along with a well-featured gallery section. In gallery, it allows users to view local images. Right now we are using Glide to load images in the gallery, it is working fine for small size images it lags a bit when it comes to handling the high quality large images in the app. So in this post, I will explaining how to handle large size  images without lagging or without taking much time. To solve this problem I am using android universal image loader library which is very light when compared to glide.

Step – 1

First step is to include the dependency in the phimpme project and it can be done by the following way

dependencies {
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'
}

Step-2

After this create an Android universal image loader instance. We can create imageloader instance in our application class if we want to use the image loader globally.

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
       this).memoryCacheExtraOptions(480, 800).defaultDisplayImageOptions(defaultOptions)
       .diskCacheExtraOptions(480, 800, null).threadPoolSize(3)
       .threadPriority(Thread.NORM_PRIORITY - 2)
       .tasksProcessingOrder(QueueProcessingType.FIFO)
       .denyCacheImageMultipleSizesInMemory()
       .memoryCache(new LruMemoryCache(MAXMEMONRY / 5))
       .diskCache(new UnlimitedDiskCache(cacheDir))
       .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
       .imageDownloader(new BaseImageDownloader(this)) // default
       .imageDecoder(new BaseImageDecoder(false)) // default
       .defaultDisplayImageOptions(DisplayImageOptions.createSimple()).build();
 
 this.imageLoader = ImageLoader.getInstance();
 imageLoader.init(config);

Add the above code in the application class.


Step-3

Now our image loader instance is created now we can load an image easily. But to avoid the out of memory error and large image size error we can set many options to an image loader. In options we can set maximum memory allowed to image loader, maximum resolution and set particular architecture, it can be done in following ways.


Step-4

File cacheDir = com.nostra13.universalimageloader.utils.StorageUtils.getCacheDirectory(this);
 int MAXMEMONRY = (int) (Runtime.getRuntime().maxMemory());

To load an image using universal image loader just pass the URI of an image and to load write the below code.
Now the time is to load an image from local storage. We can load images from local storage, drawable, assets easily.

ImageLoader imageLoader = ((MyApplication)getApplicationContext()).getImageLoader();
 imageLoader.displayImage(imageUri, imageView);

This is how I handled large size image in Phimpme.

Large Image in Phimpme


References :

Getting Image location in the Phimpme Android’s Camera

The Phimpme Android app along with a decent gallery and accounts section comes with a nice camera section stuffed with all the features which a user requires for the day to day usage. It comes with an Auto mode for the best experience and also with a manual mode for the users who like to have some tweaks in the camera according to their own liking. Along with all these, it also has an option to get the accurate coordinates where the image was clicked. When we enable the location from the settings, it extracts the latitude and longitude of the image when it is being clicked and displays the visible region of the map at the top of the image info section as depicted in the screenshot below.

In this tutorial, I will be discussing how we have implemented the location functionality to fetch the location of the image in the Phimpme app.

Step 1

For getting the location from the device, the first step we need is to add the permission in the androidmanifest.xml file to access the GPS and the location services. This can be done using the following lines of code below.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

After this, we need to download install the google play services SDK to access the Google location API. Follow the official google developer’s guide on how to install the Google play services into the project from the resources section below.

Step 2

To get the last known location of the device at the time of clicking the picture we need to make use of the FusedLocationProviderClient class and need to create an object of this class and to initialise it in the onCreate method of the camera activity. This can be done using the following lines of code below:

private FusedLocationProviderClient mFusedLocationClient;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

After we have created and initialised the object mFusedLocationClient, we need to call the getLastLocation method on it as soon as the user clicks on the take picture button in the camera. In this, we can also set onSuccessListener method which will return the Location object when it successfully extracts the present or the last known location of the device. This can be done using the following lines of code below:

mFusedLocationClient.getLastLocation()
       .addOnSuccessListener(this, new OnSuccessListener<Location>() {
           @Override
           public void onSuccess(Location location) {
               if (location != null) {
            //Get the latitude and longitude here
                  }

After this, we can successfully extract the latitude and the longitude of the device in the onSuccess method of the code snippet provided below and can store it in the shared preference to get the map view of the coordinates from a different activity of the application later on when the user tries to get the info of the images.

Step 3

After getting the latitude and longitude, we need to get the image view of the visible region of the map. We can make use of the Glide library to fetch the visible map area from the url which contains our location values and to set it to the image view.

The url of the visible map can be generated using the following lines of code.

String.format(Locale.US, getUrl(value), location.getLatitude(), location.getLongitude());

This is how we have added the functionality to fetch the coordinates of the device at the time of clicking the image and to display the map in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android GitHub repository.

Resources

  1. Google Developer’s : Location services guide – https://developer.android.com/training/location/retrieve-current.html
  2. Google Developer’s : Google play services SDK guide – https://developer.android.com/studio/intro/update.html#channels
  3. GitHub : Open camera Source Code –  https://github.com/almalence/OpenCamera
  4. GitHub : Phimpme Android – https://github.com/fossasia/phimpme-android/
  5. GitHub : Glide library – https://github.com/bumptech/glide

 

Encoding and Decoding Images as Data in UserDefaults in SUSI iOS

In this blog post, I will be explaining how to encode and decode images and save them in UserDefaults so that the image persists even if it is removed from the Photos app. It happens a number of times that images are removed from the gallery by the users which results in the app loosing the image. So, to avoid this, we save the image by encoding it in a data object and save it inside UserDefaults. In SUSI iOS app we simply select an image from the image picker, encode it and save it in UserDefaults. To set the image, we simply fetch the image data from the UserDefaults and decode it to an image.

There are two ways we can do the encoding and decoding process:

  • Using Data object
  • Using Base64 string

For the scope of this tutorial, we will use the Data object.

Implementation Steps

  1. To use the image picker, we need to add permissions to `Info.plist` file.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Susi is requesting to get your current location</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Susi needs to request your gallery access to select wallpaper</string>
  1. Select image from gallery

First, we present an alert which gives an option to select the image from the gallery.

// Show wallpaper options to set wallpaper or clear wallpaper
func showWallpaperOptions() {
  let imageDialog = UIAlertController(title: ControllerConstants.wallpaperOptionsTitle, message: nil, preferredStyle: UIAlertControllerStyle.alert)
  imageDialog.addAction(UIAlertAction(title: ControllerConstants.wallpaperOptionsPickAction, style: .default, handler: { (_: UIAlertAction!) in
  imageDialog.dismiss(animated: true, completion: nil)
  self.showImagePicker()
  }))
  imageDialog.addAction(UIAlertAction(title: ControllerConstants.wallpaperOptionsNoWallpaperAction, style: .default, handler: { (_: UIAlertAction!) in
    imageDialog.dismiss(animated: true, completion: nil)
    self.removeWallpaperFromUserDefaults()
  }))
  imageDialog.addAction(UIAlertAction(title: ControllerConstants.dialogCancelAction, style: .cancel, handler: { (_: UIAlertAction!) in
    imageDialog.dismiss(animated: true, completion: nil)
  }))
  self.present(imageDialog, animated: true, completion: nil)
}

Here, we create and UIAlertController with three options to select, one which presents the image picker controller, the second one removes the background wallpaper and the third dismisses the alert.

  1. Set the image as background view
// Callback when image is selected from gallery
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
  dismiss(animated: true, completion: nil)
  let chosenImage = info[UIImagePickerControllerOriginalImage] as? UIImage
  if let image = chosenImage {
    setBackgroundImage(image: image)
  }
}

We use the `didFinishPickingMediaWithInfo` delegate method to set the image as background. First we get the image using the the `info` dictionary using the `UIImagePickerControllerOriginalImage` key.

  1. Save the image in UserDefaults (encoding)
// Save image selected by user to user defaults
func saveWallpaperInUserDefaults(image: UIImage!) {
  let imageData = UIImageJPEGRepresentation(image!, 1.0)
  let defaults = UserDefaults.standard
  defaults.set(imageData, forKey: userDefaultsWallpaperKey)
}

We first convert the image to a data object using the `UIImageJPEGRepresentation` method followed by saving the data object in UserDefaults with the key `wallpaper`.

  1. Decode the data object back to UIImage 

Now whenever we need to decode the image, we simply get the data object from the UserDefaults and use it to display the image.

// Check if user defaults have an image data saved else return nil/Any
func getWallpaperFromUserDefaults() -> Any? {
  let defaults = UserDefaults.standard
  return defaults.object(forKey: userDefaultsWallpaperKey)
}

Below is the output when an image is selected and displayed as a background.

Resources: