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.