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     * Returns the cropping height parameter.<p>
238     *
239     * @return the cropping height parameter
240     */
241    public int getCropHeight() {
242
243        return m_cropHeight;
244    }
245
246    /**
247     * Returns the cropping width parameter.<p>
248     *
249     * @return the cropping width parameter
250     */
251    public int getCropWidth() {
252
253        return m_cropWidth;
254    }
255
256    /**
257     * Returns the cropping X parameter.<p>
258     *
259     * @return the cropping X parameter
260     */
261    public int getCropX() {
262
263        return m_cropX;
264    }
265
266    /**
267     * Returns the cropping Y parameter.<p>
268     *
269     * @return the cropping Y parameter
270     */
271    public int getCropY() {
272
273        return m_cropY;
274    }
275
276    /**
277     * Returns the used format name.<p>
278     *
279     * @return the used format name
280     */
281    public String getFormatName() {
282
283        return m_formatName;
284    }
285
286    /**
287     * Returns the original image height.<p>
288     *
289     * @return the original image height
290     */
291    public int getOrgHeight() {
292
293        return m_orgHeight;
294    }
295
296    /**
297     * Returns the original image width.<p>
298     *
299     * @return the original image width
300     */
301    public int getOrgWidth() {
302
303        return m_orgWidth;
304    }
305
306    /**
307     * Returns the resulting image ratio.<p>
308     *
309     * @return the image ratio
310     */
311    public double getRatio() {
312
313        double ratio = 1;
314        if ((getTargetWidth() == -1) || (getTargetHeight() == -1)) {
315            ratio = (double)getOrgWidth() / getOrgHeight();
316        } else {
317            ratio = (double)getTargetWidth() / getTargetHeight();
318        }
319        return ratio;
320    }
321
322    /**
323     * Returns a cropping bean with a restricted maximum target size.<p>
324     *
325     * @param maxHeight the max height
326     * @param maxWidth the max width
327     *
328     * @return the cropping bean
329     */
330    public CmsCroppingParamBean getRestrictedSizeParam(int maxHeight, int maxWidth) {
331
332        CmsCroppingParamBean result = new CmsCroppingParamBean(this);
333        if ((getTargetHeight() <= maxHeight) && (getTargetWidth() <= maxWidth)) {
334            if ((getTargetHeight() == I_CmsFormatRestriction.DIMENSION_NOT_SET) && (getOrgHeight() > maxHeight)) {
335                result.setTargetHeight(maxHeight);
336            }
337            if ((getTargetWidth() == I_CmsFormatRestriction.DIMENSION_NOT_SET) && (getOrgWidth() > maxWidth)) {
338                result.setTargetWidth(maxWidth);
339            }
340            return result;
341        }
342
343        if (((1.00 * getTargetHeight()) / getTargetWidth()) > ((1.00 * maxHeight) / maxWidth)) {
344            result.setTargetHeight(maxHeight);
345            double width = (1.00 * getTargetWidth() * maxHeight) / getTargetHeight();
346            result.setTargetWidth((int)Math.floor(width));
347            return result;
348        }
349        double height = (1.00 * getTargetHeight() * maxWidth) / getTargetWidth();
350        result.setTargetHeight((int)Math.floor(height));
351        result.setTargetWidth(maxWidth);
352        return result;
353    }
354
355    /**
356     * Returns the scale parameter to this bean for a restricted maximum target size.<p>
357     *
358     * TODO: This does not work correctly if there isn't any cropping/scaling defined.
359     *
360     * @param maxHeight the max height
361     * @param maxWidth the max width
362     *
363     * @return the scale parameter
364     */
365    public String getRestrictedSizeScaleParam(int maxHeight, int maxWidth) {
366
367        String result = toString();
368        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(result)) {
369
370            return getRestrictedSizeParam(maxHeight, maxWidth).toString();
371        }
372        if ((getOrgWidth() < maxWidth) && (getOrgHeight() < maxHeight)) {
373            return "";
374        }
375        CmsCroppingParamBean restricted = new CmsCroppingParamBean();
376        restricted.setTargetHeight(maxHeight);
377        restricted.setTargetWidth(maxWidth);
378        return restricted.toString();
379    }
380
381    /**
382     * Returns the resulting height of the cropped image.<p>
383     *
384     * @return the height
385     */
386    public int getResultingHeight() {
387
388        int height = getResultingTargetHeight();
389        if (height == -1) {
390            if (isCropped()) {
391                height = m_cropHeight;
392            } else {
393                height = m_orgHeight;
394            }
395        }
396        return height;
397    }
398
399    /**
400     * Returns the resulting width of the cropped image.<p>
401     *
402     * @return the width
403     */
404    public int getResultingWidth() {
405
406        int width = getResultingTargetWidth();
407        if (width == -1) {
408            if (isCropped()) {
409                width = m_cropWidth;
410            } else {
411                width = m_orgWidth;
412            }
413        }
414        return width;
415    }
416
417    /**
418     * Returns the scale parameter.<p>
419     *
420     * @return the scale parameter
421     */
422    public String getScaleParam() {
423
424        if (!isScaled() && !isCropped()) {
425            // the image is not cropped nor scaled, return an empty parameter
426            return "";
427        }
428        StringBuffer result = new StringBuffer();
429        if ((m_targetHeight > -1) || (m_targetWidth > -1)) {
430            result.append(SCALE_PARAM_TARGETHEIGHT).append(SCALE_PARAM_COLON).append(getResultingTargetHeight()).append(
431                SCALE_PARAM_DELIMITER);
432            result.append(SCALE_PARAM_TARGETWIDTH).append(SCALE_PARAM_COLON).append(getResultingTargetWidth()).append(
433                SCALE_PARAM_DELIMITER);
434        }
435        if (m_cropX > -1) {
436            result.append(SCALE_PARAM_CROP_X).append(SCALE_PARAM_COLON).append(m_cropX).append(SCALE_PARAM_DELIMITER);
437        }
438        if (m_cropY > -1) {
439            result.append(SCALE_PARAM_CROP_Y).append(SCALE_PARAM_COLON).append(m_cropY).append(SCALE_PARAM_DELIMITER);
440        }
441        if (m_cropHeight > -1) {
442            result.append(SCALE_PARAM_CROP_HEIGHT).append(SCALE_PARAM_COLON).append(m_cropHeight).append(
443                SCALE_PARAM_DELIMITER);
444        }
445        if (m_cropWidth > -1) {
446            result.append(SCALE_PARAM_CROP_WIDTH).append(SCALE_PARAM_COLON).append(m_cropWidth).append(
447                SCALE_PARAM_DELIMITER);
448        }
449        if (result.length() > 0) {
450            result.deleteCharAt(result.length() - 1);
451        }
452        return result.toString();
453    }
454
455    /**
456     * Returns the target height.<p>
457     *
458     * @return the target height
459     */
460    public int getTargetHeight() {
461
462        return m_targetHeight;
463    }
464
465    /**
466     * Returns the target width.<p>
467     *
468     * @return the target width
469     */
470    public int getTargetWidth() {
471
472        return m_targetWidth;
473    }
474
475    /**
476     * Returns if contained parameters indicate a cropped image.<p>
477     *
478     * @return <code>true</code> if contained parameters indicate a cropped image
479     */
480    public boolean isCropped() {
481
482        return m_cropX > I_CmsFormatRestriction.DIMENSION_NOT_SET;
483    }
484
485    /**
486     * Returns if the given cropping parameters would scale the image.<p>
487     *
488     * @return <code>true</code> if the image is scaled
489     */
490    public boolean isScaled() {
491
492        return !(((m_targetHeight == m_orgHeight) || (m_targetHeight == -1))
493            && ((m_targetWidth == m_orgWidth) || (m_targetWidth == -1)));
494    }
495
496    /**
497     * Resets the cropping parameters to no cropping.<p>
498     */
499    public void reset() {
500
501        m_cropHeight = I_CmsFormatRestriction.DIMENSION_NOT_SET;
502        m_cropWidth = I_CmsFormatRestriction.DIMENSION_NOT_SET;
503        m_cropX = I_CmsFormatRestriction.DIMENSION_NOT_SET;
504        m_cropY = I_CmsFormatRestriction.DIMENSION_NOT_SET;
505        m_targetHeight = I_CmsFormatRestriction.DIMENSION_NOT_SET;
506        m_targetWidth = I_CmsFormatRestriction.DIMENSION_NOT_SET;
507    }
508
509    /**
510     * Sets the cropping height parameter.<p>
511     *
512     * @param cropHeight the cropping height parameter to set
513     */
514    public void setCropHeight(int cropHeight) {
515
516        m_cropHeight = cropHeight;
517    }
518
519    /**
520     * Sets the cropping width parameter.<p>
521     *
522     * @param cropWidth the cropping width parameter to set
523     */
524    public void setCropWidth(int cropWidth) {
525
526        m_cropWidth = cropWidth;
527    }
528
529    /**
530     * Sets the cropping X parameter.<p>
531     *
532     * @param cropX the cropping X parameter to set
533     */
534    public void setCropX(int cropX) {
535
536        m_cropX = cropX;
537    }
538
539    /**
540     * Sets the cropping Y parameter.<p>
541     *
542     * @param cropY the cropping Y parameter to set
543     */
544    public void setCropY(int cropY) {
545
546        m_cropY = cropY;
547    }
548
549    /**
550     * Sets the used format name.<p>
551     *
552     * @param formatName the used format name to set
553     */
554    public void setFormatName(String formatName) {
555
556        m_formatName = formatName;
557    }
558
559    /**
560     * Sets the original image height.<p>
561     *
562     * @param orgHeight the original image height to set
563     */
564    public void setOrgHeight(int orgHeight) {
565
566        m_orgHeight = orgHeight;
567    }
568
569    /**
570     * Sets the original image width.<p>
571     *
572     * @param orgWidth the original image width to set
573     */
574    public void setOrgWidth(int orgWidth) {
575
576        m_orgWidth = orgWidth;
577    }
578
579    /**
580     * Sets the target height.<p>
581     *
582     * @param targetHeight the target height to set
583     */
584    public void setTargetHeight(int targetHeight) {
585
586        m_targetHeight = targetHeight;
587    }
588
589    /**
590     * Sets the target width.<p>
591     *
592     * @param targetWidth the target width to set
593     */
594    public void setTargetWidth(int targetWidth) {
595
596        m_targetWidth = targetWidth;
597    }
598
599    /**
600     * @see java.lang.Object#toString()
601     */
602    @Override
603    public String toString() {
604
605        String result = getScaleParam();
606        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(result)) {
607            result = SCALE_PARAM_NAME + SCALE_PARAM_EQ + result;
608        }
609        return result;
610    }
611
612    /**
613     * Returns the resulting target height if set, otherwise '-1'.<p>
614     *
615     * @return the height
616     */
617    private int getResultingTargetHeight() {
618
619        int height = -1;
620        if ((m_targetHeight > -1) || (m_targetWidth > -1)) {
621            if (m_targetHeight > -1) {
622                height = m_targetHeight;
623            } else {
624                height = (int)Math.floor(((1.00 * m_orgHeight) / m_orgWidth) * m_targetWidth);
625            }
626        }
627        return height;
628    }
629
630    /**
631     * Returns the resulting target width if set, otherwise '-1'.<p>
632     *
633     * @return the width
634     */
635    private int getResultingTargetWidth() {
636
637        int width = -1;
638        if ((m_targetHeight > -1) || (m_targetWidth > -1)) {
639            if (m_targetWidth > -1) {
640                width = m_targetWidth;
641            } else {
642                width = (int)Math.floor(((1.00 * m_orgWidth) / m_orgHeight) * m_targetHeight);
643            }
644        }
645        return width;
646    }
647
648}