/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * For further information about Alkacon Software GmbH, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.jsp; import org.opencms.file.CmsObject; import org.opencms.file.CmsResource; import org.opencms.flex.CmsFlexController; import org.opencms.i18n.CmsEncoder; import org.opencms.loader.CmsImageScaler; import org.opencms.main.CmsException; import org.opencms.main.CmsLog; import org.opencms.main.OpenCms; import org.opencms.staticexport.CmsLinkManager; import org.opencms.util.CmsRequestUtil; import org.opencms.util.CmsStringUtil; import org.opencms.util.CmsUriSplitter; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; import org.apache.commons.logging.Log; /** * Creates HTML code for <img src> tags that use the OpenCms image scaling capabilities.<p> * * @since 6.2.0 */ public class CmsJspTagImage extends BodyTagSupport implements I_CmsJspTagParamParent { // optional HTML attribute constants private static final String ATTR_ALIGN = "align"; private static final String ATTR_ALT = "alt"; private static final String ATTR_BORDER = "border"; private static final String ATTR_CLASS = "class"; private static final String ATTR_HSPACE = "hspace"; private static final String ATTR_ID = "id"; private static final String ATTR_LONGDESC = "longdesc"; private static final String ATTR_NAME = "name"; private static final String ATTR_STYLE = "style"; private static final String ATTR_TITLE = "title"; private static final String ATTR_USEMAP = "usemap"; private static final String ATTR_VSPACE = "vspace"; /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsJspTagImage.class); // image scaler required attribute constants private static final String SCALE_ATTR_COLOR = "scalecolor"; private static final String SCALE_ATTR_FILTER = "scalefilter"; private static final String SCALE_ATTR_HEIGHT = "height"; private static final String SCALE_ATTR_MAXHEIGHT = "maxHeight"; private static final String SCALE_ATTR_MAXWIDTH = "maxWidth"; private static final String SCALE_ATTR_PARTIALTAG = "partialtag"; private static final String SCALE_ATTR_POSITION = "scaleposition"; private static final String SCALE_ATTR_QUALITY = "scalequality"; private static final String SCALE_ATTR_RENDERMODE = "scalerendermode"; private static final String SCALE_ATTR_SRC = "src"; private static final String SCALE_ATTR_TYPE = "scaletype"; private static final String SCALE_ATTR_WIDTH = "width"; // lists for fast lookup private static final String[] SCALER_ATTRS = { SCALE_ATTR_COLOR, SCALE_ATTR_FILTER, SCALE_ATTR_HEIGHT, SCALE_ATTR_PARTIALTAG, SCALE_ATTR_POSITION, SCALE_ATTR_QUALITY, SCALE_ATTR_RENDERMODE, SCALE_ATTR_SRC, SCALE_ATTR_TYPE, SCALE_ATTR_WIDTH, SCALE_ATTR_MAXHEIGHT, SCALE_ATTR_MAXWIDTH}; private static final List<String> SCALER_ATTRS_LIST = Arrays.asList(SCALER_ATTRS); /** Serial version UID required for safe serialization. */ private static final long serialVersionUID = 6513320107441256414L; /** Map with additionally set image attributes not needed by the image scaler. */ private Map<String, String> m_attributes; /** Controls if the created HTML image tag is a full or partial tag. */ private boolean m_partialTag; /** The given image scaler parameters. */ private transient CmsImageScaler m_scaler; /** The image source. */ private String m_src; /** * Creates a new image scaling tag instance.<p> */ public CmsJspTagImage() { // initialize the image scaler parameter container m_scaler = new CmsImageScaler(); } /** * Creates the images scaler used by this image tag.<p> * * @param scaler the scaler created from this tags parameters * @param original a scaler that contains the original image dimensions * @param scaleParam optional scaler parameters for cropping * * @return the images scaler used by this image tag */ public static CmsImageScaler getScaler(CmsImageScaler scaler, CmsImageScaler original, String scaleParam) { if (scaleParam != null) { CmsImageScaler cropScaler = null; // use cropped image as a base for scaling cropScaler = new CmsImageScaler(scaleParam); if (scaler.getType() == 5) { // must reset height / width parameters in crop scaler for type 5 cropScaler.setWidth(cropScaler.getCropWidth()); cropScaler.setHeight(cropScaler.getCropHeight()); } scaler = cropScaler.getCropScaler(scaler); } // calculate target scale dimensions (if required) if (((scaler.getHeight() <= 0) || (scaler.getWidth() <= 0)) || ((scaler.getType() == 5) && scaler.isValid() && !scaler.isCropping())) { // read the image properties for the selected resource if (original.isValid()) { scaler = original.getReScaler(scaler); } } return scaler; } /** * Internal action method to create the tag content.<p> * * @param src the image source * @param scaler the image scaleing parameters * @param attributes the additional image HTML attributes * @param partialTag if <code>true</code>, the opening <code><img</code> and closing <code> /></code> is omitted * @param req the current request * * @return the created <img src> tag content * * @throws CmsException in case something goes wrong */ public static String imageTagAction( String src, CmsImageScaler scaler, Map<String, String> attributes, boolean partialTag, ServletRequest req) throws CmsException { CmsFlexController controller = CmsFlexController.getController(req); CmsObject cms = controller.getCmsObject(); // resolve possible relative URI src = CmsLinkManager.getAbsoluteUri(src, controller.getCurrentRequest().getElementUri()); CmsUriSplitter splitSrc = new CmsUriSplitter(src); String scaleParam = null; if (splitSrc.getQuery() != null) { // check if the original URI already has parameters, this is true if original has been cropped String[] scaleStr = CmsRequestUtil.createParameterMap(splitSrc.getQuery()).get(CmsImageScaler.PARAM_SCALE); if (scaleStr != null) { scaleParam = scaleStr[0]; } } CmsResource imageRes = cms.readResource(splitSrc.getPrefix()); CmsImageScaler original = new CmsImageScaler(cms, imageRes); scaler = getScaler(scaler, original, scaleParam); StringBuffer result = new StringBuffer(128); if (!partialTag) { // open tag if not a partial tag result.append("<img"); } // append the image source result.append(" src=\""); String imageLink = cms.getSitePath(imageRes); if (scaler.isValid()) { // now append the scaler parameters imageLink += scaler.toRequestParam(); } result.append(OpenCms.getLinkManager().substituteLink(cms, imageLink)); result.append("\""); if (scaler.isValid()) { // append image width and height result.append(" width=\""); result.append(scaler.getWidth()); result.append("\""); result.append(" height=\""); result.append(scaler.getHeight()); result.append("\""); } if (attributes != null) { // append the HTML attributes for (Map.Entry<String, String> entry : attributes.entrySet()) { String attr = entry.getKey(); String value = entry.getValue(); result.append(" "); result.append(attr); result.append("=\""); result.append(CmsEncoder.escapeXml(value)); result.append("\""); } } if (!partialTag) { // close tag if not a partial tag result.append(" />"); } return result.toString(); } /** * @see org.opencms.jsp.I_CmsJspTagParamParent#addParameter(java.lang.String, java.lang.String) */ public void addParameter(String name, String value) { String key = name.trim().toLowerCase(); switch (SCALER_ATTRS_LIST.indexOf(key)) { case 0: // scaleColor setScaleColor(value); break; case 1: // scaleFilter setScaleFilter(value); break; case 2: // height setHeight(value); break; case 3: // partialTag setPartialTag(value); break; case 4: // scalePosition setScalePosition(value); break; case 5: // scaleQuality setScaleQuality(value); break; case 6: // scaleRendermode setScaleRendermode(value); break; case 7: // src setSrc(value); break; case 8: // scaleType setScaleType(value); break; case 9: // width setWidth(value); break; default: // no a value used by the image scaler, treat as HTML attribute setAttribute(key, value); } } /** * @see javax.servlet.jsp.tagext.Tag#doEndTag() */ @Override public int doEndTag() throws JspException { ServletRequest req = pageContext.getRequest(); // this will always be true if the page is called through OpenCms if (CmsFlexController.isCmsRequest(req)) { try { // create the HTML image tag String imageTag = null; try { imageTag = imageTagAction(m_src, m_scaler, m_attributes, m_partialTag, req); } catch (CmsException e) { // any issue accessing the VFS - just return an empty string // otherwise template layout will get mixed up with nasty exception messages if (LOG.isWarnEnabled()) { LOG.warn(Messages.get().getBundle().key(Messages.ERR_IMAGE_TAG_VFS_ACCESS_1, m_src), e); } } // make sure that no null String is returned pageContext.getOut().print(imageTag == null ? "" : imageTag); } catch (Exception ex) { if (LOG.isErrorEnabled()) { LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "image"), ex); } throw new javax.servlet.jsp.JspException(ex); } } release(); return EVAL_PAGE; } /** * Returns <code>{@link #EVAL_BODY_BUFFERED}</code>.<p> * * @return <code>{@link #EVAL_BODY_BUFFERED}</code> * * @see javax.servlet.jsp.tagext.Tag#doStartTag() */ @Override public int doStartTag() { return EVAL_BODY_BUFFERED; } /** * Returns the value of the HTML "align" attribute.<p> * * @return the value of the HTML "align" attribute */ public String getAlign() { return getAttribute(ATTR_ALIGN); } /** * Returns the value of the HTML "alt" attribute.<p> * * @return the value of the HTML "alt" attribute */ public String getAlt() { return getAttribute(ATTR_ALT); } /** * Returns the value of the HTML "border" attribute.<p> * * @return the value of the HTML "border" attribute */ public String getBorder() { return getAttribute(ATTR_BORDER); } /** * Returns the value of the HTML "class" attribute.<p> * * @return the value of the HTML "class" attribute */ public String getCssclass() { return getAttribute(ATTR_CLASS); } /** * Returns the scaling height for the image.<p> * * @return the scaling height for the image */ public String getHeight() { return String.valueOf(m_scaler.getHeight()); } /** * Returns the value of the HTML "hspace" attribute.<p> * * @return the value of the HTML "hspace" attribute */ public String getHspace() { return getAttribute(ATTR_HSPACE); } /** * Returns the value of the HTML "id" attribute.<p> * * @return the value of the HTML "id" attribute */ @Override public String getId() { return getAttribute(ATTR_ID); } /** * Returns the value of the HTML "longdesc" attribute.<p> * * @return the value of the HTML "longdesc" attribute */ public String getLongdesc() { return getAttribute(ATTR_LONGDESC); } /** * Returns the maximum scaling height for the image, only needed if scale type is 5.<p> * * @return the maximum scaling height for the image */ public String getMaxHeight() { return String.valueOf(m_scaler.getMaxHeight()); } /** * Returns the maximum scaling width for the image, only needed if scale type is 5.<p> * * @return the maximum scaling width for the image */ public String getMaxWidth() { return String.valueOf(m_scaler.getMaxWidth()); } /** * Returns the value of the HTML "name" attribute.<p> * * @return the value of the HTML "name" attribute */ public String getName() { return getAttribute(ATTR_NAME); } /** * Returns the background color used by the image scaler.<p> * * @return the background color used by the image scaler */ public String getScaleColor() { return m_scaler.getColorString(); } /** * Returns the filter list used by the image scaler.<p> * * @return the filter list used by the image scaler */ public String getScaleFilter() { return m_scaler.getFiltersString(); } /** * Returns the position used by the image scaler.<p> * * @return the position used by the image scaler */ public String getScalePosition() { return String.valueOf(m_scaler.getPosition()); } /** * Returns the quality used by the image scaler.<p> * * @return the quality used by the image scaler */ public String getScaleQuality() { return String.valueOf(m_scaler.getQuality()); } /** * Returns the render mode used by the image scaler.<p> * * @return the render mode used by the image scaler */ public String getScaleRendermode() { return String.valueOf(m_scaler.getRenderMode()); } /** * Returns the scaling type for the image.<p> * * @return the scaling type for the image */ public String getScaleType() { return String.valueOf(m_scaler.getType()); } /** * Returns the source of the image to scale, * which will have the OpenCms webapp / servlet prefix added.<p> * * @return the source of the image to scale */ public String getSrc() { return m_src; } /** * Returns the value of the HTML "style" attribute.<p> * * @return the value of the HTML "style" attribute */ public String getStyle() { return getAttribute(ATTR_STYLE); } /** * Returns the value of the HTML "title" attribute.<p> * * @return the value of the HTML "title" attribute */ public String getTitle() { return getAttribute(ATTR_TITLE); } /** * Returns the value of the HTML "usemap" attribute.<p> * * @return the value of the HTML "usemap" attribute */ public String getUsemap() { return getAttribute(ATTR_USEMAP); } /** * Returns the value of the HTML "vspace" attribute.<p> * * @return the value of the HTML "vspace" attribute */ public String getVspace() { return getAttribute(ATTR_VSPACE); } /** * Returns the scaling width for the image.<p> * * @return the scaling width for the image */ public String getWidth() { return String.valueOf(m_scaler.getWidth()); } /** * Returns <code>"true"</code> if the HTML tag should only be created as partial tag.<p> * * @return <code>"true"</code> if the HTML tag should only be created as partial tag */ public String isPartialTag() { return String.valueOf(m_partialTag); } /** * @see javax.servlet.jsp.tagext.Tag#release() */ @Override public void release() { m_attributes = null; m_scaler = new CmsImageScaler(); m_partialTag = false; m_src = null; super.release(); } /** * Sets the value of the HTML "align" attribute.<p> * * @param value the value of the HTML "align" attribute to set */ public void setAlign(String value) { setAttribute(ATTR_ALIGN, value); } /** * Sets the value of the HTML "alt" attribute.<p> * * @param value the value of the HTML "alt" attribute to set */ public void setAlt(String value) { setAttribute(ATTR_ALT, value, true); } /** * Sets the value of the HTML "border" attribute.<p> * * @param value the value of the HTML "border" attribute to set */ public void setBorder(String value) { setAttribute(ATTR_BORDER, value); } /** * Sets the value of the HTML "class" attribute.<p> * * @param value the value of the HTML "class" attribute to set */ public void setCssclass(String value) { setAttribute(ATTR_CLASS, value); } /** * Sets the scaling height for the image.<p> * * If no valid integer is given, then "0" is used as value.<p> * * @param value the scaling height for the image to set */ public void setHeight(String value) { m_scaler.setHeight(CmsStringUtil.getIntValueRounded(value, 0, SCALE_ATTR_HEIGHT)); } /** * Sets the value of the HTML "hspace" attribute.<p> * * @param value the value of the HTML "hspace" attribute to set */ public void setHspace(String value) { setAttribute(ATTR_HSPACE, value); } /** * Sets the value of the HTML "id" attribute.<p> * * @param value the value of the HTML "id" attribute to set */ @Override public void setId(String value) { setAttribute(ATTR_ID, value); } /** * Sets the value of the HTML "longdesc" attribute.<p> * * @param value the value of the HTML "longdesc" attribute to set */ public void setLongdesc(String value) { setAttribute(ATTR_LONGDESC, value); } /** * Sets the maximum scaling height for the image, only needed if scale type is 5.<p> * * If no valid integer is given, then the value of {@link #getHeight()} is used as value.<p> * * @param value the maximum scaling height for the image to set */ public void setMaxHeight(String value) { m_scaler.setMaxHeight(CmsStringUtil.getIntValueRounded(value, -1, SCALE_ATTR_MAXHEIGHT)); } /** * Sets the maximum scaling width for the image, only needed if scale type is 5.<p> * * If no valid integer is given, then the value of {@link #getWidth()} is used as value.<p> * * @param value the maximum scaling width for the image to set */ public void setMaxWidth(String value) { m_scaler.setMaxWidth(CmsStringUtil.getIntValueRounded(value, -1, SCALE_ATTR_MAXWIDTH)); } /** * Sets the value of the HTML "name" attribute.<p> * * @param value the value of the HTML "name" attribute to set */ public void setName(String value) { setAttribute(ATTR_NAME, value); } /** * Controls if the created HTML image tag is a full or partial tag.<p> * * @param partialTag the value to set */ public void setPartialTag(String partialTag) { m_partialTag = Boolean.valueOf(partialTag).booleanValue(); } /** * Sets the background color used by the image scaler.<p> * * @param value the background color to set */ public void setScaleColor(String value) { m_scaler.setColor(value); } /** * Sets the filter(s) used by the image scaler.<p> * * @param value the filter(s) to set */ public void setScaleFilter(String value) { m_scaler.setFilters(value); } /** * Sets the position used by the image scaler.<p> * * @param value the position to set */ public void setScalePosition(String value) { m_scaler.setPosition(CmsStringUtil.getIntValue(value, 0, SCALE_ATTR_POSITION)); } /** * Sets the quality used by the image scaler.<p> * * @param value the quality to set */ public void setScaleQuality(String value) { m_scaler.setQuality(CmsStringUtil.getIntValue(value, 0, SCALE_ATTR_QUALITY)); } /** * Sets the render mode used by the image scaler.<p> * * @param value the render mode to set */ public void setScaleRendermode(String value) { m_scaler.setRenderMode(CmsStringUtil.getIntValue(value, 0, SCALE_ATTR_RENDERMODE)); } /** * Sets the scaling type for the image.<p> * * If no valid integer is given, then "0" is used as value.<p> * * @param value the scaling type for the image to set */ public void setScaleType(String value) { m_scaler.setType(CmsStringUtil.getIntValue(value, 0, SCALE_ATTR_TYPE)); } /** * Sets the source of the image.<p> * * The source must be an absolute path in the current users OpenCms site, without any * webapp or servlet prefix.<p> * * @param value the image source to set */ public void setSrc(String value) { m_src = value; } /** * Sets the value of the HTML "style" attribute.<p> * * @param value the value of the HTML "style" attribute to set */ public void setStyle(String value) { setAttribute(ATTR_STYLE, value); } /** * Sets the value of the HTML "title" attribute.<p> * * @param value the value of the HTML "title" attribute to set */ public void setTitle(String value) { setAttribute(ATTR_TITLE, value); } /** * Sets the value of the HTML "usemap" attribute.<p> * * @param value the value of the HTML "usemap" attribute to set */ public void setUsemap(String value) { setAttribute(ATTR_USEMAP, value); } /** * Sets the value of the HTML "vspace" attribute.<p> * * @param value the value of the HTML "vspace" attribute to set */ public void setVspace(String value) { setAttribute(ATTR_VSPACE, value); } /** * Sets the scaling width for the image.<p> * * If no valid integer is given, then "0" is used as value.<p> * * @param value the scaling width for the image to set */ public void setWidth(String value) { m_scaler.setWidth(CmsStringUtil.getIntValueRounded(value, 0, SCALE_ATTR_WIDTH)); } /** * Returns the given keys attribute value from the attribute map.<p> * * @param key the attribute to read from the map * @return the given keys attribute value from the attribute map */ private String getAttribute(String key) { if (m_attributes != null) { return m_attributes.get(key); } return null; } /** * Sets the given key with the given value in the attribute map.<p> * * @param key the key to set * @param value the value to set */ private void setAttribute(String key, String value) { setAttribute(key, value, false); } /** * Sets the given key with the given value in the attribute map.<p> * * @param key the key to set * @param value the value to set * @param allowEmptyValue flag to determine if an empty value (not <code>null</code>!) should be set */ private void setAttribute(String key, String value, boolean allowEmptyValue) { if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(value) || (allowEmptyValue && (value != null))) { if (m_attributes == null) { m_attributes = new HashMap<String, String>(); } m_attributes.put(key, value); } } }