Project

General

Profile

Download (25.1 KB) Statistics
| Branch: | Tag: | Revision:
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.remote.controller.iiif;
10

    
11
import java.io.IOException;
12
import java.net.URI;
13
import java.util.ArrayList;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.stream.Collectors;
18

    
19
import org.apache.http.HttpException;
20
import org.apache.log4j.Logger;
21

    
22
import de.digitalcollections.iiif.model.ImageContent;
23
import de.digitalcollections.iiif.model.MetadataEntry;
24
import de.digitalcollections.iiif.model.MimeType;
25
import de.digitalcollections.iiif.model.PropertyValue;
26
import de.digitalcollections.iiif.model.enums.ViewingDirection;
27
import de.digitalcollections.iiif.model.sharedcanvas.Canvas;
28
import de.digitalcollections.iiif.model.sharedcanvas.Manifest;
29
import de.digitalcollections.iiif.model.sharedcanvas.Resource;
30
import de.digitalcollections.iiif.model.sharedcanvas.Sequence;
31
import eu.etaxonomy.cdm.api.service.IMediaService;
32
import eu.etaxonomy.cdm.api.service.MediaServiceImpl;
33
import eu.etaxonomy.cdm.common.media.CdmImageInfo;
34
import eu.etaxonomy.cdm.model.common.Credit;
35
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
36
import eu.etaxonomy.cdm.model.common.Language;
37
import eu.etaxonomy.cdm.model.common.LanguageString;
38
import eu.etaxonomy.cdm.model.media.ImageFile;
39
import eu.etaxonomy.cdm.model.media.Media;
40
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
41
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
42
import eu.etaxonomy.cdm.model.media.MediaUtils;
43
import eu.etaxonomy.cdm.model.media.Rights;
44
import eu.etaxonomy.cdm.model.media.RightsType;
45
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
46
import eu.etaxonomy.cdm.remote.controller.TaxonPortalController.EntityMediaContext;
47
import eu.etaxonomy.cdm.remote.controller.util.IMediaToolbox;
48
import eu.etaxonomy.cdm.remote.l10n.LocaleContext;
49
import eu.etaxonomy.cdm.strategy.cache.TaggedCacheHelper;
50

    
51
/**
52
 * Factory class for creating iiif manifests.
53
 * <p>
54
 * This class is not state less therefore it is not a spring bean.
55
 *
56
 * @author a.kohlbecker
57
 * @since Aug 18, 2020
58
 */
59
public class ManifestComposer {
60

    
61
    public static final Logger logger = Logger.getLogger(ManifestComposer.class);
62

    
63
    private IMediaToolbox mediaTools;
64

    
65
    private IMediaService mediaService;
66

    
67
    private String iiifIdPrefix;
68

    
69
    private String[] thumbnailMimetypes = new String[] {"image/.*", ".*"};
70

    
71

    
72
    private boolean doJoinAttributions = false;
73

    
74
    private boolean useThumbnailDimensionsForCanvas = false;
75

    
76

    
77
    public String getIiifIdPrefix() {
78
        return iiifIdPrefix;
79
    }
80

    
81
    public void setIiifIdPrefix(String iiifIdPrefix) {
82
        this.iiifIdPrefix = iiifIdPrefix;
83
    }
84

    
85

    
86
    public String[] getThumbnailMimetypes() {
87
        return thumbnailMimetypes;
88
    }
89

    
90
    public void setThumbnailMimetypes(String[] thumbnailMimetypes) {
91
        this.thumbnailMimetypes = thumbnailMimetypes;
92
    }
93

    
94
    public boolean isDoJoinAttributions() {
95
        return doJoinAttributions;
96
    }
97

    
98
    /**
99
     * Universal viewer only shows one attribution value in the popup panel
100
     * Therefore it makes sense to join all of them.
101
     */
102
    public void setDoJoinAttributions(boolean doJoinAttributions) {
103
        this.doJoinAttributions = doJoinAttributions;
104
    }
105

    
106
    public boolean isUseThumbnailDimensionsForCanvas() {
107
        return useThumbnailDimensionsForCanvas;
108
    }
109

    
110
    /**
111
     * Width and height of the thumbnail image will be used for the canvas size when this is true.
112
     * Normally the canvas dimensions conform to the image dimension.
113
     * This trick is necessary to achieve a pleasant presentation of the thumbnails in universal viewer,
114
     * see {@linkplain https://dev.e-taxonomy.eu/redmine/issues/9132#note-21} and
115
     *  {@linkplain https://github.com/UniversalViewer/universalviewer/issues/743}
116
     *
117
     */
118
    public void setUseThumbnailDimensionsForCanvas(boolean useThumbnailDimensionsForCanvas) {
119
        this.useThumbnailDimensionsForCanvas = useThumbnailDimensionsForCanvas;
120
    }
121

    
122

    
123
    public ManifestComposer(String iiifIdPrefix, IMediaToolbox mediaTools, IMediaService mediaService) {
124
        this.mediaTools = mediaTools;
125
        this.iiifIdPrefix = iiifIdPrefix;
126
        this.mediaService = mediaService;
127
    }
128

    
129
    <T extends IdentifiableEntity> Manifest manifestFor(EntityMediaContext<T> entityMediaContext, String onEntitiyType, String onEntityUuid) throws IOException {
130

    
131
        List<Canvas> canvases = new ArrayList<>(entityMediaContext.getMedia().size());
132

    
133
//        Logger.getLogger(MediaUtils.class).setLevel(Level.DEBUG);
134
//        logger.setLevel(Level.DEBUG);
135

    
136
        int mediaID = 0;
137
        for(Media media : entityMediaContext.getMedia()){
138

    
139
            MediaRepresentation thumbnailRepresentation = mediaTools.processAndFindBestMatchingRepresentation(media, null, null, 100, 100, thumbnailMimetypes, MediaUtils.MissingValueStrategy.MAX);
140
            MediaRepresentation fullSizeRepresentation = mediaTools.processAndFindBestMatchingRepresentation(media, null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null, MediaUtils.MissingValueStrategy.MAX);
141
            // MediaRepresentation fullSizeRepresentation = MediaUtils.findBestMatchingRepresentation(media, null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null, MediaUtils.MissingValueStrategy.MAX);
142
            // MediaRepresentation thumbnailRepresentation = MediaUtils.findBestMatchingRepresentation(media, null, null, 100, 100, tumbnailMimetypes, MediaUtils.MissingValueStrategy.MAX);
143
            if(logger.isDebugEnabled()){
144
                logger.debug("fullSizeRepresentation: " + fullSizeRepresentation.getParts().get(0).getUri());
145
                logger.debug("thumbnailRepresentation: " + thumbnailRepresentation.getParts().get(0).getUri());
146
            }
147

    
148
            // FIXME the below only makes sense if the media is an Image!!!!!
149
            List<ImageContent> fullSizeImageContents = representationPartsToImageContent(fullSizeRepresentation);
150

    
151
            List<ImageContent> thumbnailImageContents;
152
            if(fullSizeRepresentation.equals(thumbnailRepresentation)){
153
                thumbnailImageContents = fullSizeImageContents;
154
            } else {
155
                thumbnailImageContents = representationPartsToImageContent(thumbnailRepresentation);
156
            }
157

    
158
            Canvas canvas = new Canvas(iiifID(onEntitiyType, onEntityUuid, Canvas.class, mediaID++));
159
            for(Language lang : media.getAllTitles().keySet()){
160
                LanguageString titleLocalized = media.getAllTitles().get(lang);
161
                canvas.addLabel(titleLocalized.getText());
162
            }
163
            canvas.setLabel(new PropertyValue(media.getTitleCache()));
164
            canvas.setThumbnails(thumbnailImageContents);
165
            for(ImageContent image  : fullSizeImageContents){
166
                canvas.addImage(image);
167
            }
168
            // TODO  if there is only one image canvas.addImage() internally sets the canvas width and height
169
            //      to the height of the image, for multiple images it is required to follow the specification:
170
            //
171
            // IIIF Presentation API 2.1.1:
172
            // It is recommended that if there is (at the time of implementation) a single image that depicts the page,
173
            // then the dimensions of the image are used as the dimensions of the canvas for simplicity. If there are
174
            // multiple full images, then the dimensions of the largest image should be used. If the largest image’s
175
            // dimensions are less than 1200 pixels on either edge, then the canvas’s dimensions should be double those
176
            // of the image.
177

    
178
            // apply hack for accurate thumbnail container aspect ratios see setUseThumbnailDimensionsForCanvas() for an
179
            // explanation
180
            if(useThumbnailDimensionsForCanvas && !thumbnailImageContents.isEmpty()) {
181
                if(thumbnailImageContents.get(0).getHeight() != null && thumbnailImageContents.get(0).getHeight() > 0 && thumbnailImageContents.get(0).getWidth() != null && thumbnailImageContents.get(0).getWidth() > 0) {
182
                    canvas.setHeight(thumbnailImageContents.get(0).getHeight());
183
                    canvas.setWidth(thumbnailImageContents.get(0).getWidth());
184
                }
185
            }
186

    
187
            List<MetadataEntry> mediaMetadata = mediaMetaData(media);
188
            List<MetadataEntry> representationMetadata;
189
            try {
190
                representationMetadata = mediaService.readResourceMetadataFiltered(fullSizeRepresentation)
191
                         .entrySet()
192
                         .stream()
193
                         .map(e -> new MetadataEntry(e.getKey(), e.getValue())).collect(Collectors.toList());
194
                mediaMetadata.addAll(representationMetadata);
195
            } catch (IOException e) {
196
                logger.error("Error reading media metadata", e);
197
            } catch (HttpException e) {
198
                logger.error("Error accessing remote media resource", e);
199
            }
200

    
201
            // extractAndAddDesciptions(canvas, mediaMetadata);
202
            mediaMetadata = deduplicateMetadata(mediaMetadata);
203
            canvas = addAttributionAndLicense(media, canvas, mediaMetadata);
204
            orderMedatadaItems(canvas);
205
            canvas.addMetadata(mediaMetadata.toArray(new MetadataEntry[mediaMetadata.size()]));
206
            canvases.add(canvas);
207
        }
208

    
209
        Sequence sequence = null;
210
        if(canvases.size() > 0) {
211
            sequence = new Sequence(iiifID(onEntitiyType, onEntityUuid, Sequence.class, "default"));
212
            sequence.setViewingDirection(ViewingDirection.LEFT_TO_RIGHT);
213
            sequence.setCanvases(canvases);
214
            sequence.setStartCanvas(canvases.get(0).getIdentifier());
215
        }
216

    
217
        Manifest manifest = new Manifest(iiifID(onEntitiyType, onEntityUuid, Manifest.class, null));
218
        if(sequence != null){
219
            // manifest.setLabel(new PropertyValue("Media for " + onEntitiyType + "[" + onEntityUuid + "]")); // TODO better label!!
220
            manifest.addSequence(sequence);
221
        } else {
222
            manifest.setLabel(new PropertyValue("No media found for " + onEntitiyType + "[" + onEntityUuid + "]")); // TODO better label!!
223
        }
224
        List<MetadataEntry> entityMetadata = entityMetadata(entityMediaContext.getEntity());
225
        manifest.addMetadata(entityMetadata.toArray(new MetadataEntry[entityMetadata.size()]));
226
        copyAttributionAndLicenseToManifest(manifest);
227

    
228
        return manifest;
229
    }
230

    
231
    /**
232
     * Due to limitations in universal viewer it seems not to be able
233
     * to show attribution and licenses, therefore we copy this data to
234
     * also to the metadata
235
     *
236
     * <b>NOTE:</b> This method expects that the canvas attributions and
237
     * licenses are not localized!!!!
238
     *
239
     * @param canvas
240
     */
241
    private void copyAttributionAndLicenseToManifest(Manifest manifest) {
242

    
243
         PropertyValue attributions = new PropertyValue();
244
         List<URI> licenses = new ArrayList<>();
245
         String firstAttributionString = null;
246
         boolean hasAttributions = false;
247
         boolean hasLicenses = false;
248
         boolean hasDiversAttributions = false;
249
         boolean hasDiversLicenses = false;
250
         String firstLicensesString = null;
251

    
252
         if(manifest.getSequences() == null){
253
             // nothing to do, skip!
254
             return;
255
         }
256

    
257
        for (Sequence sequence : manifest.getSequences()) {
258
            for (Canvas canvas : sequence.getCanvases()) {
259
                if (canvas.getAttribution() != null) {
260
                    canvas.getAttribution().getValues().stream().forEachOrdered(val -> attributions.addValue(val));
261
                    String thisAttributionString = canvas.getAttribution().getValues()
262
                                .stream()
263
                                .sorted()
264
                                .collect(Collectors.joining());
265
                    if(firstAttributionString == null){
266
                        firstAttributionString = thisAttributionString;
267
                        hasAttributions = true;
268
                    } else {
269
                        hasDiversAttributions |=  !firstAttributionString.equals(thisAttributionString);
270
                    }
271
                }
272
                if (canvas.getLicenses() != null && canvas.getLicenses().size() > 0) {
273
                    licenses.addAll(canvas.getLicenses());
274
                    String thisLicensesString = canvas.getLicenses()
275
                                .stream()
276
                                .map(URI::toString)
277
                                .sorted()
278
                                .collect(Collectors.joining());
279
                    if(firstLicensesString == null){
280
                        firstLicensesString = thisLicensesString;
281
                        hasLicenses = true;
282
                    } else {
283
                        hasDiversLicenses |=  !firstLicensesString.equals(thisLicensesString);
284
                    }
285
                }
286
            }
287
        }
288
        String diversityInfo = "";
289

    
290
        if(hasAttributions || hasLicenses){
291
            String dataTypes ;
292
            if(hasAttributions && hasLicenses) {
293
                dataTypes = "attributions and licenses";
294
            } else if(hasAttributions){
295
                dataTypes = "attributions";
296
            } else {
297
                dataTypes = "licenses";
298
            }
299
            if(hasDiversAttributions || hasDiversLicenses){
300
                diversityInfo = "Individual " + dataTypes + " per Item:";
301
            } else {
302
                diversityInfo = "Same " + dataTypes + " for any Item:";
303
            }
304
            if(hasAttributions){
305
                List<String> attrs = new ArrayList<>(attributions.getValues());
306
                attrs = attrs.stream().sorted().distinct().collect(Collectors.toList());
307
                if(doJoinAttributions){
308
                    attrs.add(0, diversityInfo + "<br/>" + attrs.get(0));
309
                    attrs.remove(1);
310
                    manifest.addAttribution(attrs.stream()
311
                            .sorted()
312
                            .distinct()
313
                            .collect(Collectors.joining("; ")));
314
                } else {
315
                    manifest.addAttribution(diversityInfo, attrs.toArray(
316
                            new String[attributions.getValues().size()]
317
                            ));
318
                }
319
            }
320
            licenses.stream()
321
                .map(URI::toString)
322
                .sorted()
323
                .distinct()
324
                .forEachOrdered(l -> manifest.addLicense(l));
325
        }
326
    }
327

    
328
    private void orderMedatadaItems(Canvas canvas) {
329
        // TODO Auto-generated method stub
330
        // order by label name, Title, description, author, license, attribution should come first.
331
    }
332

    
333
    private List<MetadataEntry> deduplicateMetadata(List<MetadataEntry> mediaMetadata) {
334
        Map<String, MetadataEntry> dedupMap = new HashMap<>();
335
        mediaMetadata.stream().forEach(mde -> {
336
                String dedupKey = mde.getLabelString() + ":" + mde.getValueString();
337
                dedupMap.put(dedupKey, mde);
338
            }
339
        );
340
        return new ArrayList<>(dedupMap.values());
341
    }
342

    
343
    private void extractAndAddDesciptions(Resource resource, List<MetadataEntry> mediaMetadata) {
344
        List<MetadataEntry> descriptions = mediaMetadata.stream()
345
            .filter(mde -> mde.getLabelString().toLowerCase().matches(".*description.*|.*caption.*"))
346
            .collect(Collectors.toList());
347
        mediaMetadata.removeAll(descriptions);
348
        // FIXME deduplicate mde.getValueString()
349
        // descriptions.sream ...
350
        descriptions.stream().forEach(mde -> resource.addDescription(mde.getValueString()));
351
    }
352

    
353
    private <T extends IdentifiableEntity> List<MetadataEntry> entityMetadata(T entity) {
354

    
355
        List<MetadataEntry> metadata = new ArrayList<>();
356
        if(entity instanceof TaxonBase){
357
            List taggedTitle = ((TaxonBase)entity).getTaggedTitle();
358
            if(taggedTitle != null){
359
                //FIXME taggedTitel to HTML!!!!
360
                metadata.add(new MetadataEntry(entity.getClass().getSimpleName(), TaggedCacheHelper.createString(taggedTitle)));
361
            }
362
        } else {
363
            String titleCache = entity.getTitleCache();
364
            if(titleCache != null){
365
                metadata.add(new MetadataEntry(entity.getClass().getSimpleName(), titleCache));
366
            }
367
        }
368

    
369
        return metadata;
370
    }
371

    
372
    /**
373
     * @deprecated unused as media metadata is now read via the mediaService, see
374
     */
375
    @Deprecated
376
    private List<MetadataEntry> mediaRepresentationMetaData(MediaRepresentation representation) {
377

    
378
        List<MetadataEntry> metadata = new ArrayList<>();
379
        boolean needsPrefix = representation.getParts().size() > 1;
380
        int partIndex = 1;
381

    
382
        for (MediaRepresentationPart part : representation.getParts()) {
383
            String prefix = "";
384
            if (needsPrefix) {
385
                prefix = "Part" + partIndex + " ";
386
            }
387
            if (part.getUri() != null) {
388
                try {
389
                    CdmImageInfo cdmImageInfo = CdmImageInfo.NewInstanceWithMetaData(part.getUri(), MediaServiceImpl.IMAGE_READ_TIMEOUT);
390
                    Map<String, String> result = cdmImageInfo.getMetaData();
391
                    if(result != null){
392
                        for (String key : result.keySet()) {
393
                            metadata.add(new MetadataEntry(key, result.get(key)));
394
                        }
395
                    }
396
                } catch (IOException | HttpException e) {
397
                    logger.error("Problem while loading image metadata", e);
398
                    metadata.add(new MetadataEntry(prefix + " Error:", "Problem while loading image metadata <br/><small>(" + e.getLocalizedMessage() + ")</small>"));
399
                }
400
            }
401
        }
402

    
403
        return metadata;
404
  }
405

    
406
    private List<MetadataEntry> mediaMetaData(Media media) {
407
        List<MetadataEntry> metadata = new ArrayList<>();
408
        List<Language> languages = LocaleContext.getLanguages();
409

    
410

    
411
        if(media.getTitle() != null){
412
            // TODO get localized titleCache
413
            metadata.add(new MetadataEntry("Title", media.getTitleCache()));
414
        }
415
        if(media.getArtist() != null){
416
            metadata.add(new MetadataEntry("Artist", media.getArtist().getTitleCache()));
417
        }
418
        if(media.getAllDescriptions().size() > 0){
419
            // TODO get localized description
420
            PropertyValue descriptionValues = new PropertyValue();
421
            for(LanguageString description : media.getAllDescriptions().values()){
422
                descriptionValues.addValue(description.getText());
423
            }
424
            metadata.add(new MetadataEntry(new PropertyValue("Description"), descriptionValues));
425
        }
426
        if(media.getMediaCreated() != null){
427
            metadata.add(new MetadataEntry("Created on", media.getMediaCreated().toString())); // TODO is this correct to string conversion?
428
        }
429
        return metadata;
430
    }
431

    
432
    private <T extends Resource<T>> T addAttributionAndLicense(IdentifiableEntity<?> entity, T resource, List<MetadataEntry> metadata) {
433

    
434
        List<Language> languages = LocaleContext.getLanguages();
435

    
436
        List<String> rightsTexts = new ArrayList<>();
437
        List<String> creditTexts = new ArrayList<>();
438
        List<URI> license = new ArrayList<>();
439

    
440
        if(entity.getRights() != null && entity.getRights().size() > 0){
441
            for(Rights right : entity.getRights()){
442
                String rightText = "";
443
                // TODO get localized texts below
444
                // --- LICENSE
445
                if(right.getType().equals(RightsType.LICENSE())){
446
                    String licenseText = "";
447
                    String licenseAbbrev = "";
448
                    if(right.getText() != null){
449
                        licenseText = right.getText();
450
                    }
451
                    if(right.getAbbreviatedText() != null){
452
                        licenseAbbrev = right.getAbbreviatedText().trim();
453
                    }
454
                    if(right.getUri() != null){
455
                        if(!licenseAbbrev.isEmpty()) {
456
                            licenseAbbrev =  htmlLink(right.getUri(), licenseAbbrev);
457
                        } else if(!licenseText.isEmpty()) {
458
                            licenseText =  htmlLink(right.getUri(), licenseText);
459
                        } else {
460
                            licenseText =  htmlLink(right.getUri(), right.getUri().toString());
461
                        }
462
                        license.add(right.getUri());
463
                    }
464
                    rightText = licenseAbbrev + (licenseText.isEmpty() ? "" : " ") + licenseText;
465
                }
466
                // --- COPYRIGHT
467
                if(right.getType().equals(RightsType.COPYRIGHT())){
468
                    // titleCache + agent
469
                    String copyRightText = "";
470
                    if(right.getText() != null){
471
                        copyRightText = right.getText();
472
                        //  sanitize potential '(c)' away
473
                        copyRightText = copyRightText.replace("(c)", "").trim();
474
                    }
475
                    if(right.getAgent() != null){
476
                        // may only apply to RightsType.accessRights
477
                        copyRightText += " " + right.getAgent().getTitleCache();
478
                    }
479
                    if(!copyRightText.isEmpty()){
480
                        copyRightText = "© " + copyRightText;
481
                    }
482
                    rightText = copyRightText;
483
                }
484
                if(right.getType().equals(RightsType.ACCESS_RIGHTS())){
485
                    // titleCache + agent
486
                    String accessRights = right.getText();
487
                    if(right.getAgent() != null){
488
                        // may only apply to RightsType.accessRights
489
                        accessRights = " " + right.getAgent().getTitleCache();
490
                    }
491
                    rightText = accessRights;
492
                }
493
                if(!rightText.isEmpty()){
494
                    rightsTexts.add(rightText);
495
                }
496
            }
497
        }
498
        if(entity.getCredits() != null && entity.getCredits().size() > 0){
499
            for(Credit credit : entity.getCredits()){
500
                String creditText = "";
501
                if(credit.getText() != null){
502
                    creditText += credit.getText();
503
                }
504
                if(creditText.isEmpty() && credit.getAbbreviatedText() != null){
505
                    creditText += credit.getAbbreviatedText();
506
                }
507
                if(credit.getAgent() != null){
508
                    // may only apply to RightsType.accessRights
509
                    creditText += " " + credit.getAgent().getTitleCache();
510
                }
511
                creditTexts.add(creditText);
512
            }
513
        }
514

    
515
        if(rightsTexts.size() > 0){
516
            String joinedRights = rightsTexts.stream().collect(Collectors.joining(", "));
517
            resource.addAttribution(joinedRights);
518
            if(metadata != null){
519
                metadata.add(new MetadataEntry(new PropertyValue("Copyright"), new PropertyValue(joinedRights)));
520
            }
521
        }
522
        if(creditTexts.size() > 0){
523
            String joinedCredits = creditTexts.stream().collect(Collectors.joining(", "));
524
            resource.addAttribution(joinedCredits);
525
            if(metadata != null){
526
                metadata.add(new MetadataEntry(new PropertyValue("Credit"), new PropertyValue(joinedCredits)));
527
            }
528
        }
529
        resource.setLicenses(license);
530
        return resource;
531
    }
532

    
533
    private String htmlLink(URI uri, String text) {
534
        return String.format(" <a href=\"%s\">%s</a>", uri, text);
535
    }
536

    
537
    private List<ImageContent> representationPartsToImageContent(MediaRepresentation representation) {
538
        List<ImageContent> imageContents = new ArrayList<>();
539
        for(MediaRepresentationPart part : representation.getParts()){
540
            if(part.getUri() != null){
541
                ImageContent ic = new ImageContent(part.getUri().toString());
542
                if(part instanceof ImageFile){
543
                    ImageFile image = (ImageFile)part;
544
                    if(image.getWidth() != null && image.getWidth() > 0){
545
                        ic.setWidth(image.getWidth());
546
                    }
547
                    if(image.getHeight() != null && image.getHeight() > 0){
548
                        ic.setHeight(image.getHeight());
549
                    }
550
                    if(representation.getMimeType() != null){
551
                        ic.setFormat(MimeType.fromTypename(representation.getMimeType()));
552
                    } else {
553
                        ic.setFormat(MimeType.MIME_IMAGE);
554
                    }
555
                }
556
                imageContents.add(ic);
557
            }
558
        }
559
        return imageContents;
560
    }
561

    
562
    private String iiifID(String onEntitiyType, String onEntityUuid, Class<? extends Resource> iiifType, Object index) {
563
        String indexPart = "";
564
        if(index != null){
565
            indexPart = "/" + index.toString();
566
        }
567
        return this.iiifIdPrefix + onEntitiyType + "/" + onEntityUuid + "/" + iiifType.getSimpleName().toLowerCase() + indexPart;
568
    }
569

    
570
}
(1-1/2)