package org.janelia.render.client; import com.beust.jcommander.Parameter; import com.beust.jcommander.ParametersDelegate; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.LinkedHashMap; import java.util.Map; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.janelia.alignment.RenderParameters; import org.janelia.render.client.parameter.CommandLineParameters; import org.janelia.render.client.parameter.RenderWebServiceParameters; import org.janelia.render.client.response.BufferedImageResponseHandler; import org.janelia.render.client.response.FileResponseHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple client for rendering based upon a JSON parameters spec. * * @author Eric Trautman */ public class RenderClient { public static final String JPEG_FORMAT = "jpeg"; public static final String PNG_FORMAT = "png"; public static class Parameters extends CommandLineParameters { @ParametersDelegate public RenderWebServiceParameters renderWeb = new RenderWebServiceParameters(); @Parameter(names = "--in", description = "Path to render parameters json file", required = true) public String in; @Parameter(names = "--out", description = "Path for the output image file (if omitted, image will be displayed in window)", required = false) public String out; @Parameter(names = "--format", description = "Format for output image (jpeg or png, default is jpeg)", required = false) public String format; public boolean renderInWindow() { return (out == null); } } public static void main(final String[] args) { final ClientRunner clientRunner = new ClientRunner(args) { @Override public void runClient(final String[] args) throws Exception { final Parameters parameters = new Parameters(); parameters.parse(args); LOG.info("runClient: entry, parameters={}", parameters); final RenderClient client = new RenderClient(parameters.renderWeb.baseDataUrl, parameters.renderWeb.project); if (parameters.renderInWindow()) { client.renderInWindow(parameters.in, parameters.out); } else { client.renderToFile(parameters.in, parameters.out, parameters.format); } } }; clientRunner.run(); } private final Map<String, URI> formatToRenderUriMap; private final CloseableHttpClient httpClient; /** * @param baseUriString base URI for web service (e.g. http://renderer.int.janelia.org/render-ws/v1). * @param owner owner (e.g. 'flyTEM') for all requests. * * @throws IllegalArgumentException * if the render URI instances cannot be constructed. */ public RenderClient(final String baseUriString, final String owner) throws IllegalArgumentException { final String trimmedBaseUriString; if (baseUriString.endsWith("/")) { trimmedBaseUriString = baseUriString.substring(0, baseUriString.length() - 1); } else { trimmedBaseUriString = baseUriString; } final String projectUriString = trimmedBaseUriString + "/owner/" + owner; final URI jpegUri = createUri(projectUriString + "/jpeg-image"); final URI pngUri = createUri(projectUriString + "/png-image"); final Map<String, URI> map = new LinkedHashMap<>(); map.put(JPEG_FORMAT.toLowerCase(), jpegUri); map.put(PNG_FORMAT.toLowerCase(), pngUri); this.formatToRenderUriMap = map; this.httpClient = HttpClients.createDefault(); } /** * @param format image format. * * @return render URI for the specified format. */ public URI getRenderUriForFormat(final String format) { final String lowerCaseFormat; if (format == null) { lowerCaseFormat = JPEG_FORMAT; } else { lowerCaseFormat = format.toLowerCase(); } URI uri = formatToRenderUriMap.get(lowerCaseFormat); if (uri == null) { LOG.warn("getRenderUriForFormat: unknown format '" + format + "' requested, using '" + JPEG_FORMAT + "' instead, known formats are: " + formatToRenderUriMap.keySet()); uri = formatToRenderUriMap.get(JPEG_FORMAT); } return uri; } @Override public String toString() { return "RenderClient{formatToRenderUriMap=" + formatToRenderUriMap + '}'; } /** * Invokes the Render Web Service using parameters loaded from the specified file and * writes the resulting image to the specified output file. * * @param renderParametersPath path of render parameters (json) file. * @param outputFilePath path of result image file. * @param outputFormat format of result image (e.g. 'jpeg' or 'png'). * * @throws IOException * if the render request fails for any reason. */ public void renderToFile(final String renderParametersPath, final String outputFilePath, final String outputFormat) throws IOException { final File parametersFile = new File(renderParametersPath); final RenderParameters renderParameters = RenderParameters.parseJson(parametersFile); final File outputFile = new File(outputFilePath).getCanonicalFile(); renderToFile(renderParameters, outputFile, outputFormat); } /** * Invokes the Render Web Service using specified parameters and * writes the resulting image to the specified output file. * * @param renderParameters render parameters. * @param outputFile result image file. * @param outputFormat format of result image (e.g. 'jpeg' or 'png'). * * @throws IOException * if the render request fails for any reason. */ public void renderToFile(final RenderParameters renderParameters, final File outputFile, final String outputFormat) throws IOException { LOG.info("renderToFile: entry, renderParameters={}, outputFile={}, outputFormat={}", renderParameters, outputFile, outputFormat); if (outputFile.exists()) { if (! outputFile.canWrite()) { throw new IOException("output file " + outputFile.getAbsolutePath() + " cannot be overwritten"); } } else { File parentFile = outputFile.getParentFile(); while (parentFile != null) { if (parentFile.exists()) { if (! parentFile.canWrite()) { throw new IOException("output file cannot be written to parent directory " + parentFile.getAbsolutePath()); } break; } parentFile = parentFile.getParentFile(); } } final String json = renderParameters.toJson(); final StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON); final URI uri = getRenderUriForFormat(outputFormat); final FileResponseHandler responseHandler = new FileResponseHandler("PUT " + uri, outputFile); final HttpPut httpPut = new HttpPut(uri); httpPut.setEntity(stringEntity); httpClient.execute(httpPut, responseHandler); LOG.info("renderToFile: exit, wrote image to {}", outputFile.getAbsolutePath()); } /** * Invokes the Render Web Service using parameters loaded from the specified file and * displays the resulting image in a window. * * @param renderParametersPath path of render parameters (json) file. * @param outputFormat format of result image (e.g. 'jpeg' or 'png'). * * @throws IOException * if the render request fails for any reason. */ public void renderInWindow(final String renderParametersPath, final String outputFormat) throws IOException { final File parametersFile = new File(renderParametersPath); final RenderParameters renderParameters = RenderParameters.parseJson(parametersFile); renderInWindow(renderParameters, outputFormat); } /** * Invokes the Render Web Service using specified parameters and * displays the resulting image in a window. * * @param renderParameters render parameters. * @param outputFormat format of result image (e.g. 'jpeg' or 'png'). * * @throws IOException * if the render request fails for any reason. */ public void renderInWindow(final RenderParameters renderParameters, final String outputFormat) throws IOException { LOG.info("renderInWindow: entry, renderParameters={}, outputFormat={}", renderParameters, outputFormat); final String json = renderParameters.toJson(); final StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON); final URI uri = getRenderUriForFormat(outputFormat); final BufferedImageResponseHandler responseHandler = new BufferedImageResponseHandler("PUT " + uri); final HttpPut httpPut = new HttpPut(uri); httpPut.setEntity(stringEntity); final BufferedImage image = httpClient.execute(httpPut, responseHandler); final ScrollableImageWindow window = new ScrollableImageWindow(renderParameters.toString(), image); window.setVisible(true); LOG.info("renderInWindow: exit, created {}", image); } private URI createUri(final String uriString) throws IllegalArgumentException { final URI uri; try { uri = new URI(uriString); } catch (final URISyntaxException e) { throw new IllegalArgumentException("failed to parse URI string: " + uriString, e); } return uri; } private static final Logger LOG = LoggerFactory.getLogger(RenderClient.class); }