package com.hammurapi.jcapture; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.border.LineBorder; import netscape.javascript.JSObject; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; /** * License: LGPL. * @author Pavel Vlasov. * */ public class CaptureFrame extends javax.swing.JFrame { private JPanel capturePanel; private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss-SSS"); private int counter; private CaptureConfig captureConfig; private AbstractCaptureApplet applet; private JButton recordButton; public CaptureConfig getCaptureConfig() { return captureConfig; } public CaptureFrame(final AbstractCaptureApplet applet) throws Exception { super("Screen capture"); setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource("camera.png"))); setUndecorated(true); Translucener.makeFrameTranslucent(this); setAlwaysOnTop(true); this.applet = applet; captureConfig = new CaptureConfig(); captureConfig.load(applet.loadConfig()); captureConfig.setBackgroundProcessor(applet.getBackgroundProcessor()); //--- GUI construction --- capturePanel = new JPanel(); final JLabel dimensionsLabel = new JLabel(""); capturePanel.add(dimensionsLabel, BorderLayout.CENTER); capturePanel.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { super.componentResized(e); dimensionsLabel.setText(e.getComponent().getWidth()+" x "+e.getComponent().getHeight()); } }); JButton captureButton = new JButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { Rectangle bounds = capturePanel.getBounds(); Point loc = bounds.getLocation(); SwingUtilities.convertPointToScreen(loc, capturePanel); bounds.setLocation(loc); Properties props = captureConfig.setRecordingRectangle(bounds); if (props!=null) { getApplet().storeConfig(props); } capturing.set(true); setVisible(false); } }); captureButton.setText("Capture"); captureButton.setToolTipText("Create a snapshot of the screen"); capturePanel.add(captureButton, BorderLayout.CENTER); recordButton = new JButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { Rectangle bounds = capturePanel.getBounds(); Point loc = bounds.getLocation(); SwingUtilities.convertPointToScreen(loc, capturePanel); bounds.setLocation(loc); Properties props = captureConfig.setRecordingRectangle(bounds); if (props!=null) { getApplet().storeConfig(props); } recording.set(true); setVisible(false); } }); recordButton.setText("Record"); setRecordButtonState(); capturePanel.add(recordButton, BorderLayout.CENTER); JButton optionsButton = new JButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { new CaptureOptionsDialog(CaptureFrame.this).setVisible(true); } }); optionsButton.setText("Options"); capturePanel.add(optionsButton, BorderLayout.CENTER); JButton cancelButton = new JButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { CaptureFrame.this.setVisible(false); } }); cancelButton.setText("Cancel"); capturePanel.add(cancelButton, BorderLayout.CENTER); getContentPane().add(capturePanel, BorderLayout.CENTER); capturePanel.setBorder(new LineBorder(new java.awt.Color(0,0,0), 1, false)); if (captureConfig.getRecordingRectangle()==null) { setSize(400, 300); setLocationRelativeTo(null); } else { setBounds(captureConfig.getRecordingRectangle()); } Insets dragInsets = new Insets(5, 5, 5, 5); new ComponentResizer(dragInsets, this); ComponentMover cm = new ComponentMover(); cm.registerComponent(this); cm.setDragInsets(dragInsets); addComponentListener(new ComponentListener() { @Override public void componentShown(ComponentEvent e) { // TODO Auto-generated method stub } @Override public void componentResized(ComponentEvent e) { // TODO Auto-generated method stub } @Override public void componentMoved(ComponentEvent e) { // TODO Auto-generated method stub } @Override public void componentHidden(ComponentEvent e) { if (capturing.get()) { capturing.set(false); try { capture(); } catch (Exception ex) { ex.printStackTrace(); } } else if (recording.get()) { recording.set(false); record(); } } }); } void setRecordButtonState() { if (captureConfig.getEncoder()==null) { recordButton.setEnabled(false); recordButton.setToolTipText("Video format not selected. Use Options dialog to select video format."); } else { recordButton.setEnabled(true); recordButton.setToolTipText("Record screen activity and audio"); } } public AbstractCaptureApplet getApplet() { return applet; } protected void capture() throws Exception { try { Thread.sleep(200); // For Ubuntu. } catch (InterruptedException ie) { // Ignore } BufferedImage screenShot = captureConfig.createScreenShot(null, null).call().getRegions().get(0).getImage().getImage(); String prefix = getDatePrefix(); String defaultImageFormat = applet.getParameter("imageFormat"); if (defaultImageFormat==null || defaultImageFormat.trim().length()==0) { defaultImageFormat = "PNG"; } final String defaultFileExtension=defaultImageFormat.toLowerCase(); final String fileName = JOptionPane.showInputDialog(CaptureFrame.this, "Upload as", applet.getParameter("pageName")+"-capture-"+prefix+"-" + nextCounter() +"."+defaultFileExtension); if (fileName!=null) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int idx = fileName.lastIndexOf('.'); String imageFormat = idx==-1 ? defaultImageFormat : fileName.substring(idx+1).toUpperCase(); ImageIO.write(screenShot, imageFormat, baos); final byte[] imageBytes = baos.toByteArray(); System.out.println("Image size: "+imageBytes.length); // Uploading SwingWorker task = new SwingWorker() { @Override protected Boolean doInBackground() throws Exception { System.out.println("Uploading in background"); try { HttpResponse iResponse = applet.post( CaptureFrame.this, new ByteArrayInputStream(imageBytes), imageBytes.length, fileName, "application/octet-stream"); System.out.println("Response status line: "+iResponse.getStatusLine()); if (iResponse.getStatusLine().getStatusCode()!=HttpStatus.SC_OK) { errorMessage = iResponse.getStatusLine(); errorTitle = "Error saving image"; return false; } return true; } catch (Error e) { errorMessage=e.toString(); errorTitle = "Upload error"; e.printStackTrace(); return false; } } private Object errorMessage; private String errorTitle; protected void done() { try { if (get()) { JSObject window = JSObject.getWindow(applet); String toEval = "insertAtCarret('"+applet.getParameter("edid")+"','{{:"+fileName+"|}}')"; System.out.println("Evaluating: "+toEval); window.eval(toEval); CaptureFrame.this.setVisible(false); } else { JOptionPane.showMessageDialog( CaptureFrame.this, errorMessage, errorTitle, JOptionPane.ERROR_MESSAGE); } } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog( CaptureFrame.this, e.toString(), "Exception", JOptionPane.ERROR_MESSAGE); } }; }; task.execute(); } catch (IOException ex) { JOptionPane.showMessageDialog( applet, ex.toString(), "Error saving image", JOptionPane.ERROR_MESSAGE); } } } public int nextCounter() { return counter++; } public String getDatePrefix() { return dateFormat.format(new Date()); } protected void record() { try { Thread.sleep(200); // For Ubuntu. } catch (InterruptedException ie) { // Ignore } int borderWidth = 1; JFrame[] borderFrames = new JFrame[4]; Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); Rectangle rr = captureConfig.getRecordingRectangle(); Color borderColor = Color.RED; if (rr.x>=borderWidth) { // West border borderFrames[0] = new JFrame(); borderFrames[0].setDefaultCloseOperation(DISPOSE_ON_CLOSE); borderFrames[0].setSize(borderWidth, rr.height+borderWidth*2); borderFrames[0].setLocation(rr.x-borderWidth, rr.y-borderWidth); borderFrames[0].setUndecorated(true); borderFrames[0].setAlwaysOnTop(true); borderFrames[0].setFocusableWindowState(false); borderFrames[0].getContentPane().setBackground(borderColor); } if (rr.x+rr.width=borderWidth) { // North border borderFrames[2] = new JFrame(); borderFrames[2].setDefaultCloseOperation(DISPOSE_ON_CLOSE); borderFrames[2].setSize(rr.width, borderWidth); borderFrames[2].setLocation(rr.x, rr.y-borderWidth); borderFrames[2].setUndecorated(true); borderFrames[2].setAlwaysOnTop(true); borderFrames[2].setFocusableWindowState(false); borderFrames[2].getContentPane().setBackground(borderColor); } if (rr.y+rr.heightdim.getWidth()) { x = dim.width-inst.getWidth(); } else if (x<0) { x = 0; } int y = rr.getLocation().y+getHeight()+1; if (y+inst.getHeight()>dim.height) { y = rr.getLocation().y-inst.getHeight(); if (y<0) { y=dim.height-inst.getHeight(); } } inst.setLocation(x, y); inst.setVisible(true); } private AtomicBoolean capturing = new AtomicBoolean(false); private AtomicBoolean recording = new AtomicBoolean(false); }