View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.iiif.image.parser;
20  
21  import org.mycore.iiif.image.model.MCRIIIFImageTargetSize;
22  
23  public class MCRIIIFScaleParser {
24  
25      private String targetScale;
26  
27      private int sourceRegionWidth;
28  
29      private int sourceRegionHeight;
30  
31      public MCRIIIFScaleParser(String targetScale, int w, int h) {
32          this.targetScale = targetScale;
33          this.sourceRegionWidth = w;
34          this.sourceRegionHeight = h;
35      }
36  
37      private boolean isFull() {
38          return "full".equals(targetScale) || "max".equals(targetScale);
39      }
40  
41      private boolean isPercent() {
42          return targetScale.startsWith("pct:");
43      }
44  
45      private boolean isBestFit() {
46          return targetScale.startsWith("!");
47      }
48  
49      public MCRIIIFImageTargetSize parseTargetScale() {
50          if (isFull()) {
51              return new MCRIIIFImageTargetSize(sourceRegionWidth, sourceRegionHeight);
52          }
53  
54          if (isPercent()) {
55              return parsePercentValue();
56          }
57  
58          StringBuilder wBuilder = new StringBuilder();
59          StringBuilder hBuilder = new StringBuilder();
60          getWidthAndHeightStrings(wBuilder, hBuilder);
61          String w = wBuilder.toString();
62          String h = hBuilder.toString();
63  
64          try {
65              if (w.length() == 0) {
66                  return scaleToHeight(Integer.parseInt(h));
67              } else if (h.length() == 0) {
68                  return scaleToWidth(Integer.parseInt(w));
69              } else if (isBestFit()) {
70                  return bestFit(Integer.parseInt(w), Integer.parseInt(h));
71              } else {
72                  return scale(Integer.parseInt(w), Integer.parseInt(h));
73              }
74          } catch (NumberFormatException e) {
75              throw new IllegalArgumentException(h + " or " + w + " ist not a valid scale value!", e);
76          }
77  
78      }
79  
80      private MCRIIIFImageTargetSize scale(int w, int h) {
81          if (w <= 0) {
82              throw new IllegalArgumentException("width to scale must be positive! [" + w + "]");
83          }
84          if (h <= 0) {
85              throw new IllegalArgumentException("height to scale must be positive! [" + h + "]");
86          }
87          return new MCRIIIFImageTargetSize(w, h);
88      }
89  
90      private MCRIIIFImageTargetSize bestFit(int w, int h) {
91          if (w <= 0) {
92              throw new IllegalArgumentException("width to scale must be positive! [" + w + "]");
93          }
94          if (h <= 0) {
95              throw new IllegalArgumentException("height to scale must be positive! [" + h + "]");
96          }
97          double ratio = Math.min(((double) w) / this.sourceRegionWidth, ((double) h) / this.sourceRegionHeight);
98          return new MCRIIIFImageTargetSize((int) Math.round(this.sourceRegionWidth * ratio),
99              (int) Math.round(this.sourceRegionHeight * ratio));
100     }
101 
102     private MCRIIIFImageTargetSize scaleToWidth(Integer w) {
103         if (w <= 0) {
104             throw new IllegalArgumentException("width to scale must be positive! [" + w + "]");
105         }
106         double ratio = ((double) this.sourceRegionHeight) / this.sourceRegionWidth;
107         return new MCRIIIFImageTargetSize(w, (int) Math.ceil(ratio * w));
108     }
109 
110     private MCRIIIFImageTargetSize scaleToHeight(Integer h) {
111         if (h <= 0) {
112             throw new IllegalArgumentException("height to scale must be positive! [" + h + "]");
113         }
114         double ratio = ((double) this.sourceRegionWidth) / this.sourceRegionHeight;
115         return new MCRIIIFImageTargetSize((int) Math.ceil(ratio * h), h);
116     }
117 
118     private MCRIIIFImageTargetSize parsePercentValue() {
119         String rightValue = this.targetScale.substring("pct:".length());
120         double percentValue;
121 
122         try {
123             percentValue = Double.parseDouble(rightValue);
124         } catch (NumberFormatException e) {
125             throw new IllegalArgumentException(rightValue + " is not a valid scale!", e);
126         }
127 
128         if (percentValue <= 0) {
129             throw new IllegalArgumentException("Scale has to be positive! [" + percentValue + "]");
130         }
131 
132         return new MCRIIIFImageTargetSize((int) Math.ceil(percentValue / 100 * sourceRegionWidth),
133             (int) Math.ceil(percentValue / 100 * sourceRegionHeight));
134     }
135 
136     private void getWidthAndHeightStrings(StringBuilder wBuilder, StringBuilder hBuilder) {
137         char[] chars = this.targetScale.toCharArray();
138         boolean writeW = true;
139         boolean first = true;
140         for (char currentChar : chars) {
141             switch (currentChar) {
142             case ',':
143                 first = false;
144                 if (!writeW) {
145                     throw new IllegalArgumentException("second , found in scale!");
146                 }
147                 writeW = false;
148                 break;
149             case '!':
150                 if (!first) {
151                     throw new IllegalArgumentException("! should be located only in the first position of scale!");
152                 }
153                 first = false;
154                 break;
155             default:
156                 first = false;
157                 if (writeW) {
158                     wBuilder.append(currentChar);
159                 } else {
160                     hBuilder.append(currentChar);
161                 }
162                 break;
163             }
164         }
165 
166     }
167 
168 }