diff --git a/install/cope/README.md b/install/cope/README.md
new file mode 100644
index 0000000..c4abb5d
--- /dev/null
+++ b/install/cope/README.md
@@ -0,0 +1,50 @@
+
+# COPE scripts
+
+## EIP extraction
+
+The script `eip_prepare_for_cope.py` extracts EIP files in a source directory to a target directory. It renames a specific subdirectory (`CaptureOne/Settings153` to `CaptureOne/Settings131`) and moves the EIP files into the `_raw` image directory.
+
+## Usage
+
+```
+usage: eip_prepare_for_cope.py [-h] -s SOURCE -t TARGET
+
+options:
+ -h, --help show this help message and exit
+ -s SOURCE, --source SOURCE
+ Source directory
+ -t TARGET, --target TARGET
+ Target directory
+```
+
+in Goobi workflow this can be integrated in a script step like this:
+
+```shell
+/opt/digiverso/goobi/scripts/eip_prepare_for_cope.py -s {origpath} -t {origpath}
+```
+
+## COPE conversion
+
+The script `cope_folder.py` converts IIQ files from the source directory and uses COPE to convert them to tiff files located in the target directory. Optionally the given resolution value will be used.
+
+## Usage
+
+```
+usage: cope_folder.py [-h] -s SOURCE -t TARGET [-r RESOLUTION]
+
+options:
+ -h, --help show this help message and exit
+ -s SOURCE, --source SOURCE
+ -t TARGET, --target TARGET
+ -r RESOLUTION, --resolution RESOLUTION
+```
+
+The path to the cope binary can be given by an environment variable named `COPE_PATH`.
+
+In Goobi workflow a script step in the external queue can be used to run the script on a Windows workernode like this:
+
+```CMD
+C:\Windows\py.exe D:\intranda\cope_folder.py -s "//mediaSMB-isilonArchive/GoobiMetadata/{s3_origpath}" -t "//mediaSMB-isilonArchive/GoobiMetadata/{s3_origpath}" -r "{process.File Resolution}"
+```
+
diff --git a/install/cope/cope_folder.py b/install/cope/cope_folder.py
new file mode 100755
index 0000000..d9c72d7
--- /dev/null
+++ b/install/cope/cope_folder.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+
+import logging
+import os
+import shutil
+import subprocess
+from argparse import ArgumentParser
+from pathlib import Path
+
+loglevel = (os.environ.get('PYTHON_LOGLEVEL') or "DEBUG").upper()
+numeric_level = getattr(logging, loglevel.upper(), None)
+logging.basicConfig(
+ format='%(asctime)s %(levelname)-8s %(message)s', level=numeric_level)
+
+file_name_pattern = "*.IIQ"
+path_cope = (os.environ.get('COPE_PATH') or Path(
+ "C:/cope.Win.13.1.15-name_cope131/COPE/Bin/COPE.exe"))
+
+cope_options = ["-bits=8"]
+
+
+def find_files(root_dir: Path, file_name_pattern: str) -> list[list]:
+ """find files matching file_name_pattern in direct subdirectories of root_dir
+
+ Args:
+ root_dir (Path): top level directory to perform search in
+ file_name_pattern (str): globbing expression to match for
+
+ Returns:
+ list[list]: a list of lists with the filename and the parent directory basename of matching files
+ """
+ found_files = []
+ for file in Path(root_dir).glob("*/"+file_name_pattern):
+ found_files.append([file, file.parent.stem])
+ return (found_files)
+
+
+def get_parser():
+ """provides argument parser"""
+ parser = ArgumentParser()
+ parser.add_argument("-s", "--source", dest="source",
+ required=True, type=str)
+ parser.add_argument("-t", "--target", dest="target",
+ required=True, type=str)
+ parser.add_argument("-r", "--resolution", dest="resolution",
+ required=False, type=int)
+ return parser
+
+
+if __name__ == "__main__":
+ parser = get_parser()
+ args = parser.parse_args()
+
+ sourcedir = Path(args.source)
+ targetdir = Path(args.target)
+ resolution = args.resolution
+
+ logging.debug(f"path to cope: {path_cope}")
+ logging.debug(f"source directory: {sourcedir}")
+ logging.debug(f"target directory: {targetdir}")
+
+ if resolution:
+ logging.debug(f"resolution: {resolution}")
+ cope_options.append(f"-resolution={resolution}")
+
+ if not os.path.isdir(sourcedir):
+ logging.error("source directory does not exist")
+ exit(1)
+
+ if not os.path.isdir(targetdir):
+ os.mkdir(targetdir)
+ logging.info("target directory created, as it did not exist")
+
+ logging.info("start processing...")
+ files = find_files(sourcedir, file_name_pattern)
+
+ if not files:
+ logging.info("no matching files found in source directory")
+
+ for file, base in files:
+ target = Path(targetdir) / (base + ".tif")
+ logging.info(f"processing {file}")
+
+ cope_command = [Path(path_cope), file, target] + cope_options
+
+ logging.debug(f"running {cope_command}")
+
+ # execute cope
+ try:
+ subprocess.run(cope_command, check=True)
+ except FileNotFoundError:
+ logging.error(f"cope executable was not found: {path_cope}")
+ exit(1)
+ except Exception as err:
+ logging.error(f"Unexpected {err=}, {type(err)=}")
+ raise
+
+ # cope does not appear to make much use of exit codes, thus we check the existence of the expected tiff file here
+ if not target.is_file():
+ logging.error(f"tiff file expected but not found: {target}")
+ exit(1)
+ else:
+ logging.debug(f"removing source package {target.with_suffix('')}")
+ shutil.rmtree(target.with_suffix(''))
diff --git a/install/cope/eip_prepare_for_cope.py b/install/cope/eip_prepare_for_cope.py
new file mode 100755
index 0000000..448c425
--- /dev/null
+++ b/install/cope/eip_prepare_for_cope.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+
+# This script extracts eip files in a source directory to a target directory, renames a specific subdirectory and moves the original eip files
+
+import os
+import shutil
+from argparse import ArgumentParser
+from pathlib import Path
+
+
+def extract_and_rename_eip(source_dir, target_dir):
+ # Check if source directory exists
+ if not os.path.isdir(source_dir):
+ print("Source directory does not exist")
+ exit(1)
+
+ # Create target directory if it does not exist
+ os.makedirs(target_dir, exist_ok=True)
+
+ if source_dir.name.endswith("_master"):
+ raw_directory = Path.joinpath(
+ source_dir.parent, source_dir.name.replace("_master", "_raw"))
+ os.makedirs(raw_directory, exist_ok=True)
+
+ for filename in os.listdir(source_dir):
+ if filename.endswith(".eip"):
+ file_path = os.path.join(source_dir, filename)
+ if os.path.isfile(file_path):
+ # Unzip eip to target directory
+ unzip_dir = os.path.join(
+ target_dir, os.path.splitext(filename)[0])
+ shutil.unpack_archive(filename=file_path,
+ extract_dir=unzip_dir, format="zip")
+
+ capture_one_dir = os.path.join(unzip_dir, "CaptureOne")
+ settings_old = os.path.join(capture_one_dir, "Settings153")
+ settings_new = os.path.join(capture_one_dir, "Settings131")
+
+ # Check if CaptureOne directory exists
+ if not os.path.isdir(capture_one_dir):
+ print(f"{capture_one_dir} does not exist")
+ exit(1)
+
+ # Rename setting directory to matching version for cope
+ if os.path.isdir(settings_old):
+ os.rename(settings_old, settings_new)
+
+ os.rename(file_path, Path.joinpath(raw_directory, filename))
+
+
+def get_parser():
+ """provides argument parser"""
+ parser = ArgumentParser()
+ parser.add_argument("-s", "--source", dest="source",
+ required=True, type=str, help="Source directory")
+ parser.add_argument("-t", "--target", dest="target",
+ required=True, type=str, help="Target directory")
+ return parser
+
+
+if __name__ == "__main__":
+ parser = get_parser()
+ args = parser.parse_args()
+
+ extract_and_rename_eip(Path(args.source), Path(args.target))
diff --git a/install/plugin_intranda_export_adm_bsme.xml b/install/plugin_intranda_export_adm_bsme.xml
index e0295cb..b63adef 100644
--- a/install/plugin_intranda_export_adm_bsme.xml
+++ b/install/plugin_intranda_export_adm_bsme.xml
@@ -1,30 +1,46 @@
- /opt/digiverso/viewer/hotfolderMagazines/
- /opt/digiverso/viewer/hotfolderNewspapers/
+ /opt/digiverso/export/bsme/mnt/export/Newspapers/
+ /opt/digiverso/export/bsme/mnt/export/Magazines/
+ /opt/digiverso/export/bsme/mnt/export/Positives/
+ /opt/digiverso/export/bsme/mnt/export/Negatives/
+ /opt/digiverso/export/bsme/mnt/export/Slides/
+ /opt/digiverso/export/bsme/mnt/export/Generic/
+
+ /opt/digiverso/export/bsme/mnt/pdf/Newspapers/
+ /opt/digiverso/export/bsme/mnt/pdf/Magazines/
+
- https://adm.goobi.cloud/viewer/>
-
-
- $(template.Rights to Use)
- $(template.Rights Details)
- Goobi
- $(template.Media Type)
- $(template.Media Group)
- $(template.Source Organization)
- $(template.Issue Frequency)
-
+ $(template.Rights to Use)
+ $(template.Rights Details)
+ Goobi
+ $(template.Media Type)
+ $(template.Media Group)
+ $(template.Source Organization)
+ $(template.Issue Frequency)
+ $(template.Event Name)
+ $(template.Event Date)
+ $(template.Subject)
+ $(template.Photographer)
+ $(template.Persons in Image)
+ $(template.Locations)
+ $(template.Description)
+ $(template.Editor in Chief)
+ $(template.Format)
- https://adm.goobi.cloud/viewer/sourcefile?id=
- https://adm.goobi.cloud/viewer/piresolver?id=
+ https://adm.goobi.cloud/viewer/sourcefile?id=
+
+ https://adm.goobi.cloud/viewer/piresolver?id=
+
https://adm.goobi.cloud/viewer/sourcefile?id=$(meta.topstruct.CatalogIDDigital).xml
https://adm.goobi.cloud/viewer/sourcefile?id=$(meta.CatalogIDDigital).xml
@@ -65,11 +81,11 @@
AnchorID
AnchorTitle
AccessConditionUse
- AccessConditionDetails
+ AccessConditionDetails
+
Frequency
-
-
+
Newspaper
Year
@@ -78,5 +94,5 @@
NewspaperIssue
NewspaperStub
-
-
\ No newline at end of file
+
+
diff --git a/module-base/pom.xml b/module-base/pom.xml
index d980785..fb9636c 100644
--- a/module-base/pom.xml
+++ b/module-base/pom.xml
@@ -3,7 +3,7 @@
io.goobi.workflow.plugin
plugin-export-adm-bsme
- 24.04.30
+ 24.05
plugin-export-adm-bsme-base
jar
diff --git a/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportHelper.java b/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportHelper.java
index 1d953d3..54307ba 100644
--- a/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportHelper.java
+++ b/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportHelper.java
@@ -3,6 +3,8 @@
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
@@ -95,16 +97,54 @@ public static String getLanguageFullname(DocStruct ds, String field) {
String lang = getMetdata(ds, field);
switch (lang) {
case "Arabic":
- return "عربي – Arabic";
+ return "عربي - Arabic";
case "ara":
- return "عربي – Arabic";
+ return "عربي - Arabic";
case "English":
- return "انجليزي – English";
+ return "انجليزي - English";
case "eng":
- return "انجليزي – English";
+ return "انجليزي - English";
case "ger":
return "German";
}
return lang;
}
+
+ /**
+ * convert the date from dd-mm-yyyy to format yyyy-mm-dd and give it back
+ *
+ * @param inputDate
+ * @return
+ */
+ public static String convertDateFormatToDayMonthYear(String inputDate) {
+ return convertDateFormat(inputDate, "yyyy-MM-dd", "dd-MM-yyyy");
+ }
+
+ /**
+ * convert the date from yyyy-mm-dd to format dd-mm-yyyy and give it back
+ *
+ * @param inputDate
+ * @return
+ */
+ public static String convertDateFormatToYearMonthDay(String inputDate) {
+ return convertDateFormat(inputDate, "dd-MM-yyyy", "yyyy-MM-dd");
+ }
+
+ /**
+ * convert the date from one format to the other
+ *
+ * @param inputDate
+ * @return
+ */
+ private static String convertDateFormat(String inputDate, String inFormat, String outFormat) {
+ SimpleDateFormat inputFormatter = new SimpleDateFormat(inFormat);
+ SimpleDateFormat outputFormatter = new SimpleDateFormat(outFormat);
+
+ try {
+ Date date = inputFormatter.parse(inputDate);
+ return outputFormatter.format(date);
+ } catch (Exception e) {
+ return inputDate;
+ }
+ }
}
diff --git a/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportPlugin.java b/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportPlugin.java
index 124a69e..d030689 100644
--- a/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportPlugin.java
+++ b/module-base/src/main/java/de/intranda/goobi/plugins/AdmBsmeExportPlugin.java
@@ -84,17 +84,33 @@ public boolean startExport(Process process, String destination)
success = ne.startExport();
} else {
- // do a regular export
- IExportPlugin export = new ExportDms();
- export.setExportFulltext(false);
- export.setExportImages(false);
- success = export.startExport(process);
-
// for magazines do a specific export
- if (success && "Periodical".equals(topStruct.getType().getName())) {
+ if ("Periodical".equals(topStruct.getType().getName())) {
// if it is a Magazine
- MagazineExporter me = new MagazineExporter(ConfigPlugins.getPluginConfig(title), process, prefs, dd);
- success = me.startExport();
+
+ // do a regular export
+ IExportPlugin export = new ExportDms();
+ export.setExportFulltext(false);
+ export.setExportImages(false);
+ success = export.startExport(process);
+
+ // do the specific export
+ if (success) {
+ MagazineExporter ex = new MagazineExporter(ConfigPlugins.getPluginConfig(title), process, prefs, dd);
+ success = ex.startExport();
+ }
+
+ }
+ if ("AdmNegative".equals(topStruct.getType().getName())) {
+ // if it is a Negative
+ NegativeExporter ex = new NegativeExporter(ConfigPlugins.getPluginConfig(title), process, prefs, dd);
+ success = ex.startExport();
+ }
+
+ if ("AdmSlide".equals(topStruct.getType().getName())) {
+ // if it is a Slide
+ SlideExporter ex = new SlideExporter(ConfigPlugins.getPluginConfig(title), process, prefs, dd);
+ success = ex.startExport();
}
}
diff --git a/module-base/src/main/java/de/intranda/goobi/plugins/MagazineExporter.java b/module-base/src/main/java/de/intranda/goobi/plugins/MagazineExporter.java
index 01b7b07..70024d0 100644
--- a/module-base/src/main/java/de/intranda/goobi/plugins/MagazineExporter.java
+++ b/module-base/src/main/java/de/intranda/goobi/plugins/MagazineExporter.java
@@ -12,6 +12,7 @@
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.apache.commons.lang.StringUtils;
import org.goobi.beans.JournalEntry;
import org.goobi.beans.Process;
import org.goobi.production.enums.LogType;
@@ -49,6 +50,7 @@ public class MagazineExporter {
private DigitalDocument dd;
private String viewerUrl;
private String targetFolder;
+ private String pdfCopyFolder;
// keep a list of all image files as they need to be renamed
private Map fileMap;
@@ -74,6 +76,7 @@ public MagazineExporter(XMLConfiguration config, Process process, Prefs prefs, D
this.dd = dd;
viewerUrl = config.getString("viewerUrl", "https://viewer.goobi.io");
targetFolder = config.getString("targetDirectoryMagazines", "/opt/digiverso/goobi/output/");
+ pdfCopyFolder = config.getString("pdfCopyMagazines");
}
/**
@@ -121,8 +124,6 @@ public boolean startExport() {
volume.addContent(new Element("Media_Source").setText(source));
volume.addContent(new Element("Media_type").setText(mediaType));
volume.addContent(new Element("Media_Group").setText(mediaGroup));
- // not needed anymore
- // volume.addContent(new Element("Publication_ID").setText(volumeId));
volume.addContent(new Element("Publication_Name")
.setText(AdmBsmeExportHelper.getMetdata(anchor, config.getString("/metadata/titleLabel"))));
volume.addContent(new Element("Language")
@@ -130,6 +131,8 @@ public boolean startExport() {
volume.addContent(
new Element("Source_Organization").setText(sourceOrganisation));
+ // volume.addContent(new Element("Publication_ID").setText(volumeId));
+
// add all journal entries as technical notes
if (process.getJournal() != null) {
Element technicalNotes = new Element("Technical_Notes");
@@ -151,7 +154,11 @@ public boolean startExport() {
issue.addContent(
new Element("issueNumber").setText(AdmBsmeExportHelper.getMetdata(topStruct, config.getString("/metadata/issueNumber"))));
issue.addContent(new Element("issueID").setText(volumeId));
- issue.addContent(new Element("issueDate").setText(AdmBsmeExportHelper.getMetdata(topStruct, config.getString("/metadata/dateOfOrigin"))));
+
+ // get the date and transform it from dd-mm-yyyy to yyyy-mm-dd
+ String date = AdmBsmeExportHelper.getMetdata(topStruct, config.getString("/metadata/dateOfOrigin"));
+ date = AdmBsmeExportHelper.convertDateFormatToYearMonthDay(date);
+ issue.addContent(new Element("issueDate").setText(date));
// get all title information
String anchorTitle = AdmBsmeExportHelper.getMetdata(anchor, config.getString("/metadata/titleLabel"));
@@ -309,6 +316,12 @@ public boolean startExport() {
fout = new FileOutputStream(pdfi.getName());
new GetPdfAction().writePdf(map, ContentServerConfiguration.getInstance(), fout);
fout.close();
+
+ // if a separate PDF copy shall be stored
+ if (StringUtils.isNotBlank(pdfCopyFolder)) {
+ StorageProvider.getInstance().copyFile(Paths.get(pdfi.getName()), Paths.get(pdfCopyFolder, volumeId + ".pdf"));
+ }
+
} catch (IOException | ContentLibException e) {
log.error("Error while generating PDF files", e);
return false;
diff --git a/module-base/src/main/java/de/intranda/goobi/plugins/NegativeExporter.java b/module-base/src/main/java/de/intranda/goobi/plugins/NegativeExporter.java
new file mode 100644
index 0000000..c96d0dc
--- /dev/null
+++ b/module-base/src/main/java/de/intranda/goobi/plugins/NegativeExporter.java
@@ -0,0 +1,248 @@
+package de.intranda.goobi.plugins;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.goobi.beans.JournalEntry;
+import org.goobi.beans.Process;
+import org.goobi.production.enums.LogType;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.output.Format;
+import org.jdom2.output.XMLOutputter;
+
+import de.sub.goobi.helper.StorageProvider;
+import de.sub.goobi.helper.StorageProviderInterface;
+import de.sub.goobi.helper.VariableReplacer;
+import de.sub.goobi.helper.exceptions.DAOException;
+import de.sub.goobi.helper.exceptions.SwapException;
+import de.unigoettingen.sub.commons.contentlib.exceptions.ImageManagerException;
+import de.unigoettingen.sub.commons.contentlib.imagelib.ImageInterpreter;
+import de.unigoettingen.sub.commons.contentlib.imagelib.ImageManager;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+import net.xeoh.plugins.base.annotations.PluginImplementation;
+import ugh.dl.DigitalDocument;
+import ugh.dl.DocStruct;
+import ugh.dl.Prefs;
+import ugh.dl.Reference;
+
+@PluginImplementation
+@Log4j2
+public class NegativeExporter {
+
+ private XMLConfiguration config;
+ private Process process;
+ private Prefs prefs;
+ private DigitalDocument dd;
+ private String targetFolder;
+
+ // keep a list of all image files as they need to be renamed
+ private Map fileMap;
+ private int fileCounter;
+ private VariableReplacer vr;
+
+ @Getter
+ private List problems;
+
+ /**
+ * Constructor
+ *
+ * @param config
+ * @param process
+ * @param prefs
+ * @param dd
+ */
+ public NegativeExporter(XMLConfiguration config, Process process, Prefs prefs, DigitalDocument dd) {
+ this.config = config;
+ config.setExpressionEngine(new XPathExpressionEngine());
+ this.process = process;
+ this.prefs = prefs;
+ this.dd = dd;
+ targetFolder = config.getString("targetDirectoryNegatives", "/opt/digiverso/goobi/output/");
+ }
+
+ /**
+ * Do the actual export for a newspaper volume
+ *
+ * @param process
+ * @param destination
+ * @return
+ */
+ public boolean startExport() {
+ vr = new VariableReplacer(dd, prefs, process, null);
+ problems = new ArrayList<>();
+ fileMap = new HashMap();
+ fileCounter = 0;
+ log.debug("Export directory for AdmBsmeExportPlugin: " + targetFolder);
+ DocStruct topStruct = dd.getLogicalDocStruct();
+
+ // prepare xml document
+ Document doc = new Document();
+ doc.setRootElement(new Element("envelope"));
+
+ // add volume information
+ Element info = new Element("envelopeInfo");
+ doc.getRootElement().addContent(info);
+ String identifier = AdmBsmeExportHelper.getMetdata(topStruct, config.getString("/metadata/identifier"));
+
+ String rightsToUse = vr.replace(config.getString("/rightsToUse"));
+ String rightsDetails = vr.replace(config.getString("/rightsDetails"));
+ String source = vr.replace(config.getString("/source"));
+ String mediaType = vr.replace(config.getString("/mediaType"));
+ String mediaGroup = vr.replace(config.getString("/mediaGroup"));
+ String sourceOrganisation = vr.replace(config.getString("/sourceOrganisation"));
+ String eventDate = vr.replace(config.getString("/eventDate"));
+ String eventName = vr.replace(config.getString("/eventName"));
+ String subject = vr.replace(config.getString("/subject"));
+ String photographer = vr.replace(config.getString("/photographer"));
+ String personsInImage = vr.replace(config.getString("/personsInImage"));
+ String locations = vr.replace(config.getString("/locations"));
+ String description = vr.replace(config.getString("/description"));
+ String editorInChief = vr.replace(config.getString("/editorInChief"));
+ String format = vr.replace(config.getString("/format"));
+
+ info.addContent(new Element("Rights_to_Use").setText(rightsToUse));
+ info.addContent(new Element("Right_Details").setText(rightsDetails));
+ info.addContent(new Element("Media_Source").setText(source));
+ info.addContent(new Element("Media_type").setText(mediaType));
+ info.addContent(new Element("Envelope_Barcode").setText(identifier));
+ info.addContent(new Element("Publication_Name")
+ .setText(AdmBsmeExportHelper.getMetdata(topStruct, config.getString("/metadata/titleLabel"))));
+ info.addContent(
+ new Element("Source_Organization").setText(sourceOrganisation));
+ info.addContent(new Element("Event_Date").setText(eventDate));
+ info.addContent(new Element("Event_Name").setText(eventName));
+ info.addContent(new Element("Subject").setText(subject));
+ info.addContent(new Element("Photographer").setText(photographer));
+ info.addContent(new Element("Film_Format").setText(format));
+ info.addContent(new Element("Persons_in_Image").setText(personsInImage));
+ info.addContent(new Element("Editor_in_Chief").setText(editorInChief));
+ info.addContent(new Element("location").setText(locations));
+ info.addContent(new Element("Description").setText(description));
+
+ // info.addContent(new Element("Media_Group").setText(mediaGroup));
+
+ // add all journal entries as technical notes
+ if (process.getJournal() != null) {
+ Element technicalNotes = new Element("Technical_Notes");
+ for (JournalEntry je : process.getJournal()) {
+ if (je.getType() == LogType.USER) {
+ technicalNotes.addContent(new Element("Entry").setAttribute("date", je.getFormattedCreationDate())
+ .setAttribute("type", je.getType().getTitle())
+ .setText(je.getFormattedContent()));
+ }
+ }
+ info.addContent(technicalNotes);
+ } else {
+ info.addContent(new Element("Technical_Notes").setText("- no entry available -"));
+ }
+
+ // add file information
+ Element files = new Element("Images");
+ doc.getRootElement().addContent(files);
+
+ List refs = topStruct.getAllToReferences("logical_physical");
+ if (refs != null) {
+ for (Reference ref : refs) {
+ DocStruct page = ref.getTarget();
+ String realFileName = page.getImageName();
+ String realFileNameWithoutExtension = realFileName.substring(0, realFileName.indexOf("."));
+
+ // get the new file name for the image and reuse if created previously
+ String exportFileName = fileMap.get(realFileNameWithoutExtension);
+ if (exportFileName == null) {
+ String counter = String.format("%04d", ++fileCounter);
+ exportFileName = identifier + "-" + counter;
+ fileMap.put(realFileNameWithoutExtension, exportFileName);
+ }
+
+ // add file element
+ Element file = new Element("Image");
+ file.setAttribute("id", String.format("%04d", fileCounter));
+ Element master = new Element("master");
+
+ // add image information
+ try {
+ File realFile = new File(process.getImagesOrigDirectory(false),
+ realFileNameWithoutExtension + ".tif");
+ try (ImageManager sourcemanager = new ImageManager(realFile.toURI())) {
+ ImageInterpreter si = sourcemanager.getMyInterpreter();
+
+ // MimeType
+ // master.setAttribute("Format", si.getFormatType().getFormat().getMimeType());
+ master.addContent(new Element("Format").setText(si.getFormatType().getFormat().getMimeType()));
+
+ // Unit for the resolution, always ppi
+ // master.setAttribute("ResolutionUnit", "PPI");
+ master.addContent(new Element("ResolutionUnit").setText("PPI"));
+
+ // Resolution
+ // master.setAttribute("Resolution", String.valueOf(si.getOriginalImageXResolution()));
+ master.addContent(new Element("Resolution").setText(String.valueOf(si.getOriginalImageXResolution())));
+
+ // ColorDepth
+ // master.setAttribute("BitDepth", String.valueOf(si.getColordepth()));
+ master.addContent(new Element("BitDepth").setText(String.valueOf(si.getColordepth())));
+
+ // bitonal, grey, "color"
+ // master.setAttribute("ColorSpace", si.getFormatType().getColortype().getLabel());
+ master.addContent(new Element("ColorSpace").setText(si.getFormatType().getColortype().getLabel()));
+
+ // Scanning device
+ master.addContent(new Element("ScanningDevice").setText(vr.replace("${process.Capturing device}")));
+
+ // Scanning device id
+ String scanningDeviceId = "- no serial number available -"; //si.getMetadata().toString();
+ master.addContent(new Element("ScanningDeviceID").setText(scanningDeviceId));
+
+ // Width
+ master.addContent(new Element("Width").setText(String.valueOf(si.getOriginalImageWidth())));
+
+ // Height
+ master.addContent(new Element("Height").setText(String.valueOf(si.getOriginalImageHeight())));
+ sourcemanager.close();
+ }
+ } catch (IOException | SwapException | DAOException | ImageManagerException e) {
+ log.error("Error while reading image metadata", e);
+ return false;
+ }
+
+ master.addContent(new Element("file").setText(exportFileName + ".tif"));
+ file.addContent(master);
+ files.addContent(file);
+ }
+ }
+
+ // write the xml file
+ XMLOutputter xmlOutputter = new XMLOutputter();
+ xmlOutputter.setFormat(Format.getPrettyFormat());
+ File xmlfile = new File(targetFolder + identifier + ".xml");
+ try (FileOutputStream fileOutputStream = new FileOutputStream(xmlfile)) {
+ xmlOutputter.output(doc, fileOutputStream);
+ } catch (IOException e) {
+ log.error("Error writing the simple xml file", e);
+ return false;
+ }
+
+ try {
+ // copy all important files to target folder
+ AdmBsmeExportHelper.copyFolderContent(process.getImagesOrigDirectory(false), "tif", fileMap, targetFolder);
+ StorageProviderInterface sp = StorageProvider.getInstance();
+
+ } catch (IOException | SwapException | DAOException e) {
+ log.error("Error while copying the image files to export folder", e);
+ return false;
+ }
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/module-base/src/main/java/de/intranda/goobi/plugins/NewspaperExporter.java b/module-base/src/main/java/de/intranda/goobi/plugins/NewspaperExporter.java
index c51b132..dc82852 100644
--- a/module-base/src/main/java/de/intranda/goobi/plugins/NewspaperExporter.java
+++ b/module-base/src/main/java/de/intranda/goobi/plugins/NewspaperExporter.java
@@ -3,6 +3,7 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -10,6 +11,7 @@
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.apache.commons.lang.StringUtils;
import org.goobi.beans.JournalEntry;
import org.goobi.beans.Process;
import org.goobi.production.enums.LogType;
@@ -19,6 +21,7 @@
import org.jdom2.output.XMLOutputter;
import de.sub.goobi.helper.Helper;
+import de.sub.goobi.helper.StorageProvider;
import de.sub.goobi.helper.VariableReplacer;
import de.sub.goobi.helper.exceptions.DAOException;
import de.sub.goobi.helper.exceptions.SwapException;
@@ -50,6 +53,7 @@ public class NewspaperExporter {
private DigitalDocument dd;
private String viewerUrl;
private String targetFolder;
+ private String pdfCopyFolder;
// keep a list of all image files as they need to be renamed
private Map fileMap;
@@ -76,6 +80,7 @@ public NewspaperExporter(XMLConfiguration config, Process process, Prefs prefs,
this.dd = dd;
viewerUrl = config.getString("viewerUrl", "https://viewer.goobi.io");
targetFolder = config.getString("targetDirectoryNewspapers", "/opt/digiverso/goobi/output/");
+ pdfCopyFolder = config.getString("pdfCopyNewspapers");
pdfIssues = new ArrayList<>();
}
@@ -129,8 +134,6 @@ public boolean startExport() {
volume.addContent(new Element("Media_Source").setText(source));
volume.addContent(new Element("Media_type").setText(mediaType));
volume.addContent(new Element("Media_Group").setText(mediaGroup));
- // not needed anymore
- // volume.addContent(new Element("Publication_ID").setText(volumeId));
volume.addContent(new Element("Publication_Name")
.setText(AdmBsmeExportHelper.getMetdata(anchor, config.getString("/metadata/titleLabel"))));
volume.addContent(new Element("Language")
@@ -138,6 +141,8 @@ public boolean startExport() {
volume.addContent(
new Element("Source_Organization").setText(sourceOrganisation));
+ // volume.addContent(new Element("Publication_ID").setText(volumeId));
+
// add all journal entries as technical notes
if (process.getJournal() != null) {
Element technicalNotes = new Element("Technical_Notes");
@@ -171,10 +176,14 @@ public boolean startExport() {
String issueTitle =
AdmBsmeExportHelper.getCleanIssueLabel(AdmBsmeExportHelper.getMetdata(ds, config.getString("/metadata/titleLabel")));
+ // convert date from from yyyy-mm-dd to dd-mm-yyyy
+ String date = AdmBsmeExportHelper.getMetdata(ds, config.getString("/metadata/issueDate"));
+ date = AdmBsmeExportHelper.convertDateFormatToDayMonthYear(date);
+
// add an English title
- issue.addContent(new Element("issueTitleENG").setText(anchorTitleEng + "-" + issueTitle));
+ issue.addContent(new Element("issueTitleENG").setText(anchorTitleEng + "-" + date));
// add an Arabic title
- issue.addContent(new Element("issueTitleARA").setText(issueTitle + "-" + anchorTitleAra));
+ issue.addContent(new Element("issueTitleARA").setText(date + "-" + anchorTitleAra));
issue.addContent(new Element("issueDate").setText(AdmBsmeExportHelper.getMetdata(ds, config.getString("/metadata/issueDate"))));
issue.addContent(new Element("Open_In_Viewer").setText(viewerUrl + volumeId + "-" + simpleDate));
@@ -320,6 +329,13 @@ public boolean startExport() {
fout = new FileOutputStream(pi.getName());
new GetPdfAction().writePdf(map, ContentServerConfiguration.getInstance(), fout);
fout.close();
+
+ // if a separate PDF copy shall be stored
+ if (StringUtils.isNotBlank(pdfCopyFolder)) {
+ StorageProvider.getInstance()
+ .copyFile(Paths.get(pi.getName()), Paths.get(pdfCopyFolder, Paths.get(pi.getName()).getFileName().toString()));
+ }
+
} catch (IOException | ContentLibException e) {
log.error("Error while generating PDF files", e);
return false;
diff --git a/module-base/src/main/java/de/intranda/goobi/plugins/SlideExporter.java b/module-base/src/main/java/de/intranda/goobi/plugins/SlideExporter.java
new file mode 100644
index 0000000..4c5b7d1
--- /dev/null
+++ b/module-base/src/main/java/de/intranda/goobi/plugins/SlideExporter.java
@@ -0,0 +1,242 @@
+package de.intranda.goobi.plugins;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.goobi.beans.JournalEntry;
+import org.goobi.beans.Process;
+import org.goobi.production.enums.LogType;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.output.Format;
+import org.jdom2.output.XMLOutputter;
+
+import de.sub.goobi.helper.StorageProvider;
+import de.sub.goobi.helper.StorageProviderInterface;
+import de.sub.goobi.helper.VariableReplacer;
+import de.sub.goobi.helper.exceptions.DAOException;
+import de.sub.goobi.helper.exceptions.SwapException;
+import de.unigoettingen.sub.commons.contentlib.exceptions.ImageManagerException;
+import de.unigoettingen.sub.commons.contentlib.imagelib.ImageInterpreter;
+import de.unigoettingen.sub.commons.contentlib.imagelib.ImageManager;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+import net.xeoh.plugins.base.annotations.PluginImplementation;
+import ugh.dl.DigitalDocument;
+import ugh.dl.DocStruct;
+import ugh.dl.Prefs;
+import ugh.dl.Reference;
+
+@PluginImplementation
+@Log4j2
+public class SlideExporter {
+
+ private XMLConfiguration config;
+ private Process process;
+ private Prefs prefs;
+ private DigitalDocument dd;
+ private String targetFolder;
+
+ // keep a list of all image files as they need to be renamed
+ private Map fileMap;
+ private int fileCounter;
+ private VariableReplacer vr;
+
+ @Getter
+ private List problems;
+
+ /**
+ * Constructor
+ *
+ * @param config
+ * @param process
+ * @param prefs
+ * @param dd
+ */
+ public SlideExporter(XMLConfiguration config, Process process, Prefs prefs, DigitalDocument dd) {
+ this.config = config;
+ config.setExpressionEngine(new XPathExpressionEngine());
+ this.process = process;
+ this.prefs = prefs;
+ this.dd = dd;
+ targetFolder = config.getString("targetDirectorySlides", "/opt/digiverso/goobi/output/");
+ }
+
+ /**
+ * Do the actual export for a newspaper volume
+ *
+ * @param process
+ * @param destination
+ * @return
+ */
+ public boolean startExport() {
+ vr = new VariableReplacer(dd, prefs, process, null);
+ problems = new ArrayList<>();
+ fileMap = new HashMap();
+ fileCounter = 0;
+ log.debug("Export directory for AdmBsmeExportPlugin: " + targetFolder);
+ DocStruct topStruct = dd.getLogicalDocStruct();
+
+ // prepare xml document
+ Document doc = new Document();
+ doc.setRootElement(new Element("image"));
+
+ // add volume information
+ Element info = new Element("SlideInfo");
+ doc.getRootElement().addContent(info);
+ String identifier = AdmBsmeExportHelper.getMetdata(topStruct, config.getString("/metadata/identifier"));
+
+ String rightsToUse = vr.replace(config.getString("/rightsToUse"));
+ String rightsDetails = vr.replace(config.getString("/rightsDetails"));
+ String source = vr.replace(config.getString("/source"));
+ String mediaType = vr.replace(config.getString("/mediaType"));
+ String mediaGroup = vr.replace(config.getString("/mediaGroup"));
+ String sourceOrganisation = vr.replace(config.getString("/sourceOrganisation"));
+ String eventDate = vr.replace(config.getString("/eventDate"));
+ String eventName = vr.replace(config.getString("/eventName"));
+ String subject = vr.replace(config.getString("/subject"));
+ String photographer = vr.replace(config.getString("/photographer"));
+ String personsInImage = vr.replace(config.getString("/personsInImage"));
+ String locations = vr.replace(config.getString("/locations"));
+ String description = vr.replace(config.getString("/description"));
+ String editorInChief = vr.replace(config.getString("/editorInChief"));
+ String format = vr.replace(config.getString("/format"));
+
+ info.addContent(new Element("Rights_to_Use").setText(rightsToUse));
+ info.addContent(new Element("Right_Details").setText(rightsDetails));
+ info.addContent(new Element("Media_Source").setText(source));
+ info.addContent(new Element("Media_type").setText(mediaType));
+ info.addContent(new Element("Publication_Name")
+ .setText(AdmBsmeExportHelper.getMetdata(topStruct, config.getString("/metadata/titleLabel"))));
+ info.addContent(
+ new Element("Source_Organization").setText(sourceOrganisation));
+ info.addContent(new Element("Barcode").setText(identifier));
+ info.addContent(new Element("Event_Date").setText(eventDate));
+ info.addContent(new Element("Event_Name").setText(eventName));
+ info.addContent(new Element("Photographer").setText(photographer));
+ info.addContent(new Element("Format").setText(format));
+ info.addContent(new Element("Persons_in_Image").setText(personsInImage));
+ info.addContent(new Element("location").setText(locations));
+ info.addContent(new Element("Description").setText(description));
+
+ // info.addContent(new Element("Editor_in_Chief").setText(editorInChief));
+ // info.addContent(new Element("Media_Group").setText(mediaGroup));
+ // info.addContent(new Element("Subject").setText(subject));
+
+ // add all journal entries as technical notes
+ if (process.getJournal() != null) {
+ Element technicalNotes = new Element("Technical_Notes");
+ for (JournalEntry je : process.getJournal()) {
+ if (je.getType() == LogType.USER) {
+ technicalNotes.addContent(new Element("Entry").setAttribute("date", je.getFormattedCreationDate())
+ .setAttribute("type", je.getType().getTitle())
+ .setText(je.getFormattedContent()));
+ }
+ }
+ info.addContent(technicalNotes);
+ } else {
+ info.addContent(new Element("Technical_Notes").setText("- no entry available -"));
+ }
+
+ // add file information
+ List refs = topStruct.getAllToReferences("logical_physical");
+ if (refs != null) {
+ for (Reference ref : refs) {
+ DocStruct page = ref.getTarget();
+ String realFileName = page.getImageName();
+ String realFileNameWithoutExtension = realFileName.substring(0, realFileName.indexOf("."));
+
+ // get the new file name for the image and reuse if created previously
+ String exportFileName = fileMap.get(realFileNameWithoutExtension);
+ if (exportFileName == null) {
+ String counter = String.format("%04d", ++fileCounter);
+ exportFileName = identifier + "-" + counter;
+ fileMap.put(realFileNameWithoutExtension, exportFileName);
+ }
+
+ // add file element
+ Element master = new Element("master");
+
+ // add image information
+ try {
+ File realFile = new File(process.getImagesOrigDirectory(false),
+ realFileNameWithoutExtension + ".tif");
+ try (ImageManager sourcemanager = new ImageManager(realFile.toURI())) {
+ ImageInterpreter si = sourcemanager.getMyInterpreter();
+
+ // MimeType
+ // master.setAttribute("Format", si.getFormatType().getFormat().getMimeType());
+ master.addContent(new Element("Format").setText(si.getFormatType().getFormat().getMimeType()));
+
+ // Unit for the resolution, always ppi
+ // master.setAttribute("ResolutionUnit", "PPI");
+ master.addContent(new Element("ResolutionUnit").setText("PPI"));
+
+ // Resolution
+ // master.setAttribute("Resolution", String.valueOf(si.getOriginalImageXResolution()));
+ master.addContent(new Element("Resolution").setText(String.valueOf(si.getOriginalImageXResolution())));
+
+ // ColorDepth
+ // master.setAttribute("BitDepth", String.valueOf(si.getColordepth()));
+ master.addContent(new Element("BitDepth").setText(String.valueOf(si.getColordepth())));
+
+ // bitonal, grey, "color"
+ // master.setAttribute("ColorSpace", si.getFormatType().getColortype().getLabel());
+ master.addContent(new Element("ColorSpace").setText(si.getFormatType().getColortype().getLabel()));
+
+ // Scanning device
+ master.addContent(new Element("ScanningDevice").setText(vr.replace("${process.Capturing device}")));
+
+ // Scanning device id
+ String scanningDeviceId = "- no serial number available -"; //si.getMetadata().toString();
+ master.addContent(new Element("ScanningDeviceID").setText(scanningDeviceId));
+
+ // Width
+ master.addContent(new Element("Width").setText(String.valueOf(si.getOriginalImageWidth())));
+
+ // Height
+ master.addContent(new Element("Height").setText(String.valueOf(si.getOriginalImageHeight())));
+ sourcemanager.close();
+ }
+ } catch (IOException | SwapException | DAOException | ImageManagerException e) {
+ log.error("Error while reading image metadata", e);
+ return false;
+ }
+
+ master.addContent(new Element("file").setText(exportFileName + ".tif"));
+ doc.getRootElement().addContent(master);
+ }
+ }
+
+ // write the xml file
+ XMLOutputter xmlOutputter = new XMLOutputter();
+ xmlOutputter.setFormat(Format.getPrettyFormat());
+ File xmlfile = new File(targetFolder + identifier + ".xml");
+ try (FileOutputStream fileOutputStream = new FileOutputStream(xmlfile)) {
+ xmlOutputter.output(doc, fileOutputStream);
+ } catch (IOException e) {
+ log.error("Error writing the simple xml file", e);
+ return false;
+ }
+
+ try {
+ // copy all important files to target folder
+ AdmBsmeExportHelper.copyFolderContent(process.getImagesOrigDirectory(false), "tif", fileMap, targetFolder);
+ StorageProviderInterface sp = StorageProvider.getInstance();
+
+ } catch (IOException | SwapException | DAOException e) {
+ log.error("Error while copying the image files to export folder", e);
+ return false;
+ }
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 72f923f..3601dc5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
io.goobi.workflow
workflow-base
- 24.04.30
+ 24.05
io.goobi.workflow.plugin