/*
* 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.
*/
package org.apache.pdfbox.pdmodel.font;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.fontbox.afm.FontMetrics;
import org.apache.fontbox.pfb.PfbParser;
import org.apache.fontbox.type1.Type1Font;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.COSArrayList;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.font.encoding.Encoding;
import org.apache.pdfbox.pdmodel.font.encoding.GlyphList;
import org.apache.pdfbox.pdmodel.font.encoding.Type1Encoding;
/**
* Embedded PDType1Font builder. Helper class to populate a PDType1Font from a PFB and AFM.
*
* @author Michael Niedermair
*/
class PDType1FontEmbedder
{
private final Encoding fontEncoding;
private final Type1Font type1;
/**
* This will load a PFB to be embedded into a document.
*
* @param doc The PDF document that will hold the embedded font.
* @param dict The Font dictionary to write to.
* @param pfbStream The pfb input.
* @throws IOException If there is an error loading the data.
*/
PDType1FontEmbedder(PDDocument doc, COSDictionary dict, InputStream pfbStream,
Encoding encoding) throws IOException
{
dict.setItem(COSName.SUBTYPE, COSName.TYPE1);
// read the pfb
byte[] pfbBytes = IOUtils.toByteArray(pfbStream);
PfbParser pfbParser = new PfbParser(pfbBytes);
type1 = Type1Font.createWithPFB(pfbBytes);
if (encoding == null)
{
fontEncoding = Type1Encoding.fromFontBox(type1.getEncoding());
}
else
{
fontEncoding = encoding;
}
// build font descriptor
PDFontDescriptor fd = buildFontDescriptor(type1);
PDStream fontStream = new PDStream(doc, pfbParser.getInputStream(), COSName.FLATE_DECODE);
fontStream.getCOSObject().setInt("Length", pfbParser.size());
for (int i = 0; i < pfbParser.getLengths().length; i++)
{
fontStream.getCOSObject().setInt("Length" + (i + 1), pfbParser.getLengths()[i]);
}
fd.setFontFile(fontStream);
// set the values
dict.setItem(COSName.FONT_DESC, fd);
dict.setName(COSName.BASE_FONT, type1.getName());
// widths
List<Integer> widths = new ArrayList<>(256);
for (int code = 0; code <= 255; code++)
{
String name = fontEncoding.getName(code);
int width = Math.round(type1.getWidth(name));
widths.add(width);
}
dict.setInt(COSName.FIRST_CHAR, 0);
dict.setInt(COSName.LAST_CHAR, 255);
dict.setItem(COSName.WIDTHS, COSArrayList.converterToCOSArray(widths));
}
/**
* Returns a PDFontDescriptor for the given PFB.
*/
static PDFontDescriptor buildFontDescriptor(Type1Font type1)
{
boolean isSymbolic = type1.getEncoding()
instanceof org.apache.fontbox.encoding.BuiltInEncoding;
PDFontDescriptor fd = new PDFontDescriptor();
fd.setFontName(type1.getName());
fd.setFontFamily(type1.getFamilyName());
fd.setNonSymbolic(!isSymbolic);
fd.setSymbolic(isSymbolic);
fd.setFontBoundingBox(new PDRectangle(type1.getFontBBox()));
fd.setItalicAngle(type1.getItalicAngle());
fd.setAscent(type1.getFontBBox().getUpperRightY());
fd.setDescent(type1.getFontBBox().getLowerLeftY());
fd.setCapHeight(type1.getBlueValues().get(2).floatValue());
fd.setStemV(0); // for PDF/A
return fd;
}
/**
* Returns a PDFontDescriptor for the given AFM. Used only for Standard 14 fonts.
*
* @param metrics AFM
*/
static PDFontDescriptor buildFontDescriptor(FontMetrics metrics)
{
boolean isSymbolic = metrics.getEncodingScheme().equals("FontSpecific");
PDFontDescriptor fd = new PDFontDescriptor();
fd.setFontName(metrics.getFontName());
fd.setFontFamily(metrics.getFamilyName());
fd.setNonSymbolic(!isSymbolic);
fd.setSymbolic(isSymbolic);
fd.setFontBoundingBox(new PDRectangle(metrics.getFontBBox()));
fd.setItalicAngle(metrics.getItalicAngle());
fd.setAscent(metrics.getAscender());
fd.setDescent(metrics.getDescender());
fd.setCapHeight(metrics.getCapHeight());
fd.setXHeight(metrics.getXHeight());
fd.setAverageWidth(metrics.getAverageCharacterWidth());
fd.setCharacterSet(metrics.getCharacterSet());
fd.setStemV(0); // for PDF/A
return fd;
}
/**
* Returns the font's encoding.
*/
public Encoding getFontEncoding()
{
return fontEncoding;
}
/**
* Returns the font's glyph list.
*/
public GlyphList getGlyphList()
{
return GlyphList.getAdobeGlyphList();
}
/**
* Returns the Type 1 font.
*/
public Type1Font getType1Font()
{
return type1;
}
}