001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.galleries.client.preview;
029
030import org.opencms.util.CmsStringUtil;
031
032/**
033 * Scale parameter data bean.<p>
034 *
035 * @since 8.0.0
036 */
037public class CmsCroppingParamBean {
038
039    /** Format parameter name. */
040    private static final String SCALE_FORMAT_NAME_PARAM = "format";
041
042    /** The scale parameter colon. */
043    private static final String SCALE_PARAM_COLON = ":";
044
045    /** Scale parameter name. */
046    private static final String SCALE_PARAM_CROP_HEIGHT = "ch";
047
048    /** Scale parameter name. */
049    private static final String SCALE_PARAM_CROP_WIDTH = "cw";
050
051    /** Scale parameter name. */
052    private static final String SCALE_PARAM_CROP_X = "cx";
053
054    /** Scale parameter name. */
055    private static final String SCALE_PARAM_CROP_Y = "cy";
056
057    /** The scale parameter delimiter. */
058    private static final String SCALE_PARAM_DELIMITER = ",";
059
060    /** The scale parameter equal. */
061    private static final String SCALE_PARAM_EQ = "=";
062
063    /** Scale parameter name. */
064    private static final String SCALE_PARAM_NAME = "__scale";
065
066    /** Scale parameter name. */
067    private static final String SCALE_PARAM_TARGETHEIGHT = "h";
068
069    /** Scale parameter name. */
070    private static final String SCALE_PARAM_TARGETWIDTH = "w";
071
072    /** The cropping height parameter. */
073    private int m_cropHeight = I_CmsFormatRestriction.DIMENSION_NOT_SET;
074
075    /** The cropping width parameter. */
076    private int m_cropWidth = I_CmsFormatRestriction.DIMENSION_NOT_SET;
077
078    /** The cropping X parameter. */
079    private int m_cropX = I_CmsFormatRestriction.DIMENSION_NOT_SET;
080
081    /** The cropping Y parameter. */
082    private int m_cropY = I_CmsFormatRestriction.DIMENSION_NOT_SET;
083
084    /** The used format name. */
085    private String m_formatName;
086
087    /** The original image height. */
088    private int m_orgHeight = I_CmsFormatRestriction.DIMENSION_NOT_SET;
089
090    /** The original image width. */
091    private int m_orgWidth = I_CmsFormatRestriction.DIMENSION_NOT_SET;
092
093    /** The target height. */
094    private int m_targetHeight = I_CmsFormatRestriction.DIMENSION_NOT_SET;
095
096    /** The target width. */
097    private int m_targetWidth = I_CmsFormatRestriction.DIMENSION_NOT_SET;
098
099    /**
100     * Constructor.<p>
101     */
102    public CmsCroppingParamBean() {
103
104        // nothing to do here
105    }
106
107    /**
108     * Copy constructor.<p>
109     *
110     * @param copy the copy values to use
111     */
112    public CmsCroppingParamBean(CmsCroppingParamBean copy) {
113
114        this(copy.getOrgHeight(), copy.getOrgWidth());
115        m_cropHeight = copy.getCropHeight();
116        m_cropWidth = copy.getCropWidth();
117        m_cropX = copy.getCropX();
118        m_cropY = copy.getCropY();
119        m_targetHeight = copy.getTargetHeight();
120        m_targetWidth = copy.getTargetWidth();
121    }
122
123    /**
124     * Constructor.<p>
125     *
126     * @param orgHeight the original image height
127     * @param orgWidth the original image width
128     */
129    public CmsCroppingParamBean(int orgHeight, int orgWidth) {
130
131        m_orgHeight = orgHeight;
132        m_orgWidth = orgWidth;
133    }
134
135    /**
136     * Parses an image scale parameter and returns the parsed data.<p>
137     *
138     * @param selectedPath the image path including the scale parameter
139     *
140     * @return the cropping data
141     */
142    public static CmsCroppingParamBean parseImagePath(String selectedPath) {
143
144        CmsCroppingParamBean result = null;
145        int pos = selectedPath.indexOf(SCALE_PARAM_NAME + SCALE_PARAM_EQ);
146        if (pos > -1) {
147            // removing string part before the scaling parameter
148            String param = selectedPath.substring(pos + SCALE_PARAM_NAME.length() + SCALE_PARAM_EQ.length());
149
150            // removing string part after the scaling parameter
151            pos = param.indexOf("&");
152            if (pos > -1) {
153                param = param.substring(0, pos);
154            }
155            result = parseScaleParam(param);
156        } else {
157            result = new CmsCroppingParamBean();
158        }
159        // look up format name if available
160        pos = selectedPath.indexOf(SCALE_FORMAT_NAME_PARAM + SCALE_PARAM_EQ);
161        if (pos > -1) {
162            String param = selectedPath.substring(pos + SCALE_FORMAT_NAME_PARAM.length() + SCALE_PARAM_EQ.length());
163
164            // removing string part after the scaling parameter
165            pos = param.indexOf("&");
166            if (pos > -1) {
167                param = param.substring(0, pos);
168            }
169            result.setFormatName(param);
170        }
171        return result;
172    }
173
174    /**
175     * Parses an image scale parameter and returns the parsed data.<p>
176     *
177     * @param param the image path including the scale parameter
178     *
179     * @return the cropping data
180     */
181    public static CmsCroppingParamBean parseScaleParam(String param) {
182
183        CmsCroppingParamBean result = new CmsCroppingParamBean();
184        if (CmsStringUtil.isEmptyOrWhitespaceOnly(param)) {
185            return result;
186        }
187        String[] parameters = param.split(SCALE_PARAM_DELIMITER);
188        for (int i = 0; i < parameters.length; i++) {
189            String scaleParam = parameters[i].trim();
190            if (scaleParam.startsWith(SCALE_PARAM_TARGETHEIGHT + SCALE_PARAM_COLON)) {
191                result.setTargetHeight(parseValue(SCALE_PARAM_TARGETHEIGHT, scaleParam));
192                continue;
193            }
194            if (scaleParam.startsWith(SCALE_PARAM_TARGETWIDTH + SCALE_PARAM_COLON)) {
195                result.setTargetWidth(parseValue(SCALE_PARAM_TARGETWIDTH, scaleParam));
196                continue;
197            }
198            if (scaleParam.startsWith(SCALE_PARAM_CROP_X + SCALE_PARAM_COLON)) {
199                result.setCropX(parseValue(SCALE_PARAM_CROP_X, scaleParam));
200                continue;
201            }
202            if (scaleParam.startsWith(SCALE_PARAM_CROP_Y + SCALE_PARAM_COLON)) {
203                result.setCropY(parseValue(SCALE_PARAM_CROP_Y, scaleParam));
204                continue;
205            }
206            if (scaleParam.startsWith(SCALE_PARAM_CROP_HEIGHT + SCALE_PARAM_COLON)) {
207                result.setCropHeight(parseValue(SCALE_PARAM_CROP_HEIGHT, scaleParam));
208                continue;
209            }
210            if (scaleParam.startsWith(SCALE_PARAM_CROP_WIDTH + SCALE_PARAM_COLON)) {
211                result.setCropWidth(parseValue(SCALE_PARAM_CROP_WIDTH, scaleParam));
212                continue;
213            }
214        }
215        return result;
216    }
217
218    /**
219     * Parses a single scale value. Returning <code>-1</code> -->
220     * {@link I_CmsFormatRestriction#DIMENSION_NOT_SET} invalid parameters.<p>
221     *
222     * @param paramName the parameter name
223     * @param param the parameter
224     *
225     * @return the value
226     */
227    private static native int parseValue(String paramName, String param)/*-{
228        param = param.substr(paramName.length + 1);
229        var result = parseInt(param);
230        if (isNaN(result)) {
231            return I_CmsFormatRestriction.DIMENSION_NOT_SET;
232        }
233        return result;
234    }-*/;
235
236    /**
237     * Converts this bean to a scaling parameter string.
238     *
239     * @param highRes true if we want the high-resolution version
240     * @return the scaling parameter string
241     */
242    public String convertToScalingParam(boolean highRes) {
243
244        String result = getScaleParam(highRes);
245        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(result)) {
246            result = SCALE_PARAM_NAME + SCALE_PARAM_EQ + result;
247        }
248        return result;
249    }
250
251    /**
252     * Returns the cropping height parameter.<p>
253     *
254     * @return the cropping height parameter
255     */
256    public int getCropHeight() {
257
258        return m_cropHeight;
259    }
260
261    /**
262     * Returns the cropping width parameter.<p>
263     *
264     * @return the cropping width parameter
265     */
266    public int getCropWidth() {
267
268        return m_cropWidth;
269    }
270
271    /**
272     * Returns the cropping X parameter.<p>
273     *
274     * @return the cropping X parameter
275     */
276    public int getCropX() {
277
278        return m_cropX;
279    }
280
281    /**
282     * Returns the cropping Y parameter.<p>
283     *
284     * @return the cropping Y parameter
285     */
286    public int getCropY() {
287
288        return m_cropY;
289    }
290
291    /**
292     * Returns the used format name.<p>
293     *
294     * @return the used format name
295     */
296    public String getFormatName() {
297
298        return m_formatName;
299    }
300
301    /**
302     * Returns the original image height.<p>
303     *
304     * @return the original image height
305     */
306    public int getOrgHeight() {
307
308        return m_orgHeight;
309    }
310
311    /**
312     * Returns the original image width.<p>
313     *
314     * @return the original image width
315     */
316    public int getOrgWidth() {
317
318        return m_orgWidth;
319    }
320
321    /**
322     * Returns the resulting image ratio.<p>
323     *
324     * @return the image ratio
325     */
326    public double getRatio() {
327
328        double ratio = 1;
329        if ((getTargetWidth() == -1) || (getTargetHeight() == -1)) {
330            ratio = (double)getOrgWidth() / getOrgHeight();
331        } else {
332            ratio = (double)getTargetWidth() / getTargetHeight();
333        }
334        return ratio;
335    }
336
337    /**
338     * Returns a cropping bean with a restricted maximum target size.<p>
339     *
340     * @param maxHeight the max height
341     * @param maxWidth the max width
342     *
343     * @return the cropping bean
344     */
345    public CmsCroppingParamBean getRestrictedSizeParam(int maxHeight, int maxWidth) {
346
347        CmsCroppingParamBean result = new CmsCroppingParamBean(this);
348        if ((getTargetHeight() <= maxHeight) && (getTargetWidth() <= maxWidth)) {
349            if ((getTargetHeight() == I_CmsFormatRestriction.DIMENSION_NOT_SET) && (getOrgHeight() > maxHeight)) {
350                result.setTargetHeight(maxHeight);
351            }
352            if ((getTargetWidth() == I_CmsFormatRestriction.DIMENSION_NOT_SET) && (getOrgWidth() > maxWidth)) {
353                result.setTargetWidth(maxWidth);
354            }
355            return result;
356        }
357
358        if (((1.00 * getTargetHeight()) / getTargetWidth()) > ((1.00 * maxHeight) / maxWidth)) {
359            result.setTargetHeight(maxHeight);
360            double width = (1.00 * getTargetWidth() * maxHeight) / getTargetHeight();
361            result.setTargetWidth((int)Math.floor(width));
362            return result;
363        }
364        double height = (1.00 * getTargetHeight() * maxWidth) / getTargetWidth();
365        result.setTargetHeight((int)Math.floor(height));
366        result.setTargetWidth(maxWidth);
367        return result;
368    }
369
370    /**
371     * Returns the scale parameter to this bean for a restricted maximum target size.<p>
372     *
373     * TODO: This does not work correctly if there isn't any cropping/scaling defined.
374     *
375     * @param maxHeight the max height
376     * @param maxWidth the max width
377     *
378     * @return the scale parameter
379     */
380    public String getRestrictedSizeScaleParam(int maxHeight, int maxWidth) {
381
382        String result = toString();
383        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(result)) {
384
385            return getRestrictedSizeParam(maxHeight, maxWidth).toString();
386        }
387        if ((getOrgWidth() < maxWidth) && (getOrgHeight() < maxHeight)) {
388            return "";
389        }
390        CmsCroppingParamBean restricted = new CmsCroppingParamBean();
391        restricted.setTargetHeight(maxHeight);
392        restricted.setTargetWidth(maxWidth);
393        return restricted.toString();
394    }
395
396    /**
397     * Returns the resulting height of the cropped image.<p>
398     *
399     * @return the height
400     */
401    public int getResultingHeight() {
402
403        int height = getResultingTargetHeight();
404        if (height == -1) {
405            if (isCropped()) {
406                height = m_cropHeight;
407            } else {
408                height = m_orgHeight;
409            }
410        }
411        return height;
412    }
413
414    /**
415     * Returns the resulting width of the cropped image.<p>
416     *
417     * @return the width
418     */
419    public int getResultingWidth() {
420
421        int width = getResultingTargetWidth();
422        if (width == -1) {
423            if (isCropped()) {
424                width = m_cropWidth;
425            } else {
426                width = m_orgWidth;
427            }
428        }
429        return width;
430    }
431
432    /**
433     * Returns the scale parameter.<p>
434     *
435     * @param highres true if we want the high resolution version
436     *
437     * @return the scale parameter
438     */
439    public String getScaleParam(boolean highres) {
440
441        int m = highres ? 2 : 1;
442
443        if (!isScaled() && !isCropped()) {
444            // the image is not cropped nor scaled, return an empty parameter
445            return "";
446        }
447        StringBuffer result = new StringBuffer();
448        if ((m_targetHeight > -1) || (m_targetWidth > -1)) {
449            result.append(SCALE_PARAM_TARGETHEIGHT).append(SCALE_PARAM_COLON).append(
450                m * getResultingTargetHeight()).append(SCALE_PARAM_DELIMITER);
451            result.append(SCALE_PARAM_TARGETWIDTH).append(SCALE_PARAM_COLON).append(
452                m * getResultingTargetWidth()).append(SCALE_PARAM_DELIMITER);
453        }
454        if (m_cropX > -1) {
455            result.append(SCALE_PARAM_CROP_X).append(SCALE_PARAM_COLON).append(m_cropX).append(SCALE_PARAM_DELIMITER);
456        }
457        if (m_cropY > -1) {
458            result.append(SCALE_PARAM_CROP_Y).append(SCALE_PARAM_COLON).append(m_cropY).append(SCALE_PARAM_DELIMITER);
459        }
460        if (m_cropHeight > -1) {
461            result.append(SCALE_PARAM_CROP_HEIGHT).append(SCALE_PARAM_COLON).append(m_cropHeight).append(
462                SCALE_PARAM_DELIMITER);
463        }
464        if (m_cropWidth > -1) {
465            result.append(SCALE_PARAM_CROP_WIDTH).append(SCALE_PARAM_COLON).append(m_cropWidth).append(
466                SCALE_PARAM_DELIMITER);
467        }
468        if (result.length() > 0) {
469            result.deleteCharAt(result.length() - 1);
470        }
471        return result.toString();
472    }
473
474    /**
475     * Returns the target height.<p>
476     *
477     * @return the target height
478     */
479    public int getTargetHeight() {
480
481        return m_targetHeight;
482    }
483
484    /**
485     * Returns the target width.<p>
486     *
487     * @return the target width
488     */
489    public int getTargetWidth() {
490
491        return m_targetWidth;
492    }
493
494    /**
495     * Returns if contained parameters indicate a cropped image.<p>
496     *
497     * @return <code>true</code> if contained parameters indicate a cropped image
498     */
499    public boolean isCropped() {
500
501        return m_cropX > I_CmsFormatRestriction.DIMENSION_NOT_SET;
502    }
503
504    /**
505     * Returns if the given cropping parameters would scale the image.<p>
506     *
507     * @return <code>true</code> if the image is scaled
508     */
509    public boolean isScaled() {
510
511        return !(((m_targetHeight == m_orgHeight) || (m_targetHeight == -1))
512            && ((m_targetWidth == m_orgWidth) || (m_targetWidth == -1)));
513    }
514
515    /**
516     * Resets the cropping parameters to no cropping.<p>
517     */
518    public void reset() {
519
520        m_cropHeight = I_CmsFormatRestriction.DIMENSION_NOT_SET;
521        m_cropWidth = I_CmsFormatRestriction.DIMENSION_NOT_SET;
522        m_cropX = I_CmsFormatRestriction.DIMENSION_NOT_SET;
523        m_cropY = I_CmsFormatRestriction.DIMENSION_NOT_SET;
524        m_targetHeight = I_CmsFormatRestriction.DIMENSION_NOT_SET;
525        m_targetWidth = I_CmsFormatRestriction.DIMENSION_NOT_SET;
526    }
527
528    /**
529     * Sets the cropping height parameter.<p>
530     *
531     * @param cropHeight the cropping height parameter to set
532     */
533    public void setCropHeight(int cropHeight) {
534
535        m_cropHeight = cropHeight;
536    }
537
538    /**
539     * Sets the cropping width parameter.<p>
540     *
541     * @param cropWidth the cropping width parameter to set
542     */
543    public void setCropWidth(int cropWidth) {
544
545        m_cropWidth = cropWidth;
546    }
547
548    /**
549     * Sets the cropping X parameter.<p>
550     *
551     * @param cropX the cropping X parameter to set
552     */
553    public void setCropX(int cropX) {
554
555        m_cropX = cropX;
556    }
557
558    /**
559     * Sets the cropping Y parameter.<p>
560     *
561     * @param cropY the cropping Y parameter to set
562     */
563    public void setCropY(int cropY) {
564
565        m_cropY = cropY;
566    }
567
568    /**
569     * Sets the used format name.<p>
570     *
571     * @param formatName the used format name to set
572     */
573    public void setFormatName(String formatName) {
574
575        m_formatName = formatName;
576    }
577
578    /**
579     * Sets the original image height.<p>
580     *
581     * @param orgHeight the original image height to set
582     */
583    public void setOrgHeight(int orgHeight) {
584
585        m_orgHeight = orgHeight;
586    }
587
588    /**
589     * Sets the original image width.<p>
590     *
591     * @param orgWidth the original image width to set
592     */
593    public void setOrgWidth(int orgWidth) {
594
595        m_orgWidth = orgWidth;
596    }
597
598    /**
599     * Sets the target height.<p>
600     *
601     * @param targetHeight the target height to set
602     */
603    public void setTargetHeight(int targetHeight) {
604
605        m_targetHeight = targetHeight;
606    }
607
608    /**
609     * Sets the target width.<p>
610     *
611     * @param targetWidth the target width to set
612     */
613    public void setTargetWidth(int targetWidth) {
614
615        m_targetWidth = targetWidth;
616    }
617
618    /**
619     * @see java.lang.Object#toString()
620     */
621    @Override
622    public String toString() {
623
624        boolean highRes = false;
625        return convertToScalingParam(highRes);
626    }
627
628    /**
629     * Returns the resulting target height if set, otherwise '-1'.<p>
630     *
631     * @return the height
632     */
633    private int getResultingTargetHeight() {
634
635        int height = -1;
636        if ((m_targetHeight > -1) || (m_targetWidth > -1)) {
637            if (m_targetHeight > -1) {
638                height = m_targetHeight;
639            } else {
640                height = (int)Math.floor(((1.00 * m_orgHeight) / m_orgWidth) * m_targetWidth);
641            }
642        }
643        return height;
644    }
645
646    /**
647     * Returns the resulting target width if set, otherwise '-1'.<p>
648     *
649     * @return the width
650     */
651    private int getResultingTargetWidth() {
652
653        int width = -1;
654        if ((m_targetHeight > -1) || (m_targetWidth > -1)) {
655            if (m_targetWidth > -1) {
656                width = m_targetWidth;
657            } else {
658                width = (int)Math.floor(((1.00 * m_orgWidth) / m_orgHeight) * m_targetHeight);
659            }
660        }
661        return width;
662    }
663
664}