Revision 8165e2b9
ref #9134 no longer storing DefaultMediaTransformations in the db, better exception handling and more documentation
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/iiif/ManifestController.java | ||
---|---|---|
159 | 159 |
return iiifMapper.writeValueAsString(manifest); |
160 | 160 |
} |
161 | 161 |
|
162 |
private <T extends IdentifiableEntity> Manifest manifestFor(EntityMediaContext<T> entityMediaContext, String onEntitiyType, String onEntityUuid) { |
|
162 |
private <T extends IdentifiableEntity> Manifest manifestFor(EntityMediaContext<T> entityMediaContext, String onEntitiyType, String onEntityUuid) throws IOException {
|
|
163 | 163 |
|
164 | 164 |
List<Canvas> canvases = new ArrayList<>(entityMediaContext.getMedia().size()); |
165 | 165 |
|
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/util/IMediaToolbox.java | ||
---|---|---|
8 | 8 |
*/ |
9 | 9 |
package eu.etaxonomy.cdm.remote.controller.util; |
10 | 10 |
|
11 |
import java.io.IOException; |
|
11 | 12 |
import java.util.List; |
12 | 13 |
|
13 | 14 |
import eu.etaxonomy.cdm.model.media.Media; |
... | ... | |
21 | 22 |
*/ |
22 | 23 |
public interface IMediaToolbox { |
23 | 24 |
|
25 |
/** |
|
26 |
* Extend the set of media representations in <code>media</code>, filter the resulting representations by the |
|
27 |
* attributes defined via the parameters <code>type</code>, <code>size</code>, <code>height</code>, <code>widthOrDuration</code> |
|
28 |
* and <code>mimeTypes</code> and finally return the list of matching MediaRepresentations ordered by the ranging of the match. |
|
29 |
* |
|
30 |
*/ |
|
24 | 31 |
List<Media> processAndFilterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, |
25 |
String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size, List<Media> taxonGalleryMedia); |
|
32 |
String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size, List<Media> taxonGalleryMedia) throws IOException;
|
|
26 | 33 |
|
27 |
List<Media> filterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, String[] mimeTypes, |
|
28 |
Integer widthOrDuration, Integer height, Integer size, List<Media> taxonGalleryMedia); |
|
34 |
/** |
|
35 |
* Filters the Media objects and the contained MediaRepresentations the by the |
|
36 |
* attributes defined via the parameters <code>type</code>, <code>size</code>, <code>height</code>, <code>widthOrDuration</code> |
|
37 |
* and <code>mimeTypes</code> and finally return the media objects which have at lease one matching representation. |
|
38 |
* The MediaRepresentations are also filtered and ordered by the ranging of the match. |
|
39 |
*/ |
|
40 |
List<Media> filterPreferredMediaRepresentations(List<Media> mediaList, Class<? extends MediaRepresentationPart> type, |
|
41 |
String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size); |
|
29 | 42 |
|
43 |
/** |
|
44 |
* Extend the set of media representations in <code>media</code>, filter the resulting representations by the |
|
45 |
* attributes defined via the parameters <code>type</code>, <code>size</code>, <code>height</code>, <code>widthOrDuration</code> |
|
46 |
* and <code>mimeTypes</code> and finally return the best matching MediaRepresentation. |
|
47 |
* |
|
48 |
* @param media |
|
49 |
* @param type |
|
50 |
* @param size |
|
51 |
* @param height |
|
52 |
* @param widthOrDuration |
|
53 |
* @param mimeTypes |
|
54 |
* @param missingValStrategy Strategies for replacing <code>null</code> values with a numeric value. |
|
55 |
* @return |
|
56 |
* @throws IOException |
|
57 |
*/ |
|
30 | 58 |
MediaRepresentation processAndFindBestMatchingRepresentation(Media media, |
31 | 59 |
Class<? extends MediaRepresentationPart> type, Integer size, Integer height, Integer widthOrDuration, |
32 |
String[] mimeTypes, MissingValueStrategy missingValStrategy); |
|
60 |
String[] mimeTypes, MissingValueStrategy missingValStrategy) throws IOException;
|
|
33 | 61 |
|
34 | 62 |
} |
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/util/MediaToolbox.java | ||
---|---|---|
14 | 14 |
|
15 | 15 |
import org.apache.log4j.Logger; |
16 | 16 |
import org.springframework.beans.factory.annotation.Autowired; |
17 |
import org.springframework.stereotype.Component; |
|
17 | 18 |
|
18 | 19 |
import com.fasterxml.jackson.core.JsonProcessingException; |
19 | 20 |
import com.fasterxml.jackson.databind.JsonMappingException; |
... | ... | |
21 | 22 |
import com.fasterxml.jackson.databind.type.CollectionType; |
22 | 23 |
|
23 | 24 |
import eu.etaxonomy.cdm.api.service.IPreferenceService; |
25 |
import eu.etaxonomy.cdm.api.service.media.DefaultMediaTransformations; |
|
24 | 26 |
import eu.etaxonomy.cdm.api.service.media.MediaUriTransformation; |
25 | 27 |
import eu.etaxonomy.cdm.api.service.media.MediaUriTransformationProcessor; |
26 |
import eu.etaxonomy.cdm.api.service.media.SearchReplace; |
|
27 | 28 |
import eu.etaxonomy.cdm.model.media.Media; |
28 | 29 |
import eu.etaxonomy.cdm.model.media.MediaRepresentation; |
29 | 30 |
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart; |
... | ... | |
35 | 36 |
import eu.etaxonomy.cdm.model.metadata.PreferenceSubject; |
36 | 37 |
|
37 | 38 |
/** |
38 |
* See {@link MediaUriTransformationProcessor} and {@link MediaUriTransformation} |
|
39 |
* Utility service which which creates volatile object which must not be persisted. |
|
40 |
* <p> |
|
41 |
* By now this class provides methods for filtering {@link Media} and {@link MediaRepresentation}s |
|
42 |
* <p> |
|
43 |
* See also {@link MediaUriTransformationProcessor} and {@link MediaUriTransformation} |
|
39 | 44 |
* |
40 | 45 |
* @author a.kohlbecker |
41 | 46 |
* @since Jul 8, 2020 |
42 | 47 |
*/ |
48 |
@Component // not used for component scan, see eu.etaxonomy.cdm.remote.config.CdmRemoteConfiguration |
|
43 | 49 |
public class MediaToolbox implements IMediaToolbox { |
44 | 50 |
|
45 |
private static final String SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET = "mediaRepresentationTransformationsReset"; |
|
46 |
|
|
47 | 51 |
private static final Logger logger = Logger.getLogger(MediaToolbox.class); |
48 | 52 |
|
49 | 53 |
private List<MediaUriTransformation> transformations = null; |
... | ... | |
55 | 59 |
|
56 | 60 |
@Override |
57 | 61 |
public List<Media> processAndFilterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, String[] mimeTypes, |
58 |
Integer widthOrDuration, Integer height, Integer size, List<Media> galleryMedia) {
|
|
62 |
Integer widthOrDuration, Integer height, Integer size, List<Media> mediaList) {
|
|
59 | 63 |
|
60 | 64 |
MediaUriTransformationProcessor mediaTransformationProcessor = new MediaUriTransformationProcessor(); |
61 | 65 |
mediaTransformationProcessor.addAll(readTransformations()); |
62 | 66 |
|
63 |
for(Media media : galleryMedia) {
|
|
67 |
for(Media media : mediaList) {
|
|
64 | 68 |
List<MediaRepresentation> newRepr = new ArrayList<>(); |
65 | 69 |
for(MediaRepresentation repr : media.getRepresentations()) { |
66 | 70 |
for(MediaRepresentationPart part : repr.getParts()) { |
... | ... | |
69 | 73 |
} |
70 | 74 |
media.getRepresentations().addAll(newRepr); |
71 | 75 |
} |
72 |
return filterPreferredMediaRepresentations(type, mimeTypes, widthOrDuration, height, size, galleryMedia);
|
|
76 |
return filterPreferredMediaRepresentations(mediaList, type, mimeTypes, widthOrDuration, height, size);
|
|
73 | 77 |
} |
74 | 78 |
|
75 | 79 |
@Override |
... | ... | |
90 | 94 |
|
91 | 95 |
return MediaUtils.findBestMatchingRepresentation(media, type, size, height, widthOrDuration, mimeTypes, |
92 | 96 |
missingValStrategy); |
93 |
|
|
94 | 97 |
} |
95 | 98 |
|
96 | 99 |
@Override |
97 |
public List<Media> filterPreferredMediaRepresentations(Class<? extends MediaRepresentationPart> type, String[] mimeTypes, |
|
98 |
Integer widthOrDuration, Integer height, Integer size, List<Media> galleryMedia) { |
|
100 |
public List<Media> filterPreferredMediaRepresentations(List<Media> mediaList, Class<? extends MediaRepresentationPart> type, |
|
101 |
String[] mimeTypes, Integer widthOrDuration, Integer height, Integer size) { |
|
102 |
|
|
99 | 103 |
|
100 |
Map<Media, MediaRepresentation> mediaRepresentationMap = MediaUtils.findPreferredMedia( |
|
101 |
galleryMedia, type, mimeTypes, widthOrDuration, height, size, MediaUtils.MissingValueStrategy.MAX); |
|
104 |
Map<Media, MediaRepresentation> mediaRepresentationMap = MediaUtils.findPreferredMedia(mediaList, type, mimeTypes, widthOrDuration, height, size, MediaUtils.MissingValueStrategy.MAX); |
|
102 | 105 |
|
103 | 106 |
List<Media> filteredMedia = new ArrayList<>(mediaRepresentationMap.size()); |
104 | 107 |
for (Media media : mediaRepresentationMap.keySet()) { |
... | ... | |
109 | 112 |
return filteredMedia; |
110 | 113 |
} |
111 | 114 |
|
115 |
/** |
|
116 |
* Read the {@link MediaUriTransformation MediaUriTransformations} from the cdm preferences ({@link PreferencePredicate.MediaRepresentationTransformations} |
|
117 |
* or use the default defined in {@link DefaultMediaTransformations#digilib()} |
|
118 |
* |
|
119 |
*/ |
|
112 | 120 |
private List<MediaUriTransformation> readTransformations() { |
113 | 121 |
|
114 |
//System.setProperty(SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET, "1"); |
|
115 | 122 |
PrefKey key = CdmPreference.NewKey(PreferenceSubject.NewDatabaseInstance(), PreferencePredicate.MediaRepresentationTransformations); |
116 | 123 |
CdmPreference pref = preferenceService.find(key); |
117 | 124 |
if(pref != null && pref.getValue() != null) { |
118 |
if(System.getProperty(SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET) == null |
|
119 |
|| mediaRepresentationTransformationsLastHash == null |
|
120 |
|| mediaRepresentationTransformationsLastHash != pref.getValue().hashCode()) { |
|
125 |
if(mediaRepresentationTransformationsLastHash == null || mediaRepresentationTransformationsLastHash != pref.getValue().hashCode()) { |
|
121 | 126 |
// loaded value is different from last value |
122 | 127 |
ObjectMapper mapper = new ObjectMapper(); |
123 | 128 |
CollectionType javaType = mapper.getTypeFactory() |
... | ... | |
132 | 137 |
} |
133 | 138 |
} |
134 | 139 |
} |
135 |
if(transformations == null || System.getProperty(SYS_PROP_MEDIA_REPRESENTATION_TRANSFORMATIONS_RESET) != null) { |
|
136 |
|
|
137 |
transformations = new ArrayList<>(); |
|
138 |
MediaUriTransformation tr1 = new MediaUriTransformation(); |
|
139 |
|
|
140 |
tr1.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!200,200/0/default.jpg")); |
|
141 |
tr1.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
142 |
tr1.setMimeType("image/jpeg"); |
|
143 |
tr1.setWidth(200); |
|
144 |
tr1.setHeight(200); |
|
145 |
|
|
146 |
MediaUriTransformation tr2 = new MediaUriTransformation(); |
|
147 |
|
|
148 |
tr2.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!400,400/0/default.jpg")); |
|
149 |
tr2.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
150 |
tr2.setMimeType("image/jpeg"); |
|
151 |
tr2.setWidth(400); |
|
152 |
tr2.setHeight(400); |
|
153 |
|
|
154 |
|
|
155 |
MediaUriTransformation tr3 = new MediaUriTransformation(); |
|
156 |
tr3.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!400,400/0/default.jpg")); |
|
157 |
tr3.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
158 |
tr3.setMimeType("image/jpeg"); |
|
159 |
tr3.setWidth(400); |
|
160 |
tr3.setHeight(400); |
|
161 |
|
|
162 |
MediaUriTransformation tr4 = new MediaUriTransformation(); |
|
163 |
tr4.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", "digilib/Scaler/IIIF/$1!$2/full/!200,200/0/default.jpg")); |
|
164 |
tr4.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
165 |
tr4.setMimeType("image/jpeg"); |
|
166 |
tr4.setWidth(200); |
|
167 |
tr4.setHeight(200); |
|
168 |
|
|
169 |
transformations.add(tr1); |
|
170 |
transformations.add(tr2); |
|
171 |
transformations.add(tr3); |
|
172 |
transformations.add(tr4); |
|
173 |
|
|
174 |
ObjectMapper mapper = new ObjectMapper(); |
|
175 |
CollectionType javaType = mapper.getTypeFactory() |
|
176 |
.constructCollectionType(List.class, MediaUriTransformation.class); |
|
177 |
try { |
|
178 |
String json = mapper.writerFor(javaType).writeValueAsString(transformations); |
|
179 |
pref = CdmPreference.NewDatabaseInstance(PreferencePredicate.MediaRepresentationTransformations, json); |
|
180 |
preferenceService.set(pref); |
|
181 |
} catch (JsonProcessingException e) { |
|
182 |
logger.error(e); |
|
183 |
} |
|
140 |
if(transformations == null) { |
|
141 |
transformations = DefaultMediaTransformations.digilib(); |
|
184 | 142 |
} |
185 | 143 |
|
186 | 144 |
return transformations; |
187 | 145 |
} |
146 |
|
|
147 |
/** |
|
148 |
* @param trans the list of MediaUriTransformation to be serialized |
|
149 |
* @return the JSON string |
|
150 |
* @throws JsonProcessingException |
|
151 |
*/ |
|
152 |
static protected String transformationsToJson(List<MediaUriTransformation> trans) throws JsonProcessingException { |
|
153 |
|
|
154 |
ObjectMapper mapper = new ObjectMapper(); |
|
155 |
CollectionType javaType = mapper.getTypeFactory() |
|
156 |
.constructCollectionType(List.class, MediaUriTransformation.class); |
|
157 |
|
|
158 |
String json = mapper.writerFor(javaType).withDefaultPrettyPrinter().writeValueAsString(trans); |
|
159 |
return json; |
|
160 |
} |
|
161 |
|
|
162 |
/** |
|
163 |
* |
|
164 |
* @param args |
|
165 |
* @throws JsonProcessingException |
|
166 |
*/ |
|
167 |
public static void main(String[] args) throws JsonProcessingException { |
|
168 |
|
|
169 |
System.out.println("Default tansformations for digilib"); |
|
170 |
System.out.println("========================================"); |
|
171 |
System.out.println(transformationsToJson(DefaultMediaTransformations.digilib())); |
|
172 |
} |
|
173 |
|
|
188 | 174 |
} |
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/media/DefaultMediaTransformations.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2020 EDIT |
|
3 |
* European Distributed Institute of Taxonomy |
|
4 |
* http://www.e-taxonomy.eu |
|
5 |
* |
|
6 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
7 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
8 |
*/ |
|
9 |
package eu.etaxonomy.cdm.api.service.media; |
|
10 |
|
|
11 |
import java.util.ArrayList; |
|
12 |
import java.util.List; |
|
13 |
|
|
14 |
/** |
|
15 |
* Factory class to create default transformations |
|
16 |
* |
|
17 |
* @author a.kohlbecker |
|
18 |
* @since Jul 15, 2020 |
|
19 |
*/ |
|
20 |
public class DefaultMediaTransformations { |
|
21 |
|
|
22 |
/** |
|
23 |
* Create default transformations for the diglilib server: |
|
24 |
* <p> |
|
25 |
* Links: |
|
26 |
* <ul> |
|
27 |
* <li>https://robcast.github.io/digilib/scaler-api.html</li> |
|
28 |
* <li>https://robcast.github.io/digilib/iiif-api.html</li> |
|
29 |
* </ul> |
|
30 |
* |
|
31 |
* @return |
|
32 |
*/ |
|
33 |
static public List<MediaUriTransformation> digilib() { |
|
34 |
|
|
35 |
List<MediaUriTransformation> defaultTransformations = new ArrayList<>(); |
|
36 |
|
|
37 |
/* |
|
38 |
* dataPortalPreviewImage: |
|
39 |
* image which fits the default preview image size which is |
|
40 |
* for example used in the taxon general page, max extend of the resulting images is 400px |
|
41 |
*/ |
|
42 |
String dataPortalPreviewImage = "digilib/Scaler/IIIF/$1!$2/full/!400,400/0/default.jpg"; |
|
43 |
|
|
44 |
/* |
|
45 |
* universalViewerThumbnail: |
|
46 |
* crop to fit into a 200 x 147 preview box, the uvfix=1 parameter is used to |
|
47 |
* prevent the universal viewer from corrupting the last query parameter. UV appends a parameter t with |
|
48 |
* question mark character which causes problems for the URI query parser see https://dev.e-taxonomy.eu/redmine/issues/9132#note-8 |
|
49 |
*/ |
|
50 |
String universalViewerThumbnail = "digilib/Scaler/?fn=$1/$2&mo=crop&dw=200&dh=147&uvfix=1"; |
|
51 |
|
|
52 |
MediaUriTransformation tr1 = new MediaUriTransformation(); |
|
53 |
tr1.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", dataPortalPreviewImage)); |
|
54 |
tr1.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
55 |
tr1.setMimeType("image/jpeg"); |
|
56 |
tr1.setWidth(400); |
|
57 |
tr1.setHeight(400); |
|
58 |
|
|
59 |
MediaUriTransformation tr2 = new MediaUriTransformation(); |
|
60 |
tr2.setPathQueryFragment(new SearchReplace("digilib/Scaler/IIIF/([^\\!]+)\\!([^\\/]+)(.*)", universalViewerThumbnail)); |
|
61 |
tr2.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
62 |
tr2.setMimeType("image/jpeg"); |
|
63 |
tr2.setWidth(200); |
|
64 |
tr2.setHeight(200); |
|
65 |
|
|
66 |
MediaUriTransformation tr3 = new MediaUriTransformation(); |
|
67 |
tr3.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", dataPortalPreviewImage)); |
|
68 |
tr3.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
69 |
tr3.setMimeType("image/jpeg"); |
|
70 |
tr3.setWidth(400); |
|
71 |
tr3.setHeight(400); |
|
72 |
|
|
73 |
MediaUriTransformation tr4 = new MediaUriTransformation(); |
|
74 |
tr4.setPathQueryFragment(new SearchReplace("digilib/Scaler/\\?fn=([^\\\\/]+)/(\\w+)(.*)", universalViewerThumbnail)); |
|
75 |
tr4.setHost(new SearchReplace("pictures.bgbm.org", "pictures.bgbm.org")); // host part only used for matching, no replace! |
|
76 |
tr4.setMimeType("image/jpeg"); |
|
77 |
tr4.setWidth(200); |
|
78 |
tr4.setHeight(200); |
|
79 |
|
|
80 |
defaultTransformations.add(tr2); |
|
81 |
defaultTransformations.add(tr1); |
|
82 |
defaultTransformations.add(tr3); |
|
83 |
defaultTransformations.add(tr4); |
|
84 |
|
|
85 |
return defaultTransformations; |
|
86 |
} |
|
87 |
|
|
88 |
|
|
89 |
|
|
90 |
} |
Also available in: Unified diff