Usually, in an app we make users upload images like profile images or others. But there is a chance that the uploaded image is only for display purposes, that too in a short frame. So, these images do not have to be stored in a high-resolution format. Hence even if the user uploads a high-resolution pic, the image must be compressed before storing it in database storage. This article explains how to build an Android application that can compress the images before uploading them to Firebase Storage.
Step-by-Step Implementation
Step 1: Create a new project
Create a new project in Android Studio. You can refer to How to Create/Start a New Project in Android Studio. Note that select Java as the programming language.
Step 2: Add the firebase storage dependency in the build.gradle (Module : app) file
Navigate to Gradle Scripts > build.gradle (Module : app) and add the below dependency.
dependencies { implementation platform('com.google.firebase:firebase-bom:31.2.0') implementation 'com.google.firebase:firebase-storage' }
After adding the above dependencies we should sync our project.
Step 3: Working with the activity_main.xml file
Navigate to the app > res > layout > activity_main.xml and add the below code to that file. Below is the code for the activity_main.xml file. There are 3 buttons: one for selecting the image, one for uploading the image without compression, and one for uploading the image with compression. Also, one ImageView is present to display the image.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < RelativeLayout android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context = ".MainActivity" > < LinearLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:padding = "20dp" android:orientation = "vertical" > < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "GFG app to demonstrate image compression before uploading to firebase storage" android:textColor = "@color/GFGgreen" android:textSize = "20sp" /> < Button android:id = "@+id/selectImage" android:layout_marginTop = "20dp" android:layout_marginBottom = "10dp" android:layout_gravity = "center" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Select image" /> < LinearLayout android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:orientation = "horizontal" > < Button android:id = "@+id/upload" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_weight = "1" android:layout_marginRight = "5dp" android:text = "Upload Without Compress" /> < Button android:id = "@+id/uploadWithCompress" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_weight = "1" android:layout_marginLeft = "5dp" android:text = "Upload With Compress" /> </ LinearLayout > < ImageView android:id = "@+id/imageView" android:layout_marginTop = "40dp" android:layout_gravity = "center_horizontal" android:layout_width = "250dp" android:layout_height = "250dp" tools:srcCompat = "@tools:sample/avatars" /> </ LinearLayout > </ RelativeLayout > |
Step 4: Working with the MainActivity.java file
Go to the MainActivity.java file and refer to the following code. Comments are added inside the code to understand the code in more detail.
Java
package com.example.gfggo; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; import com.google.firebase.storage.UploadTask; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; public class MainActivity extends AppCompatActivity { ImageView displayImage; Button selectImage, uploadWithoutCompress, uploadWithCompress; StorageReference storageRef; private static final int REQUEST_CODE = 101 ; Uri imageUri; ProgressDialog mLoadingBar; Bitmap bmp; ByteArrayOutputStream baos; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); displayImage = findViewById(R.id.imageView); selectImage = findViewById(R.id.selectImage); uploadWithoutCompress = findViewById(R.id.upload); uploadWithCompress = findViewById(R.id.uploadWithCompress); storageRef = FirebaseStorage.getInstance().getReference().child( "Images" ); selectImage.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { // for getting images Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, REQUEST_CODE); } }); uploadWithCompress.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (imageUri!= null ){ uploadImageWithCompress(); } } }); uploadWithoutCompress.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (imageUri!= null ){ uploadImageWithoutCompress(); } } }); } private void uploadImageWithCompress() { mLoadingBar = new ProgressDialog(MainActivity. this ); mLoadingBar.setTitle( "Uploading Image with Compress" ); mLoadingBar.setCanceledOnTouchOutside( false ); mLoadingBar.show(); // images are stored with timestamp as their name String timestamp = "" + System.currentTimeMillis(); bmp = null ; try { bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri); } catch (IOException e) { e.printStackTrace(); } baos = new ByteArrayOutputStream(); // here we can choose quality factor // in third parameter(ex. here it is 25) bmp.compress(Bitmap.CompressFormat.JPEG, 25 , baos); byte [] fileInBytes = baos.toByteArray(); storageRef.child(timestamp).putBytes(fileInBytes) .addOnSuccessListener( new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { mLoadingBar.dismiss(); Toast.makeText(MainActivity. this , "Image uploaded successfully!" , Toast.LENGTH_SHORT).show(); } }).addOnFailureListener( new OnFailureListener() { @Override public void onFailure( @NonNull Exception e) { mLoadingBar.dismiss(); Toast.makeText(MainActivity. this , "Image upload failed!" , Toast.LENGTH_SHORT).show(); } }); } private void uploadImageWithoutCompress() { mLoadingBar = new ProgressDialog(MainActivity. this ); mLoadingBar.setTitle( "Uploading Image without Compress" ); mLoadingBar.setCanceledOnTouchOutside( false ); mLoadingBar.show(); final String timestamp = "" + System.currentTimeMillis(); storageRef.child(timestamp).putFile(imageUri) .addOnSuccessListener( new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { mLoadingBar.dismiss(); Toast.makeText(MainActivity. this , "Image uploaded successfully!" , Toast.LENGTH_SHORT).show(); } }).addOnFailureListener( new OnFailureListener() { @Override public void onFailure( @NonNull Exception e) { mLoadingBar.dismiss(); Toast.makeText(MainActivity. this , "Image upload failed!" , Toast.LENGTH_SHORT).show(); } }); } @Override protected void onActivityResult( int requestCode, int resultCode, @Nullable Intent data) { super .onActivityResult(requestCode, resultCode, data); if (requestCode==REQUEST_CODE && resultCode==RESULT_OK && data!= null ){ imageUri = data.getData(); displayImage.setImageURI(imageUri); } } } |
Output:
Main Activity
After selecting an image from the gallery
Firebase storage console
We can clearly observe in the firebase console that the same image which has been compressed takes less space to store.