001
002package org.opencms.jsp;
003
004import org.opencms.file.CmsObject;
005import org.opencms.flex.CmsFlexController;
006import org.opencms.jsp.util.CmsJspImageBean;
007import org.opencms.loader.CmsImageScaler;
008import org.opencms.main.CmsException;
009import org.opencms.main.CmsLog;
010import org.opencms.staticexport.CmsLinkManager;
011
012import java.util.ArrayList;
013import java.util.Collections;
014import java.util.List;
015
016import javax.servlet.ServletRequest;
017import javax.servlet.jsp.JspException;
018
019import org.apache.commons.lang3.StringUtils;
020import org.apache.commons.logging.Log;
021
022/**
023 * This tag allows using the OpenCms native image scaling mechanism within JSP.<p>
024 *
025 * <em>No output is generated by this tag!</em>
026 * Instead the tag generates a {@link org.opencms.jsp.util.CmsJspImageBean}.
027 * This can be used to further process the selected image
028 * with the provided image scaling parameters.<p>
029 *
030 * The following image formats are supported: BMP, GIF, JPEG, PNG, PNM, TIFF.<p>
031 *
032 * <em>
033 * Note: Picture scaling is by default only enabled for target size with width and height
034 * &lt;=1500. The size can be changed in the image scaler configuration in the file
035 * <code>opencms-vfs.xml</code> in the body of the tag <code>&lt;loader&gt;</code>. Also other
036 * options for the image scaler are set there.
037 * </em>
038 * <p>
039 * This tag is an alternative to the OpenCms standard tag cms:img, providing additional flexibility.
040 * This way you can use scaled images for:
041 * <ul>
042 *   <li>The standard HTML &lt;img&gt;-Tag.</li>
043 *   <li>
044 *     The HTML 5 &lt;picture&gt;-Tag with multiple sources (hi-DPI variants for retina displays)
045 *     for responsive design.
046 *   </li>
047 *   <li>Further processing a scaled image anyway you want on your JSP.</li>
048 * </ul>
049 * </em>
050 *
051 * <p>
052 * Example for a simple JSP that uses this tag to obtain information about an image:
053 * <code>
054 * &lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;<br>
055 * &lt;%@ taglib prefix=&quot;cms&quot; uri=&quot;http://www.opencms.org/taglib/cms&quot;%&gt;<br>
056 *<br>
057 * &lt;cms:scaleImage var=&quot;imgBean&quot; src=&quot;/.galleries/samples/09.jpg?__scale=h:385,w:961,cx:42,cy:32,ch:385,cw:961&quot; /&gt;<br>
058 * srcUrl: &lt;c:out value=&quot;${imgBean.srcUrl}&quot; /&gt;&lt;br&gt;<br>
059 * vfsUri: &lt;c:out value=&quot;${imgBean.vfsUri}&quot; /&gt;&lt;br&gt;<br>
060 * scalerParams: &lt;c:out value=&quot;${imgBean.scaler.requestParam}&quot; /&gt;&lt;br&gt;<br>
061 * Width: &lt;c:out value=&quot;${imgBean.width}&quot; /&gt;&lt;br&gt;<br>
062 * Height: &lt;c:out value=&quot;${imgBean.height}&quot; /&gt;&lt;br&gt;<br>
063 * scaledWidth: &lt;c:out value=&quot;${imgBean.scaler.width}&quot; /&gt;&lt;br&gt;<br>
064 * scaledHeight: &lt;c:out value=&quot;${imgBean.scaler.height}&quot; /&gt;&lt;br&gt;<br>
065 * isScaled: &lt;c:out value=&quot;${imgBean.scaled}&quot; /&gt;&lt;br&gt;<br>
066 * </code>
067 */
068public class CmsJspTagScaleImage extends CmsJspImageScalerTagSupport {
069
070    /** The log object for this class. */
071    private static final Log LOG = CmsLog.getLog(CmsJspTagScaleImage.class);
072
073    /** Serial version UID required for safe serialization. */
074    private static final long serialVersionUID = -6639978110802734737L;
075
076    /** List of hi-DPI variant sizes to produce, e.g. 1.3x, 1.5x, 2x, 3x */
077    private List<String> m_hiDpiVariantList;
078
079    /** Name of the request attribute used to store the created image bean. */
080    private String m_var;
081
082    /**
083     * Creates a new image scaling tag instance.<p>
084     */
085    public CmsJspTagScaleImage() {
086        super();
087    }
088
089    /**
090     * Internal action method to create the scaled image bean.<p>
091     *
092     * @param cms the cms context
093     * @param imageUri the image URI
094     * @param targetScaler the target image scaler
095     * @param hiDpiVariantList  optional list of hi-DPI variant sizes to produce, e.g. 1.3x, 1.5x, 2x, 3x
096     *
097     * @return the created ScaledImageBean bean
098     *
099     * @throws CmsException in case something goes wrong
100     */
101    public static CmsJspImageBean imageTagAction(
102        CmsObject cms,
103        String imageUri,
104        CmsImageScaler targetScaler,
105        List<String> hiDpiVariantList)
106    throws CmsException {
107
108        CmsJspImageBean image = new CmsJspImageBean(cms, imageUri, targetScaler);
109
110        // now handle (preset) hi-DPI variants
111        if ((hiDpiVariantList != null) && (hiDpiVariantList.size() > 0)) {
112            for (String hiDpiVariant : hiDpiVariantList) {
113
114                CmsJspImageBean hiDpiVersion = image.createHiDpiVariation(hiDpiVariant);
115
116                if (hiDpiVersion != null) {
117                    image.addHiDpiImage(hiDpiVariant, hiDpiVersion);
118                }
119            }
120        }
121        return image;
122    }
123
124    /**
125     * Does some cleanup before returning EVAL_PAGE
126     *
127     * @see javax.servlet.jsp.tagext.Tag#doEndTag()
128     */
129    @SuppressWarnings("unused")
130    @Override
131    public int doEndTag() throws JspException {
132
133        release();
134        return EVAL_PAGE;
135    }
136
137    /**
138     * Handles the Start tag, checks some parameters, uses the CmsImageScaler to create a scaled
139     * version of the image (and hi-DPI variants if necessary), stores all information in a
140     * image bean and stores it as a request attribute (the name for this attribute is given
141     * with the tag attribute "var").
142     *
143     * @return EVAL_BODY_INCLUDE or SKIP_BODY in case of an unexpected Exception (please consult
144     * the OpenCms log file if that happens)
145     */
146    @Override
147    public int doStartTag() {
148
149        ServletRequest req = pageContext.getRequest();
150
151        // this will always be true if the page is called through OpenCms
152        if (CmsFlexController.isCmsRequest(req)) {
153
154            try {
155                CmsJspImageBean scaledImage = null;
156                try {
157                    CmsFlexController controller = CmsFlexController.getController(req);
158                    CmsObject cms = controller.getCmsObject();
159                    String src = CmsLinkManager.getAbsoluteUri(m_src, controller.getCurrentRequest().getElementUri());
160                    scaledImage = imageTagAction(cms, src, m_scaler, m_hiDpiVariantList);
161                } catch (CmsException e) {
162                    // any issue accessing the VFS - just return SKIP_BODY
163                    // otherwise template layout will get mixed up with nasty exception messages
164                    if (LOG.isWarnEnabled()) {
165                        LOG.warn(Messages.get().getBundle().key(Messages.ERR_IMAGE_TAG_VFS_ACCESS_1, m_src), e);
166                    }
167                }
168                pageContext.getRequest().setAttribute(m_var, scaledImage);
169            } catch (Exception ex) {
170                if (LOG.isErrorEnabled()) {
171                    LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "scaleImage"), ex);
172                }
173                return SKIP_BODY;
174            }
175        }
176        return EVAL_BODY_INCLUDE;
177    }
178
179    /**
180     * Does some cleanup before the tag is released to the tag pool
181     *
182     * @see javax.servlet.jsp.tagext.Tag#release()
183     */
184    @Override
185    public void release() {
186
187        m_hiDpiVariantList = null;
188        m_var = null;
189        super.release();
190    }
191
192    /**
193     * Sets the String containing a comma separated list of hi-DPI variants to produce line "1.3x,1.5x,2x,3x".<p>
194     *
195     * Currently in most cases "2x" should suffice to generate an additiona image for retina screens.
196     *
197     * Please note that since 11.0 the variants are created by lazy initialization, so there is usually no
198     * need to use this.<p>
199     *
200     * @param value comma separated list of hi-DPI variants to produce, e.g. "1.3x,1.5x,2x,3x"
201     */
202    public void setHiDpiVariants(String value) {
203
204        m_hiDpiVariantList = new ArrayList<>(4);
205        String[] multipliers = StringUtils.split(value, ',');
206        Collections.addAll(m_hiDpiVariantList, multipliers);
207    }
208
209    /**
210     * Sets the name of the variable used for storing the resulting bean.
211     *
212     * @param value name of the resulting CmsJspScaledImage bean
213     */
214    public void setVar(String value) {
215
216        m_var = value;
217    }
218}