Merge Multiple Images into One Image in Android

2012, Jun 09    

Introduction: 


            This blog post is completely related to my previous post Splitting an image into smaller chunks. As far as the work is concerned both are responsible for completely opposite work. First one is responsible for splitting and this one is responsible for merging.

Where We Need This?


             As I said in my previous post this kind of splitting and merging concept is very much essential for sending and receiving larger image files across the web.
             My previous post will help you to send larger image files and this post will help you to merge the received image chunks to get the original one.

How To Achieve This?


We simply need to follow the following steps to achieve this.
  1. Get all the smaller image chunks.
  2. Find the width and height of those smaller images. (NOTE: all image chunks are of same size)
  3. Create a Bitmap with width = width_of_each_smaller_chunk * rows and height = height_of_each_smaller_chunk * columns.
  4. Create a Canvas encapsulating the Bitmap object in it.
  5. Now draw the smaller chunks on the Canvas object.

Source Code:


The below code snippet shows how to merge smaller image chunks into one.


package com.example.android.imagemerger;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;

/**
* @author Chandra Sekhar Nayak
* @version 1.0
*
* This class is an activity and will displayed first when
* application starts This Activity will display small images in a grid
* view It also shows a button showing "Merge" on it. When clicks
* merges the small image chunks
*/
public class SmallImagesActivity extends Activity implements OnClickListener {

ArrayList<Bitmap> smallImages;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_grid);

// This application will for merging number of smaller chunks to make
// the original So for that we need some smaller image chunks. As I
// don't have any smaller images, so I programmatically first split an
// image to get the smaller image chunks and then merge them to get the
// original one. If you want you can also get some smaller chunks and
// directly merge them. The below 4 lines of code does the splitting
// operation
ImageView image = new ImageView(getApplicationContext());
image.setImageResource(R.drawable.katewinslet);
int chunkNumbers = 25;
smallImages = splitImage(image, chunkNumbers);

// This code is to show all the smaller image chunks into a grid
// structure
GridView grid = (GridView) findViewById(R.id.gridview);
grid.setAdapter(new ImageAdapter(this, smallImages));
grid.setNumColumns(5);

// This gets the merge button and registers an click listener on it.
Button mergeButton = (Button) findViewById(R.id.merge_button);
mergeButton.setOnClickListener(this);
}

/**
* Splits the source image and show them all into a grid in a new activity
*
* @param image The source image to split
* @param chunkNumbers The target number of small image chunks to be formed
* from the source image
* @return ArrayList<Bitmap> The resulted smaller image chunks in a List of
* Bitmaps
*/
private ArrayList<Bitmap> splitImage(ImageView image, int chunkNumbers) {

// For the number of rows and columns of the grid to be displayed
int rows, cols;
rows = cols = 5;

// For height and width of the small image chunks
int chunkHeight, chunkWidth;

// To store all the small image chunks in bitmap format in this list
ArrayList<Bitmap> chunkedImages = new ArrayList<Bitmap>(chunkNumbers);

// Getting the scaled bitmap of the source image
BitmapDrawable drawable = (BitmapDrawable) image.getDrawable();
Bitmap bitmap = drawable.getBitmap();
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(),
bitmap.getHeight(), true);

rows = cols = (int) Math.sqrt(chunkNumbers);
chunkHeight = bitmap.getHeight() / rows;
chunkWidth = bitmap.getWidth() / cols;

// xCoord and yCoord are the pixel positions of the image chunks
int yCoord = 0;
for (int x = 0; x < rows; x++) {
int xCoord = 0;
for (int y = 0; y < cols; y++) {
chunkedImages.add(Bitmap.createBitmap(scaledBitmap, xCoord, yCoord, chunkWidth,
chunkHeight));
xCoord += chunkWidth;
}
yCoord += chunkHeight;
}
return chunkedImages;
}

/**
* This method actually implements the code for merging the small images
* @see android.view.View.OnClickListener#onClick(android.view.View)
*/
@Override
public void onClick(View view) {

// Get the width and height of the smaller chunks
int chunkWidth = smallImages.get(0).getWidth();
int chunkHeight = smallImages.get(0).getHeight();

// create a bitmap of a size which can hold the complete image after
// merging
Bitmap bitmap = Bitmap.createBitmap(chunkWidth * 5, chunkHeight * 5,
Bitmap.Config.ARGB_4444);

// create a canvas for drawing all those small images
Canvas canvas = new Canvas(bitmap);
int count = 0;
for (int rows = 0; rows < 5; rows++) {
for (int cols = 0; cols < 5; cols++) {
canvas.drawBitmap(smallImages.get(count), chunkWidth * cols, chunkHeight * rows,
null);
count++;
}
}

// The result image is shown in a new Activity
Intent intent = new Intent(SmallImagesActivity.this, MergedImage.class);
intent.putExtra("merged_image", bitmap);
startActivity(intent);
}
}

Some Important points:


            Note that the actual code for merge operation is inside the onClick() method of the above code snippet. Below is the description about the variables of the onClick() method.
  1. chunkHeight & chunkWidth : Height and Width of smaller image chunks.
  2. smallImages : An ArrayList<Bitmap> object which stores all the smaller image chunks in their bitmap format.
  3. bitmap : The target bitmap which will represent the original image after merge.
  4. canvas : The canvas object encapsulating the target bitmap to draw the smaller image chunks.
You need to FOCUS more on the following line of code of onClick() method.

Bitmap bitmap = Bitmap.createBitmap(chunkWidth * 5, chunkHeight * 5, Bitmap.Config.ARGB_4444); 


            The 3rd argument of the createBitmap() method is the configuration for the Bitmap. I used Bitmap.Config.ARGB_4444. Documentation recommends ARGB_8888 instead of ARGB_4444. As ARGB_8888 will give you more qualitative image, so there is every chance of getting BINDER TRANSACTION FAILED error if your device configuration is low. So I used ARGB_4444, if you are not getting any error with ARGB_8888, ten better go for that. For more information about these configuration see this.

Reference:


You can download the complete source code from My Google Drive Account.
If you want to achieve the same in Java using ImageIO, then you can see this.

Screen Shots:


Source Images
Source Images
Result Image
Result Image