From: Bertrand Delacretaz Date: Wed, 27 Sep 2006 15:36:13 +0000 (+0000) Subject: Missing files from previous commit, Vincent Hennebert's patch, attachment 18917 to... X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=1853c7c12fba20b9e947f40f10482dd7e01807ff;p=xmlgraphics-fop.git Missing files from previous commit, Vincent Hennebert's patch, attachment 18917 to bugzilla 35948. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/foray-font@450481 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/fop/pdf/FontMap.java b/src/java/org/apache/fop/pdf/FontMap.java new file mode 100644 index 000000000..3aa23a8cb --- /dev/null +++ b/src/java/org/apache/fop/pdf/FontMap.java @@ -0,0 +1,125 @@ +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed 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.util.Hashtable; +import java.util.Map; +import java.util.Set; + +import org.axsl.fontR.FontConsumer; +import org.axsl.fontR.FontUse; + +/** + * Class that stores a mapping of each FontUse to a corresponding internal name + * (F1, F2...), used to refer to a font in the PDF file. + */ +public class FontMap { + + /** + * The Map iself. Keys are FontUse instances, values are String (internal + * name). + */ + private Map fontMap; + + /** + * Font consumer associated to this map. + */ + private FontConsumer fontConsumer; + + + /** + * Builds a font mapping of the FontUses available from the font server + * associated to the given font consumer. + * + * @param fontConsumer font consumer from which to get the FontUses + */ + public FontMap(FontConsumer fontConsumer) { + this.fontConsumer = fontConsumer; + this.fontMap = new Hashtable(); + } + + /** + * Builds a font mapping of (possibly all) the FontUses available from the + * font server associated to the given font consumer. + * + * @param fontConsumer + * font consumer from which to get the FontUses + * @param registerAllFonts + * if true, all of the FontUses available from + * the font server are registered (useful for poscript output). + * Otherwise font uses are only registered when needed. This is + * the default. + */ + public FontMap(FontConsumer fontConsumer, boolean registerAllFonts) { + this.fontConsumer = fontConsumer; + if (!registerAllFonts) { + this.fontMap = new Hashtable(); + } else { + // TODO vh: re-enable +// FontUse[] fontUses = fontConsumer.getFontServer().getAllFontUses(true, false); +// fontMap = new Hashtable(fontUses.length); +// for (int i = 0; i < fontUses.length; i++) { +// fontMap.put(fontUses[i], "F" + new Integer(i)); +// } + } + } + + /** + * Returns the font consumer associated to this font map. + * @return the font consumer + */ + public FontConsumer getFontConsumer() { + return fontConsumer; + } + + /** + * Returns the internal name associated to the given FontUse instance. + * @param fontUse a FontUse + * @return the corresponding internal name + */ + public String getInternalName(FontUse fontUse) { + String internalName; + if (!fontMap.containsKey(fontUse)) { + internalName = "F" + (fontMap.size() + 1); + fontMap.put(fontUse, internalName); + } else { + internalName = (String) fontMap.get(fontUse); + } + return internalName; + } + + /** + * Returns the number of registered font uses. + * @return number of mappings + */ + public int getSize() { + return fontMap.size(); + } + + /** + * Returns the mappings contained in this font map. Each element in the + * returned set is a Map.Entry, in which the key is a FontUse and the value + * its corresponding internal name. + * + * @return a set of the mappings contained in this font map. + */ + public Set getMappings() { + return fontMap.entrySet(); + } +} diff --git a/src/java/org/apache/fop/pdf/PDFFontFileStream.java b/src/java/org/apache/fop/pdf/PDFFontFileStream.java new file mode 100644 index 000000000..ca28d57b8 --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFFontFileStream.java @@ -0,0 +1,94 @@ +/* + * Copyright 2004 The FOray Project. + * http://www.foray.org + * + * Licensed 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. + * + * This work is in part derived from the following work(s), used with the + * permission of the licensor: + * Apache FOP, licensed by the Apache Software Foundation + * + */ + +/* $Id$ */ + +package org.apache.fop.pdf; + +import org.axsl.fontR.FontConsumer; +import org.axsl.fontR.FontUse; +import org.axsl.fontR.output.FontPDF; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +public class PDFFontFileStream extends PDFStream { + private FontUse font; + private FontPDF fontOutput; + + public PDFFontFileStream(FontUse font, FontConsumer fontConsumer) { + super(); + if (!font.getFont().isEmbeddable()) { + // TODO vh: better error handling + log.error("Can't create PDFFontFileStream for a Font " + + "that is not embeddable."); + return; + } + this.font = font; + this.fontOutput = (FontPDF)font.getFontOutput("application/pdf"); + byte[] fontFileStream = fontOutput.getContents(); + // TODO vh +// addFilter("flate"); +// addFilter("ascii-85"); + try { + setData(fontFileStream); + } catch (IOException ioe) { + log.error("Failed to embed font " + + font.getPostscriptName() + ": " + ioe.getMessage()); + } + } + + protected int output(OutputStream stream) throws IOException { + int length = 0; + // TODO vh +// String filterEntry = applyFilters(); + String preData + = getObjectID() + "\n<< /Length " + + getDataLength() + + " " +// + filterEntry + + fontOutput.getPDFFontFileStreamAdditional() + + " >>\n"; + + byte[] p; + try { + p = preData.getBytes(PDFDocument.ENCODING); + } catch (UnsupportedEncodingException ue) { + p = preData.getBytes(); + } + + stream.write(p); + length += p.length; + + length += outputStreamData(data, stream); + try { + p = ("\nendobj\n").getBytes(PDFDocument.ENCODING); + } catch (UnsupportedEncodingException ue) { + p = ("\nendobj\n").getBytes(); + } + stream.write(p); + length += p.length; + return length; + } + +} 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..a1810580b --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java @@ -0,0 +1,259 @@ +package org.apache.fop.pdf; + +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(); + } + +} \ No newline at end of file