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