package com.niklim.clicktrace.service.export.html; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import javax.imageio.ImageIO; import com.google.inject.Inject; import com.google.inject.Singleton; import com.niklim.clicktrace.Files; import com.niklim.clicktrace.model.ScreenShot; import com.niklim.clicktrace.model.Session; import com.niklim.clicktrace.msg.InfoMsgs; import com.niklim.clicktrace.props.UserProperties; import com.niklim.clicktrace.service.ScreenShotUtils; import com.niklim.clicktrace.service.exception.HtmlExportException; @Singleton public class HtmlExportService { private static final String HTML_EXPORT_FOLDER = "html-export/"; @Inject private HtmlExportRenderer renderer; @Inject private UserProperties props; public void export(Session session, String outputDirPath, int initImageWidth) throws HtmlExportException, IOException { if (!outputDirPath.endsWith(File.separator)) { outputDirPath += File.separator; } if (!Files.exists(outputDirPath)) { throw new HtmlExportException(InfoMsgs.HTML_EXPORT_FOLDER_NOT_EXISTS); } if (Files.exists(outputDirPath + session.getName())) { throw new HtmlExportException("Unable to create '" + session.getName() + "' folder in given directory. Already exists."); } copyFiles(session, outputDirPath); String html = renderer.renderHtml(session, HTML_EXPORT_FOLDER, initImageWidth); saveHtml(session, outputDirPath, html); } private void saveHtml(Session session, String outputDirPath, String html) throws IOException { try { String indexPath = outputDirPath + session.getName() + File.separator + "clicktrace.html"; File index = new File(indexPath); index.createNewFile(); FileOutputStream output = new FileOutputStream(index); output.write(html.getBytes()); output.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } private void copyFiles(Session session, String outputDirPath) throws IOException { createDirectories(session, outputDirPath); copyStaticResources(session, outputDirPath); copyShots(session, outputDirPath); } private void copyShots(Session session, String outputDirPath) throws IOException { for (ScreenShot shot : session.getShots()) { String fromPath = props.getSessionsDirPath() + session.getName() + File.separator + shot.getFilename(); String toPath = outputDirPath + session.getName() + File.separator + "shots" + File.separator + shot.getFilename(); Files.copy(fromPath, toPath); drawClicks(shot, toPath); } } /** * For backward compatibility. Draws click on the image. Not needed anymore * cause clicks are drawn on recording. * * @param shot * @param toPath * @throws IOException */ private void drawClicks(ScreenShot shot, String toPath) throws IOException { if (shot.getClicks().size() > 0) { BufferedImage withClicks = ScreenShotUtils.markClicks(ImageIO.read(new File(toPath)), shot.getClicks()); File outputfile = new File(toPath); ImageIO.write(withClicks, shot.getFilename().substring(shot.getFilename().lastIndexOf(".") + 1), outputfile); } } private void copyStaticResources(Session session, String outputDirPath) throws IOException { copy("resources/clicktrace.css", outputDirPath + session.getName()); copy("resources/clicktrace.js", outputDirPath + session.getName()); copy("resources/footer.png", outputDirPath + session.getName()); copy("resources/zoom_in.png", outputDirPath + session.getName()); copy("resources/zoom_out.png", outputDirPath + session.getName()); } private void createDirectories(Session session, String outputDirPath) throws IOException { Files.createDirectory(outputDirPath + session.getName()); Files.createDirectory(outputDirPath + session.getName() + File.separator + "resources"); Files.createDirectory(outputDirPath + session.getName() + File.separator + "shots"); } private void copy(String source, String targetBasePath) throws IOException { InputStream resource = Thread.currentThread().getContextClassLoader() .getResourceAsStream(HTML_EXPORT_FOLDER + source); Files.copy(resource, targetBasePath + File.separator + source); } }