MediaUtil.java
/*
* Copyright (C) 2000 - 2024 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.silverpeas.components.gallery;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.io.FileUtils;
import org.silverpeas.components.gallery.constant.MediaMimeType;
import org.silverpeas.components.gallery.constant.MediaResolution;
import org.silverpeas.components.gallery.constant.MediaType;
import org.silverpeas.components.gallery.media.DrewMediaMetadataExtractor;
import org.silverpeas.components.gallery.media.MediaMetadataException;
import org.silverpeas.components.gallery.media.MediaMetadataExtractor;
import org.silverpeas.components.gallery.model.GalleryRuntimeException;
import org.silverpeas.components.gallery.model.InternalMedia;
import org.silverpeas.components.gallery.model.Media;
import org.silverpeas.components.gallery.model.MediaPK;
import org.silverpeas.components.gallery.model.MetaData;
import org.silverpeas.components.gallery.model.Photo;
import org.silverpeas.components.gallery.model.Sound;
import org.silverpeas.components.gallery.model.Video;
import org.silverpeas.core.io.media.Definition;
import org.silverpeas.core.io.media.MetadataExtractor;
import org.silverpeas.core.io.media.image.ImageTool;
import org.silverpeas.core.io.media.image.option.AbstractImageToolOption;
import org.silverpeas.core.io.media.image.option.AnchoringPosition;
import org.silverpeas.core.io.media.image.option.DimensionOption;
import org.silverpeas.core.io.media.image.option.OrientationOption;
import org.silverpeas.core.io.media.image.option.WatermarkImageOption;
import org.silverpeas.core.io.media.image.option.WatermarkTextOption;
import org.silverpeas.core.io.media.video.VideoThumbnailExtractor;
import org.silverpeas.core.notification.message.MessageManager;
import org.silverpeas.core.process.io.file.FileHandler;
import org.silverpeas.core.process.io.file.HandledFile;
import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.core.util.file.FileUtil;
import org.silverpeas.kernel.logging.SilverLogger;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import static org.apache.commons.io.FilenameUtils.getExtension;
import static org.apache.commons.io.filefilter.FileFilterUtils.*;
import static org.silverpeas.components.gallery.constant.MediaResolution.*;
import static org.silverpeas.core.io.media.image.ImageInfoType.HEIGHT_IN_PIXEL;
import static org.silverpeas.core.io.media.image.ImageInfoType.WIDTH_IN_PIXEL;
import static org.silverpeas.core.io.media.image.ImageToolDirective.GEOMETRY_SHRINK;
import static org.silverpeas.core.io.media.image.ImageToolDirective.PREVIEW_WORK;
import static org.silverpeas.core.io.media.video.ThumbnailPeriod.VIDEO_THUMBNAIL_FILE_EXTENSION;
import static org.silverpeas.core.io.media.video.ThumbnailPeriod.VIDEO_THUMBNAIL_FILE_PREFIX;
import static org.silverpeas.kernel.util.StringUtil.defaultStringIfNotDefined;
import static org.silverpeas.kernel.util.StringUtil.isDefined;
public class MediaUtil {
private MediaUtil() {
}
private static void pasteFile(final HandledFile fromFile, final HandledFile toFile,
final boolean cut) {
if (fromFile.exists()) {
try {
if (cut) {
fromFile.moveFile(toFile);
} else {
fromFile.copyFile(toFile);
}
} catch (final Exception e) {
SilverLogger.getLogger(MediaUtil.class).error(
"Unable to copy file : fromImage = " + fromFile.getFile().getPath() + ", toImage = " +
toFile.getFile().getPath(), e);
}
}
}
/**
* Gets a handled file.
* @param fileHandler the current session file handler
* @param media the original media file to get.
* @return the handled file
*/
private static HandledFile getHandledFile(FileHandler fileHandler, InternalMedia media) {
if (StringUtil.isNotDefined(media.getFileName())) {
throw new IllegalArgumentException("media.getFilename() must return a defined name");
}
return fileHandler.getHandledFile(Media.BASE_PATH, media.getComponentInstanceId(),
media.getWorkspaceSubFolderName(), media.getFileName());
}
private static void setMetaData(final FileHandler fileHandler, final Photo photo,
final String lang) throws MediaMetadataException, IOException {
if (MediaMimeType.JPG == photo.getFileMimeType()) {
final HandledFile handledFile = fileHandler
.getHandledFile(Media.BASE_PATH, photo.getInstanceId(), photo.getWorkspaceSubFolderName(),
photo.getFileName());
if (handledFile.exists()) {
try {
final MediaMetadataExtractor extractor = new DrewMediaMetadataExtractor(photo.
getInstanceId());
extractor.extractImageExifMetaData(handledFile.getFile(), lang)
.forEach(photo::addMetaData);
extractor.extractImageIptcMetaData(handledFile.getFile(), lang)
.forEach(photo::addMetaData);
} catch (UnsupportedEncodingException e) {
SilverLogger.getLogger(MediaUtil.class).silent(e)
.error("Bad metadata encoding in image " + photo.getTitle() + ": " + e.getMessage());
}
}
}
}
/**
* Saves uploaded sound file on file system
* @param fileHandler the current session file handler
* @param sound the current sound media
* @param fileItem the current uploaded sound
* @throws Exception
*/
public static synchronized void processSound(final FileHandler fileHandler, Sound sound,
final FileItem fileItem) throws Exception {
if (fileItem != null) {
String name = fileItem.getName();
if (name != null) {
try {
sound.setFileName(StringUtil.normalize(FileUtil.getFilename(name)));
final HandledFile handledSoundFile = getHandledFile(fileHandler, sound);
handledSoundFile.copyInputStreamToFile(fileItem.getInputStream());
new SoundProcess(handledSoundFile, sound).process();
} finally {
fileItem.delete();
}
}
}
}
/**
* Saves uploaded sound file on file system (In case of drag And Drop upload)
* @param fileHandler the current session file handler
* @param sound the current sound media
* @param uploadedFile the current uploaded sound
* @throws Exception
*/
public static synchronized void processSound(final FileHandler fileHandler, Sound sound,
final File uploadedFile) throws Exception {
if (uploadedFile != null) {
try {
sound.setFileName(StringUtil.normalize(uploadedFile.getName()));
final HandledFile handledSoundFile = getHandledFile(fileHandler, sound);
fileHandler.copyFile(uploadedFile, handledSoundFile);
new SoundProcess(handledSoundFile, sound).process();
} finally {
FileUtils.deleteQuietly(uploadedFile);
}
}
}
/**
* Saves uploaded video file on file system
* @param fileHandler the current session file handler
* @param video the current video media
* @param fileItem the current uploaded video
* @throws Exception
*/
public static synchronized void processVideo(final FileHandler fileHandler, Video video,
final FileItem fileItem) throws Exception {
if (fileItem != null) {
String name = fileItem.getName();
if (name != null) {
try {
video.setFileName(StringUtil.normalize(FileUtil.getFilename(name)));
final HandledFile handledVideoFile = getHandledFile(fileHandler, video);
handledVideoFile.copyInputStreamToFile(fileItem.getInputStream());
new VideoProcess(handledVideoFile, video).process();
} finally {
fileItem.delete();
}
}
}
}
/**
* Saves uploaded video file on file system (In case of drag And Drop upload)
* @param fileHandler the current session file handler
* @param video the current video media
* @param uploadedFile the current uploaded video
* @throws Exception
*/
public static synchronized void processVideo(final FileHandler fileHandler, Video video,
final File uploadedFile) throws Exception {
if (uploadedFile != null) {
try {
video.setFileName(StringUtil.normalize(uploadedFile.getName()));
final HandledFile handledVideoFile = getHandledFile(fileHandler, video);
fileHandler.copyFile(uploadedFile, handledVideoFile);
new VideoProcess(handledVideoFile, video).process();
} finally {
FileUtils.deleteQuietly(uploadedFile);
}
}
}
/**
* Saves uploaded photo file on file system with associated thumbnails and watermarks.
* @param fileHandler the current session file handler
* @param photo the photo media
* @param image the image to register
* @param watermark if watermark must be handled, the data are represented by this
* {@link Watermark} instance.
* @throws Exception on technical error.
*/
public static synchronized void processPhoto(final FileHandler fileHandler, final Photo photo,
final FileItem image, final Watermark watermark) throws Exception {
if (image != null) {
String name = image.getName();
if (name != null) {
try {
photo.setFileName(StringUtil.normalize(image.getName()));
final HandledFile handledImageFile = getHandledFile(fileHandler, photo);
handledImageFile.copyInputStreamToFile(image.getInputStream());
new PhotoProcess(handledImageFile, photo, watermark).process();
} finally {
image.delete();
}
}
}
}
/**
* Saves uploaded photo file on file system with associated thumbnails and watermarks. (In case
* of
* drag And Drop upload)
* @param fileHandler the current session file handler
* @param photo the photo media
* @param image the image to register
* @param watermark if watermark must be handled, the data are represented by this
* {@link Watermark} instance.
* @throws Exception on technical error.
*/
public static synchronized void processPhoto(final FileHandler fileHandler, final Photo photo,
final File image, final Watermark watermark) throws Exception {
if (image != null) {
try {
photo.setFileName(StringUtil.normalize(image.getName()));
final HandledFile handledImageFile = getHandledFile(fileHandler, photo);
fileHandler.copyFile(image, handledImageFile);
new PhotoProcess(handledImageFile, photo, watermark).process();
} finally {
FileUtils.deleteQuietly(image);
}
}
}
/**
* Pastes media from a source to a destination.
* @param fileHandler the file handler (space quota management).
* @param fromPK the source.
* @param media the destination.
* @param cut true if it is a cut operation, false if it is a copy one.
*/
public static synchronized void pasteInternalMedia(final FileHandler fileHandler,
final MediaPK fromPK, final InternalMedia media, final boolean cut) {
InternalMedia fromMedia = media.getType().newInstance();
fromMedia.setMediaPK(fromPK);
fromMedia.setFileName(media.getFileName());
final HandledFile fromDir = getHandledFile(fileHandler, fromMedia).getParentHandledFile();
final HandledFile toDir = getHandledFile(fileHandler, media).getParentHandledFile();
// Copy and rename all media that exist into source folder
if (fromDir.exists()) {
// Copy all files which the name starts with the media identifier
Collection<HandledFile> srcFiles =
fromDir.listFiles(
or(
prefixFileFilter(fromPK.getId()),
asFileFilter(file -> file.getName().matches(
"^" + VIDEO_THUMBNAIL_FILE_PREFIX + "[0-9]+" +
VIDEO_THUMBNAIL_FILE_EXTENSION + "$"))
),
falseFileFilter());
int substringIndex = fromPK.getId().length();
for (HandledFile srcFile : srcFiles) {
String srcFileName = srcFile.getFile().getName();
String dstFileName = (srcFileName.startsWith(fromPK.getId())) ?
(media.getId() + srcFileName.substring(substringIndex)) : srcFileName;
pasteFile(srcFile, toDir.getHandledFile(dstFileName), cut);
}
// Copy original image
pasteFile(fromDir.getHandledFile(media.getFileName()), toDir.getHandledFile(media.
getFileName()), cut);
// On cut operation, deleting the source repo
if (cut && !fromPK.getInstanceId().equals(media.getInstanceId())) {
try {
fromDir.delete();
} catch (Exception e) {
SilverLogger.getLogger(MediaUtil.class).error(
"Unable to delete source folder : folder path = " + fromDir.getFile().getPath(), e);
}
}
}
}
/**
* Sets metadata to given instance which represents a photo in memory.
* @param fileHandler the file handler (quota space management).
* @param photo the photo to set.
* @throws IOException
* @throws MediaMetadataException
*/
public static void setMetaData(final FileHandler fileHandler, final Photo photo)
throws MediaMetadataException {
try {
setMetaData(fileHandler, photo, MessageManager.getLanguage());
} catch (IOException e) {
throw new MediaMetadataException(e);
}
}
/**
* In charge of processing an internal media.
* @param <M>
*/
private abstract static class MediaProcess<M extends InternalMedia> {
private final HandledFile handledFile;
private final M media;
private final Set<MediaMimeType> supportedMimeTypes;
private MediaMimeType physicalFileMimeType = null;
private org.silverpeas.core.io.media.MetaData physicalFileMetaData = null;
private MediaProcess(final HandledFile handledFile, final M media) {
this.handledFile = handledFile;
this.media = media;
this.supportedMimeTypes = MediaMimeType.getSupportedMimeTypes(media.getType());
}
/**
* Processes the media files.
* @throws Exception
*/
public void process() throws Exception {
setInternalMetadata();
generateFiles();
}
/**
* Generates specific media files.
* @throws Exception
*/
protected abstract void generateFiles();
/**
* Sets the internal metadata. If metadata
* @return true if internal data have been set, false otherwise.
* @throws GalleryRuntimeException if no supported mime type.
*/
private void setInternalMetadata() throws Exception {
File fileForData = getHandledFile().getFile();
MediaMimeType mediaMimeType = getPhysicalFileMimeType();
if (supportedMimeTypes.contains(mediaMimeType)) {
getMedia().setFileName(fileForData.getName());
getMedia().setFileMimeType(mediaMimeType);
getMedia().setFileSize(fileForData.length());
final MediaType mediaType = getMedia().getType();
if (mediaType.isPhoto()) {
getMedia().getPhoto().setDefinition(getPhysicalFileMetaData().getDefinition());
} else if (mediaType.isVideo()) {
getMedia().getVideo().setDefinition(getPhysicalFileMetaData().getDefinition());
}
if (getPhysicalFileMetaData().getDuration() != null) {
if (mediaType.isVideo()) {
getMedia().getVideo()
.setDuration(getPhysicalFileMetaData().getDuration().getTimeAsLong());
} else if (mediaType.isSound()) {
getMedia().getSound()
.setDuration(getPhysicalFileMetaData().getDuration().getTimeAsLong());
}
}
if (StringUtil.isNotDefined(getMedia().getTitle()) &&
isDefined(getPhysicalFileMetaData().getTitle())) {
getMedia().setTitle(getPhysicalFileMetaData().getTitle());
}
} else {
getMedia().setFileName(null);
try {
throw new GalleryRuntimeException(
"Mime-Type of " + fileForData.getName() + " is not supported (" +
FileUtil.getMimeType(fileForData.getPath()) + ")");
} finally {
getHandledFile().delete();
}
}
}
/**
* Gets the meta data of the physical file.
* @return meta data.
*/
org.silverpeas.core.io.media.MetaData getPhysicalFileMetaData() {
if (physicalFileMetaData == null) {
physicalFileMetaData = MetadataExtractor.get().extractMetadata(getHandledFile().getFile());
}
return physicalFileMetaData;
}
/**
* Gets lazily the mime type from the physical file which represents the media file.
* @return the mime type of the physical file.
*/
private MediaMimeType getPhysicalFileMimeType() {
if (physicalFileMimeType == null) {
physicalFileMimeType = MediaMimeType.fromFile(getHandledFile().getFile());
}
return physicalFileMimeType;
}
/**
* Gets the handled physical file.
* @return
*/
HandledFile getHandledFile() {
return handledFile;
}
/**
* Gets the representation of the handled media.
* @return the media instance.
*/
public M getMedia() {
return media;
}
}
private static class SoundProcess extends MediaProcess<Sound> {
private SoundProcess(final HandledFile handledFile, final Sound media) {
super(handledFile, media);
}
@Override
protected void generateFiles() {
// No generation.
}
}
private static class VideoProcess extends MediaProcess<Video> {
private VideoProcess(final HandledFile handledFile, final Video media) {
super(handledFile, media);
}
@Override
protected void generateFiles() {
VideoThumbnailExtractor vte = VideoThumbnailExtractor.get();
if (vte.isActivated()) {
vte.generateThumbnailsFrom(getPhysicalFileMetaData(), super.getHandledFile().getFile());
}
}
}
private static class PhotoProcess extends MediaProcess<Photo> {
private Set<AbstractImageToolOption> watermarkNormalOptions = Collections.emptySet();
private Set<AbstractImageToolOption> watermarkThumbnailOptions = Collections.emptySet();
private HandledFile[] thumbnailSrc = new HandledFile[2];
private List<MetaData> cachedIptcMetadata = null;
private PhotoProcess(final HandledFile handledFile, final Photo photo,
final Watermark watermark) {
super(handledFile, photo);
computeWatermarks(watermark);
}
private static ImageTool getImageTool() {
return ImageTool.get();
}
@Override
protected void generateFiles() {
final Photo photo = getMedia();
if (photo.isPreviewable()) {
// Registering the size of the image
registerResolutionData();
// Creating normal pictures (normal and watermark)
createNormals(photo);
// Creating preview and thumbnails
try {
createThumbnails();
} catch (final Exception e) {
SilverLogger.getLogger(MediaUtil.class)
.error("image = " + photo.getTitle() + " (#" + photo.getId() + ")", e);
}
}
}
/**
* Registers the resolution of a photo.
*/
private void registerResolutionData() {
if (getMedia().getDefinition().getWidth() != 0 &&
getMedia().getDefinition().getHeight() != 0) {
// definition already set.
return;
}
String[] widthAndHeight = null;
try {
widthAndHeight = getImageTool().getImageInfo(super.getHandledFile().getFile(),
WIDTH_IN_PIXEL, HEIGHT_IN_PIXEL);
} catch (Exception e) {
SilverLogger.getLogger(this)
.error("impossible to read the width and height of file ''{0}''",
new Object[]{super.getHandledFile().getFile().getName()}, e);
}
final int widthAndHeightSize = 2;
if (widthAndHeight == null || widthAndHeight.length != widthAndHeightSize) {
getMedia().setDefinition(Definition.fromZero());
} else {
getMedia().setDefinition(
Definition.of(Integer.valueOf(widthAndHeight[0]), Integer.valueOf(widthAndHeight[1])));
}
}
/**
* Creates all the thumbnails around a photo.
* @throws Exception on technical error.
*/
private void createThumbnails() throws Exception {
Photo photo = getMedia();
// File name
final String photoId = photo.getId();
// Processing order :
// Large (preview without watermark)
// Preview
// Medium
// Small
// Tiny
final MediaResolution[] mediaResolutions =
new MediaResolution[]{LARGE, PREVIEW, MEDIUM, SMALL, TINY};
final HandledFile originalFile = super.getHandledFile();
final HandledFile[] sources = Stream.of(thumbnailSrc).toArray(HandledFile[]::new);
final String originalFileExt = "." + getExtension(photo.getFileName());
for (MediaResolution mediaResolution : mediaResolutions) {
final boolean watermarkApplicable = mediaResolution.isWatermarkApplicable();
final int index = watermarkApplicable && thumbnailSrc[1] != null ? 1 : 0;
final HandledFile currentThumbnail = originalFile.getParentHandledFile()
.getHandledFile(photoId + mediaResolution.getThumbnailSuffix() + originalFileExt);
generateThumbnail(thumbnailSrc[index], currentThumbnail, mediaResolution);
// The first thumbnail that has to be created must be the larger one and without watermark.
// This first thumbnail is cached and reused for the following thumbnail creation.
if (sources[index] == thumbnailSrc[index]) {
thumbnailSrc[index] = currentThumbnail;
}
}
if (sources[1] != null) {
sources[1].delete();
}
}
/**
* Return the written file
* @param sourceFile
* @param outputFile
* @param mediaResolution
* @throws Exception
*/
private void generateThumbnail(final HandledFile sourceFile, final HandledFile outputFile,
MediaResolution mediaResolution) throws Exception {
final boolean watermarkToApply =
mediaResolution.isWatermarkApplicable() && !watermarkThumbnailOptions.isEmpty();
final Definition definition = getMedia().getDefinition();
final boolean resizeToPerform = definition.getWidth() > mediaResolution.getWidth() ||
definition.getHeight() > mediaResolution.getHeight();
if (!resizeToPerform && !watermarkToApply) {
// Simple copy
sourceFile.copyFile(outputFile);
return;
}
// Optimized media processing
final Set<AbstractImageToolOption> options = new HashSet<>();
options.add(OrientationOption.auto());
if (resizeToPerform) {
options.add(DimensionOption
.widthAndHeight(mediaResolution.getWidth(), mediaResolution.getHeight()));
}
getImageTool().convert(sourceFile.getFile(), outputFile.getFile(), options, PREVIEW_WORK,
GEOMETRY_SHRINK);
}
private void computeWatermarks(Watermark watermark) {
String wText = null;
File wImage = null;
String thumbnailWText = null;
File thumbnailWImage = null;
final Photo photo = getMedia();
if (watermark != null && watermark.isEnabled()) {
try {
wText = defaultStringIfNotDefined(
getIptcWatermarkValue(watermark, photo, watermark.getIPTCPropertyForHD()),
watermark.getTextForHD());
wImage = watermark.getImageForHD();
if (watermark.isDefinedForThumbnails()) {
thumbnailWText = defaultStringIfNotDefined(
getIptcWatermarkValue(watermark, photo, watermark.getIPTCPropertyForThumbnails()),
watermark.getTextForThumbnails());
thumbnailWImage = watermark.getImageForThumbnails();
}
} catch (MediaMetadataException e) {
SilverLogger.getLogger(MediaUtil.class).silent(e).error(
"Bad image file format " + super.getHandledFile().getFile().getPath() + ": " +
e.getMessage());
} catch (IOException e) {
SilverLogger.getLogger(MediaUtil.class).silent(e).error(
"Bad metadata encoding in image " + super.getHandledFile().getFile().getPath() +
": " + e.getMessage());
}
}
watermarkNormalOptions = computeWatermarkOptions(wText, wImage);
watermarkThumbnailOptions = computeWatermarkOptions(thumbnailWText, thumbnailWImage);
}
private void createNormals(final Photo photo) {
final String originalFileExt = "." + getExtension(photo.getFileName());
// Normal duplication (for orientation)
final HandledFile normalFile = super.getHandledFile()
.getParentHandledFile()
.getHandledFile(photo.getId() + "_normal" + originalFileExt);
getImageTool().convert(super.getHandledFile().getFile(), normalFile.getFile(),
OrientationOption.auto());
thumbnailSrc[0] = normalFile;
// Photo duplication that is stamped with a Watermark.
if (!watermarkNormalOptions.isEmpty()) {
final HandledFile watermarkFile = super.getHandledFile()
.getParentHandledFile()
.getHandledFile(photo.getId() + "_watermark" + originalFileExt);
getImageTool().convert(super.getHandledFile().getFile(), watermarkFile.getFile(),
watermarkNormalOptions);
}
if (!watermarkThumbnailOptions.isEmpty()) {
final HandledFile watermarkFileForThumbnails = super.getHandledFile().getParentHandledFile()
.getHandledFile(photo.getId() + "_watermark_for_thumbnails" + originalFileExt);
getImageTool()
.convert(super.getHandledFile().getFile(), watermarkFileForThumbnails.getFile(),
watermarkThumbnailOptions);
thumbnailSrc[1] = watermarkFileForThumbnails;
}
}
private Set<AbstractImageToolOption> computeWatermarkOptions(final String textToWatermark,
final File imageToWatermark) {
final Set<AbstractImageToolOption> options = new HashSet<>();
if (isDefined(textToWatermark)) {
final WatermarkTextOption wText = WatermarkTextOption.text(textToWatermark);
if (imageToWatermark != null) {
wText.withAnchoringPosition(AnchoringPosition.SOUTH_WEST);
}
options.add(wText);
}
if (imageToWatermark != null) {
options.add(WatermarkImageOption.image(imageToWatermark));
}
if (!options.isEmpty()) {
options.add(OrientationOption.auto());
}
return options;
}
/**
* Gets lazily the IPTC data from a photo.
* @return
* @throws MediaMetadataException
* @throws IOException
*/
private List<MetaData> getIptcMetaData() throws MediaMetadataException, IOException {
if (cachedIptcMetadata == null) {
final MediaMetadataExtractor extractor =
new DrewMediaMetadataExtractor(getMedia().getInstanceId());
cachedIptcMetadata = extractor.extractImageIptcMetaData(super.getHandledFile().getFile());
}
return cachedIptcMetadata;
}
private String getIptcWatermarkValue(final Watermark watermark, final Photo photo,
final String property)
throws MediaMetadataException, IOException {
String value = null;
if (watermark.isBasedOnIPTC() && photo.getFileMimeType().isIPTCCompliant()) {
value = getIptcMetaData().stream()
.filter(i -> property.equalsIgnoreCase(i.getProperty()))
.map(MetaData::getValue)
.findFirst()
.orElse(null);
}
return value;
}
}
}