/*
* cameracontrol
* Copyright (C) 2010 Stefano Fornari
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY Stefano Fornari, Stefano Fornari
* DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, see http://www.gnu.org/licenses or write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*/
package ste.cameracontrol.ui;
import ch.ntb.usb.USBBusyException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import ste.cameracontrol.CameraController;
import ste.cameracontrol.Configuration;
import ste.cameracontrol.Photo;
import ste.ptp.PTPException;
/**
* This is a command line tool to access EOS PTP cameras.
*
* @author Stefano Fornari
*/
public class CameraControlCLI {
/** No instances permitted */
private CameraControlCLI() {
}
// options
static private File directory;
static private String device;
static private boolean overwrite;
static private int storageId;
static private CameraController controller = null;
private static void usage(int status) {
System.err.println("Usage: jphoto command [options]");
System.err.println("Key commands include:");
System.err.println(" cameras ... lists devices by portid");
System.err.println(" get-events ... checks and list camera events");
System.err.println(" capture ... starts image/object capture");
System.err.println(" devinfo ... shows device info");
System.err.println(" devprops ... shows all device properties");
System.err.println(" format ... reformat a storage unit");
System.err.println(" images ... download images/videos to directory (default 'images')");
System.err.println(" reset ... reset request");
System.err.println(" storage ... shows storage info");
System.err.println(" tree ... lists storage contents");
System.err.println(" shoot ... take a picture without transferring the impage");
System.err.println("Other commands include:");
// System.err.println (" delete filename ... deletes one object");
System.err.println(" devices ... (same as 'cameras')");
System.err.println(" getprop propname ... shows one device property");
System.err.println(" help ... shows this message");
System.err.println(" powerdown ... powers down device");
// System.err.println (" print ... prints according to DPOF order");
System.err.println(" put fileOrURL [...] ... copy object(s) to device");
System.err.println(" selftest ... runs basic selftest");
// System.err.println (" settime ... sets clock on device");
System.err.println(" status ... status summary");
System.err.println(" thumbs ... download thumbs to directory (default 'thumbs')");
System.err.println("Options include:");
System.err.println(" --camera value (or, -c value)");
System.err.println(" --directory value (or, -d value)");
System.err.println(" --help (or, -h)");
System.err.println(" --overwrite (or, -w)");
System.err.println(" --storage value (or, -s value)");
System.err.println("Documentation and Copyright at: "
+ "http://code.google.com/p/cameracontrol");
System.err.println("Licensed under the Affero GNU General Public License 3.0.");
System.err.println("No Warranty.");
System.err.println();
if (status != 0) {
System.exit(status);
}
}
/**
* Parameters are a command and any option parameters
* such as <em><b>--camera</b> port-id</em>
* specifying the the port id for a camera.
* (See <em>usb.core.PortIdentifier</em> for information
* about those identifiers.)
* Such port ids may be omitted when there is only one
* camera currently connected; list them
* using the <em>cameras</em> commands.
* PTP devices may support only some of these commands.
*
* <table border=1 cellpadding=3 cellspacing=0 width="80%">
* <tr bgcolor="#ccccff" class="TableHeadingColor">
* <th>Command and Arguments</th>
* <th>Description</th>
* <th>Options</th>
* </tr>
*
* <tr valign=top>
* <td> <code>cameras</code> </td>
* <td> (same as "devices") </td>
* <td> <em>none</em> </td>
* </tr>
*
* <tr valign=top>
* <td> <code>capture</code> </td>
* <td> starts capturing images or other objects, according
* to the current device properties. </td>
* <td> <em>--port-id</em> id <br />
* <em>--storage</em> id
* </td>
* </tr>
*
* <tr valign=top>
* <td> <code>devices</code> </td>
* <td> Lists PTP devices with their port identifiers </td>
* <td> <em>none</em> </td>
* </tr>
*
* <tr valign=top>
* <td> <code>devinfo</code> </td>
* <td> Displays the DeviceInfo for a camera, including
* all the operations, events, device properties,
* and object formats supported. </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* <tr valign=top>
* <td> <code>devprops</code> </td>
* <td> shows all device properties, with types and values. </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* <tr valign=top>
* <td> <code>format</code> </td>
* <td> Reformats the specified storage unit (zero based). </td>
* <td> <em>--port-id</em> id
* <br> <em>--storage</em> number
* </td>
* </tr>
*
* <tr valign=top>
* <td> <code>getprop</code> <em>propname</em></td>
* <td> shows named device property, with type and value. </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* <tr valign=top>
* <td> <code>help</code> </td>
* <td> shows command summary</td>
* <td> <em>none</em> </td>
* </tr>
*
* <tr valign=top>
* <td> <code>images</code> </td>
* <td> Downloads image files to directory </td>
* <td> <em>--port-id</em> id
* <br> <em>--overwrite</em>
* <br> <em>--directory</em> directory (default "images") </td>
* </tr>
*
* <tr valign=top>
* <td> <code>powerdown</code> </td>
* <td> Causes the device to power down. </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* <tr valign=top>
* <td> <code>put</code> <em>file-or-URL [...]</em> </td>
* <td> Copies images or other objects to device. </td>
* <td> <em>--port-id</em> id <br />
* <em>--storage</em> id
* </tr>
*
* <tr valign=top>
* <td> <code>reset</code> </td>
* <td> Issues a PTP level reset. </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* <tr valign=top>
* <td> <code>selftest</code> </td>
* <td> Runs a basic device self test. </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* <tr valign=top>
* <td> <code>status</code> </td>
* <td> Shows status summary for the device </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* <tr valign=top>
* <td> <code>storage</code> </td>
* <td> Displays the StorageInfo for the device's
* storage units, all or just the specified (zero base) store </td>
* <td> <em>--port-id</em> id
* <br> <em>--storage</em> number
* </td>
* </tr>
*
* <tr valign=top>
* <td> <code>thumbs</code> </td>
* <td> Downloads image thumbnails to directory </td>
* <td> <em>--port-id</em> id
* <br> <em>--overwrite</em>
* <br> <em>--directory</em> directory (default "thumbs") </td>
* </tr>
*
* <tr valign=top>
* <td> <code>tree</code> </td>
* <td> Lists contents of camera storage. </td>
* <td> <em>--port-id</em> id </td>
* </tr>
*
* </table>
*/
public static void main(String[] args) throws Exception {
if (args.length == 0) {
usage(-1);
}
Options options = new Options();
options.addOption(
OptionBuilder.withLongOpt( "camera" )
.withArgName("c")
.hasArg()
.withArgName("value")
.create()
);
options.addOption("d", "directory", true , "");
options.addOption("h", "help" , false, "");
options.addOption("w", "overwrite", false, "");
options.addOption("s", "storage" , true , "");
CommandLineParser parser = new PosixParser();
CommandLine line = parser.parse(options, args);
try {
if (line.hasOption('c')) {
device = line.getOptionValue('c');
}
if (line.hasOption('d')) {
directory = new File(line.getOptionValue('d'));
} else {
directory = new File("images");
}
if (line.hasOption('h')) {
usage(0);
System.exit(0);
}
if (line.hasOption('s')) {
storageId = Integer.parseInt(line.getOptionValue('s'));
if (storageId < 0) {
System.err.println("--storage N ... "
+ "parameter must be an integer");
usage(-1);
}
}
if (line.hasOption('w')) {
overwrite = true;
}
if (!directory.exists()) {
directory.mkdirs();
}
Configuration c = new Configuration();
c.setImageDir(directory.getAbsolutePath());
controller = CameraController.getInstance();
controller.initialize(c);
controller.startCamera();
for (String arg: line.getArgs()) {
/*
if ("cameras".equals (argv [c]) || "devices".equals (argv [c]))
cameras (argv, c);
else
*/
if ("get-events".equals(arg)) {
getEvents();
} else if ("shoot".equals(arg)) {
shoot();
} else if ("devinfo".equals(arg)) {
devinfo();
} /*else if ("devprops".equals (argv [c]))
devprops (argv, c);
else if ("format".equals (argv [c]))
format (argv, c);
else if ("getprop".equals (argv [c]))
getprop (argv, c);
*/ else if ("help".equals(arg)) {
usage(0);
} /*
else if ("images".equals (argv [c]))
images (argv, c);
else if ("put".equals (argv [c]))
put (argv, c);
else if ("powerdown".equals (argv [c]))
powerdown (argv, c);
else if ("reset".equals (argv [c]))
reset (argv, c);
else if ("selftest".equals (argv [c]))
selftest (argv, c);
else if ("status".equals (argv [c]))
status (argv, c);
else if ("storage".equals (argv [c]))
storage (argv, c);
else if ("thumbs".equals (argv [c]))
thumbs (argv, c);
else if ("tree".equals (argv [c]))
tree (argv, c);
*/ else {
usage(-1);
}
}
} catch (UnsupportedOperationException e) {
System.err.println("Device does not support " + e.getMessage());
System.exit(1);
} catch (PTPException e) {
//
// Let's intercept for now when a device is busy
//
Throwable cause = e.getCause();
if (cause instanceof USBBusyException) {
System.err.println("The camera is busy. Please make sure not any other program is using and locking the device.");
} else {
System.err.println(e.getMessage());
}
System.exit(1);
} catch (SecurityException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
/*--------------------------------------------------------------------*/
private static void indent(PrintStream out, int depth) {
while (depth >= 8) {
out.print("\t");
depth -= 8;
}
while (depth != 0) {
out.print(" ");
depth--;
}
}
private static void devinfo()
throws PTPException {
controller.devinfo();
}
private static void getEvents()
throws PTPException {
controller.dumpEvents();
}
private static void shoot()
throws IOException, PTPException {
Photo[] photos = controller.shootAndDownload();
for (Photo photo: photos) {
controller.savePhoto(photo);
}
}
}