/**
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.jpedal.org
*
* (C) Copyright 2011, IDRsolutions and Contributors.
*
* This file is part of JPedal
*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---------------
* TTFontWriter.java
* ---------------
* (C) Copyright 2011, by IDRsolutions and Contributors.
*
*
* --------------------------
*/
package org.jpedal.fonts.tt.conversion;
import org.jpedal.fonts.PdfFont;
import org.jpedal.fonts.TrueType;
import org.jpedal.fonts.Type1C;
import org.jpedal.fonts.glyph.PdfGlyph;
import org.jpedal.fonts.glyph.PdfJavaGlyphs;
import org.jpedal.fonts.glyph.T1Glyphs;
import org.jpedal.fonts.tt.TTGlyphs;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public class PS2OTFFontWriter extends FontWriter{
byte[] cff;
byte[] cmap=null;
PdfFont pdfFont,orginalFont;
PdfJavaGlyphs glyphs;
int minCharCode;
int maxCharCode;
//Glyph Metrics
private int xAvgCharWidth=0;
private double xMaxExtent= Double.MIN_VALUE;
private double minRightSideBearing = Double.MAX_VALUE;
private double minLeftSideBearing = Double.MAX_VALUE;
private double advanceWidthMax = Double.MIN_VALUE;
private double lowestDescender = -1;
private double highestAscender = 1;
private float[] fontBBox = new float[4];
private int[] advanceWidths;
private HashMap<String,Integer> widthMap;
public PS2OTFFontWriter(PdfFont orginalFont,byte[] rawFontData, String fileType, HashMap<String,Integer> widths) throws Exception {
boolean is1C=fileType.equals("cff");
name=orginalFont.getBaseFontName();
this.widthMap = widths;
//adjust for TT or Postscript
String typeSpecificTable="CFF ";
if(fileType.equals("ttf")){
//read the data into our T1/t1c object so we can then parse
glyphs=new TTGlyphs();
pdfFont=new TrueType(rawFontData,glyphs);
typeSpecificTable="glyf";
}else{
/**
* for the moment we reread with diff paramters to extract other data
*/
//read the data into our T1/t1c object so we can then parse
glyphs=new T1Glyphs(false,is1C);
pdfFont=new Type1C(rawFontData,glyphs,is1C);
}
glyphCount=glyphs.getGlyphCount();
this.orginalFont=orginalFont;
this.cff=rawFontData;
/**
* required fonts (CMAP must be before OS2 ans it does a precalculation for it)
*/
final String[] tablesUsed=new String[]{typeSpecificTable,
// "FFTM",
// "GDEF",
"OS/2",
"cmap",
"head",
"hhea",
"hmtx",
"maxp",
"name",
"post"
};
tableList=new ArrayList();
numTables=tablesUsed.length;
int floor = 1;
while (floor*2 <= numTables)
floor *= 2;
searchRange = floor * 16;
entrySelector = 0;
while (Math.pow(2,entrySelector) < floor)
entrySelector++;
rangeShift = (numTables*16) - searchRange;
tableList.addAll(Arrays.asList(tablesUsed).subList(0, numTables));
//location of tables
checksums=new int[tableCount][1];
tables=new int[tableCount][1];
tableLength =new int[tableCount][1];
type=OPENTYPE;
//@sam - used to hack in font
// if(name.contains("KTBBOD+HermesFB-Bold")){
//// if(name.contains("ZapfEchos")){
//
// try{
// File file=new File("C:/Users/Sam/Downloads/HermesFB-Regular.otf");
//// File file=new File("C:/Users/Sam/Downloads/zapfechosWorks.otf");
// int len=(int)file.length();
// byte[] data=new byte[len];
// FileInputStream fis=new FileInputStream(file);
// fis.read(data);
// fis.close();
// FontFile2 f=new FontFile2(data,false);
//
//
// for(int l=0;l<numTables;l++){
//
// String tag= (String) tableList.get(l);
//
// //read table value (including for head which is done differently at end)
// int id= getTableID(tag);
//
// if(id!=-1){
// this.tables[id][currentFontID]=f.getTableStart(id);
// }
// }
//
// }catch(Exception e){
// e.printStackTrace();
// }
// }
}
void readTables() {
//Fetch advance widths
int totalWidth=0;
advanceWidths = new int[glyphCount];
if (widthMap != null) {
for (int i=0; i < glyphCount; i++) {
Integer w = widthMap.get(glyphs.getIndexForCharString(i+1));
if (w != null)
advanceWidths[i] = w;
else {
w = widthMap.get("JPedalDefaultWidth");
if (w != null)
advanceWidths[i] = w;
}
advanceWidthMax = advanceWidthMax > advanceWidths[i] ? advanceWidthMax : advanceWidths[i];
totalWidth += advanceWidths[i];
}
}
//Store average width
if(glyphCount>0)
xAvgCharWidth= (int) ((double)totalWidth/(double)glyphCount);
//Collect glyph metrics
double maxX = Double.MIN_VALUE;
for (int i=0; i<glyphCount && i<256; i++) {
PdfGlyph glyph = glyphs.getEmbeddedGlyph(new org.jpedal.fonts.glyph.T1GlyphFactory(),
pdfFont.getMappedChar(i, false),
new float[][]{{1,0},{0,1}},
i,
pdfFont.getGlyphValue(i),
pdfFont.getWidth(i),
pdfFont.getMappedChar(i, false));
if (glyph != null && glyph.getShape() != null) {
Rectangle2D area = glyph.getShape().getBounds2D();
double lsb = area.getMinX();
double rsb = advanceWidths[i]-area.getMaxX();
double extent = area.getMinX() + area.getWidth();
minLeftSideBearing = minLeftSideBearing < lsb ? minLeftSideBearing : lsb;
minRightSideBearing = minRightSideBearing < rsb ? minRightSideBearing : rsb;
xMaxExtent = xMaxExtent > extent ? xMaxExtent : extent;
lowestDescender = lowestDescender < area.getMinY() ? lowestDescender : area.getMinY();
highestAscender = highestAscender > area.getMaxY() ? highestAscender : area.getMaxY();
maxX = maxX > area.getMaxX() ? maxX : area.getMaxX();
}
}
fontBBox = pdfFont.FontBBox;
minLeftSideBearing = minLeftSideBearing < fontBBox[0] ? minLeftSideBearing : fontBBox[0];
lowestDescender = lowestDescender < fontBBox[1] ? lowestDescender : fontBBox[1];
maxX = maxX > fontBBox[2] ? maxX : fontBBox[2];
highestAscender = highestAscender > fontBBox[3] ? highestAscender : fontBBox[3];
fontBBox = new float[]{(float)minLeftSideBearing, (float)lowestDescender, (float)maxX, (float)highestAscender};
}
public byte[] getTableBytes(int tableID){
byte[] fontData=new byte[0];
FontTableWriter tableWriter=null;
switch(tableID){
case CFF:
if (pdfFont.is1C()) {
//fix bad commands in CFF data
fontData = (new CFFFixer(cff)).getBytes();
} else {
//convert type 1 to 1c
tableWriter=new CFFWriter(glyphs, name);
// try {
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// BufferedReader reader = new BufferedReader(new FileReader(new File("C:\\Users\\Sam\\Desktop\\FontForgeAmerican.txt")));
//
// while (reader.ready()) {
// String line = reader.readLine();
// String first = line.split("\t")[0];
// first = first.replaceAll("[^01]", "");
// if (first.length() == 8) {
// int mag = 128;
// byte val = 0;
// for (int i=0; i<8; i++) {
// boolean is1 = first.charAt(i) == '1';
// if (is1)
// val += mag;
//
// mag = mag / 2;
// }
//
// bos.write(val);
// fontData = bos.toByteArray();
// }
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
}
break;
case HEAD:
tableWriter=new HeadWriter(fontBBox);
break;
case CMAP :
// if(name.contains("BKJFHK+HermesFB-Regular")){
tableWriter=new CMAPWriter(pdfFont,glyphs);
minCharCode=tableWriter.getIntValue(FontTableWriter.MIN_CHAR_CODE);
maxCharCode=tableWriter.getIntValue(FontTableWriter.MAX_CHAR_CODE);
// }
break;
case HHEA:
tableWriter=new HheaWriter(glyphs, xMaxExtent, minRightSideBearing, minLeftSideBearing, advanceWidthMax, lowestDescender, highestAscender);
break;
case HMTX:
tableWriter=new HmtxWriter(pdfFont,glyphs,advanceWidths);
break;
case OS2 :
tableWriter=new OS2Writer(glyphs, xAvgCharWidth, minCharCode, maxCharCode, fontBBox);
break;
case MAXP :
tableWriter=new MAXPWriter(glyphs);
break;
case NAME:
tableWriter=new NameWriter(pdfFont, glyphs, name);
break;
case POST:
tableWriter=new PostWriter();
break;
default:
// //@sam - code to hack table from manulaly converted
// // font (setup fro Zapf)
// if(name.contains("BKJFHK+HermesFB-Regular")){
//// if(name.contains("apf")){
//
// try {
// File file=new File("C:/Users/Sam/Downloads/BKJFHK+HermesFB-Regular.otf");
//// File file=new File("C:/Users/Sam/Downloads/zapfechosWorks.otf");
// int len=(int)file.length();
// byte[] data=new byte[len];
// FileInputStream fis=new FileInputStream(file);
// fis.read(data);
// fis.close();
// FontFile2 f=new FontFile2(data,false);
// f.selectTable(tableID);
// fontData=f.getTableBytes(tableID);
// }catch(Exception e){
// e.printStackTrace();
// }
// }
break;
}
if(tableWriter!=null){
try {
fontData=tableWriter.writeTable();
} catch (Exception e) {
e.printStackTrace();
}
}
//@sam - code to print out bytes in either hacked table or our version
// if(tableID==CFF && name.contains("AmericanTypewriter")){
//// if(tableID==POST && name.contains("apf")){
// System.out.println("--name--"+name);
// for(int aa=0;aa<fontData.length;aa++) {
// //Old printout
//// System.out.println(aa+" "+fontData[aa]);
// String bin = Integer.toBinaryString(fontData[aa]);
// int addZeros = 8 - bin.length();
// for (int i=0; i<addZeros; i++)
// System.out.print("0");
// if (addZeros < 0)
// bin = bin.substring(-addZeros);
// int val = fontData[aa];
// if (val < 0)
// val += 256;
// System.out.println(bin+"\t"+val);
// }
//
// }
return fontData;
}
}