/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.pdf; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Set; import org.apache.fop.fonts.CIDFontType; // based on work by Takayuki Takeuchi /** * Class representing a "character identifier" font (p 210 and onwards). */ public class PDFCIDFont extends PDFObject { private String basefont; private CIDFontType cidtype; private Integer dw; private PDFWArray w; private int[] dw2; private PDFWArray w2; private PDFCIDSystemInfo systemInfo; private PDFCIDFontDescriptor descriptor; private PDFCMap cmap; /** * /CIDToGIDMap (only for CIDFontType2, see p 212) * can be either "Identity" (default) or a PDFStream */ private PDFStream cidMap; /** * Create the /Font object * @param basefont Name of the basefont * @param cidtype CID type * @param dw default width * @param w array of character widths * @param registry name of the issuer * @param ordering Unique name of the font * @param supplement Supplement number * @param descriptor CID font descriptor */ public PDFCIDFont(String basefont, CIDFontType cidtype, int dw, int[] w, String registry, String ordering, int supplement, PDFCIDFontDescriptor descriptor) { this(basefont, cidtype, dw, new PDFWArray(w), new PDFCIDSystemInfo(registry, ordering, supplement), descriptor); } /** * Create the /Font object * @param basefont Name of the basefont * @param cidtype CID type * @param dw default width * @param w array of character widths * @param systemInfo CID system info * @param descriptor CID font descriptor */ public PDFCIDFont(String basefont, CIDFontType cidtype, int dw, int[] w, PDFCIDSystemInfo systemInfo, PDFCIDFontDescriptor descriptor) { this(basefont, cidtype, dw, new PDFWArray(w), systemInfo, descriptor); } /** * Create the /Font object * @param basefont Name of the basefont * @param cidtype CID type * @param dw default width * @param w array of character widths * @param systemInfo CID system info * @param descriptor CID font descriptor */ public PDFCIDFont(String basefont, CIDFontType cidtype, int dw, PDFWArray w, PDFCIDSystemInfo systemInfo, PDFCIDFontDescriptor descriptor) { super(); this.basefont = basefont; this.cidtype = cidtype; this.dw = dw; this.w = w; this.dw2 = null; this.w2 = null; systemInfo.setParent(this); this.systemInfo = systemInfo; this.descriptor = descriptor; this.cidMap = null; this.cmap = null; } /** * Set the /DW attribute * @param dw the default width */ public void setDW(int dw) { this.dw = dw; } /** * Set the /W array * @param w the width array */ public void setW(PDFWArray w) { this.w = w; } /** * Set the (two elements) /DW2 array * @param dw2 the default metrics for vertical writing */ public void setDW2(int[] dw2) { this.dw2 = dw2; } /** * Set the two elements of the /DW2 array * @param posY position vector * @param displacementY displacement vector */ public void setDW2(int posY, int displacementY) { this.dw2 = new int[] { posY, displacementY }; } /** * Set the CMap used as /ToUnicode cmap * @param cmap character map */ public void setCMAP(PDFCMap cmap) { this.cmap = cmap; } /** * Set the /W2 array * @param w2 array of metrics for vertical writing */ public void setW2(PDFWArray w2) { this.w2 = w2; } /** * Set the /CIDToGIDMap (to be used only for CIDFontType2) * @param map mapping information */ public void setCIDMap(PDFStream map) { this.cidMap = map; } /** * Set the /CIDToGIDMap (to be used only for CIDFontType2) to "Identity" */ public void setCIDMapIdentity() { this.cidMap = null; // not an error here, simply use the default } /** * Returns the PDF name for a certain CID font type. * @param cidFontType CID font type * @return corresponding PDF name */ protected String getPDFNameForCIDFontType(CIDFontType cidFontType) { if (cidFontType == CIDFontType.CIDTYPE0) { return cidFontType.getName(); } else if (cidFontType == CIDFontType.CIDTYPE2) { return cidFontType.getName(); } else { throw new IllegalArgumentException("Unsupported CID font type: " + cidFontType.getName()); } } /** * {@inheritDoc} */ public String toPDFString() { StringBuffer p = new StringBuffer(128); p.append("<< /Type /Font"); p.append("\n/BaseFont /"); p.append(this.basefont); p.append(" \n/CIDToGIDMap "); if (cidMap != null) { p.append(cidMap.referencePDF()); } else { p.append("/Identity"); //This is the default. We still write it because PDF/A requires it. } p.append(" \n/Subtype /"); p.append(getPDFNameForCIDFontType(this.cidtype)); p.append("\n"); p.append(systemInfo.toPDFString()); p.append("\n/FontDescriptor "); p.append(this.descriptor.referencePDF()); if (cmap != null) { p.append("\n/ToUnicode "); p.append(cmap.referencePDF()); } if (dw != null) { p.append("\n/DW "); p.append(this.dw); } if (w != null) { p.append("\n/W "); p.append(w.toPDFString()); } if (dw2 != null) { p.append("\n/DW2 ["); // always two values, see p 211 p.append(this.dw2[0]); p.append(this.dw2[1]); p.append("]"); } if (w2 != null) { p.append("\n/W2 "); p.append(w2.toPDFString()); } p.append("\n>>"); return p.toString(); } /** * {@inheritDoc} */ public byte[] toPDF() { ByteArrayOutputStream bout = new ByteArrayOutputStream(128); try { bout.write(encode("<< /Type /Font\n")); bout.write(encode("/BaseFont /")); bout.write(encode(this.basefont)); bout.write(encode(" \n")); bout.write(encode("/CIDToGIDMap ")); bout.write(encode(cidMap != null ? cidMap.referencePDF() : "/Identity")); bout.write(encode(" \n")); bout.write(encode("/Subtype /")); bout.write(encode(getPDFNameForCIDFontType(this.cidtype))); bout.write(encode("\n")); bout.write(encode("/CIDSystemInfo ")); bout.write(systemInfo.toPDF()); bout.write(encode("\n")); bout.write(encode("/FontDescriptor ")); bout.write(encode(this.descriptor.referencePDF())); bout.write(encode("\n")); if (cmap != null) { bout.write(encode("/ToUnicode ")); bout.write(encode(cmap.referencePDF())); bout.write(encode("\n")); } if (dw != null) { bout.write(encode("/DW ")); bout.write(encode(this.dw.toString())); bout.write(encode("\n")); } if (w != null) { bout.write(encode("/W ")); bout.write(encode(w.toPDFString())); bout.write(encode("\n")); } if (dw2 != null) { bout.write(encode("/DW2 [")); // always two values, see p 211 bout.write(encode(Integer.toString(this.dw2[0]))); bout.write(encode(Integer.toString(this.dw2[1]))); bout.write(encode("]\n")); } if (w2 != null) { bout.write(encode("/W2 ")); bout.write(encode(w2.toPDFString())); bout.write(encode("\n")); } bout.write(encode(">>")); } catch (IOException ioe) { log.error("Ignored I/O exception", ioe); } return bout.toByteArray(); } @Override public void getChildren(Set<PDFObject> children) { super.getChildren(children); if (cidMap != null) { children.add(cidMap); cidMap.getChildren(children); } children.add(descriptor); descriptor.getChildren(children); if (cmap != null) { children.add(cmap); cmap.getChildren(children); } } }