package org.joget.apps.app.controller; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import org.joget.apps.app.model.AppDefinition; import org.joget.apps.app.service.AppService; import org.joget.apps.ext.ConsoleWebPlugin; import org.joget.commons.util.FileLimitException; import org.joget.commons.util.FileStore; import org.joget.commons.util.LogUtil; import org.joget.commons.util.ResourceBundleUtil; import org.joget.commons.util.SecurityUtil; import org.joget.commons.util.SetupManager; import org.joget.plugin.base.PluginManager; import org.joget.workflow.model.WorkflowProcess; import org.joget.workflow.model.service.WorkflowManager; import org.joget.workflow.util.XpdlImageUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; @Controller public class ProcessBuilderWebController { @Autowired AppService appService; @Autowired WorkflowManager workflowManager; @Autowired PluginManager pluginManager; @RequestMapping("/console/app/(*:appId)/(~:version)/process/builder") public String processBuilder(ModelMap model, HttpServletRequest request, HttpServletResponse response, @RequestParam("appId") String appId, @RequestParam(value = "version", required = false) String version) throws IOException { // verify app version ConsoleWebPlugin consoleWebPlugin = (ConsoleWebPlugin)pluginManager.getPlugin(ConsoleWebPlugin.class.getName()); String page = consoleWebPlugin.verifyAppVersion(appId, version); if (page != null) { return page; } AppDefinition appDef = appService.getAppDefinition(appId, version); if (appDef == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return null; } model.addAttribute("appId", appDef.getId()); model.addAttribute("version", appDef.getVersion()); model.addAttribute("appDefinition", appDef); return "pbuilder/pbuilder"; } @RequestMapping(value="/console/app/(*:appId)/(~:version)/process/screenshot/(*:processDefId)") public String processBuilderScreenshot(ModelMap map, @RequestParam(value = "appId") String appId, @RequestParam(value = "version", required = false) String version, @RequestParam(value = "processDefId") String processDefId, @RequestParam(value = "callback", required = false) String callback) throws IOException { // get process info WorkflowProcess wfProcess = workflowManager.getProcess(processDefId); // get process xpdl byte[] xpdlBytes = workflowManager.getPackageContent(wfProcess.getPackageId(), wfProcess.getVersion()); if (xpdlBytes != null) { String xpdl = null; try { xpdl = new String(xpdlBytes, "UTF-8"); } catch (Exception e) { LogUtil.debug(ConsoleWebController.class.getName(), "XPDL cannot load"); } map.addAttribute("appId", appId); map.addAttribute("wfProcess", wfProcess); map.addAttribute("xpdl", xpdl); map.addAttribute("callback", callback); } String viewer = "pbuilder/pscreenshot"; return viewer; } @RequestMapping(value="/console/app/(*:appId)/(~:version)/process/builder/screenshot/submit", method = RequestMethod.POST) public void processBuilderScreenshotSubmit(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "appId") String appId, @RequestParam(value = "version", required = false) String version, @RequestParam(value = "processDefId") String processDefId) throws IOException { // validate input appId = SecurityUtil.validateStringInput(appId); processDefId = SecurityUtil.validateStringInput(processDefId); // get base64 encoded image in POST body MultipartFile xpdlimage = null; try { xpdlimage = FileStore.getFile("xpdlimage"); } catch (FileLimitException e) { LogUtil.warn(ProcessBuilderWebController.class.getName(), ResourceBundleUtil.getMessage("general.error.fileSizeTooLarge", new Object[]{FileStore.getFileSizeLimit()})); return; } if (xpdlimage != null) { ByteArrayInputStream stream = null; try { stream =new ByteArrayInputStream(xpdlimage.getBytes()); String imageBase64 = IOUtils.toString(stream, "UTF-8"); imageBase64 = imageBase64.substring("data:image/png;base64,".length()); // convert into bytes byte[] decodedBytes = Base64.decodeBase64(imageBase64.getBytes()); // save into image file String filename = processDefId + XpdlImageUtil.IMAGE_EXTENSION; String path = SetupManager.getBaseDirectory() + File.separator + "app_xpdlImages" + File.separator + appId; new File(path).mkdirs(); BufferedImage image = ImageIO.read(new ByteArrayInputStream(decodedBytes)); File f = new File(path + File.separator + filename); ImageIO.write(image, "png", f); // create thumbnail createThumbnail(image, path, processDefId); LogUtil.debug(getClass().getName(), "Created screenshot for process " + appId); } finally { if (stream != null) { stream.close(); } } } } protected void createThumbnail(Image image, String path, String processDefId) { int thumbWidth = 400; int thumbHeight = 400; BufferedOutputStream out = null; try{ double thumbRatio = (double) thumbWidth / (double) thumbHeight; int imageWidth = image.getWidth(null); int imageHeight = image.getHeight(null); double imageRatio = (double) imageWidth / (double) imageHeight; if (thumbRatio < imageRatio) { thumbHeight = (int) (thumbWidth / imageRatio); } else { thumbWidth = (int) (thumbHeight * imageRatio); } BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB); Graphics2D graphics2D = thumbImage.createGraphics(); graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null); out = new BufferedOutputStream(new FileOutputStream(path + File.separator + "thumb-" + processDefId + XpdlImageUtil.IMAGE_EXTENSION)); ImageIO.write(thumbImage, "png", out); out.flush(); } catch (Exception ex) { LogUtil.error(getClass().getName(), ex, "Error generating thumbnail [processDefId=" + processDefId + "]"); } finally { try { if (out != null) { out.close(); } } catch (Exception ex) { LogUtil.error(getClass().getName(), ex, ""); } } } }