29

I want to draw text on image ( for saving that image with text ). i have image view i set bitmap to that image i want to Draw the text on image (text entered by user ). i tried this before saving.....

void saveImage() {
    File myDir=new File("/sdcard/saved_images");
    myDir.mkdirs();
    Random generator = new Random();
    int n = 10000;
    n = generator.nextInt(n);
    String fname = "Image-"+ n +".jpg";
    File file = new File (myDir, fname);
    if (file.exists ()) file.delete (); 
    try {
           FileOutputStream out = new FileOutputStream(file);
           originalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
           out.flush();
           out.close();

    } catch (Exception e) {
           e.printStackTrace();
    }
}

Xml code is..

<FrameLayout 
     android:id="@+id/framelayout"
     android:layout_marginTop="30dip"
     android:layout_height="fill_parent" 
     android:layout_width="fill_parent">

     <ImageView 
          android:id="@+id/ImageView01"
          android:layout_alignParentTop="true"
          android:layout_height="wrap_content" 
          android:layout_width="wrap_content"/>

     <TextView android:id="@+id/text_view2"
          android:layout_marginTop="20dip"
          android:layout_width="wrap_content" 
          android:text="SampleText"
          android:textSize="12pt"
          android:layout_alignTop="@+id/ImageView01" 
          android:layout_height="wrap_content"/>  

</FrameLayout>
RajaReddy PolamReddy
  • 22,428
  • 19
  • 115
  • 166

7 Answers7

61

As suggested by Vladislav Skoumal, try this method:

public Bitmap drawTextToBitmap(Context mContext,  int resourceId,  String mText) {
    try {
         Resources resources = mContext.getResources();
         float scale = resources.getDisplayMetrics().density;
         Bitmap bitmap = BitmapFactory.decodeResource(resources, resourceId);
         android.graphics.Bitmap.Config bitmapConfig =   bitmap.getConfig();
         // set default bitmap config if none
         if(bitmapConfig == null) {
           bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
         }
         // resource bitmaps are imutable,
         // so we need to convert it to mutable one
         bitmap = bitmap.copy(bitmapConfig, true);

         Canvas canvas = new Canvas(bitmap);
         // new antialised Paint
         Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
         // text color - #3D3D3D
         paint.setColor(Color.rgb(110,110, 110));
         // text size in pixels
         paint.setTextSize((int) (12 * scale));
         // text shadow
         paint.setShadowLayer(1f, 0f, 1f, Color.DKGRAY);

         // draw text to the Canvas center
         Rect bounds = new Rect();
         paint.getTextBounds(mText, 0, mText.length(), bounds);
         int x = (bitmap.getWidth() - bounds.width())/6;
         int y = (bitmap.getHeight() + bounds.height())/5;

         canvas.drawText(mText, x * scale, y * scale, paint);

         return bitmap;
    } catch (Exception e) {
        // TODO: handle exception

        return null;
    }

}

call this method

Bitmap bmp =drawTextToBitmap(this,R.drawable.aa,"Hello Android");
img.setImageBitmap(bmp);

the output

enter image description here

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Ashish Dwivedi
  • 8,048
  • 5
  • 58
  • 78
  • 1
    @Ruhollahツ I posted this answer 4 year back, Now there are multiple library available for work on image. – Ashish Dwivedi May 08 '17 at 05:17
  • 3
    @DwivediJi hi, can you please share the name of these libraries ? – dreampowder Jun 04 '18 at 12:21
  • @DwivediJi, there is one problem with this approach. If the image size is small, the text drawn over the image appears enlarged. However, If the image size is large, the text appears shrunk. Please refer to this for greater details https://stackoverflow.com/questions/69578026/canvas-drawtext-changes-text-size-for-different-size-images – iCantC Oct 16 '21 at 10:57
30

Updated SaveImage() method, to support text drawing.

void saveImage() {
    File myDir=new File("/sdcard/saved_images");
    myDir.mkdirs();
    Random generator = new Random();
    int n = 10000;
    n = generator.nextInt(n);
    String fname = "Image-"+ n +".jpg";
    File file = new File (myDir, fname);
    if (file.exists ()) file.delete (); 
    try {
        FileOutputStream out = new FileOutputStream(file);

        // NEWLY ADDED CODE STARTS HERE [
            Canvas canvas = new Canvas(originalBitmap);

            Paint paint = new Paint();
            paint.setColor(Color.WHITE); // Text Color
            paint.setTextSize(12); // Text Size
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); // Text Overlapping Pattern
            // some more settings...

            canvas.drawBitmap(originalBitmap, 0, 0, paint);
            canvas.drawText("Testing...", 10, 10, paint);
        // NEWLY ADDED CODE ENDS HERE ]

        originalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();
    } catch (Exception e) {
       e.printStackTrace();
    }
}

Let me know if this works for you.

Shash

Dmide
  • 6,422
  • 3
  • 24
  • 31
Shash316
  • 2,218
  • 18
  • 19
1
  1. create an empty bitmap
  2. create a new Canvas object and pass this bitmap to it
  3. call view.draw(Canvas) passing it the canvas object you just created. Refer Documentation of method for details.
  4. Use Bitmap.compress() to write the contents of the bitmap to an OutputStream, file maybe.

Pseudo code:

Bitmap  bitmap = Bitmap.createBitmap(200,200,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawText();
//necessary arguments and draw whatever you want. thes all are drawn on the bitmap.finally save this bitmap
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); 
Balaji.K
  • 8,745
  • 5
  • 30
  • 39
  • where i have to use this.. in save function or in onCreate () . – RajaReddy PolamReddy Sep 06 '11 at 13:44
  • here view means the view where you want to draw.If you want to directly save as image then ignore view.draw(canvas); – Balaji.K Sep 06 '11 at 13:54
  • i am getting force close error :java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor, after modification my code is :Bitmap bitmap = Bitmap.createBitmap(originalBitmap); Canvas canvas = new Canvas(bitmap); canvas.drawText(my_text, 0, 0, null);FileOutputStream out = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); – RajaReddy PolamReddy Sep 06 '11 at 14:21
1

You can extend a view to create a custom view. Something like

public class PieView extends View { 
    public PieView(Context context) {
        super(context);
        overlayBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.piechart_shade, 
        null);
        overlayWidth  = overlayBitmap.getWidth();
        setLayoutParams(new LayoutParams(overlayWidth, overlayWidth));      
    }

    @Override     
    protected void onDraw(Canvas canvas) {      
        super.onDraw(canvas);
    }
}

In the ondraw method you can use canvas.drawBitmap and canvas.drawText to draw bitmaps and text.

This way you do not requirre a framelayout as everything is in a single custom view.

You can include this in your xml file as

<com.raj.PieView android:id="@+id/framelayout" android:layout_marginTop="30dip"      
    android:layout_height="fill_parent" android:layout_width="fill_parent"/>
blessanm86
  • 31,439
  • 14
  • 68
  • 79
0

I solve this problem (immutable file), but nothing is write in file... follow my code: public static File writeOnImage(File file) throws IOException {

    Bitmap originalBitmap = BitmapFactory.decodeFile(file.getPath());
    originalBitmap = convertToMutable(originalBitmap);
    FileOutputStream out = new FileOutputStream(file);

    try {
        Canvas canvas = new Canvas(originalBitmap);

        Paint paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(12);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        canvas.drawBitmap(originalBitmap, 0, 0, paint);
        canvas.drawText("Testing...", 10, 10, paint);

        originalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();

    } catch (Exception e) {
        e.printStackTrace();
    }

    return file;
}
LeandroPortnoy
  • 312
  • 1
  • 2
  • 8
0

In case you using Glide to get the image, i modified @Dwivedi's answer to this (using kotlin) :

Glide.with(this)
        .asBitmap()
        .load("https://images.pexels.com/photos/1387577/pexels-photo-1387577.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260")
        .into(object : CustomTarget<Bitmap>() {
            override fun onLoadCleared(placeholder: Drawable?) {}

            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                val bm = resource.copy(Bitmap.Config.ARGB_8888, true)
                val tf = Typeface.create("Helvetica", Typeface.BOLD)

                val paint = Paint()
                paint.style = Paint.Style.FILL
                paint.color = Color.WHITE
                paint.typeface = tf
                paint.textAlign = Paint.Align.LEFT
                paint.textSize = dip(25).toFloat()

                val textRect = Rect()
                paint.getTextBounds("HELLO WORLD", 0, "HELLO WORLD".length, textRect)

                val canvas = Canvas(bm)

                //If the text is bigger than the canvas , reduce the font size
                if (textRect.width() >= canvas.width - 4)
                //the padding on either sides is considered as 4, so as to appropriately fit in the text
                    paint.textSize = dip(12).toFloat()

                //Calculate the positions
                val xPos = canvas.width.toFloat()/2 + -2

                //"- ((paint.descent() + paint.ascent()) / 2)" is the distance from the baseline to the center.
                val yPos = (canvas.height / 2 - (paint.descent() + paint.ascent()) / 2) + 0

                canvas.drawText("HELLO WORLD", xPos, yPos, paint)

                binding.imageDrawable.setImageBitmap(bm)
            }

        })
0

Inflate a text view over the image . Refer http://www.android10.org/index.php/forums/43-view-layout-a-resource/715-tutorial-android-xml-view-inflation for a basic example. This should be the easiest way.

LinearLayout lLayout;

lLayout = (LinearLayout)findViewById(R.id.layout1);

layout1 is the main layout.

final LayoutInflater  inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);

TextView tv = (TextView)inflater.inflate(R.layout.text, null);

lLayout.addView(tv);
Chirag
  • 56,621
  • 29
  • 151
  • 198
Pavankumar Vijapur
  • 1,196
  • 2
  • 10
  • 15
  • Replace it with text view. Have a text view in an xml and inflate it the same way as they have done it for button. – Pavankumar Vijapur Sep 06 '11 at 13:18
  • put in your main.xml ............................. then copy and paste the above piece of code in your oncreate . replace layout1 with main. add a value to dynamic_text in string s.xml – Pavankumar Vijapur Sep 06 '11 at 13:31
  • getting force close error after adding this part of code..fl = (FrameLayout) findViewById(R.id.framelayout); final LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); tv = (TextView) inflater.inflate(R.id.text_view2, null); fl.addView(tv); see my edit i added some part of code.. – RajaReddy PolamReddy Sep 06 '11 at 13:39