Adding an Image Frame or Watermark for Video in Android Programmatically

In this article, we’ll explore how to add an image frame or watermark to a video programmatically in Android. This technique is useful for branding your videos, adding a visual element, or protecting your content. We’ll cover both image frames and watermarks, providing a step-by-step guide and code examples.

Image Frame

An image frame adds a decorative border around your video. This can be a simple frame or a more complex design that complements the video’s content.

1. Set up your Project

  • Create a new Android Studio project.
  • Add the necessary dependencies (e.g., video playback library). You can use the standard `VideoView` or a library like `ExoPlayer` for more advanced features.

2. Prepare the Frame Image

  • Create an image file (e.g., PNG, JPEG) that will be used as your frame. Ensure the image’s size is appropriate for the video’s aspect ratio.
  • Add the image to your project’s drawable resources.

3. Programmatic Implementation

Here’s an example using the `VideoView` and `SurfaceView` to overlay the frame image:

package com.example.videoframe;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class FramedVideoView extends SurfaceView implements SurfaceHolder.Callback {

    private VideoView videoView;
    private Drawable frameDrawable;
    private SurfaceHolder surfaceHolder;

    public FramedVideoView(Context context) {
        super(context);
        init();
    }

    public FramedVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public FramedVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        getHolder().addCallback(this);
        videoView = new VideoView(getContext());
        frameDrawable = getResources().getDrawable(R.drawable.frame_image);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        surfaceHolder = holder;
        videoView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        videoView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                // Not required for this example
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                // Not required for this example
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                // Not required for this example
            }
        });
        addView(videoView);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // Not required for this example
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Not required for this example
    }

    public void setVideoPath(String path) {
        videoView.setVideoPath(path);
        videoView.start();
    }

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

        // Draw the video view
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        videoView.draw(canvas);

        // Draw the frame image
        int frameWidth = frameDrawable.getIntrinsicWidth();
        int frameHeight = frameDrawable.getIntrinsicHeight();
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();

        // Calculate scaling factors to fit the frame image
        float scaleX = (float) canvasWidth / frameWidth;
        float scaleY = (float) canvasHeight / frameHeight;

        // Adjust scaling based on the aspect ratio
        if (scaleX < scaleY) {
            scaleX = scaleY;
        } else {
            scaleY = scaleX;
        }

        // Draw the frame with scaling
        canvas.save();
        canvas.scale(scaleX, scaleY);
        frameDrawable.setBounds(0, 0, canvasWidth, canvasHeight);
        frameDrawable.draw(canvas);
        canvas.restore();
    }
}

<?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:orientation="vertical">

    <com.example.videoframe.FramedVideoView
        android:id="@+id/framedVideoView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    </com.example.videoframe.FramedVideoView>

</LinearLayout>
package com.example.videoframe;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.MediaController;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FramedVideoView framedVideoView = findViewById(R.id.framedVideoView);
        MediaController mediaController = new MediaController(this);
        mediaController.setAnchorView(framedVideoView);
        framedVideoView.setVideoPath("android.resource://" + getPackageName() + "/" + R.raw.your_video);
        framedVideoView.start();
        framedVideoView.setMediaController(mediaController);
    }
}

4. Explanation

  • In this code, we create a custom `FramedVideoView` that extends `SurfaceView`. This allows us to draw on top of the video view.
  • The `onDraw` method is overridden to draw both the video and the frame image. We use a `Paint` object to define the frame image's color and transparency.
  • The scaling logic ensures that the frame image is resized to fit the video view without distortion.

Watermark

A watermark is a semi-transparent image placed over the video, typically in a corner or centered, to indicate ownership or branding. Watermarks can be static or dynamic, appearing throughout the video.

1. Prepare the Watermark Image

  • Create an image file that will serve as the watermark. Make sure the image's size and transparency level are suitable.
  • Add the watermark image to your project's drawable resources.

2. Programmatic Implementation

Here's how you can add a watermark using a custom `VideoView` subclass:

package com.example.watermarkvideo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class WatermarkedVideoView extends SurfaceView implements SurfaceHolder.Callback {

    private VideoView videoView;
    private Drawable watermarkDrawable;
    private SurfaceHolder surfaceHolder;

    public WatermarkedVideoView(Context context) {
        super(context);
        init();
    }

    public WatermarkedVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public WatermarkedVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        getHolder().addCallback(this);
        videoView = new VideoView(getContext());
        watermarkDrawable = getResources().getDrawable(R.drawable.watermark_image);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        surfaceHolder = holder;
        videoView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        videoView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                // Not required for this example
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                // Not required for this example
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                // Not required for this example
            }
        });
        addView(videoView);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // Not required for this example
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Not required for this example
    }

    public void setVideoPath(String path) {
        videoView.setVideoPath(path);
        videoView.start();
    }

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

        // Draw the video view
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        videoView.draw(canvas);

        // Draw the watermark image
        int watermarkWidth = watermarkDrawable.getIntrinsicWidth();
        int watermarkHeight = watermarkDrawable.getIntrinsicHeight();
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();

        // Position the watermark (bottom-right corner in this example)
        int watermarkX = canvasWidth - watermarkWidth;
        int watermarkY = canvasHeight - watermarkHeight;

        // Draw the watermark
        watermarkDrawable.setBounds(watermarkX, watermarkY, watermarkX + watermarkWidth, watermarkY + watermarkHeight);
        watermarkDrawable.draw(canvas);
    }
}

<?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:orientation="vertical">

    <com.example.watermarkvideo.WatermarkedVideoView
        android:id="@+id/watermarkedVideoView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    </com.example.watermarkvideo.WatermarkedVideoView>

</LinearLayout>
package com.example.watermarkvideo;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.MediaController;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WatermarkedVideoView watermarkedVideoView = findViewById(R.id.watermarkedVideoView);
        MediaController mediaController = new MediaController(this);
        mediaController.setAnchorView(watermarkedVideoView);
        watermarkedVideoView.setVideoPath("android.resource://" + getPackageName() + "/" + R.raw.your_video);
        watermarkedVideoView.start();
        watermarkedVideoView.setMediaController(mediaController);
    }
}

3. Explanation

  • The `onDraw` method now handles both video and watermark rendering. We define the watermark's position and draw it on top of the video.
  • By adjusting the watermark image's transparency, you can control its visibility and blend it with the video.
  • The watermark can be dynamically positioned using calculations or user input.

Comparison Table

Feature Image Frame Watermark
Purpose Decorative border, visual enhancement Ownership/branding, content protection
Placement Surrounds the entire video Typically in a corner or centered
Transparency Usually opaque, but can be semi-transparent Often semi-transparent
Size Fits the video's aspect ratio Smaller than the video frame

Conclusion

Adding image frames or watermarks to your Android videos programmatically is a straightforward process. By customizing the image, position, and transparency, you can achieve unique visual effects and enhance the overall presentation of your content.

Leave a Reply

Your email address will not be published. Required fields are marked *