Text on Photo Android Application Example

In this tutorial, we are going to learn how to create a Text On Photo Android Application. Text on photo app is used when you want to write a message on a picture. It can as well let you send the pictures with your written text to close friends and relatives.

There are many Text On Photo android apps in Google Play. You can search Google Play with keyword text on photo to see examples of this application.

We are not going to include all the features you can think about. If you want to develop it further and add more features, just give it a try.

What our Text On Photo android application example will do is as follow

1. It will let you choose a photo image from your device gallery

2. It offers the ability to write any word on the selected image photo.

3. It lets you save the words on your selected image when you finish writing.

We are going to use one Activity page for this Text On Photo android tutorial. We will make use of the following View controls for our interface design.

1. ImageView – which will hold any of our selected photo image from the device gallery

2. Three Button View controls – First button will launch the device gallery, the second button will launch EditText in a dialog which will accept text input that will appear on the selected photo and the third button will save the text on the photo when a user is done writing.

Right now it is important for us to understand what we are planning to achieve in this tutorial. The screen-shot of our project is shown below.

Android text on image

Before we start, it is important for you to understand the tools and environment I used in this android tutorial. Feel free to use tools you are familiar with.

Windows 7

Android Studio

Sony Xperia ZL

Min SDK 14

Target SDK 23

To create a new android application project, following the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidTextOnImage

Package: com.inducesmile.androidtextonimage

Select Blank Activity

Keep other default selections

Continue to click on next button until Finish button is active, then click on Finish Button.

If you are using Android Studio as your choice IDE, the new project will create a default
MainActivity.java file and its corresponding layout file.

The default layout file is the activity_main.xml. Open you layout file and add all the required View components that we need or alternatively, you can copy and paste the code below in your layout file.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.inducesmile.textonimage.MainActivity"
    tools:showIn="@layout/activity_main">
    <ImageView
        android:id="@+id/main_background"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/sub_menu"
        android:background="@drawable/bg"
        android:layout_alignParentTop="true"/>
    <TextView
        android:id="@+id/text_on_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="32dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:textColor="@color/colorBlack"
        android:textSize="20sp"
        android:textStyle="bold"/>
    <LinearLayout
        android:id="@+id/sub_menu"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@color/colorPrimaryDark"
        android:orientation="horizontal">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center|center_horizontal"
            android:paddingTop="8dp"
            android:orientation="vertical">
            <Button
                android:id="@+id/insert_image"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/insertimage"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center|center_horizontal"
            android:paddingTop="8dp"
            android:orientation="vertical">
            <Button
                android:id="@+id/write_on_image"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/saveimage"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center|center_horizontal"
            android:paddingTop="8dp"
            android:orientation="vertical">
            <Button
                android:id="@+id/save_image"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/saveimage"/>
        </LinearLayout>
        
    </LinearLayout>
</RelativeLayout>

As you can see, our main layout file is very simple to understand. The image resource that were used in the main layout can be found on the download project file. You can change these image resources to you own image of choose.

We are going to make use of android dialog. We want a situation when a button is click it will open an overlay alert dialog that will contain an EditText control which will accept input from users.

In order to create a custom layout for the alert dialog, we are going to create a new layout file called custom_dialog.xml in the project layout folder.

Once you have created this layout file, open the file, copy and paste the following code snippet inside this file.

custom_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:orientation="vertical">
    <EditText
        android:id="@+id/add_text_on_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textColor="@color/colorBlack"
        android:textSize="24sp"
        android:lines="6"
        android:focusable="true"
        android:inputType="text">
        <requestFocus />
    </EditText>
</LinearLayout>

In our MainActivity class, we will get the instances of our View controls; For the three buttons, a click event listener are wired to them so that whenever a user click on each of the Button View control, it will execute a given task.

Inside the load image button object onClickListener() method, we have added an Intent for action pick which will open the device image gallery for image selection.

We have also created a method that is called in the write button object. This method task is to create a custom AlertDialog for text input from users.

Finally, the save button object click event, will create a new photo from the selected photo image with the text written over the selected image. The method ProcessingBitmap(String captionString) takes a string as parameter and return a Bitmap with text on it. The storeImage(Bitmap mBitmap, String path) method takes the returned Bitmap and convert it to image file and store a copy of it in the device.

The code snippet for the MainActivity.java file is shown below.

MainActivity.java

import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class MainActivity extends AppCompatActivity {
    private ImageView mImageView;
    private Button mInsertImageButton;
    private Button mSaveImageButton;
    private Button mWriteOnImage;
    private TextView mTextOnImage;
    private final int RESULT_LOAD_IMAGE = 20;
    private String userInputValue = "";
    private String imagePath = "";
    private Uri pickedImage;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mImageView = (ImageView)findViewById(R.id.main_background);
        mInsertImageButton = (Button)findViewById(R.id.insert_image);
        mSaveImageButton = (Button)findViewById(R.id.save_image);
        mWriteOnImage = (Button)findViewById(R.id.write_on_image);
        mTextOnImage = (TextView)findViewById(R.id.text_on_image);
        mInsertImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                startActivityForResult(i, RESULT_LOAD_IMAGE);
            }
        });
        mWriteOnImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                displayTextBox();
            }
        });
        mSaveImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (userInputValue.equals("") || userInputValue.isEmpty()) {
                    return;
                }
                /*if(imagePath.isEmpty() || imagePath.equals("")){
                    return;
                }*/
                //Bitmap bm = writeTextOnDrawable(userInputValue).getBitmap();
                Bitmap bm = ProcessingBitmap(userInputValue);
                String pathLink = Environment.getExternalStorageDirectory() + File.separator + "testing.jpg";
                storeImage(bm, pathLink);
                //mImageView.setImageBitmap(bm);
                Toast.makeText(MainActivity.this, userInputValue, Toast.LENGTH_LONG).show();
            }
        });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK){
            pickedImage = data.getData();
            String[] filePath = { MediaStore.Images.Media.DATA };
            Cursor cursor = getContentResolver().query(pickedImage, filePath, null, null, null);
            cursor.moveToFirst();
            imagePath = cursor.getString(cursor.getColumnIndex(filePath[0]));
            mImageView.setBackground(convertImagePathToDrawable(imagePath));
        }
    }
    private Drawable convertImagePathToDrawable(String imagePath){
        Drawable d = Drawable.createFromPath(imagePath);
        return d;
    }
    private void displayTextBox(){
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
        LayoutInflater inflater = this.getLayoutInflater();
        final View dialogView = inflater.inflate(R.layout.custom_dialog, null);
        dialogBuilder.setView(dialogView);
        final EditText textContent = (EditText) dialogView.findViewById(R.id.add_text_on_image);
        dialogBuilder.setTitle("");
        dialogBuilder.setMessage("");
        dialogBuilder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                userInputValue = textContent.getText().toString();
                if(!userInputValue.equals("") || !userInputValue.isEmpty()){
                    // assign the content to the TextView object
                    mTextOnImage.setText(userInputValue);
                }
            }
        });
        dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
               dialog.dismiss();
            }
        });
        AlertDialog b = dialogBuilder.create();
        b.show();
    }
    
    private Bitmap ProcessingBitmap(String captionString) {
    Bitmap bm1 = null;
    Bitmap newBitmap = null;
    try {
        Toast.makeText(MainActivity.this, pickedImage.getPath(), Toast.LENGTH_LONG).show();
        bm1 = BitmapFactory.decodeStream(getContentResolver().openInputStream(pickedImage));
        Bitmap.Config config = bm1.getConfig();
        if (config == null) {
            config = Bitmap.Config.ARGB_8888;
        }
        newBitmap = Bitmap.createBitmap(bm1.getWidth(), bm1.getHeight(), config);
        Canvas canvas = new Canvas(newBitmap);
        canvas.drawBitmap(bm1, 0, 0, null);
        Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
        paintText.setColor(Color.BLUE);
        paintText.setTextSize(50);
        paintText.setStyle(Paint.Style.FILL);
        paintText.setShadowLayer(10f, 10f, 10f, Color.BLACK);
        Rect textRect = new Rect();
        paintText.getTextBounds(captionString, 0, captionString.length(), textRect);
        if(textRect.width() >= (canvas.getWidth() - 4))
            paintText.setTextSize(convertToPixels(7));
        int xPos = (canvas.getWidth() / 2) - 2;
        int yPos = (int) ((canvas.getHeight() / 2) - ((paintText.descent() + paintText.ascent()) / 2)) ;
        canvas.drawText(captionString, xPos, yPos, paintText);
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return newBitmap;
}

private void storeImage(Bitmap mBitmap, String path) {
    OutputStream fOut = null;
    File file = new File(path);
        try {
            fOut = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        mBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
        try {
            fOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

This brings us to the end of this tutorial, If you find anything confusing kindly contact me with your questions or use the comment box below.

Now, when you run your application you will see the interface that looks similar to the sample that was shown earlier on.

You can download the code for this tutorial below. If you are having hard time downloading the tutorials, kindly contact me.

Remember to subscribe with your email address so that you will be among the first to receive our new post once it is published.

Please if you love this tutorial, kindly download my new android app – Daily Pocket Calculator – in Google Play Store and let me know what you think about it.

OTHER INTERESTING POSTS:

Add a Comment