From 6025b6016517c6d898d8957d1d7e03ba71431912 Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 1 Dec 2006 12:20:24 +0000 Subject: Initial import of release 2.2. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@4 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../java/com/lowagie/text/pdf/CFFFontSubset.java | 1633 ++++++++++++++++++++ 1 file changed, 1633 insertions(+) create mode 100644 src/main/java/com/lowagie/text/pdf/CFFFontSubset.java (limited to 'src/main/java/com/lowagie/text/pdf/CFFFontSubset.java') diff --git a/src/main/java/com/lowagie/text/pdf/CFFFontSubset.java b/src/main/java/com/lowagie/text/pdf/CFFFontSubset.java new file mode 100644 index 0000000..111f899 --- /dev/null +++ b/src/main/java/com/lowagie/text/pdf/CFFFontSubset.java @@ -0,0 +1,1633 @@ +/* + * $Id: CFFFontSubset.java,v 1.3 2005/02/17 09:20:54 blowagie Exp $ + * $Name: $ + * + * Copyright 2004 Oren Manor and Ygal Blum + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +package com.lowagie.text.pdf; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.ArrayList; +import java.io.*; + +/** + * This Class subsets a CFF Type Font. The subset is preformed for CID fonts and NON CID fonts. + * The Charstring is subseted for both types. For CID fonts only the FDArray which are used are embedded. + * The Lsubroutines of the FDArrays used are subsetted as well. The Subroutine subset supports both Type1 and Type2 + * formatting altough only tested on Type2 Format. + * For Non CID the Lsubroutines are subsetted. On both types the Gsubroutines is subsetted. + * A font which was not of CID type is transformed into CID as a part of the subset process. + * The CID synthetic creation was written by Sivan Toledo + * @author Oren Manor & Ygal Blum + */ +public class CFFFontSubset extends CFFFont { + + /** + * The Strings in this array represent Type1/Type2 operator names + */ + static final String SubrsFunctions[] = { + "RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto", + "rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13", + "endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask", + "cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto", + "hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto" + }; + /** + * The Strings in this array represent Type1/Type2 escape operator names + */ + static final String SubrsEscapeFuncs[] = { + "RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6", + "RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg", + "eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse", + "random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31", + "RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST" + }; + + /** + * A HashMap containing the glyphs used in the text after being converted + * to glyph number by the CMap + */ + HashMap GlyphsUsed; + /** + * The GlyphsUsed keys as an ArrayList + */ + ArrayList glyphsInList; + /** + * A HashMap for keeping the FDArrays being used by the font + */ + HashMap FDArrayUsed = new HashMap(); + /** + * A HashMaps array for keeping the subroutines used in each FontDict + */ + HashMap[] hSubrsUsed; + /** + * The SubroutinesUsed HashMaps as ArrayLists + */ + ArrayList[] lSubrsUsed; + /** + * A HashMap for keeping the Global subroutines used in the font + */ + HashMap hGSubrsUsed = new HashMap(); + /** + * The Global SubroutinesUsed HashMaps as ArrayLists + */ + ArrayList lGSubrsUsed = new ArrayList(); + /** + * A HashMap for keeping the subroutines used in a non-cid font + */ + HashMap hSubrsUsedNonCID = new HashMap(); + /** + * The SubroutinesUsed HashMap as ArrayList + */ + ArrayList lSubrsUsedNonCID = new ArrayList(); + /** + * An array of the new Indexs for the local Subr. One index for each FontDict + */ + byte[][] NewLSubrsIndex; + /** + * The new subroutines index for a non-cid font + */ + byte[] NewSubrsIndexNonCID; + /** + * The new global subroutines index of the font + */ + byte[] NewGSubrsIndex; + /** + * The new CharString of the font + */ + byte[] NewCharStringsIndex; + + /** + * The bias for the global subroutines + */ + int GBias = 0; + + /** + * The linked list for generating the new font stream + */ + LinkedList OutputList; + + /** + * Number of arguments to the stem operators in a subroutine calculated recursivly + */ + int NumOfHints=0; + + + /** + * C'tor for CFFFontSubset + * @param rf - The font file + * @param GlyphsUsed - a HashMap that contains the glyph used in the subset + */ + public CFFFontSubset(RandomAccessFileOrArray rf,HashMap GlyphsUsed){ + // Use CFFFont c'tor in order to parse the font file. + super(rf); + this.GlyphsUsed = GlyphsUsed; + //Put the glyphs into a list + glyphsInList = new ArrayList(GlyphsUsed.keySet()); + + + for (int i=0;i=0) + { + // Proces the FDSelect + readFDSelect(i); + // Build the FDArrayUsed hashmap + BuildFDArrayUsed(i); + } + if (fonts[i].isCID) + // Build the FD Array used Hash Map + ReadFDArray(i); + // compute the charset length + fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs); + } + } + + /** + * Calculates the length of the charset according to its format + * @param Offset The Charset Offset + * @param NumofGlyphs Number of glyphs in the font + * @return the length of the Charset + */ + int CountCharset(int Offset,int NumofGlyphs){ + int format; + int Length=0; + seek(Offset); + // Read the format + format = getCard8(); + // Calc according to format + switch (format){ + case 0: + Length = 1+2*NumofGlyphs; + break; + case 1: + Length = 1+3*CountRange(NumofGlyphs,1); + break; + case 2: + Length = 1+4*CountRange(NumofGlyphs,2); + break; + default: + break; + } + return Length; + } + + /** + * Function calculates the number of ranges in the Charset + * @param NumofGlyphs The number of glyphs in the font + * @param Type The format of the Charset + * @return The number of ranges in the Charset data structure + */ + int CountRange(int NumofGlyphs,int Type){ + int num=0; + char Sid; + int i=1,nLeft,Places; + while (i= 0) + GBias = CalcBias(gsubrIndexOffset,j); + + // Prepare the new CharStrings Index + BuildNewCharString(j); + // Prepare the new Global and Local Subrs Indices + BuildNewLGSubrs(j); + // Build the new file + byte[] Ret = BuildNewFile(j); + return Ret; + } + finally { + try { + buf.close(); + } + catch (Exception e) { + // empty on purpose + } + } + } + + /** + * Function calcs bias according to the CharString type and the count + * of the subrs + * @param Offset The offset to the relevent subrs index + * @param Font the font + * @return The calculated Bias + */ + protected int CalcBias(int Offset,int Font) + { + seek(Offset); + int nSubrs = getCard16(); + // If type==1 -> bias=0 + if (fonts[Font].CharstringType == 1) + return 0; + // else calc according to the count + else if (nSubrs < 1240) + return 107; + else if (nSubrs < 33900) + return 1131; + else + return 32768; + } + + /** + *Function uses BuildNewIndex to create the new index of the subset charstrings + * @param FontIndex the font + * @throws IOException + */ + protected void BuildNewCharString(int FontIndex) throws IOException + { + NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed); + } + + /** + * Function builds the new local & global subsrs indices. IF CID then All of + * the FD Array lsubrs will be subsetted. + * @param Font the font + * @throws IOException + */ + protected void BuildNewLGSubrs(int Font)throws IOException + { + // If the font is CID then the lsubrs are divided into FontDicts. + // for each FD array the lsubrs will be subsetted. + if(fonts[Font].isCID) + { + // Init the hasmap-array and the arraylist-array to hold the subrs used + // in each private dict. + hSubrsUsed = new HashMap[fonts[Font].fdprivateOffsets.length]; + lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.length]; + // A [][] which will store the byte array for each new FD Array lsubs index + NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.length][]; + // An array to hold the offset for each Lsubr index + fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.length]; + // A [][] which will store the offset array for each lsubr index + fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.length][]; + + // Put the FDarrayUsed into a list + ArrayList FDInList = new ArrayList(FDArrayUsed.keySet()); + // For each FD array which is used subset the lsubr + for (int j=0;j=0) + { + //Scans the Charsting data storing the used Local and Global subroutines + // by the glyphs. Scans the Subrs recursivley. + BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]); + // Builds the New Local Subrs index + NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD]); + } + } + } + // If the font is not CID && the Private Subr exists then subset: + else if (fonts[Font].privateSubrs>=0) + { + // Build the subrs offsets; + fonts[Font].SubrsOffsets = getIndex(fonts[Font].privateSubrs); + //Scans the Charsting data storing the used Local and Global subroutines + // by the glyphs. Scans the Subrs recursivley. + BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID); + } + // For all fonts susbset the Global Subroutines + // Scan the Global Subr Hashmap recursivly on the Gsubrs + BuildGSubrsUsed(Font); + if (fonts[Font].privateSubrs>=0) + // Builds the New Local Subrs index + NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID); + //Builds the New Global Subrs index + NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed); + } + + /** + * The function finds for the FD array processed the local subr offset and its + * offset array. + * @param Font the font + * @param FD The FDARRAY processed + */ + protected void BuildFDSubrsOffsets(int Font,int FD) + { + // Initiate to -1 to indicate lsubr operator present + fonts[Font].PrivateSubrsOffset[FD] = -1; + // Goto begining of objects + seek(fonts[Font].fdprivateOffsets[FD]); + // While in the same object: + while (getPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD]) + { + getDictItem(); + // If the dictItem is the "Subrs" then find and store offset, + if (key=="Subrs") + fonts[Font].PrivateSubrsOffset[FD] = ((Integer)args[0]).intValue()+fonts[Font].fdprivateOffsets[FD]; + } + //Read the lsub index if the lsubr was found + if (fonts[Font].PrivateSubrsOffset[FD] >= 0) + fonts[Font].PrivateSubrsOffsetsArray[FD] = getIndex(fonts[Font].PrivateSubrsOffset[FD]); + } + + /** + * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap. + * The HashMap (of the lsub only) is then scaned recursivly for Lsubr & Gsubrs + * calls. + * @param Font the font + * @param FD FD array processed. 0 indicates function was called by non CID font + * @param SubrOffset the offset to the subr index to calc the bias + * @param SubrsOffsets the offset array of the subr index + * @param hSubr HashMap of the subrs used + * @param lSubr ArrayList of the subrs used + */ + protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,HashMap hSubr,ArrayList lSubr) + { + + // Calc the Bias for the subr index + int LBias = CalcBias(SubrOffset,Font); + + // For each glyph used find its GID, start & end pos + for (int i=0;i= 0) + { + EmptyStack(); + NumOfHints=0; + // Using FDSELECT find the FD Array the glyph belongs to. + int GlyphFD = fonts[Font].FDSelect[glyph]; + // If the Glyph is part of the FD being processed + if (GlyphFD == FD) + // Find the Subrs called by the glyph and insert to hash: + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + else + // If the font is not CID + //Find the Subrs called by the glyph and insert to hash: + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + // For all Lsubrs used, check recusrivly for Lsubr & Gsubr used + for (int i=0;i=0) + { + // Read and process the subr + int Start = SubrsOffsets[Subr]; + int End = SubrsOffsets[Subr+1]; + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + } + } + + /** + * Function scans the Glsubr used ArrayList to find recursive calls + * to Gsubrs and adds to Hashmap & ArrayList + * @param Font the font + */ + protected void BuildGSubrsUsed(int Font) + { + int LBias = 0; + int SizeOfNonCIDSubrsUsed = 0; + if (fonts[Font].privateSubrs>=0) + { + LBias = CalcBias(fonts[Font].privateSubrs,Font); + SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size(); + } + + // For each global subr used + for (int i=0;i=0) + { + // Read the subr and process + int Start = gsubrOffsets[Subr]; + int End = gsubrOffsets[Subr+1]; + + if (fonts[Font].isCID) + ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null); + else + { + ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); + if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.size()) + { + for (int j=SizeOfNonCIDSubrsUsed;j=0) + { + // Read the subr and process + int LStart = fonts[Font].SubrsOffsets[LSubr]; + int LEnd = fonts[Font].SubrsOffsets[LSubr+1]; + ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); + } + } + SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size(); + } + } + } + } + } + + /** + * The function reads a subrs (glyph info) between begin and end. + * Adds calls to a Lsubr to the hSubr and lSubrs. + * Adds calls to a Gsubr to the hGSubr and lGSubrs. + * @param begin the start point of the subr + * @param end the end point of the subr + * @param GBias the bias of the Global Subrs + * @param LBias the bias of the Local Subrs + * @param hSubr the HashMap for the lSubrs + * @param lSubr the ArrayList for the lSubrs + */ + protected void ReadASubr(int begin,int end,int GBias,int LBias,HashMap hSubr,ArrayList lSubr,int[] LSubrsOffsets) + { + // Clear the stack for the subrs + EmptyStack(); + NumOfHints = 0; + // Goto begining of the subr + seek(begin); + while (getPosition() < end) + { + // Read the next command + ReadCommand(); + int pos = getPosition(); + Object TopElement=null; + if (arg_count > 0) + TopElement = args[arg_count-1]; + int NumOfArgs = arg_count; + // Check the modification needed on the Argument Stack according to key; + HandelStack(); + // a call to a Lsubr + if (key=="callsubr") + { + // Verify that arguments are passed + if (NumOfArgs > 0) + { + // Calc the index of the Subrs + int Subr = ((Integer)TopElement).intValue() + LBias; + // If the subr isn't in the HashMap -> Put in + if (!hSubr.containsKey(new Integer (Subr))) + { + hSubr.put(new Integer(Subr),null); + lSubr.add(new Integer(Subr)); + } + CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + seek(pos); + } + } + // a call to a Gsubr + else if (key=="callgsubr") + { + // Verify that arguments are passed + if (NumOfArgs > 0) + { + // Calc the index of the Subrs + int Subr = ((Integer)TopElement).intValue() + GBias; + // If the subr isn't in the HashMap -> Put in + if (!hGSubrsUsed.containsKey(new Integer (Subr))) + { + hGSubrsUsed.put(new Integer(Subr),null); + lGSubrsUsed.add(new Integer(Subr)); + } + CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + seek(pos); + } + } + // A call to "stem" + else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") + // Increment the NumOfHints by the number couples of of arguments + NumOfHints += NumOfArgs/2; + // A call to "mask" + else if (key == "hintmask" || key == "cntrmask") + { + // Compute the size of the mask + int SizeOfMask = NumOfHints/8; + if (NumOfHints%8 != 0 || SizeOfMask == 0) + SizeOfMask++; + // Continue the pointer in SizeOfMask steps + for (int i=0;i flush the stack + */ + protected int StackOpp() + { + if (key == "ifelse") + return -3; + if (key == "roll" || key == "put") + return -2; + if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" || + key == "div" || key == "mul" || key == "drop" || key == "and" || + key == "or" || key == "eq") + return -1; + if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" || + key == "index" || key == "get" || key == "not" || key == "return") + return 0; + if (key == "random" || key == "dup") + return 1; + return 2; + } + + /** + * Empty the Type2 Stack + * + */ + protected void EmptyStack() + { + // Null the arguments + for (int i=0; i0) + { + args[arg_count-1]=null; + arg_count--; + } + } + + /** + * Add an item to the stack + * + */ + protected void PushStack() + { + arg_count++; + } + + /** + * The function reads the next command after the file pointer is set + */ + protected void ReadCommand() + { + key = null; + boolean gotKey = false; + // Until a key is found + while (!gotKey) { + // Read the first Char + char b0 = getCard8(); + // decode according to the type1/type2 format + if (b0 == 28) // the two next bytes represent a short int; + { + int first = getCard8(); + int second = getCard8(); + args[arg_count] = new Integer(first<<8 | second); + arg_count++; + continue; + } + if (b0 >= 32 && b0 <= 246) // The byte read is the byte; + { + args[arg_count] = new Integer(b0 - 139); + arg_count++; + continue; + } + if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constetute a short int + { + int w = getCard8(); + args[arg_count] = new Integer((b0-247)*256 + w + 108); + arg_count++; + continue; + } + if (b0 >= 251 && b0 <= 254)// Same as above except negative + { + int w = getCard8(); + args[arg_count] = new Integer(-(b0-251)*256 - w - 108); + arg_count++; + continue; + } + if (b0 == 255)// The next for bytes represent a double. + { + int first = getCard8(); + int second = getCard8(); + int third = getCard8(); + int fourth = getCard8(); + args[arg_count] = new Integer(first<<24 | second<<16 | third<<8 | fourth); + arg_count++; + continue; + } + if (b0<=31 && b0 != 28) // An operator was found.. Set Key. + { + gotKey=true; + // 12 is an escape command therefor the next byte is a part + // of this command + if (b0 == 12) + { + int b1 = getCard8(); + if (b1>SubrsEscapeFuncs.length-1) + b1 = SubrsEscapeFuncs.length-1; + key = SubrsEscapeFuncs[b1]; + } + else + key = SubrsFunctions[b0]; + continue; + } + } + } + + /** + * The function reads the subroutine and returns the number of the hint in it. + * If a call to another subroutine is found the function calls recursively. + * @param begin the start point of the subr + * @param end the end point of the subr + * @param LBias the bias of the Local Subrs + * @param GBias the bias of the Global Subrs + * @param LSubrsOffsets The Offsets array of the subroutines + * @return The number of hints in the subroutine read. + */ + protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets) + { + // Goto begining of the subr + seek(begin); + while (getPosition() < end) + { + // Read the next command + ReadCommand(); + int pos = getPosition(); + Object TopElement = null; + if (arg_count>0) + TopElement = args[arg_count-1]; + int NumOfArgs = arg_count; + //Check the modification needed on the Argument Stack according to key; + HandelStack(); + // a call to a Lsubr + if (key=="callsubr") + { + if (NumOfArgs>0) + { + int Subr = ((Integer)TopElement).intValue() + LBias; + CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + seek(pos); + } + } + // a call to a Gsubr + else if (key=="callgsubr") + { + if (NumOfArgs>0) + { + int Subr = ((Integer)TopElement).intValue() + GBias; + CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + seek(pos); + } + } + // A call to "stem" + else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") + // Increment the NumOfHints by the number couples of of arguments + NumOfHints += NumOfArgs/2; + // A call to "mask" + else if (key == "hintmask" || key == "cntrmask") + { + // Compute the size of the mask + int SizeOfMask = NumOfHints/8; + if (NumOfHints%8 != 0 || SizeOfMask == 0) + SizeOfMask++; + // Continue the pointer in SizeOfMask steps + for (int i=0;i>> 8) & 0xff); + NewIndex[Place++] = (byte) ((Count >>> 0) & 0xff); + // Write the offsize field + NewIndex[Place++] = Offsize; + // Write the offset array according to the offsize + for (int i=0;i>> 24) & 0xff); + case 3: + NewIndex[Place++] = (byte) ((Num >>> 16) & 0xff); + case 2: + NewIndex[Place++] = (byte) ((Num >>> 8) & 0xff); + case 1: + NewIndex[Place++] = (byte) ((Num >>> 0) & 0xff); + } + } + // Write the new object array one by one + for (int i=0;i=0) + OutputList.addLast(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength)); + // Else create a new one + else + CreateFDSelect(fdselectRef,fonts[Font].nglyphs); + + // Copy the Charset + // Mark the beginning and copy entirly + OutputList.addLast(new MarkerItem(charsetRef)); + OutputList.addLast(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength)); + + // Copy the FDArray + // If an FDArray exists + if (fonts[Font].fdarrayOffset>=0) + { + // Mark the beginning + OutputList.addLast(new MarkerItem(fdarrayRef)); + // Build a new FDArray with its private dicts and their LSubrs + Reconstruct(Font); + } + else + // Else create a new one + CreateFDArray(fdarrayRef,privateRef,Font); + + } + // If the font is not CID + else + { + // create FDSelect + CreateFDSelect(fdselectRef,fonts[Font].nglyphs); + // recreate a new charset + CreateCharset(charsetRef,fonts[Font].nglyphs); + // create a font dict index (fdarray) + CreateFDArray(fdarrayRef,privateRef,Font); + } + + // if a private dict exists insert its subsetted version + if (fonts[Font].privateOffset>=0) + { + // Mark the beginning of the private dict + IndexBaseItem PrivateBase = new IndexBaseItem(); + OutputList.addLast(PrivateBase); + OutputList.addLast(new MarkerItem(privateRef)); + + OffsetItem Subr = new DictOffsetItem(); + // Build and copy the new private dict + CreateNonCIDPrivate(Font,Subr); + // Copy the new LSubrs index + CreateNonCIDSubrs(Font,PrivateBase,Subr); + } + + // copy the charstring index + OutputList.addLast(new MarkerItem(charstringsRef)); + + // Add the subsetted charstring + OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.length)); + + // now create the new CFF font + int[] currentOffset = new int[1]; + currentOffset[0] = 0; + // Count and save the offset for each item + Iterator listIter = OutputList.iterator(); + while ( listIter.hasNext() ) { + Item item = (Item) listIter.next(); + item.increment(currentOffset); + } + // Compute the Xref for each of the offset items + listIter = OutputList.iterator(); + while ( listIter.hasNext() ) { + Item item = (Item) listIter.next(); + item.xref(); + } + + int size = currentOffset[0]; + byte[] b = new byte[size]; + + // Emit all the items into the new byte array + listIter = OutputList.iterator(); + while ( listIter.hasNext() ) { + Item item = (Item) listIter.next(); + item.emit(b); + } + // Return the new stream + return b; + } + + /** + * Function Copies the header from the original fileto the output list + */ + protected void CopyHeader() + { + seek(0); + int major = getCard8(); + int minor = getCard8(); + int hdrSize = getCard8(); + int offSize = getCard8(); + nextIndexOffset = hdrSize; + OutputList.addLast(new RangeItem(buf,0,hdrSize)); + } + + /** + * Function Build the header of an index + * @param Count the count field of the index + * @param Offsize the offsize field of the index + * @param First the first offset of the index + */ + protected void BuildIndexHeader(int Count,int Offsize,int First) + { + // Add the count field + OutputList.addLast(new UInt16Item((char)Count)); // count + // Add the offsize field + OutputList.addLast(new UInt8Item((char)Offsize)); // offSize + // Add the first offset according to the offsize + switch(Offsize){ + case 1: + OutputList.addLast(new UInt8Item((char)First)); // first offset + break; + case 2: + OutputList.addLast(new UInt16Item((char)First)); // first offset + break; + case 3: + OutputList.addLast(new UInt24Item((char)First)); // first offset + break; + case 4: + OutputList.addLast(new UInt32Item((char)First)); // first offset + break; + default: + break; + } + } + + /** + * Function adds the keys into the TopDict + * @param fdarrayRef OffsetItem for the FDArray + * @param fdselectRef OffsetItem for the FDSelect + * @param charsetRef OffsetItem for the CharSet + * @param charstringsRef OffsetItem for the CharString + */ + protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef) + { + // create an FDArray key + OutputList.addLast(fdarrayRef); + OutputList.addLast(new UInt8Item((char)12)); + OutputList.addLast(new UInt8Item((char)36)); + // create an FDSelect key + OutputList.addLast(fdselectRef); + OutputList.addLast(new UInt8Item((char)12)); + OutputList.addLast(new UInt8Item((char)37)); + // create an charset key + OutputList.addLast(charsetRef); + OutputList.addLast(new UInt8Item((char)15)); + // create a CharStrings key + OutputList.addLast(charstringsRef); + OutputList.addLast(new UInt8Item((char)17)); + } + + /** + * Function takes the original string item and adds the new strings + * to accomodate the CID rules + * @param Font the font + */ + protected void CreateNewStringIndex(int Font) + { + String fdFontName = fonts[Font].name+"-OneRange"; + if (fdFontName.length() > 127) + fdFontName = fdFontName.substring(0,127); + String extraStrings = "Adobe"+"Identity"+fdFontName; + + int origStringsLen = stringOffsets[stringOffsets.length-1] + - stringOffsets[0]; + int stringsBaseOffset = stringOffsets[0]-1; + + byte stringsIndexOffSize; + if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1; + else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2; + else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3; + else stringsIndexOffSize = 4; + + OutputList.addLast(new UInt16Item((char)((stringOffsets.length-1)+3))); // count + OutputList.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize + for (int i=0; i= 0) + { + OutputList.addLast(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i])); + OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].length)); + } + } + } + + /** + * Calculates how many byte it took to write the offset for the subrs in a specific + * private dict. + * @param Offset The Offset for the private dict + * @param Size The size of the private dict + * @return The size of the offset of the subrs in the private dict + */ + int CalcSubrOffsetSize(int Offset,int Size) + { + // Set the size to 0 + int OffsetSize = 0; + // Go to the beginning of the private dict + seek(Offset); + // Go until the end of the private dict + while (getPosition() < Offset+Size) + { + int p1 = getPosition(); + getDictItem(); + int p2 = getPosition(); + // When reached to the subrs offset + if (key=="Subrs") { + // The Offsize (minus the subrs key) + OffsetSize = p2-p1-1; + } + // All other keys are ignored + } + // return the size + return OffsetSize; + } + + /** + * Function computes the size of an index + * @param indexOffset The offset for the computed index + * @return The size of the index + */ + protected int countEntireIndexRange(int indexOffset) + { + // Go to the beginning of the index + seek(indexOffset); + // Read the count field + int count = getCard16(); + // If count==0 -> size=2 + if (count==0) + return 2; + else + { + // Read the offsize field + int indexOffSize = getCard8(); + // Go to the last element of the offset array + seek(indexOffset+2+1+count*indexOffSize); + // The size of the object array is the value of the last element-1 + int size = getOffset(indexOffSize)-1; + // Return the size of the entire index + return 2+1+(count+1)*indexOffSize+size; + } + } + + /** + * The function creates a private dict for a font that was not CID + * All the keys are copied as is except for the subrs key + * @param Font the font + * @param Subr The OffsetItem for the subrs of the private + */ + void CreateNonCIDPrivate(int Font,OffsetItem Subr) + { + // Go to the beginning of the private dict and read untill the end + seek(fonts[Font].privateOffset); + while (getPosition() < fonts[Font].privateOffset+fonts[Font].privateLength) + { + int p1 = getPosition(); + getDictItem(); + int p2 = getPosition(); + // If the dictItem is the "Subrs" then, + // use marker for offset and write operator number + if (key=="Subrs") { + OutputList.addLast(Subr); + OutputList.addLast(new UInt8Item((char)19)); // Subrs + } + // Else copy the entire range + else + OutputList.addLast(new RangeItem(buf,p1,p2-p1)); + } + } + + /** + * the function marks the beginning of the subrs index and adds the subsetted subrs + * index to the output list. + * @param Font the font + * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs + * @param Subrs OffsetItem for the subrs + * @throws IOException + */ + void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs)throws IOException + { + // Mark the beginning of the Subrs index + OutputList.addLast(new SubrMarkerItem(Subrs,PrivateBase)); + // Put the subsetted new subrs index + OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.length)); + } +} \ No newline at end of file -- cgit v1.2.3