From 0ca1440be847bb6e60347a6c30ff3f7e873d60bb Mon Sep 17 00:00:00 2001 From: Bertrand Delacretaz Date: Tue, 10 Oct 2006 13:14:19 +0000 Subject: [PATCH] (this file was missing in previous commit) Applied patch from bugzilla 5335, comment 10. Generates a ToUnicode table for embedded CID fonts. Patch provided by Adam Strzelecki, ono@java.pl. The patch contains code for the FOray project, used with permission (bugzilla 5335 comment #13). git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@454731 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/pdf/PDFToUnicodeCMap.java | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java diff --git a/src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java b/src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java new file mode 100644 index 000000000..88264cf08 --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java @@ -0,0 +1,322 @@ +/* + * $Id: PDFToUnicodeCMap.java,v 1.3.2.1 2005/12/01 12:00:00 ono Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber . For more information on the Apache + * Software Foundation, please see . + */ +package org.apache.fop.pdf; + +/** + * Class representing ToUnicode CMaps. + * Here are some documentation resources: + * + */ +import org.apache.fop.fonts.CIDFont; + +public class PDFToUnicodeCMap extends PDFCMap { + + /** + * handle to read font + */ + protected CIDFont cidFont; + + /** + * Constructor. + * + * @param name One of the registered names found in Table 5.14 in PDF + * Reference, Second Edition. + * @param sysInfo The attributes of the character collection of the CIDFont. + */ + public PDFToUnicodeCMap(CIDFont cidMetrics, String name, PDFCIDSystemInfo sysInfo) { + super(name, sysInfo); + cidFont = cidMetrics; + } + + public void fillInPDF(StringBuffer p) { + writeCIDInit(p); + writeCIDSystemInfo(p); + writeVersionTypeName(p); + writeCodeSpaceRange(p); + writeBFEntries(p); + writeWrapUp(p); + add(p.toString()); + } + + protected void writeCIDSystemInfo(StringBuffer p) { + p.append("/CIDSystemInfo\n"); + p.append("<< /Registry (Adobe)\n"); + p.append("/Ordering (UCS)\n"); + p.append("/Supplement 0\n"); + p.append(">> def\n"); + } + + protected void writeVersionTypeName(StringBuffer p) { + p.append("/CMapName /Adobe-Identity-UCS def\n"); + p.append("/CMapType 2 def\n"); + } + + /** + * Writes the character mappings for this font. + */ + protected void writeBFEntries(StringBuffer p) { + if(cidFont == null) return; + + char[] charArray = cidFont.getCharsUsed(); + + if(charArray != null) { + writeBFCharEntries(p, charArray); + writeBFRangeEntries(p, charArray); + } + } + + protected void writeBFCharEntries(StringBuffer p, char[] charArray) { + int completedEntries = 0; + int totalEntries = 0; + for (int i = 0; i < charArray.length; i++) { + if (! partOfRange(charArray, i)) { + totalEntries ++; + } + } + if (totalEntries < 1) { + return; + } + int remainingEntries = totalEntries; + /* Limited to 100 entries in each section */ + int entriesThisSection = Math.min(remainingEntries, 100); + int remainingEntriesThisSection = entriesThisSection; + p.append(entriesThisSection + " beginbfchar\n"); + for (int i = 0; i < charArray.length; i++) { + if (partOfRange(charArray, i)) { + continue; + } + p.append("<" + padHexString(Integer.toHexString(i), 4) + + "> "); + p.append("<" + padHexString(Integer.toHexString(charArray[i]), 4) + + ">\n"); + /* Compute the statistics. */ + completedEntries ++; + remainingEntries = totalEntries - completedEntries; + remainingEntriesThisSection --; + if (remainingEntriesThisSection < 1) { + if (remainingEntries > 0) { + p.append("endbfchar\n"); + entriesThisSection = Math.min(remainingEntries, 100); + remainingEntriesThisSection = entriesThisSection; + p.append(entriesThisSection + " beginbfchar\n"); + } + } + } + p.append("endbfchar\n"); + } + + protected void writeBFRangeEntries(StringBuffer p, char[] charArray) { + int completedEntries = 0; + int totalEntries = 0; + for (int i = 0; i < charArray.length; i++) { + if (startOfRange(charArray, i)) { + totalEntries ++; + } + } + if (totalEntries < 1) { + return; + } + int remainingEntries = totalEntries; + int entriesThisSection = Math.min(remainingEntries, 100); + int remainingEntriesThisSection = entriesThisSection; + p.append(entriesThisSection + " beginbfrange\n"); + for (int i = 0; i < charArray.length; i++) { + if (! startOfRange(charArray, i)) { + continue; + } + p.append("<" + + padHexString(Integer.toHexString(i), 4) + + "> "); + p.append("<" + + padHexString(Integer.toHexString + (endOfRange(charArray, i)), 4) + + "> "); + p.append("<" + + padHexString(Integer.toHexString(charArray[i]), 4) + + ">\n"); + /* Compute the statistics. */ + completedEntries ++; + remainingEntries = totalEntries - completedEntries; + if (remainingEntriesThisSection < 1) { + if (remainingEntries > 0) { + p.append("endbfrange\n"); + entriesThisSection = Math.min(remainingEntries, 100); + remainingEntriesThisSection = entriesThisSection; + p.append(entriesThisSection + " beginbfrange\n"); + } + } + } + p.append("endbfrange\n"); + } + + /** + * Find the end of the current range. + * @param charArray The array which is being tested. + * @param startOfRange The index to the array element that is the start of + * the range. + * @return The index to the element that is the end of the range. + */ + private int endOfRange(char[] charArray, int startOfRange) { + int endOfRange = -1; + for (int i = startOfRange; i < charArray.length - 1 && endOfRange < 0; + i++) { + if (! sameRangeEntryAsNext(charArray, i)) { + endOfRange = i; + } + } + return endOfRange; + } + + /** + * Determine whether this array element should be part of a bfchar entry or + * a bfrange entry. + * @param charArray The array to be tested. + * @param arrayIndex The index to the array element to be tested. + * @return True if this array element should be included in a range. + */ + private boolean partOfRange(char[] charArray, int arrayIndex) { + if (charArray.length < 2) { + return false; + } + if (arrayIndex == 0) { + return sameRangeEntryAsNext(charArray, 0); + } + if (arrayIndex == charArray.length - 1) { + return sameRangeEntryAsNext(charArray, arrayIndex - 1); + } + if (sameRangeEntryAsNext(charArray, arrayIndex - 1)) { + return true; + } + if (sameRangeEntryAsNext(charArray, arrayIndex)) { + return true; + } + return false; + } + + /** + * Determine whether two bytes can be written in the same bfrange entry. + * @param charArray The array to be tested. + * @param firstItem The first of the two items in the array to be tested. + * The second item is firstItem + 1. + * @return True if both 1) the next item in the array is sequential with + * this one, and 2) the first byte of the character in the first position + * is equal to the first byte of the character in the second position. + */ + private boolean sameRangeEntryAsNext(char[] charArray, int firstItem) { + if (charArray[firstItem] + 1 != charArray[firstItem + 1]) { + return false; + } + if (firstItem / 256 != (firstItem + 1) / 256) { + return false; + } + return true; + } + + /** + * Determine whether this array element should be the start of a bfrange + * entry. + * @param charArray The array to be tested. + * @param arrayIndex The index to the array element to be tested. + * @return True if this array element is the beginning of a range. + */ + private boolean startOfRange(char[] charArray, int arrayIndex) { + // Can't be the start of a range if not part of a range. + if (! partOfRange(charArray, arrayIndex)) { + return false; + } + // If first element in the array, must be start of a range + if (arrayIndex == 0) { + return true; + } + // If last element in the array, cannot be start of a range + if (arrayIndex == charArray.length - 1) { + return false; + } + /* + * If part of same range as the previous element is, cannot be start + * of range. + */ + if (sameRangeEntryAsNext(charArray, arrayIndex - 1)) { + return false; + } + // Otherwise, this is start of a range. + return true; + } + + /** + * Prepends the input string with a sufficient number of "0" characters to + * get the returned string to be numChars length. + * @param input The input string. + * @param numChars The minimum characters in the output string. + * @return The padded string. + */ + public static String padHexString(String input, int numChars) { + int length = input.length(); + if (length >= numChars) { + return input; + } + StringBuffer returnString = new StringBuffer(); + for (int i = 1; i <= numChars - length; i++) { + returnString.append("0"); + } + returnString.append(input); + return returnString.toString(); + } + +} -- 2.39.5