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 java.util.Arrays;
22  import java.util.List;
23  import java.util.Locale;
24  import java.util.stream.Collectors;
25  
26  import org.mycore.iiif.image.model.MCRIIIFImageSourceRegion;
27  
28  public class MCRIIIFRegionParser {
29  
30      public static final String PERCENT_PREFIX = "pct:";
31  
32      private final int w;
33  
34      private final int h;
35  
36      private final String sourceRegion;
37  
38      private boolean completeValid = true;
39  
40      public MCRIIIFRegionParser(String sourceRegion, int w, int h) {
41          this.sourceRegion = sourceRegion.toLowerCase(Locale.ENGLISH);
42  
43          this.w = w;
44          this.h = h;
45  
46          if (w < 0 || h < 0) {
47              throw new IllegalArgumentException("w or h are zero!");
48          }
49  
50          if (isFull()) {
51              return;
52          }
53  
54          if (isSquare()) {
55              return;
56          }
57  
58          if (parseNumbers().size() != 4) {
59              completeValid = false;
60              throw new IllegalArgumentException("sourceRegion must have 4 numbers!");
61          }
62      }
63  
64      public MCRIIIFImageSourceRegion parseImageRegion() throws NumberFormatException {
65          if (isPercent()) {
66              return parsePercentImageRegion();
67          } else if (isFull()) {
68              return new MCRIIIFImageSourceRegion(0, 0, w - 1, h - 1);
69          } else if (isSquare()) {
70              final int shorterDimension = Math.min(w, h);
71              final int x1 = (int) Math.floor(w / 2.0 - shorterDimension / 2.0);
72              final int y1 = (int) Math.floor(h / 2.0 - shorterDimension / 2.0);
73              return new MCRIIIFImageSourceRegion(x1, y1, x1 + shorterDimension, y1 + shorterDimension);
74          }
75  
76          return parseAbsoluteImageRegion();
77      }
78  
79      private MCRIIIFImageSourceRegion parsePercentImageRegion() {
80          List<Double> doubles = parseNumbers();
81  
82          double x = Math.floor(doubles.get(0) * (w / 100.0));
83          double y = Math.floor(doubles.get(1) * (h / 100.0));
84          double x2 = Math.ceil(x + (doubles.get(2) * (w / 100.0)));
85          double y2 = Math.ceil(y + (doubles.get(3) * (w / 100.0)));
86  
87          return parseImageRegion((int) x, (int) y, (int) x2, (int) y2);
88      }
89  
90      private MCRIIIFImageSourceRegion parseAbsoluteImageRegion() {
91          List<Double> doubles = parseNumbers();
92          Double x1 = doubles.get(0);
93          Double y1 = doubles.get(1);
94          Double x2 = doubles.get(2) + x1;
95          Double y2 = doubles.get(3) + y1;
96          return parseImageRegion((int) Math.round(x1), (int) Math.round(y1), (int) Math.round(x2), (int) Math.round(y2));
97      }
98  
99      private MCRIIIFImageSourceRegion parseImageRegion(int x1, int y1, int x2, int y2) {
100         if (x1 >= w || y1 >= h) {
101             completeValid = false;
102             throw new IllegalArgumentException(
103                 "x[" + x1 + "] or y[" + y1 + "] cant be bigger then or equal image size[" + w + "x" + h + "]!");
104         }
105 
106         if (!(y1 < y2 && x1 < x2 && x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h)) {
107             completeValid = false;
108         }
109 
110         // negative values become 0
111         int nx1 = Math.max(0, x1);
112         int ny1 = Math.max(0, y1);
113 
114         // end values bigger then image become as big as image
115         int nx2 = Math.min(w - 1, x2);
116         int ny2 = Math.min(h - 1, y2);
117 
118         return new MCRIIIFImageSourceRegion(nx1, ny1, nx2, ny2);
119     }
120 
121     private boolean isPercent() {
122         return this.sourceRegion.startsWith(PERCENT_PREFIX);
123     }
124 
125     private boolean isFull() {
126         return "full".equals(sourceRegion);
127     }
128 
129     private boolean isSquare() {
130         return "square".equals(sourceRegion);
131     }
132 
133     private List<Double> parseNumbers() {
134         return Arrays
135             .stream((isPercent() ? this.sourceRegion.substring(PERCENT_PREFIX.length()) : this.sourceRegion).split(","))
136             .map(Double::parseDouble)
137             .collect(Collectors.toList());
138     }
139 
140     public boolean isCompleteValid() {
141         return completeValid;
142     }
143 }