/** * This file Copyright (c) 2012 Magnolia International * Ltd. (http://www.magnolia-cms.com). All rights reserved. * * * This file is dual-licensed under both the Magnolia * Network Agreement and the GNU General Public License. * You may elect to use one or the other of these licenses. * * This file is distributed in the hope that it will be * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. * Redistribution, except as permitted by whichever of the GPL * or MNA you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or * modify this file under the terms of the GNU General * Public License, Version 3, as published by the Free Software * Foundation. You should have received a copy of the GNU * General Public License, Version 3 along with this program; * if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * 2. For the Magnolia Network Agreement (MNA), this file * and the accompanying materials are made available under the * terms of the MNA which accompanies this distribution, and * is available at http://www.magnolia-cms.com/mna.html * * Any modifications to this file must keep this entire header * intact. * */ package info.magnolia.templating.jsp.taglib; import info.magnolia.cms.beans.runtime.FileProperties; import info.magnolia.cms.core.Content; import info.magnolia.cms.core.NodeData; import info.magnolia.context.MgnlContext; import info.magnolia.jcr.util.NodeTypes; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.devlib.schmidt.imageinfo.ImageInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.AccessDeniedException; import javax.jcr.Node; import javax.jcr.PathNotFoundException; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.SimpleTagSupport; import java.awt.Color; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.TimeZone; /** * A base class for image related tags e.g. {@link ScaleImageTag}. * @author Fabrizio Giustina */ public abstract class BaseImageTag extends SimpleTagSupport { /** * The value of the extension nodeData in the properties node. */ protected static final String PROPERTIES_EXTENSION_VALUE = "PNG"; /** * The valye of the contentType nodeData in the properties node. */ protected static final String PROPERTIES_CONTENTTYPE_VALUE = "image/png"; /** * Logger. */ private static Logger log = LoggerFactory.getLogger(BaseImageTag.class); /** * Attribute: The node where the images are to be saved. If null, the default will be the current active page. */ protected String parentContentNodeName; /** * Attribute: The name of the new content node to create. The images will be saved under this node. If this name * starts with a '/', it will be assumed to be a node handle that is relative to the rooot of the website. * Otherwise, it is assumed to be a path relative to the currentActivePage. */ protected String imageContentNodeName; /** * Setter for the <code>imageContentNodeName</code> tag attribute. * @param imageContentNodeName */ public void setImageContentNodeName(String imageContentNodeName) { this.imageContentNodeName = imageContentNodeName; } /** * Setter for the <code>parentContentNodeName</code> tag attribute. * @param parentContentNodeName */ public void setParentContentNodeName(String parentContentNodeName) { this.parentContentNodeName = parentContentNodeName; } protected abstract String getFilename(); protected HttpServletRequest getRequest() { return (HttpServletRequest) ((PageContext) this.getJspContext()).getRequest(); } /** * @throws PathNotFoundException * @throws RepositoryException * @throws AccessDeniedException */ protected Node getImageContentNode() throws PathNotFoundException, RepositoryException, info.magnolia.cms.security.AccessDeniedException { Session session = MgnlContext.getJCRSession(MgnlContext.getAggregationState().getRepository()); Node imageContentNode; Node currentActivePage = MgnlContext.getJCRSession(MgnlContext.getAggregationState().getRepository()).getNode(MgnlContext.getAggregationState().getHandle()); Node paragraph = MgnlContext.getAggregationState().getCurrentContent().getJCRNode(); Node parentContentNode = null; // set the image parent node if (StringUtils.isEmpty(this.parentContentNodeName)) { parentContentNode = paragraph != null ? paragraph : currentActivePage; } else { // if this name starts with a '/', then assume it is a node handle // otherwise assume that its is a path relative to the current active page if (this.parentContentNodeName.startsWith("/")) { parentContentNode = session.getNode(this.parentContentNodeName); } else { parentContentNode = session.getNode(currentActivePage.getPath() + "/" + this.parentContentNodeName); } } // set the node under which the images will be saved imageContentNode = null; if (StringUtils.isEmpty(this.imageContentNodeName)) { imageContentNode = parentContentNode; } else if (parentContentNode.hasNode(this.imageContentNodeName)) { imageContentNode = parentContentNode.getNode(this.imageContentNodeName); } else { imageContentNode = parentContentNode.addNode(this.imageContentNodeName, NodeTypes.ContentNode.NAME); session.save(); } return imageContentNode; } /** * Replace any special characters that are not letters or numbers with a replacement string. The two exceptions are * '-' and '_', which are allowed. */ public String convertToSimpleString(String string) { final StringBuffer result = new StringBuffer(); final StringCharacterIterator iterator = new StringCharacterIterator(string); char character = iterator.current(); while (character != CharacterIterator.DONE) { int charType = Character.getType(character); if (charType == Character.SPACE_SEPARATOR) { result.append("-"); } else if ((charType != Character.UPPERCASE_LETTER) && (charType != Character.LOWERCASE_LETTER) && (charType != Character.DECIMAL_DIGIT_NUMBER) && (charType != Character.CONNECTOR_PUNCTUATION) && (charType != Character.DASH_PUNCTUATION)) { result.append("u" + (int) character); } else { // the char is not a special one // add it to the result as is result.append(character); } character = iterator.next(); } return result.toString(); } /** * Converts HEX color to RGB color. * @param hex HEX value */ public int[] convertHexToRGB(String hex) { hex.trim(); if (hex.startsWith("#")) { hex = hex.substring(1); } if (hex.length() == 3) { // allow three digit codes like for css hex = String.valueOf(hex.charAt(0)) + String.valueOf(hex.charAt(0)) + String.valueOf(hex.charAt(1)) + String.valueOf(hex.charAt(1)) + String.valueOf(hex.charAt(2)) + String.valueOf(hex.charAt(2)); } int[] rgb = new int[3]; try { // Convert rrggbb string to hex ints rgb[0] = Integer.parseInt(hex.substring(0, 2), 16); rgb[1] = Integer.parseInt(hex.substring(2, 4), 16); rgb[2] = Integer.parseInt(hex.substring(4), 16); } catch (NumberFormatException e) { log.error("NumberFormatException occured during text-to-image conversion: " + "Attempting to convert Hex [" + hex + "] color to RGB color: " + e.getMessage(), e); rgb = new int[]{255, 0, 0}; // red } return rgb; } public Color convertHexToColor(String hex) { int[] rgb = convertHexToRGB(hex); Color color = new Color(rgb[0], rgb[1], rgb[2]); return color; } /** * Create a new imageNode with the image in it. The node is saved under a node that groups all image nodes, whose * name is set to the value of the attribute imageContentNodeName. The name of the node will be set to a name that * is unique for the image. The property that stores the image will be set to the value of * PROPERTIES_FILENAME_VALUE. A sub-node is also created that stores the image properties. * @param imageFile the file * @param imageNode The node that will contain the text images. */ protected void createImageNode(File imageFile, Content imageNode) throws PathNotFoundException, AccessDeniedException, RepositoryException, FileNotFoundException, IOException { // Create and save the image data NodeData data; data = imageNode.getNodeData(getFilename()); if (!data.isExist()) { data = imageNode.createNodeData(getFilename(), PropertyType.BINARY); } InputStream iis = new FileInputStream(imageFile); data.setValue(iis); IOUtils.closeQuietly(iis); data.setAttribute(FileProperties.PROPERTY_FILENAME, getFilename()); data.setAttribute(FileProperties.PROPERTY_CONTENTTYPE, PROPERTIES_CONTENTTYPE_VALUE); Calendar value = new GregorianCalendar(TimeZone.getDefault()); data.setAttribute(FileProperties.PROPERTY_LASTMODIFIED, value); data.setAttribute(FileProperties.PROPERTY_SIZE, Long.toString(imageFile.length())); data.setAttribute(FileProperties.PROPERTY_EXTENSION, PROPERTIES_EXTENSION_VALUE); InputStream raf = null; try { ImageInfo ii = new ImageInfo(); raf = new FileInputStream(imageFile); ii.setInput(raf); if (ii.check()) { data.setAttribute(FileProperties.PROPERTY_WIDTH, Long.toString(ii.getWidth())); data.setAttribute(FileProperties.PROPERTY_HEIGHT, Long.toString(ii.getHeight())); } } catch (FileNotFoundException e) { log.error("FileNotFoundException caught when parsing {}, image data will not be available", imageFile .getAbsolutePath()); } finally { IOUtils.closeQuietly(raf); } // delete the temporary file imageFile.delete(); // update modification date and save the new image node NodeTypes.LastModified.update(imageNode.getJCRNode()); imageNode.getParent().save(); } }