1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package cz.hobrasoft.pdfmu.operation;
18
19 import com.itextpdf.text.pdf.PdfStamper;
20 import cz.hobrasoft.pdfmu.PdfmuUtils;
21 import static cz.hobrasoft.pdfmu.error.ErrorType.ATTACH_ATTACHMENT_EQUALS_OUTPUT;
22 import static cz.hobrasoft.pdfmu.error.ErrorType.ATTACH_FAIL;
23 import cz.hobrasoft.pdfmu.jackson.EmptyResult;
24 import cz.hobrasoft.pdfmu.operation.args.InOutPdfArgs;
25 import java.io.File;
26 import java.io.IOException;
27 import java.util.AbstractMap.SimpleEntry;
28 import java.util.logging.Logger;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31 import net.sourceforge.argparse4j.impl.Arguments;
32 import net.sourceforge.argparse4j.inf.Namespace;
33 import net.sourceforge.argparse4j.inf.Subparser;
34
35
36
37
38
39
40 public class OperationAttach extends OperationCommon {
41
42 private static final Logger logger = Logger.getLogger(OperationAttach.class.getName());
43
44 private final String metavarIn = "IN.pdf";
45 private final InOutPdfArgs inout = new InOutPdfArgs(metavarIn);
46
47 @Override
48 public Subparser configureSubparser(Subparser subparser) {
49 String help = "Attach a file to a PDF document";
50
51 subparser.help(help)
52 .description(help)
53 .defaultHelp(true);
54
55 inout.addArguments(subparser);
56
57 String metavarAttachment = "ATTACHMENT";
58
59
60 subparser.addArgument("attachment")
61 .help(String.format("file to attach to %s", metavarIn))
62 .metavar(metavarAttachment)
63 .type(Arguments.fileType().acceptSystemIn());
64 subparser.addArgument("-r", "--rename")
65 .help(String.format("attachment filename shown in the output PDF document (default: <%s>)", metavarAttachment))
66 .metavar("FILENAME")
67 .type(String.class);
68 subparser.addArgument("-d", "--description")
69 .help("attachment description shown in the output PDF document (default: <none>)")
70 .type(String.class);
71
72 return subparser;
73 }
74
75 @Override
76 public void execute(Namespace namespace) throws OperationException {
77 inout.setFromNamespace(namespace);
78
79 File file = namespace.get("attachment");
80
81 File outFile = inout.getOut().getFile();
82 assert outFile != null;
83 if (outFile.equals(file)) {
84 throw new OperationException(ATTACH_ATTACHMENT_EQUALS_OUTPUT,
85 PdfmuUtils.sortedMap(
86 new SimpleEntry<String, Object>("outputFile", outFile),
87 new SimpleEntry<String, Object>("attachmentFile", file)));
88 }
89
90 String description = namespace.getString("description");
91 String fileDisplay = namespace.getString("rename");
92
93 if (fileDisplay == null) {
94 fileDisplay = file.getName();
95 }
96
97 try {
98 inout.open();
99 execute(inout.getPdfStamper(), description, file.getPath(), fileDisplay);
100 inout.close(true);
101 } finally {
102 inout.close(false);
103 }
104
105 writeResult(new EmptyResult());
106 }
107
108 private static final Pattern filenameWithExtension = Pattern.compile(".*\\.[^\\.]+");
109
110 private static void execute(PdfStamper stp, String description, String file, String fileDisplay) throws OperationException {
111 {
112 assert stp != null;
113 assert file != null;
114 assert fileDisplay != null;
115
116 logger.info(String.format("Attached file: %s", file));
117 logger.info(String.format("Description: %s", (description != null ? description : "<none>")));
118 logger.info(String.format("Display name: %s", fileDisplay));
119 {
120 Matcher m = filenameWithExtension.matcher(fileDisplay);
121 if (!m.matches()) {
122 logger.warning("Display name does not contain a file extension. Adobe Reader XI does not allow opening or saving such attachment.");
123 }
124 }
125 }
126 try {
127 stp.addFileAttachment(description, null, file, fileDisplay);
128 } catch (IOException ex) {
129 throw new OperationException(ATTACH_FAIL, ex,
130 PdfmuUtils.sortedMap(new String[]{"file"}, new Object[]{file}));
131 }
132 logger.info(String.format("The file \"%s\" has been attached.", file));
133 }
134
135 private static Operation instance = null;
136
137 public static Operation getInstance() {
138 if (instance == null) {
139 instance = new OperationAttach();
140 }
141 return instance;
142 }
143
144 private OperationAttach() {
145
146 }
147
148 }