这里是一个非常非常简单的PDF Creator类的快速攻克,除了在彩色背景上用彩色写Courier文本外,它无能为力:
public class SimplePdfCreator{ public SimplePdfCreator(OutputStream os) throws IOException { pdfOs = os instanceof BufferedOutputStream ? (BufferedOutputStream) os : new BufferedOutputStream(os); writeHeader(); fontObjectNr = writeFont(); initPage(); } public void color(float r, float g, float b) { pageBuilder.append(r) .append(' ') .append(g) .append(' ') .append(b) .append(" rgn"); } public void backColor(float r, float g, float b) { backBuilder.append(r) .append(' ') .append(g) .append(' ') .append(b) .append(" rgn"); } public void print(int x, int y, String string) { pageBuilder.append(x - xNow) .append(' ') .append(y - yNow) .append(" Td (") .append(string) .append(") Tjn"); xNow = x; yNow = y; fillBack(string); } public void print(String string) { pageBuilder.append("(") .append(string) .append(") 'n"); yNow -= leading; fillBack(string); } public void storePage() throws IOException { writePageContent(); initPage(); } public double getStringWidth(String string) { return string.length() * fontSize * .6; } public int getFontSize() { return fontSize; } public int getLeading() { return leading; } public void close() throws IOException { int pagesObjectNr = writePages(); int catalogObjectNr = writeCatalog(pagesObjectNr); long xrefPosition = writeXref(); writeTrailer(catalogObjectNr); writeFooter(xrefPosition); pdfOs.close();; } // // helper methods // void writeHeader() throws IOException { write("%PDF-1.4n".getBytes(charSet)); write(new byte[]{'%', (byte)128, (byte)129, (byte)130, 'n'}); } int writeFont() throws IOException { return writeObject("<</Type/Font/Subtype/Type1/baseFont/Courier/Encoding/WinAnsiEncoding>>n".getBytes(charSet)); } void initPage() { pageBuilder.setLength(0); backBuilder.setLength(0); pageBuilder.append("BT/F0 ") .append(fontSize) .append(" Tf ") .append(leading) .append(" TL 0 gn"); backBuilder.append("1 gn"); xNow = 0; yNow = 0; } void fillBack(String string) { backBuilder.append(xNow) .append(' ') .append(yNow - leading*.2) .append(' ') .append(getStringWidth(string)) .append(' ') .append(leading) .append(" re fn"); } void writePageContent() throws IOException { pageBuilder.append("ETn"); StringBuilder contents = new StringBuilder(); contents.append("<</Length ") .append(pageBuilder.length() + backBuilder.length()) .append(">>nstreamn") .append(backBuilder) .append(pageBuilder) .append("nendstreamn"); int contentsObjectNr = writeObject(contents.toString().getBytes(charSet)); pageContentsObjects.add(contentsObjectNr); } int writePages() throws IOException { int pagesObjectNrToBe = xref.size() + pageContentsObjects.size() + 1; StringBuilder pages = new StringBuilder(); pages.append("<</Type /Pages /Count ") .append(pageContentsObjects.size()) .append("/Kids["); for (int pageContentObject : pageContentsObjects) { int pageObjectNr = writeObject(String.format("<</Type/Page/Parent %s 0 R/Contents %s 0 R>>n", pagesObjectNrToBe, pageContentObject).getBytes(charSet)); pages.append(pageObjectNr).append(" 0 R "); } pages.append("]/Resources<</ProcSet[/PDF/Text]/Font<</F0 ") .append(fontObjectNr) .append(" 0 R>>>>/MediaBox[0 0 612 792]>>n"); return writeObject(pages.toString().getBytes(charSet)); } int writeCatalog(int pagesObjectNr) throws IOException { return writeObject(String.format("<</Type/Catalog/Pages %s 0 R>>n", pagesObjectNr).getBytes(charSet)); } long writeXref() throws IOException { long xrefPos = position; byte[] eol = new byte[]{'n'}; write("xrefn".getBytes(charSet)); write(String.format("0 %sn", xref.size() + 1).getBytes(charSet)); write("0000000000 65535 f ".getBytes(charSet)); write(eol); for(long position: xref) { write(String.format("%010d 00000 n ", position).getBytes(charSet)); write(eol); } return xrefPos; } void writeTrailer(int catalogObjectNr) throws IOException { write(String.format("trailern<</Size %s/Root %s 0 R>>n", xref.size() + 1, catalogObjectNr).getBytes(charSet)); } void writeFooter(long xrefPosition) throws IOException { write(String.format("startxrefn%sn%%%%EOFn", xrefPosition).getBytes(charSet)); } int writeObject(byte[] bytes) throws IOException { int objectNr = startObject(); write(bytes); endObj(); return objectNr; } int startObject() throws IOException { xref.add(position); int objectNr = xref.size(); write(String.format("%s 0 objn", objectNr).getBytes(charSet)); return objectNr; } void endObj() throws IOException { write("endobjn".getBytes(charSet)); } long write(byte[] bytes) throws IOException { if (bytes != null) { pdfOs.write(bytes); position += bytes.length; } return position; } final BufferedOutputStream pdfOs; final Charset charSet = Charset.forName("ISO-8859-1"); final List<Long> xref = new ArrayList<Long>(); final List<Integer> pageContentsObjects = new ArrayList<Integer>(); final StringBuilder pageBuilder = new StringBuilder(); final StringBuilder backBuilder = new StringBuilder(); final int fontObjectNr; long position = 0; int xNow = 0; int yNow = 0; int fontSize = 11; int leading = 11;}You can use it like this:
public void test() throws IOException{ SimplePdfCreator creator = new SimplePdfCreator(new FileOutputStream("target/test-outputs/SimpleGenerated.pdf")); creator.print(100, 500, "Test line 1"); creator.print("Test line 2"); creator.color(1, 0, 0); creator.backColor(0, 1, 1); creator.print(100, 450, "Test line red"); creator.color(0, 1, 0); creator.backColor(1, 0, 1); creator.print("Test line green"); creator.color(0, 0, 1); creator.backColor(1, 1, 0); creator.print("Test line blue"); creator.color(1, 1, 1); creator.backColor(0, 0, 0); creator.print(100, 400, "step"); creator.print(100 + (int)creator.getStringWidth("step"), 400 - creator.getLeading(), "by"); creator.print(100 + (int)creator.getStringWidth("stepby"), 400 - 2 * creator.getLeading(), "step"); creator.storePage(); creator.print(100, 400, "Page 2"); creator.storePage(); creator.close();}并请记住,如上所述,这是一个快速技巧,可能是
概念的证明,还有很多改进之处,例如,坐标可能应为
双精度而不是int,在添加内容之前应转义字符串
(尤其是括号, …



