1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id: PDFCIDFont.java 1758773 2016-09-01 13:02:29Z ssteiner $ */
19 
20 package org.apache.fop.pdf;
21 
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.util.Set;
25 
26 import org.apache.fop.fonts.CIDFontType;
27 
28 // based on work by Takayuki Takeuchi
29 
30 /**
31  * Class representing a "character identifier" font (p 210 and onwards).
32  */
33 public class PDFCIDFont extends PDFObject {
34 
35     private String basefont;
36     private CIDFontType cidtype;
37     private Integer dw;
38     private PDFWArray w;
39     private int[] dw2;
40     private PDFWArray w2;
41     private PDFCIDSystemInfo systemInfo;
42     private PDFCIDFontDescriptor descriptor;
43     private PDFCMap cmap;
44 
45     /**
46      * /CIDToGIDMap (only for CIDFontType2, see p 212)
47      * can be either "Identity" (default) or a PDFStream
48      */
49     private PDFStream cidMap;
50 
51 
52     /**
53      * Create the /Font object
54      * @param basefont Name of the basefont
55      * @param cidtype CID type
56      * @param dw default width
57      * @param w array of character widths
58      * @param registry name of the issuer
59      * @param ordering Unique name of the font
60      * @param supplement Supplement number
61      * @param descriptor CID font descriptor
62      */
PDFCIDFont(String basefont, CIDFontType cidtype, int dw, int[] w, String registry, String ordering, int supplement, PDFCIDFontDescriptor descriptor)63     public PDFCIDFont(String basefont, CIDFontType cidtype, int dw,
64             int[] w, String registry, String ordering,
65             int supplement, PDFCIDFontDescriptor descriptor) {
66 
67         this(basefont, cidtype, dw,
68                 new PDFWArray(w),
69                 new PDFCIDSystemInfo(registry, ordering, supplement),
70                 descriptor);
71     }
72 
73     /**
74      * Create the /Font object
75      * @param basefont Name of the basefont
76      * @param cidtype CID type
77      * @param dw default width
78      * @param w array of character widths
79      * @param systemInfo CID system info
80      * @param descriptor CID font descriptor
81      */
PDFCIDFont(String basefont, CIDFontType cidtype, int dw, int[] w, PDFCIDSystemInfo systemInfo, PDFCIDFontDescriptor descriptor)82     public PDFCIDFont(String basefont, CIDFontType cidtype, int dw,
83                       int[] w, PDFCIDSystemInfo systemInfo,
84                       PDFCIDFontDescriptor descriptor) {
85 
86         this(basefont, cidtype, dw,
87                 new PDFWArray(w),
88                 systemInfo,
89                 descriptor);
90     }
91 
92     /**
93      * Create the /Font object
94      * @param basefont Name of the basefont
95      * @param cidtype CID type
96      * @param dw default width
97      * @param w array of character widths
98      * @param systemInfo CID system info
99      * @param descriptor CID font descriptor
100      */
PDFCIDFont(String basefont, CIDFontType cidtype, int dw, PDFWArray w, PDFCIDSystemInfo systemInfo, PDFCIDFontDescriptor descriptor)101     public PDFCIDFont(String basefont, CIDFontType cidtype, int dw,
102                       PDFWArray w, PDFCIDSystemInfo systemInfo,
103                       PDFCIDFontDescriptor descriptor) {
104 
105         super();
106 
107         this.basefont = basefont;
108         this.cidtype = cidtype;
109         this.dw = dw;
110         this.w = w;
111         this.dw2 = null;
112         this.w2 = null;
113         systemInfo.setParent(this);
114         this.systemInfo = systemInfo;
115         this.descriptor = descriptor;
116         this.cidMap = null;
117         this.cmap = null;
118     }
119 
120     /**
121      * Set the /DW attribute
122      * @param dw the default width
123      */
setDW(int dw)124     public void setDW(int dw) {
125         this.dw = dw;
126     }
127 
128     /**
129      * Set the /W array
130      * @param w the width array
131      */
setW(PDFWArray w)132     public void setW(PDFWArray w) {
133         this.w = w;
134     }
135 
136     /**
137      * Set the (two elements) /DW2 array
138      * @param dw2 the default metrics for vertical writing
139      */
setDW2(int[] dw2)140     public void setDW2(int[] dw2) {
141         this.dw2 = dw2;
142     }
143 
144     /**
145      * Set the two elements of the /DW2 array
146      * @param posY position vector
147      * @param displacementY displacement vector
148      */
setDW2(int posY, int displacementY)149     public void setDW2(int posY, int displacementY) {
150         this.dw2 = new int[] {
151             posY, displacementY
152         };
153     }
154 
155     /**
156      * Set the CMap used as /ToUnicode cmap
157      * @param cmap character map
158      */
setCMAP(PDFCMap cmap)159     public void setCMAP(PDFCMap cmap) {
160         this.cmap = cmap;
161     }
162 
163     /**
164      * Set the /W2 array
165      * @param w2 array of metrics for vertical writing
166      */
setW2(PDFWArray w2)167     public void setW2(PDFWArray w2) {
168         this.w2 = w2;
169     }
170 
171     /**
172      * Set the /CIDToGIDMap (to be used only for CIDFontType2)
173      * @param map mapping information
174      */
setCIDMap(PDFStream map)175     public void setCIDMap(PDFStream map) {
176         this.cidMap = map;
177     }
178 
179     /**
180      * Set the /CIDToGIDMap (to be used only for CIDFontType2) to "Identity"
181      */
setCIDMapIdentity()182     public void setCIDMapIdentity() {
183         this.cidMap = null;    // not an error here, simply use the default
184     }
185 
186     /**
187      * Returns the PDF name for a certain CID font type.
188      * @param cidFontType CID font type
189      * @return corresponding PDF name
190      */
getPDFNameForCIDFontType(CIDFontType cidFontType)191     protected String getPDFNameForCIDFontType(CIDFontType cidFontType) {
192         if (cidFontType == CIDFontType.CIDTYPE0) {
193             return cidFontType.getName();
194         } else if (cidFontType == CIDFontType.CIDTYPE2) {
195             return cidFontType.getName();
196         } else {
197             throw new IllegalArgumentException("Unsupported CID font type: "
198                         + cidFontType.getName());
199         }
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
toPDFString()205     public String toPDFString() {
206         StringBuffer p = new StringBuffer(128);
207         p.append("<< /Type /Font");
208         p.append("\n/BaseFont /");
209         p.append(this.basefont);
210         p.append(" \n/CIDToGIDMap ");
211         if (cidMap != null) {
212             p.append(cidMap.referencePDF());
213         } else {
214             p.append("/Identity");
215             //This is the default. We still write it because PDF/A requires it.
216         }
217         p.append(" \n/Subtype /");
218         p.append(getPDFNameForCIDFontType(this.cidtype));
219         p.append("\n");
220         p.append(systemInfo.toPDFString());
221         p.append("\n/FontDescriptor ");
222         p.append(this.descriptor.referencePDF());
223 
224         if (cmap != null) {
225             p.append("\n/ToUnicode ");
226             p.append(cmap.referencePDF());
227         }
228         if (dw != null) {
229             p.append("\n/DW ");
230             p.append(this.dw);
231         }
232         if (w != null) {
233             p.append("\n/W ");
234             p.append(w.toPDFString());
235         }
236         if (dw2 != null) {
237             p.append("\n/DW2 [");    // always two values, see p 211
238             p.append(this.dw2[0]);
239             p.append(this.dw2[1]);
240             p.append("]");
241         }
242         if (w2 != null) {
243             p.append("\n/W2 ");
244             p.append(w2.toPDFString());
245         }
246         p.append("\n>>");
247         return p.toString();
248     }
249 
250     /**
251      * {@inheritDoc}
252      */
toPDF()253     public byte[] toPDF() {
254         ByteArrayOutputStream bout = new ByteArrayOutputStream(128);
255         try {
256             bout.write(encode("<< /Type /Font\n"));
257             bout.write(encode("/BaseFont /"));
258             bout.write(encode(this.basefont));
259             bout.write(encode(" \n"));
260             bout.write(encode("/CIDToGIDMap "));
261             bout.write(encode(cidMap != null ? cidMap.referencePDF() : "/Identity"));
262             bout.write(encode(" \n"));
263             bout.write(encode("/Subtype /"));
264             bout.write(encode(getPDFNameForCIDFontType(this.cidtype)));
265             bout.write(encode("\n"));
266             bout.write(encode("/CIDSystemInfo "));
267             bout.write(systemInfo.toPDF());
268             bout.write(encode("\n"));
269             bout.write(encode("/FontDescriptor "));
270             bout.write(encode(this.descriptor.referencePDF()));
271             bout.write(encode("\n"));
272             if (cmap != null) {
273                 bout.write(encode("/ToUnicode "));
274                 bout.write(encode(cmap.referencePDF()));
275                 bout.write(encode("\n"));
276             }
277             if (dw != null) {
278                 bout.write(encode("/DW "));
279                 bout.write(encode(this.dw.toString()));
280                 bout.write(encode("\n"));
281             }
282             if (w != null) {
283                 bout.write(encode("/W "));
284                 bout.write(encode(w.toPDFString()));
285                 bout.write(encode("\n"));
286             }
287             if (dw2 != null) {
288                 bout.write(encode("/DW2 [")); // always two values, see p 211
289                 bout.write(encode(Integer.toString(this.dw2[0])));
290                 bout.write(encode(Integer.toString(this.dw2[1])));
291                 bout.write(encode("]\n"));
292             }
293             if (w2 != null) {
294                 bout.write(encode("/W2 "));
295                 bout.write(encode(w2.toPDFString()));
296                 bout.write(encode("\n"));
297             }
298             bout.write(encode(">>"));
299         } catch (IOException ioe) {
300             log.error("Ignored I/O exception", ioe);
301         }
302         return bout.toByteArray();
303     }
304 
305     @Override
getChildren(Set<PDFObject> children)306     public void getChildren(Set<PDFObject> children) {
307         super.getChildren(children);
308         if (cidMap != null) {
309             children.add(cidMap);
310             cidMap.getChildren(children);
311         }
312         children.add(descriptor);
313         descriptor.getChildren(children);
314         if (cmap != null) {
315             children.add(cmap);
316             cmap.getChildren(children);
317         }
318     }
319 
320 }
321 
322