View Javadoc
1   /* 
2    * Copyright (C) 2016 Hobrasoft s.r.o.
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU Affero General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU Affero General Public License for more details.
13   *
14   * You should have received a copy of the GNU Affero General Public License
15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16   */
17  package cz.hobrasoft.pdfmu.operation.metadata;
18  
19  import com.itextpdf.text.pdf.PdfReader;
20  import cz.hobrasoft.pdfmu.MapSorter;
21  import cz.hobrasoft.pdfmu.PdfmuUtils;
22  import cz.hobrasoft.pdfmu.PreferenceListComparator;
23  import cz.hobrasoft.pdfmu.operation.args.ArgsConfiguration;
24  import java.util.AbstractMap;
25  import java.util.Arrays;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.SortedMap;
30  import net.sourceforge.argparse4j.impl.Arguments;
31  import net.sourceforge.argparse4j.inf.ArgumentGroup;
32  import net.sourceforge.argparse4j.inf.ArgumentParser;
33  import net.sourceforge.argparse4j.inf.Namespace;
34  
35  public class MetadataParameters implements ArgsConfiguration {
36  
37      private Map<String, String> info = new HashMap<>();
38      private boolean clearall = false;
39  
40      public Map<String, String> getInfo(PdfReader pdfReader) {
41          if (clearall) {
42              // We need the keys that are already set in the input file.
43              Map<String, String> inInfo = pdfReader.getInfo();
44              Map<String, String> res = new HashMap<>();
45              for (String key : inInfo.keySet()) {
46                  // Unset the property `key`
47                  // TODO?: Do not unset the properties "Producer" and "ModDate"
48                  res.put(key, null);
49              }
50              // Set all the properties in `info`, possibly overwriting the unset properties
51              res.putAll(info);
52              return res;
53          }
54          return info;
55      }
56  
57      // Table with the descriptions:
58      // http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf
59      // (table 317, section 14.3.3, page 550)
60      private static final Map<String, String> standardProperties = PdfmuUtils.sortedMap(
61              new AbstractMap.SimpleEntry<>("Title", "The document's title."),
62              new AbstractMap.SimpleEntry<>("Subject", "The subject of the document."),
63              new AbstractMap.SimpleEntry<>("Author", "The name of the person who created the document."),
64              new AbstractMap.SimpleEntry<>("Keywords", "Keywords associated with the document."),
65              new AbstractMap.SimpleEntry<>("Creator", "The name of the product that created the document in the original format."),
66              new AbstractMap.SimpleEntry<>("Producer", "The name of the product that converted the document from the original format to PDF."),
67              new AbstractMap.SimpleEntry<>("CreationDate", "The date and time the document was created, in human-readable form."),
68              new AbstractMap.SimpleEntry<>("ModDate", "The date and time the document was most recently modified, in human-readable form."),
69              new AbstractMap.SimpleEntry<>("Trapped", "Has the document been modified to include trapping information? (recommended values: True,False,Unknown)")
70      );
71  
72      // iText does not let us set the Producer property.
73      // The ModDate property also seems to be set automatically.
74      // TODO: Check spelling of "settable"
75      private static final List<String> standardSettableProperties = Arrays.asList(new String[]{
76          "Title", "Subject", "Author", "Keywords", "Creator", "CreationDate", "Trapped"});
77  
78      @Override
79      public void addArguments(ArgumentParser parser) {
80          // Generic properties
81          parser.addArgument("-s", "--set")
82                  .help("set the property P to the value V")
83                  .metavar("P", "V")
84                  .nargs(2)
85                  .type(String.class)
86                  .action(Arguments.append());
87  
88          parser.addArgument("-c", "--clear")
89                  .help("clear the property P")
90                  .metavar("P")
91                  .type(String.class)
92                  .action(Arguments.append());
93  
94          // Remove all properties
95          parser.addArgument("--clear-all")
96                  .help("clear all the properties")
97                  .type(boolean.class)
98                  .action(Arguments.storeTrue());
99  
100         // Standard properties
101         ArgumentGroup group = parser.addArgumentGroup("standard properties")
102                 .description("These are simple shortcuts for setting the standard properties. For example, `--Title TITLE` is equivalent to `--set Title TITLE`.");
103         for (String property : standardSettableProperties) {
104             assert standardProperties.containsKey(property);
105             String help = standardProperties.get(property);
106             group.addArgument("--" + property)
107                     .help(help)
108                     .type(String.class);
109         }
110     }
111 
112     @Override
113     public void setFromNamespace(Namespace namespace) {
114         clearall = namespace.getBoolean("clear_all");
115 
116         // Clear the selected properties
117         { // clearedProperties
118             List<String> clearedProperties = namespace.getList("clear");
119             if (clearedProperties != null) {
120                 for (String p : clearedProperties) {
121                     info.put(p, null);
122                 }
123             }
124         }
125 
126         // Generic properties
127         List<List<String>> elements = namespace.getList("set");
128         if (elements != null) {
129             for (List<String> element : elements) {
130                 String key = element.get(0);
131                 // TODO: Warn if key is Producer or ModDate
132                 String value = element.get(1);
133                 // TODO: Warn if key is Trapped and value is not one of True, False, Unknown
134                 info.put(key, value);
135             }
136         }
137 
138         // Standard properties
139         for (String property : standardSettableProperties) {
140             String value = namespace.getString(property);
141             if (value != null) {
142                 info.put(property, value);
143             }
144         }
145     }
146 
147     public void setFromInfo(Map<String, String> info) {
148         this.info = info;
149     }
150 
151     private static final MapSorter<String> propertySorter
152             = new PreferenceListComparator<>(standardProperties.keySet().iterator());
153 
154     public SortedMap<String, String> getSorted() {
155         return propertySorter.sort(info);
156     }
157 
158 }