Click here to Skip to main content
Click here to Skip to main content

Tattoo Maker

, 5 Aug 2009
Rate this:
Please Sign up or sign in to vote.
Creating a tattoo on someone's arm in a video.

QTattoo.PNG

Introduction

I've always wondered how can you edit a video file, and this article shows you one simple way to do it by first splitting your video to a series of bitmaps, making your changes on them, and finally merging them back to form a video, keeping in mind to include the audio stream of the original video.

Application.PNG

Background

You don't have to know much about video or image processing, neither will you learn much from this article as this application is depending on two major helping applications. To split up the video frames, I used VirtualDub 1.7.2 which also did the work of extracting the audio stream of the video, and later when merging back the frames, I used a little neat application called Bmp2Avi which also managed the compression of the video using the Xvid MPEG-4 Codec format.

Using the code

First, we create a BackGroundWorker object which will handle the frames editing.

string FramesFolder;
string tmpFramesDir;
private void bgw_ProcessFrames_DoWork(object sender, DoWorkEventArgs e)
{
    string tmpStatus = "Idle";
    int tmpProgress = 0;

    tmpFramesDir = Environment.GetEnvironmentVariable("TEMP") + 
                               "\\Tatoo_Frames";
    if (!Directory.Exists(tmpFramesDir))
        Directory.CreateDirectory(tmpFramesDir);

    FileStream fs = null;
    Bitmap bm = null;
    Graphics gfx = null;


    FramesFolder = Application.StartupPath + "\\VideoFrames";
    string[] strFrames = Directory.GetFiles(FramesFolder, 
             "*.jpeg", SearchOption.TopDirectoryOnly);
    foreach (string strFrame in strFrames)
    {
        fs = new FileStream(strFrame, FileMode.Open, FileAccess.Read);
        bm = new Bitmap(Image.FromStream(fs));
        fs.Close();

        //Stamp website
        gfx = Graphics.FromImage(bm);
        gfx.DrawString("www.QSoftOnline.com", 
          new Font("Arial", 10f, FontStyle.Bold), 
          new SolidBrush(Color.Yellow), new Point(170,220));


        if (Convert.ToInt16(strFrame.Replace(FramesFolder + "\\", 
                              String.Empty).Split('.')[0]) >= 475)
        {
            //Start Tatooing
            gfx.RotateTransform(25f);

            gfx.DrawImage(QTatoo.Properties.Resources.Dragon,110,35,40,40);
            gfx.DrawString(strWording, new Font("Freestyle Script", 20f, 
                FontStyle.Bold), new SolidBrush(Color.Black), new Point(80, 70));
            gfx.Dispose();
            //Saving changes
            bm.Save(tmpFramesDir + "\\" + strFrame.Replace(FramesFolder + 
                    "\\", String.Empty).Replace(".jpeg", ".bmp"), 
                    System.Drawing.Imaging.ImageFormat.Bmp);

        }
        else
            bm.Save(tmpFramesDir + "\\" + strFrame.Replace(FramesFolder + "\\", 
                    String.Empty).Replace(".jpeg", ".bmp"), 
                    System.Drawing.Imaging.ImageFormat.Bmp);

            /////Reporting/////
            tmpProgress = Convert.ToInt16(strFrame.Replace(FramesFolder + "\\", 
                          String.Empty).Split('.')[0])*100 / strFrames.Length;
            tmpStatus = "Converting frame " + Convert.ToInt16(strFrame.Replace(
                        FramesFolder + "\\", String.Empty).Split('.')[0]);
            if (tmpProgress <= 100)
            bgw_ProcessFrames.ReportProgress(tmpProgress, tmpStatus);
            ////////////////////////
        }
    }

Notice that the individual bitmaps are loaded using a stream which is immediately closed after the retrieval of the frame.

fs = new FileStream(strFrame, FileMode.Open, FileAccess.Read);
bm = new Bitmap(Image.FromStream(fs));
fs.Close();

Now, we start editing the frames after a certain frame "475", in this case.

if (Convert.ToInt16(strFrame.Replace(FramesFolder + "\\", String.Empty).Split('.')[0]) >= 475)
{
    //Start Tatooing
    gfx.RotateTransform(25f);

    gfx.DrawImage(QTatoo.Properties.Resources.Dragon,110,35,40,40);
    gfx.DrawString(strWording, new Font("Freestyle Script", 20f, 
                   FontStyle.Bold), new SolidBrush(Color.Black), new Point(80, 70));
    gfx.Dispose();
    //Saving changes
    bm.Save(tmpFramesDir + "\\" + strFrame.Replace(FramesFolder + "\\", 
            String.Empty).Replace(".jpeg",".bmp"), 
            System.Drawing.Imaging.ImageFormat.Bmp);

}

Finally, we merge the edited frames back to one video file including the previously extracted audio stream and applying some basic compression.

Environment.CurrentDirectory = tmpFramesDir;

Environment.SetEnvironmentVariable("PATH", "%PATH%;" + tmpFramesDir);
prc_ProduceVideo.StartInfo.FileName = "B2A";
prc_ProduceVideo.StartInfo.Arguments = 
    @"-f 24 -w Channel.wav -c ""Xvid MPEG-4 Codec"" -o Output";
prc_ProduceVideo.Start(); 

The little dragon you see above the wording is an embedded image within the solution which can be changed by replacing it in the resources directory.

You may also download the demo application from QSoftOnline.

History

  • QTattoo ver. 1.0.0: 29th June 2009
  • QTattoo ver. 1.0.1: 3rd July 2009

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Muammar©
Retired QSoft
Yemen Yemen
Biography?! I'm not dead yet!
www.QSoftOnline.com

Comments and Discussions

 
GeneralRe: My vote of 1 Pinmemberp_a_k11-Aug-09 4:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140827.1 | Last Updated 5 Aug 2009
Article Copyright 2009 by Muammar©
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid