Thursday, May 30, 2013

Video Player


The VideoPlayer program allows you select a sound or video file to play. In this program, you learn to use the JMF API to create a player that can be used to play sound (.wav) or video file (.mov, and .mpg) and add visual and control components to the player so user can see the movie and control the movie play . You can download JMF from http://www.sun.com website.

VideoPlayer source code:


import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Dimension;
import javax.media.*;
import javax.media.control.TrackControl;
import javax.media.datasink.*;
import javax.media.format.VideoFormat;
import javax.media.protocol.*;
import java.net.*;
import javax.swing.JFileChooser;
class PlayInterface extends JFrame implements ActionListener{

private Player vPlayer= null;
private Dimension ds=null;
private Dimension sds=null;
private URL url=null;
private JPanel panel;
private  JMenuBar mainmenu;
private  JMenu menu;
private  JMenuItem mopen;
private  JMenuItem mexit;
PlayInterface() {

addMenu();
addPanel();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(this.getExtendedState() | this.MAXIMIZED_BOTH);
setTitle("Video Player");
setVisible(true);


}
//create menu bar, menu, sub menus and add the menu bar to the program interface
public void addMenu(){
mainmenu=new JMenuBar();
menu=new JMenu("File"); //create menu
menu.setMnemonic(KeyEvent.VK_F);
mopen=new JMenuItem("Open...");
mopen.setMnemonic(KeyEvent.VK_O);
mopen.addActionListener(this);

mexit=new JMenuItem("Exit");
mexit.setMnemonic(KeyEvent.VK_X);
mexit.addActionListener(this);
menu.add(mopen);
menu.add(mexit);
mainmenu.add(menu);
setJMenuBar(mainmenu);
}
//add Panel to the Frame window
public void addPanel(){

panel=new JPanel();
panel.setLayout(null);
panel.setBackground(Color.BLACK);
add(panel, BorderLayout.CENTER);
}

//choose video file, create player, adjust visual and control component, and play the media file
public void prepareVideo(){

sds=getToolkit().getScreenSize(); //get screen dimendion width and height
//initialize height and width variables
int height=0;
int width=0;

try{
url=getFile(); //choose the video file
if(url!=null)
vPlayer=Manager.createRealizedPlayer(url); //create player object
if(vPlayer==null) System.exit(-1); //exit the program if the play can not be created from the url
ds=getVideoDimension(url); //get video dimension--width and height
Component vc=vPlayer.getVisualComponent(); //get visual component to show the video
Component cpc=vPlayer.getControlPanelComponent();//get control component to
//control the playback: play, stop, mute,...

//adjust the width and height of the components based on the widths and heights of
//the screen and video frame
if(ds!=null) //video file is selected so its dimension can be fetched
{

if(ds.getWidth()>=(int)sds.getWidth()-100)
width=(int)sds.getWidth()-100;
else
width=(int)ds.getWidth();
if(ds.getHeight()>=(int)sds.getHeight()-150)
height=(int)sds.getHeight()-150;
else
height=(int)ds.getHeight();
}
else //audio file is selected so the components must be 300px wide and 20px high
{
width=300;
height=20;
}
//specify the size and location of visual component and
//add the visual component to the panel to it is ready to show on the program interface
//if it is not null
if(vc!=null){
vc.setSize(new Dimension(width,height));
vc.setLocation((int)ds.getWidth()/2-width/2,10);
panel.add(vc);

}

//specify the size and location of control component and
//add the control component to the panel to it is ready to show on the program interface
//if it is not null
if(cpc!=null){
cpc.setSize(new Dimension(width,30));
cpc.setLocation((int)ds.getWidth()/2-width/2,height+20);
panel.add(cpc);
}
vPlayer.start(); //start the player
}
catch (Exception e){e.printStackTrace();}
}

public void actionPerformed(ActionEvent e){

JMenuItem source = (JMenuItem)(e.getSource());
if(source.getText().compareTo("Open...")==0) //The Open...sub-menu is selected
{
panel.removeAll(); //clear all components on the Panel
prepareVideo();//select file, create player, add components, play the media
repaint();//repaint the program interface
validate(); //make sure the components display properly
}

else if(source.getText().compareTo("Exit")==0) //The Exit sub-menu is selected
System.exit(0);


}



public URL getFile() throws MalformedURLException{

      JFileChooser fileChooser = new JFileChooser(); //create file chooser object
      URL url= null;      
      int result = fileChooser.showOpenDialog( null ); //open the file dialog

      if ( result == JFileChooser.APPROVE_OPTION ) // user chose a file
            url= fileChooser.getSelectedFile().toURI().toURL(); //convert the chosen file path to url
     
      return url;

}

public Dimension getVideoDimension(URL url){
Processor processor = null;
Dimension vds=null;
long startTime;
int timeOut=1000;
try {

DataSource ds= Manager.createDataSource(new MediaLocator(url)); //create datasource from the url
ds.connect(); //connect to the datasource
processor = Manager.createProcessor(ds); //create processor
processor.configure(); //configure the processor
//wait for end of processor configuration
startTime = System.currentTimeMillis();
while(processor.getState()<processor.Configured){
Thread.sleep(timeOut);
if(System.currentTimeMillis()-startTime>timeOut)
break;
}

processor.realize();//realize the processor
//wait for end of processor realization
startTime = System.currentTimeMillis();
while(processor.getState()<processor.Realized){
Thread.sleep(timeOut);
if(System.currentTimeMillis()-startTime>timeOut)
break;
}


TrackControl[] tcs=processor.getTrackControls(); //get the controls of the video track
for(TrackControl tc:tcs){
VideoFormat fv=(VideoFormat)tc.getFormat(); //get the track format from the track control
vds=fv.getSize(); //get the size of the video frame from the format
}

} catch (Exception ex){}


return vds;
}

}

class VideoPlayer{
public static void main(String[] args){
PlayInterface myplayer=new PlayInterface();

}
}


 Video Player in Java

In the program code above, the JFileChooser component is used to allow the user to selection a video file to open. When the path of the video file is obtained,  it is time to set up some components to play and controls the video play. A video Player object is created by using the createRealizedPlayer method of the Manager class. Then the getVideoDimension is called to get the width and height of the input view frame. To get the dimension of the video, you need to create a processor that encapsulates the data source of the video file. The processor must be configured and realized properly before you can use it to access information about the video format. The getTrackControls method of the processor object returns all track controls objects found in the video. A track control object contains the video format object. This object contains information about the dimension of the video frame. You can get the dimension by using the getSize method of the video format object. When you have the size or dimension of the video, you can adjust the size of the visual component dynamically. The components to be added to the program are visual component and control panel component. The visual component shows the video while the control panel component controls the video play (play, stop, and change volume status, etc). When these components are successfully set up. You can call the start method of the play to start playing the video file.

-->

Monday, May 27, 2013

Merge audio and video

The MergeAudioVideo program allows you to merge sound file (.wav) and video file(.mov). The result video file is mergedvideo.mov stored in your current folder. Merging the sound file and video file can be performed simply in Java by using the JMF API so you need to download and install JMF before the program can be compiled and run without any error.

merge audio and video in Java



MergeAudioVideo source code:

import java.io.*;
import javax.media.*;
import javax.media.control.TrackControl;
import javax.media.datasink.*;
import javax.media.format.*;
import javax.media.protocol.*;
import java.net.*;

public class MergeAudioVideo{
 
public static void main(String args[]){
if(args.length>1){
      System.out.println("Please wait...");
merging(args[0],args[1]);
    System.out.println("Merging finished");
}
else
System.out.println("Invalid files input");
System.exit(0);

}

//merge the sound and video files
public static void merging(String audioFileName, String videoFileName){


//Declare and initialize StateHelper objects: sha,shv, and shm
//sha for audio processor, shvfor audio process, and shm for merge processor
StateHelper sha=null;
StateHelper shv=null;
StateHelper shm=null;

//Declare and initialize processor objects for audio, video, and merged data
Processor audioProcessor=null;
Processor videoProcessor=null;
Processor mergeProcessor=null;

//create MediaLocator objects for audio and video files
MediaLocator audioLocator=null;
MediaLocator videoLocator=null;
MediaLocator outLocator=null;
try{
File audioFile=new File(audioFileName);
audioLocator=new MediaLocator(audioFile.toURI().toURL());

File videoFile=new File(videoFileName);
videoLocator=new MediaLocator(videoFile.toURI().toURL());

//Create MediaLocator for merged output file
File outFile=new File(System.currentTimeMillis()+"mergedvideo.mov");
outLocator=new MediaLocator(outFile.toURI().toURL());
}catch(MalformedURLException me){System.exit(-1);}

//create datasources
DataSource audioDataSource=null;
DataSource videoDataSource=null;
DataSource mergedDataSource=null;
DataSource arrayDataSource[]=null;
try{
audioDataSource = Manager.createDataSource(audioLocator); // your audio file
        videoDataSource = Manager.createDataSource(videoLocator); //your video file
        mergedDataSource = null; // data source to combine video with audio
        arrayDataSource= new DataSource[2]; //data source array
}catch(IOException ie){System.exit(-1);}
catch(NoDataSourceException ie){System.exit(-1);}
//format array for input audio and video
Format[] formats=new Format[2];
formats[0]=new AudioFormat(AudioFormat.IMA4_MS); //create audio format object
formats[1]=new VideoFormat(VideoFormat.JPEG); //create video format object

//create media file content type object
FileTypeDescriptor outftd=new FileTypeDescriptor(FileTypeDescriptor.QUICKTIME);

//create processor objects for video and audio
try{
videoProcessor = Manager.createProcessor(videoDataSource);
shv=new StateHelper(videoProcessor);        
        audioProcessor = Manager.createProcessor(audioDataSource);
sha=new StateHelper(audioProcessor);
}catch(IOException ie){System.exit(-1);}
catch(NoProcessorException ne){System.exit(-1);}
       
//Configure processors
if (!shv.configure(10000))
System.exit(-1);
if (!sha.configure(10000))
System.exit(-1);
//Realize processors

if (!shv.realize(10000))
System.exit(-1);
if (!sha.realize(10000))
System.exit(-1);

//return data sources from processors so they can be merged
arrayDataSource[0]=audioProcessor.getDataOutput();
arrayDataSource[1]=videoProcessor.getDataOutput();

//start the processors
videoProcessor.start();
   audioProcessor.start();

//create merged data source, connect, and start it
try{
mergedDataSource=Manager.createMergingDataSource(arrayDataSource);
mergedDataSource.connect();
        mergedDataSource.start();
}catch(IOException ie){System.exit(-1);}
catch(IncompatibleSourceException id){System.exit(-1);}
//processor for merged output
try{
mergeProcessor=Manager.createRealizedProcessor(new     ProcessorModel(mergedDataSource,formats,outftd));
      shm=new StateHelper(mergeProcessor);
}catch(IOException ie){System.exit(-1);}
catch(NoProcessorException ie){System.exit(-1);}
catch(CannotRealizeException ie){System.exit(-1);}
//set output file content type
mergeProcessor.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.QUICKTIME));
//query supported formats
TrackControl tcs[] =mergeProcessor.getTrackControls();
Format f[] = tcs[0].getSupportedFormats();
if (f == null || f.length <= 0)
System.exit(100);
//set track format
tcs[0].setFormat(f[0]);

//get datasource from the mergeProcessor so it is ready to write to a file by DataSink filewriter
DataSource source =mergeProcessor.getDataOutput();
//create DataSink filewrite for writing
DataSink filewriter = null;
try {
filewriter = Manager.createDataSink(source, outLocator);
filewriter.open();
} catch (NoDataSinkException e) {
System.exit(100);
} catch (IOException e) {
System.exit(100);
} catch (SecurityException e) {
System.exit(100);
}

// now start the filewriter and mergeProcessor
try {
mergeProcessor.start();
filewriter.start();
} catch (IOException e) {
System.exit(-1);
}
// wait 2 seconds for end of media stream
shm.waitToEndOfMedia(2000);
shm.close();
filewriter.close();


}


}

//The StateHelper class help you determine the states of the processors
class StateHelper implements ControllerListener {
Processor p = null;
boolean configured = false;
boolean realized = false;
boolean prefetched = false;
boolean eom = false;
boolean failed = false;
boolean closed = false;
public StateHelper(Processor pr) {
p= pr;
p.addControllerListener(this);
}

public boolean configure(int timeOutMillis) {
long startTime = System.currentTimeMillis();
synchronized (this) {
p.configure();
while (!configured && !failed) {
try {
wait(timeOutMillis);
} catch (InterruptedException ie) {}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}

}
return configured;
}
public boolean realize(int timeOutMillis) {
long startTime = System.currentTimeMillis();
synchronized (this) {
p.realize();
while (!realized && !failed) {
try {
wait(timeOutMillis);
} catch (InterruptedException ie) {}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}
}
return realized;
}

public boolean prefetch(int timeOutMillis) {
long startTime = System.currentTimeMillis();
synchronized (this) {
p.prefetch();
while (!prefetched && !failed) {
try {
wait(timeOutMillis);
} catch (InterruptedException ie) {}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}
}
return prefetched && !failed;
}

public boolean waitToEndOfMedia(int timeOutMillis) {
long startTime = System.currentTimeMillis();
eom = false;
synchronized (this) {
while (!eom && !failed) {
try {
wait(timeOutMillis);
} catch (InterruptedException ie){}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}
}
return eom && !failed;
}

public void close() {
synchronized (this) {
p.close();
while (!closed) {
try {
wait(100);
} catch (InterruptedException ie) {}
}

}
p.removeControllerListener(this);
}

public synchronized void controllerUpdate(ControllerEvent ce) {
if (ce instanceof RealizeCompleteEvent) {
realized = true;
} else if (ce instanceof ConfigureCompleteEvent) {
configured = true;
} else if (ce instanceof PrefetchCompleteEvent) {
prefetched = true;
} else if (ce instanceof EndOfMediaEvent) {
eom = true;
} else if (ce instanceof ControllerErrorEvent) {
failed = true;
} else if (ce instanceof ControllerClosedEvent) {
closed = true;
} else {
return;
}
notifyAll();
}

}

The process of merging an audio file and an video file is not too hard to understand. You need three MeidaLocator objects to point to the source audio file and video file, and the last one MediaLocator is needed for the output merged file. To read the data of the audio file and video file, you can use the createDataSource (MediaLocator locator) method of the Manager class. This method returns the DataSource object that contains the data of the audio or video file. You will call this method two times. One for reading the data of the audio file and another one for reading the data of the video file. One you have the DataSource objects you can pass them to the processors to start the merging process. To process the files, you also will define three processor objects. One is to process the data of the audio file; one is for video file; and another one for the output merged file. Before the processors can fully perform their, they must be configured and realized. The StateHelper class helps to do these tasks. To merge the two source files, the createMergingDataSource(DataSource[] data) method of the Manager class is used. This method returns a new DataSource that combines the DataSource elements of the DataSource array together. One you have the merged data source, you can create a DataSink object that acts a a file writer to write the merged data to the output file. You might like to read Sound Recording post to get the related information about Processor, DataSource, and DataSink.

Saturday, May 25, 2013

Sound recording


The SoundRecording program is able to record external sound and save the sound file in your current working folder. The main API used in the SoundRecoding program is JMF (Java Media Framework). You need to download and install JMF from www.sun.com.  After installing JMF in your computer system, in order  to record external sound and save it, you have to check whether your computer has proper audio capture card installed and you have a microphone.

Sound recording or audio recorder in Java

SoundRecording source code:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.Vector;
import javax.media.*;
import javax.media.control.TrackControl;
import javax.media.datasink.*;
import javax.media.format.*;
import javax.media.protocol.*;
import java.net.*;

class SoundRecording extends JFrame implements ActionListener{
  JButton btCap;
Recorder rd;
SoundRecording() throws AWTException{

btCap=new JButton("Start Recording");
btCap.addActionListener(this);
add(btCap,BorderLayout.CENTER);
setTitle("Audio Recorder");
setPreferredSize(new Dimension(300,80));
setResizable(false);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();

}

public void actionPerformed(ActionEvent e){
try{
if(btCap.getText().equals("Start Recording")){
setMess(btCap, "Stop Recording");
setState(ICONIFIED);
rd=new Recorder();
rd.start();
}
else if(btCap.getText().equals("Stop Recording")){
rd.stopCapture();
setMess(btCap, "Start Recording");
}

}catch(Exception ee){}
}


public void setMess(JButton btCap, String mess){
btCap.setText(mess);

}

class Recorder extends Thread{
StateHelper sh;
public void run(){
//declare processor p
Processor p=null;
//Find device that supports the specified audio format
CaptureDeviceManager cdm=new CaptureDeviceManager();
AudioFormat af=new AudioFormat("linear", 44100, 16, 2);
Vector cds=cdm.getDeviceList(af);
CaptureDeviceInfo cdi=null;
if(cds.size()>0){ //found the device
cdi=(CaptureDeviceInfo)cds.firstElement();
}
else //the device for the auto format is not found
System.exit(-1);
try {
p =Manager.createProcessor(cdi.getLocator()); //create process object for the device
sh =new StateHelper(p); //create state helper object
} catch (IOException e) {System.exit(-1);
} catch (NoProcessorException e) {System.exit(-1);}

// Configure the processor
if (!sh.configure(10000))
System.exit(-1);
// Set the output file content type
p.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.WAVE));
// Get the track control objects
TrackControl track[] = p.getTrackControls();
boolean ableToEncode= false;
//search for a possible format and set it to the audio track for encoding
for (int i = 0; i < track.length; i++) {
try {
track[i].setFormat(new AudioFormat(AudioFormat.IMA4_MS));
ableToEncode = true;
} catch (Exception e) {
// cannot convert to ima4
track[i].setEnabled(false);
}
}
if (!ableToEncode) {
sh.close();
System.exit(-1);
}
//realize the process
if (!sh.realize(10000))
System.exit(-1);
// get the output of the processor
DataSource source = p.getDataOutput();
//create MediaLocator object to point to the output file locaiton
String aFileName=System.currentTimeMillis()+".wav";
File fout=new File(aFileName);
MediaLocator oml=null;
try{
oml=new MediaLocator(fout.toURI().toURL());
}catch(MalformedURLException e){}
// create a datasink and open it so writing data is possible
DataSink filewriter = null;
try {
filewriter = Manager.createDataSink(source, oml);
filewriter.open();
} catch (NoDataSinkException e) {System.exit(-1);
} catch (IOException e) {System.exit(-1);
} catch (SecurityException e) {System.exit(-1);}
// now start the processor and filewriter
try {
p.start();
filewriter.start();
} catch (IOException e) {
System.exit(-1);
}
//wait for end of media stream
//in every 5 seconds there is a check to see whether the end of stream is met
sh.waitToEndOfMedia(5000);
sh.close();
filewriter.close();
}
public void stopCapture(){
sh.turnOffRecording(); //stop the recording
}

}

public class StateHelper implements ControllerListener {
Process p= null;
boolean configured = false;
boolean realized = false;
boolean prefetched = false;
boolean eom = false;
boolean failed = false;
boolean closed = false;
public StateHelper(Processor pr) {
p= pr;
p.addControllerListener(this); //register the processor with the ControllerListener
//so each state of the processor can be detemined with the ControllerUpdate method
}

public boolean configure(int timeOutMillis) {
long startTime = System.currentTimeMillis();
synchronized (this) {
p.configure();
while (!configured && !failed) { //wait for the finish of the processor configuration
try {
wait(timeOutMillis);
} catch (InterruptedException ie) {}
if (System.currentTimeMillis() - startTime > timeOutMillis) //no wait any more
break;
}

}
return configured;
}
public boolean realize(int timeOutMillis) {
long startTime = System.currentTimeMillis();
synchronized (this) {
p.realize(); //realize the processor
while (!realized && !failed) { //wait for the finish of processor realization
try {
wait(timeOutMillis);
} catch (InterruptedException ie) {}
if (System.currentTimeMillis() - startTime > timeOutMillis) //no wait any more
break;
}
}
return realized;
}

public boolean prefetch(int timeOutMillis) {
long startTime = System.currentTimeMillis();
synchronized (this) {
p.prefetch(); // prefetch the processor
while (!prefetched && !failed) { //wait for the finish of processor prefetch
try {
wait(timeOutMillis);
} catch (InterruptedException ie) {
}
if (System.currentTimeMillis() - startTime > timeOutMillis) //no wait any more
break;
}
}
return prefetched && !failed;
}
public boolean waitToEndOfMedia(int timeOutMillis) {  //continue recording until end of media
long startTime = System.currentTimeMillis();
eom = false;
synchronized (this) {
while (!eom && !failed) {
try {
wait(timeOutMillis);
} catch (InterruptedException ie) {
}

}
}
return eom && !failed;
}

public void turnOffRecording(){ //forcing end of media recording
eom=true;
}

public void close() { //close the processor and wait 100 millliseconds for the process to finish the close
synchronized (this) {
p.close();
while (!closed) {
try {
wait(100);
} catch (InterruptedException ie) {}
}
}
p.removeControllerListener(this);
}

public synchronized void controllerUpdate(ControllerEvent ce) { //handle update events of the processor
if (ce instanceof RealizeCompleteEvent) {
realized = true;
} else if (ce instanceof ConfigureCompleteEvent) {
configured = true;
} else if (ce instanceof PrefetchCompleteEvent) {
prefetched = true;
} else if (ce instanceof EndOfMediaEvent) {
eom = true;
} else if (ce instanceof ControllerErrorEvent) {
failed = true;
} else if (ce instanceof ControllerClosedEvent) {
closed = true;
} else {
return;
}
notifyAll();
}

}

public static void main(String args[])  throws Exception{
   
new SoundRecording();
 
}


}

From the code above, before the audio capturing process can be performed, it is important to find a device that supports a specified audio format. To create an audio format object, you will use the AudioFormat class. The constructor of the AudioFormat class accepts three values: encoding, sample rate, and the number of bits per sample. You can get a list of supported devices by using the getDeviceList method of the CaptureDeviceManager class. This method accepts the specified audio format object as its argument. Once the audio capturing device is available, you can create a processor object to process data from this device by using the createProcessor method of  the Manager class. Before you can use the process object to set the content type of the audio output file or specify the track format of the audio output file, you have to ensure that the process is configured properly. Thank to the StateHelper class that helps us to configure and realize the processor. After the processor is configured successfully, it must be realized so that you can get the output audio data from it. The output audio data is stored in a DataSource object. To write the data to the output file, you need to create a DataSink object. When creating a DataSink to act as a file writer, you need to provide two values to its constructor: DataSource object and the MediaLocator object that points to output file path. After opening the file writer, call its start method to start the data writing process. You will wait a few seconds or minutes to complete this process.

Thursday, May 23, 2013

Add image to image

With the AddImageToImage program, you are easy to add an image to an original image. When the original image displays on the program interface, you can choose an image to add to this image by selecting the Add Image to Image from the Edit menu. The image to add to the original image can be resized before it is placed on the original image. The update image can be saved in a separate file or override the original file.  Placing many images on the original image is possible. If you want to cancel the editing, just select the Cancel editing from the Edit menu.

AddImageToImage source code:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.*;
import java.awt.color.*;
import javax.swing.filechooser.*;
import java.io.*;
import java.awt.*;
import java.awt.geom.*;
import javax.imageio.*;
import javax.imageio.stream.*;

class ImgArea extends Canvas{

BufferedImage orBufferedImage;
BufferedImage bimg;
BufferedImage biToAdd;
Dimension ds;
int mX;
int mY;
int x;
int y;
static boolean imageLoaded;
boolean drawn;
boolean actionDraw;
MediaTracker mt;
Toolkit tk;

public ImgArea(){
addMouseListener(new Mousexy()); //handling mouse event of the Canvas object
addMouseMotionListener(new MouseMotionList());//handling mouse motion event of the Canvas object
addKeyListener(new KList());//handling key event of the Canvas object
tk=getToolkit(); //get Toolkit object fromt the current container
ds=tk.getScreenSize(); //get the screeen size-widtha and height
mX=(int)ds.getWidth()/2;//x-axis at the center of the screen
mY=(int)ds.getHeight()/2;//y-axis at the center of the screen

}

public void paint(Graphics g){
Graphics2D g2d=(Graphics2D)g;//create graphic2d object
if(imageLoaded){ //the image is loaded


if(drawn ){ //draw update image
x=mX-bimg.getWidth()/2;
y=mY-bimg.getHeight()/2;
g2d.translate(x,y);
g2d.drawImage(bimg,0,0,null);

}

else{ //draw the original image
x=mX-orBufferedImage.getWidth()/2;
y=mY-orBufferedImage.getHeight()/2;
g2d.translate(x,y);
g2d.drawImage(orBufferedImage,0,0,null);
}
}
g2d.dispose(); //clean the graphics2d object

}

class Mousexy extends MouseAdapter{

public void mousePressed(MouseEvent e){
try{
if(actionDraw){
if(drawn) //add image to the update image
addImageToImage(e.getX()-x,e.getY()-y, bimg);
else //add image to the original image
addImageToImage(e.getX()-x,e.getY()-y, orBufferedImage);


}

}catch(Exception ie){}


}


}

public class MouseMotionList extends MouseMotionAdapter{
public void mouseMoved(MouseEvent e){
if(actionDraw){
//create custom cursor from the image to be added to old image
Cursor cur=tk.createCustomCursor(biToAdd,new Point(1,1),"Image to add");
setCursor(cur);
}
}
}
class KList extends KeyAdapter{
public void keyPressed(KeyEvent e){
if(e.getKeyCode()==27){ //the cancel key is pressed
actionDraw=false; //reset the drawing action
setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); //reset to the default cursor
}
}
}

public void addImageToImage(int x,int y, BufferedImage img){
BufferedImage bi;
bi=(BufferedImage)createImage(img.getWidth(),img.getHeight()); //create a blank bufferedimage
Graphics2D  g2d=(Graphics2D)bi.createGraphics(); //create graphics2d object from the blank bufferedimage
g2d.drawImage(img,0,0,null); //draw the old image on the blank bufferedimage
g2d.drawImage(biToAdd,x,y,null); //draw the new added image
bimg=bi; //update the image
drawn=true; //the new added image is drawn on the old image
g2d.dispose(); //clean the graphics2d object
repaint(); //repaint the drawing area so the update image can be shown
}

public void initialize(){ //initialize variables and set the default cursor type
imageLoaded=false;
actionDraw=false;
drawn=false;
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}

public void reset(String imgFileName){ //reset the drawing area when the Cancel editing menu is selected
if(imageLoaded){
prepareImage(imgFileName);
repaint();
}

}


public void prepareImage(String filename){
initialize();
Image orImg;
try{
mt=new MediaTracker(this); //create MediaTracker object
orImg=Toolkit.getDefaultToolkit().getImage(filename); //get the image from the chosen file
mt.addImage(orImg,0); //add the image to the tracker
mt.waitForID(0); //wait for image loading complete
int width=orImg.getWidth(null); //get the image width
int height=orImg.getHeight(null);//get the image height
orBufferedImage=createBufferedImageFromImage(orImg,width,height); //create bufferedimage from the original image
bimg = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); //create a blank bufferedimage
//the update image data will be stored in this bufferedimage
imageLoaded=true;//the image is loaded
}catch(Exception e){System.exit(-1);}
}


public void setActionDraw(boolean value ){//set the drawing action
actionDraw=value;

}

//create bufferedimage from an image
public BufferedImage createBufferedImageFromImage(Image image, int width, int height)
  {
BufferedImage dest ;
dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = dest.createGraphics();
    g2.drawImage(image, 0, 0, null);
    g2.dispose();
    return dest;
  }

//save the image to a file
public void saveToFile(String filename){
String ftype=filename.substring(filename.lastIndexOf('.')+1);
try{
if(drawn) //save the update image
ImageIO.write(bimg,ftype,new File(filename));
else //save the original image
ImageIO.write(orBufferedImage,ftype,new File(filename));
  }catch(IOException e){System.out.println("Error in saving the file");}
}
//set the new added image to the biToAdd bufferedimage variable
//this method is invoked when the use choose the image to add to the old image
public void setImageToAdd(BufferedImage biToAdd){
this.biToAdd=biToAdd;

}
}

//The MainInter class represents the main interface of the AddImateToImage program
//The center area of the interface is to show the image
//The interface has a menu bar that contains two menus: File and Edit
//With the File menu, you can select the image to show, save the image, and exit the program
//With Edit menu you can add image to the original image and cancel the editing
class  MainInter extends JFrame implements ActionListener{

ImgArea ia;
JFileChooser chooser;
JMenuBar mainmenu;
JMenu menufile;
JMenu menuedit;
JMenuItem mopen;
JMenuItem msaveas;
JMenuItem msave;
JMenuItem mexit;
JMenuItem maddimage;
JMenuItem mcancel;
String filename;
MainInter(){
ia=new ImgArea();
Container cont=getContentPane();
cont.add(ia,BorderLayout.CENTER );
mainmenu=new JMenuBar();
menufile=new JMenu("File");
menufile.setMnemonic(KeyEvent.VK_F);
menufile.addActionListener(this);

mopen=new JMenuItem("Open...");
mopen.setMnemonic(KeyEvent.VK_O);
mopen.addActionListener(this);

msaveas=new JMenuItem("Save as...");
msaveas.setMnemonic(KeyEvent.VK_S);
msaveas.addActionListener(this);

msave=new JMenuItem("Save");
msave.setMnemonic(KeyEvent.VK_V);
msave.addActionListener(this);

mexit=new JMenuItem("Exit");
mexit.setMnemonic(KeyEvent.VK_X);
mexit.addActionListener(this);
menufile.add(mopen);
menufile.add(msaveas);
menufile.add(msave);
menufile.add(mexit);

menuedit=new JMenu("Edit");
menuedit.setMnemonic(KeyEvent.VK_E);

maddimage=new JMenuItem("Add image to the image");
maddimage.setMnemonic(KeyEvent.VK_A);
maddimage.addActionListener(this);

mcancel=new JMenuItem("Cancel editing");
mcancel.setMnemonic(KeyEvent.VK_C);
mcancel.addActionListener(this);

menuedit.add(maddimage);
menuedit.add(mcancel);

mainmenu.add(menufile);
mainmenu.add(menuedit);
setJMenuBar(mainmenu);

setTitle("Add image to an image");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(this.getExtendedState() | this.MAXIMIZED_BOTH);
    setVisible(true);

chooser = new JFileChooser();
    FileNameExtensionFilter filter = new FileNameExtensionFilter("Image files", "jpg", "gif","bmp","png");
    chooser.setFileFilter(filter);
    chooser.setMultiSelectionEnabled(false);
enableSaving(false);
ia.requestFocus();
}

//defines actions for menu item selections
public void actionPerformed(ActionEvent e){
JMenuItem source = (JMenuItem)(e.getSource());
if(source.getText().compareTo("Open...")==0)
{
setImage();
ia.repaint();
                                                     validate();

}
else if(source.getText().compareTo("Save as...")==0)
{
showSaveFileDialog();

}
else if(source.getText().compareTo("Save")==0)
{

ia.saveToFile(filename);
}
else if(source.getText().compareTo("Add image to the image")==0)
{
if(ImgArea.imageLoaded)
new ImageAdd();
}



else if(source.getText().compareTo("Cancel editing")==0) {
ia.reset(filename);
}

else if(source.getText().compareTo("Exit")==0)
System.exit(0);


}
   

public void setImage(){ //send the chosen image (by selecting the Open... menu) to ImgArea to show

int returnVal = chooser.showOpenDialog(this);
    if(returnVal == JFileChooser.APPROVE_OPTION) {
filename=chooser.getSelectedFile().toString();
ia.prepareImage(filename);
enableSaving(true);
}
     
}

public void showSaveFileDialog(){ //display file save dialog
    int returnVal = chooser.showSaveDialog(this);
    if(returnVal == JFileChooser.APPROVE_OPTION) {
String filen=chooser.getSelectedFile().toString();
              ia.saveToFile(filen);
         
         }
}



public void enableSaving(boolean f){//enable or disable saving sub-menu items
msaveas.setEnabled(f);
msave.setEnabled(f);

}

//This class represents an interface that allows you to select an image to add to the old image
public class ImageAdd extends JFrame implements ActionListener {
JLabel lblimage;
JPanel panel;
JButton btOK;
JTextField txtWidth;
JTextField txtHeight;
BufferedImage bi;
BufferedImage biReszied;
boolean resized=false;

ImageAdd(){
setTitle("Choose image");
setPreferredSize(new Dimension(600,250));
btOK=new JButton("OK");
btOK.setBackground(Color.BLACK);
btOK.setForeground(Color.BLUE);
btOK.addActionListener(this);

txtWidth=new JTextField(4);
txtWidth.addKeyListener(new KeyList());
txtHeight=new JTextField(4);
txtHeight.addKeyListener(new KeyList());
panel=new JPanel();
panel.setLayout(new FlowLayout());
panel.add(new JLabel("Width:"));
panel.add(txtWidth);
panel.add(new JLabel("Height:"));

panel.add(txtHeight);
panel.add(btOK);
panel.setBackground(Color.GRAY);
add(panel, BorderLayout.EAST);

lblimage=new JLabel();
add(lblimage, BorderLayout.CENTER);
setVisible(true);
pack();
addImage();
}

//this method defines code to open a file dialog for new image choosing
//the image data is read from the image file by using ImageIO.read method
//the image data is converted to byte array so it can used to construct an ImageIcon
//to show on the label lblimage
public void addImage(){
int returnVal = chooser.showOpenDialog(this);
    if(returnVal == JFileChooser.APPROVE_OPTION) {
String filename=chooser.getSelectedFile().toString();
try{
bi=ImageIO.read(new File(filename));
ImageIcon img=new ImageIcon(imageToByte(bi));
lblimage.setIcon(img);
showImageDimension(bi);
repaint();
toFront();
}catch(IOException ie){}


}
     

}

//convert from bufferedimage to byte array
public byte[] imageToByte(BufferedImage bi){
ByteArrayOutputStream baos=new ByteArrayOutputStream();
try{
ImageIO.write(bi, "png", baos );
}catch(IOException ie){System.out.println("Image error");}
byte[] imageInByte=baos.toByteArray();

return imageInByte;
}

//this method defines code to resize the new image to add to the old image
//it is invoked when the user makes change to the txtWidth and txtHeight text boxes
//the user will sete resized image on the screen
public void resizeImage(BufferedImage bi,int w,int h){
biReszied=(BufferedImage)createImage(w,h);
Graphics2D g2d=(Graphics2D)biReszied.createGraphics();
g2d.drawImage(bi,0,0,w,h,null);
ImageIcon img=new ImageIcon(imageToByte(biReszied));
lblimage.setIcon(img);
repaint();
resized=true;
}

//Display the image width and height in the text boxes
public void showImageDimension(BufferedImage bi){
txtWidth.setText(""+bi.getWidth());
txtHeight.setText(""+bi.getHeight());
}

//when the user clicks the OK button the new image to add old image
//is sent to the ImgArea so it is ready to place on the old image
//once the user clicks on the old image
public void actionPerformed(ActionEvent e){
if(e.getSource()==btOK){
if(resized)
ia.setImageToAdd(biReszied);
else
ia.setImageToAdd(bi);
ia.setActionDraw(true);
dispose();
}
}

public class KeyList extends KeyAdapter{
  public void keyTyped(KeyEvent ke){

char c = ke.getKeyChar();
int intkey=(int)c;
if(!(intkey>=48 && intkey<=57 || intkey==8 || intkey==127)) //accept only number, backspace, and delete keys
{
ke.consume(); //hide the unwanted key

}
 
}
//when the user makes change to the txtWidth and txtHeight text boxes
//the image will be resized
  public void keyReleased(KeyEvent e){

if(!txtWidth.getText().equals("") && !txtHeight.getText().equals("")){
int width=Integer.parseInt(txtWidth.getText());
int height=Integer.parseInt(txtHeight.getText());
if(width>0 && height>0)
resizeImage(bi,width,height);
}

}
}

}


}

public class AddImageToImage{

public static void main(String args[]){
     new MainInter();
 
}


}

add image to image in Java

For code explanation, please read the comments along with the code of the program.