| /* |
| * 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.fop.render.pdf.pdfbox; |
| |
| import java.io.IOException; |
| import java.text.DecimalFormat; |
| import java.text.DecimalFormatSymbols; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import org.apache.pdfbox.contentstream.operator.Operator; |
| import org.apache.pdfbox.cos.COSArray; |
| import org.apache.pdfbox.cos.COSBase; |
| import org.apache.pdfbox.cos.COSBoolean; |
| import org.apache.pdfbox.cos.COSDictionary; |
| import org.apache.pdfbox.cos.COSFloat; |
| import org.apache.pdfbox.cos.COSInteger; |
| import org.apache.pdfbox.cos.COSName; |
| import org.apache.pdfbox.cos.COSNull; |
| import org.apache.pdfbox.cos.COSString; |
| import org.apache.pdfbox.pdfparser.PDFStreamParser; |
| import org.apache.pdfbox.pdmodel.common.PDStream; |
| |
| import org.apache.fop.pdf.PDFDocument; |
| |
| public class PDFWriter { |
| private DecimalFormat df = new DecimalFormat("#.####", new DecimalFormatSymbols(Locale.US)); |
| private Map<Float, String> floatCache = new HashMap<Float, String>(); |
| protected StringBuilder s = new StringBuilder(); |
| protected UniqueName key; |
| private int currentMCID; |
| protected boolean keyUsed; |
| |
| public PDFWriter(UniqueName key, int currentMCID) { |
| this.key = key; |
| this.currentMCID = currentMCID; |
| } |
| |
| public String writeText(PDStream pdStream) throws IOException { |
| PDFStreamParser pdfStreamParser = new PDFStreamParser(pdStream); |
| pdfStreamParser.parse(); |
| List<Object> it = pdfStreamParser.getTokens(); |
| List<COSBase> arguments = new ArrayList<COSBase>(); |
| for (Object o : it) { |
| if (o instanceof Operator) { |
| Operator op = (Operator)o; |
| readPDFArguments(op, arguments); |
| s.append(op.getName() + "\n"); |
| arguments.clear(); |
| if (op.getImageParameters() != null) { |
| for (Map.Entry<COSName, COSBase> cn : op.getImageParameters().entrySet()) { |
| arguments.add(cn.getKey()); |
| arguments.add(cn.getValue()); |
| } |
| readPDFArguments(op, arguments); |
| s.append("ID " + new String(op.getImageData(), PDFDocument.ENCODING)); |
| arguments.clear(); |
| s.append("EI\n"); |
| } |
| } else { |
| arguments.add((COSBase)o); |
| } |
| } |
| return s.toString(); |
| } |
| |
| protected void readPDFArguments(Operator op, Collection<COSBase> arguments) throws IOException { |
| for (COSBase c : arguments) { |
| processArg(op, c); |
| } |
| } |
| |
| protected void processArg(Operator op, COSBase c) throws IOException { |
| if (c instanceof COSInteger) { |
| s.append(((COSInteger) c).intValue()); |
| s.append(" "); |
| } else if (c instanceof COSFloat) { |
| float f = ((COSFloat) c).floatValue(); |
| if (!floatCache.containsKey(f)) { |
| addCache(f); |
| } |
| s.append(floatCache.get(f)); |
| s.append(" "); |
| if (floatCache.size() > 1024) { |
| floatCache.clear(); |
| } |
| } else if (c instanceof COSName) { |
| COSName cn = (COSName)c; |
| key.writeName(s, cn); |
| s.append(" "); |
| String name = key.getName(cn); |
| if (!name.equals(cn.getName())) { |
| keyUsed = true; |
| } |
| } else if (c instanceof COSString) { |
| s.append("<" + ((COSString) c).toHexString() + ">"); |
| } else if (c instanceof COSArray) { |
| s.append("["); |
| readPDFArguments(op, (Collection<COSBase>) ((COSArray) c).toList()); |
| s.append("] "); |
| } else if (c instanceof COSDictionary) { |
| Collection<COSBase> dictArgs = new ArrayList<COSBase>(); |
| if (currentMCID != 0 && op.getName().equals("BDC")) { |
| for (Map.Entry<COSName, COSBase> cn : ((COSDictionary)c).entrySet()) { |
| if (cn.getKey().getName().equals("MCID")) { |
| updateMCID(cn, dictArgs); |
| } else { |
| dictArgs.add(cn.getKey()); |
| dictArgs.add(cn.getValue()); |
| } |
| } |
| } else { |
| for (Map.Entry<COSName, COSBase> cn : ((COSDictionary)c).entrySet()) { |
| dictArgs.add(cn.getKey()); |
| dictArgs.add(cn.getValue()); |
| } |
| } |
| s.append("<<"); |
| readPDFArguments(op, dictArgs); |
| s.append(">>"); |
| } else if (c instanceof COSBoolean) { |
| s.append(((COSBoolean) c).getValue()).append(" "); |
| } else if (c instanceof COSNull) { |
| s.append("null "); |
| } else { |
| throw new IOException(c + " not supported"); |
| } |
| } |
| |
| protected void addCache(float f) { |
| String formatted = df.format(f); |
| floatCache.put(f, formatted); |
| } |
| |
| private void updateMCID(Map.Entry<COSName, COSBase> cn, Collection<COSBase> dictArgs) { |
| COSBase cosMCID = cn.getValue(); |
| assert cosMCID instanceof COSInteger; |
| COSInteger mcid = (COSInteger) cosMCID; |
| COSInteger updatedID = COSInteger.get(mcid.intValue() + currentMCID); |
| dictArgs.add(cn.getKey()); |
| dictArgs.add(updatedID); |
| } |
| } |