123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /*
- * 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.
- */
-
- /* $Id$ */
- package org.apache.fop.pdf;
-
- import java.awt.Dimension;
- import java.awt.Rectangle;
- import java.awt.geom.Rectangle2D;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
-
- import javax.xml.transform.stream.StreamResult;
-
- import org.junit.Assert;
- import org.junit.Test;
-
- import org.apache.fop.apps.FOUserAgent;
- import org.apache.fop.apps.FopFactory;
- import org.apache.fop.fonts.FontInfo;
- import org.apache.fop.render.intermediate.IFContext;
- import org.apache.fop.render.pdf.PDFContentGenerator;
- import org.apache.fop.render.pdf.PDFDocumentHandler;
- import org.apache.fop.render.pdf.PDFPainter;
-
- public class PDFLinearizationTestCase {
- private int objectLeast;
- private int[] objects;
-
- @Test
- public void testPDF() throws IOException {
- PDFDocument doc = new PDFDocument("");
- doc.setLinearizationEnabled(true);
- PDFResources resources = new PDFResources(doc);
- PDFResourceContext context = new PDFResourceContext(resources);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- PDFContentGenerator gen = null;
- for (int i = 0; i < 2; i++) {
- gen = new PDFContentGenerator(doc, out, context);
- Rectangle2D.Float f = new Rectangle2D.Float();
- PDFPage page = new PDFPage(resources, i, f, f, f, f);
- doc.registerObject(page);
- doc.registerObject(gen.getStream());
- page.setContents(new PDFReference(gen.getStream()));
- }
- gen.flushPDFDoc();
- byte[] data = out.toByteArray();
- checkPDF(data);
- }
-
- @Test
- public void testImage() throws Exception {
- String fopxconf = "<fop version=\"1.0\"><renderers>"
- + "<renderer mime=\"application/pdf\">"
- + "<linearization>true</linearization>"
- + "</renderer></renderers></fop>";
- FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI(),
- new ByteArrayInputStream(fopxconf.getBytes()));
- FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
- IFContext ifContext = new IFContext(foUserAgent);
- PDFDocumentHandler documentHandler = new PDFDocumentHandler(ifContext);
- documentHandler.getConfigurator().configure(documentHandler);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- documentHandler.setFontInfo(new FontInfo());
- documentHandler.setResult(new StreamResult(out));
- documentHandler.startDocument();
- documentHandler.startPage(0, "", "", new Dimension());
- PDFPainter pdfPainter = new PDFPainter(documentHandler, null);
- pdfPainter.drawImage("test/resources/fop/svg/logo.jpg", new Rectangle());
- documentHandler.endPage();
- Assert.assertFalse(out.toString().contains("/Subtype /Image"));
- documentHandler.endDocument();
- Assert.assertTrue(out.toString().contains("/Subtype /Image"));
- }
-
- private void checkPDF(byte[] data) throws IOException {
- checkHintTable(data);
- InputStream is = new ByteArrayInputStream(data);
- Map<String, StringBuilder> objs = readObjs(is);
-
- List<String> keys = new ArrayList<String>(objs.keySet());
- int start = keys.indexOf("1 0 obj");
- Assert.assertTrue(start > 1);
- int j = 1;
- for (int i = start; i < keys.size(); i++) {
- Assert.assertEquals(keys.get(i), j + " 0 obj");
- j++;
- }
- for (int i = 0; i < start; i++) {
- Assert.assertEquals(keys.get(i), j + " 0 obj");
- j++;
- }
-
- checkFirstObj(data);
- checkTrailer(data);
-
- String firstObj = objs.values().iterator().next().toString().replace("\n", "");
- Assert.assertTrue(firstObj.startsWith("<< /Linearized 1 /L " + data.length));
- Assert.assertTrue(firstObj.endsWith("startxref0%%EOF"));
- int pageObjNumber = getValue("/O", firstObj);
- Assert.assertTrue(objs.get(pageObjNumber + " 0 obj").toString().contains("/Type /Page"));
- Assert.assertTrue(objs.get("5 0 obj").toString().contains("/Type /Pages"));
-
- int total = 0;
- for (int i : objects) {
- total += i;
- }
- Assert.assertEquals(total, objs.size() - 6);
- }
-
- private void checkFirstObj(byte[] data) throws IOException {
- int firstObjPos = getValue("/E", getFirstObj(data));
- InputStream is = new ByteArrayInputStream(data);
- Assert.assertEquals(is.skip(firstObjPos), firstObjPos);
- byte[] obj = new byte[10];
- Assert.assertEquals(is.read(obj), obj.length);
- Assert.assertTrue(new String(obj).startsWith("1 0 obj"));
- }
-
- private void checkTrailer(byte[] data) throws IOException {
- int trailerPos = getValue("/T", getFirstObj(data));
- InputStream is = new ByteArrayInputStream(data);
- Assert.assertEquals(is.skip(trailerPos), trailerPos);
- byte[] obj = new byte[20];
- Assert.assertEquals(is.read(obj), obj.length);
- Assert.assertTrue(new String(obj).startsWith("0000000000 65535 f"));
- }
-
- private int getValue(String name, String firstObj) throws IOException {
- String[] split = firstObj.split(" ");
- for (int i = 0; i < split.length; i++) {
- if (split[i].equals(name)) {
- return Integer.valueOf(split[i + 1].replace(">>", ""));
- }
- }
- throw new IOException(name + " not found " + firstObj);
- }
-
- private int[] getArrayValue(String name, String firstObj) throws IOException {
- String[] split = firstObj.split(" ");
- for (int i = 0; i < split.length; i++) {
- if (split[i].equals(name)) {
- int[] v = new int[2];
- v[0] = Integer.valueOf(split[i + 1].replace("[", ""));
- v[1] = Integer.valueOf(split[i + 2].replace("]", ""));
- return v;
- }
- }
- throw new IOException(name + " not found " + firstObj);
- }
-
- private String getFirstObj(byte[] out) throws IOException {
- InputStream data = new ByteArrayInputStream(out);
- Map<String, StringBuilder> objs = readObjs(data);
- return objs.values().iterator().next().toString().replace("\n", "");
- }
-
- private void checkHintTable(byte[] out) throws IOException {
- String firstObj = getFirstObj(out);
- int hintPos = getArrayValue("/H", firstObj)[0];
- int hintLength = getArrayValue("/H", firstObj)[1];
-
- InputStream data = new ByteArrayInputStream(out);
- Assert.assertEquals(data.skip(hintPos), hintPos);
-
- byte[] hintTable = new byte[hintLength];
- Assert.assertEquals(data.read(hintTable), hintLength);
- String hintTableStr = new String(hintTable);
-
- Assert.assertTrue(hintTableStr.contains("/S "));
- Assert.assertTrue(hintTableStr.contains("/C "));
- Assert.assertTrue(hintTableStr.contains("/E "));
- Assert.assertTrue(hintTableStr.contains("/L "));
- Assert.assertTrue(hintTableStr.contains("/V "));
- Assert.assertTrue(hintTableStr.contains("/O "));
- Assert.assertTrue(hintTableStr.contains("/I "));
- Assert.assertTrue(hintTableStr.contains("/Length "));
- Assert.assertTrue(hintTableStr.contains("stream"));
- Assert.assertTrue(hintTableStr.contains("endstream"));
- Assert.assertTrue(hintTableStr.endsWith("endobj\n"));
-
- data = new ByteArrayInputStream(hintTable);
- readStart(data);
- int pages = getValue("/N", firstObj);
- readObjectsTable(data, pages);
- readSharedObjectsTable(data);
- Assert.assertEquals(objectLeast, 1);
- }
-
- private void readObjectsTable(InputStream data, int pages)
- throws IOException {
- objectLeast = read32(data);
- read32(data);
- int bitsDiffObjects = read16(data);
- read32(data);
- int bitsDiffPageLength = read16(data);
- read32(data);
- read16(data);
- read32(data);
- read16(data);
- read16(data);
- read16(data);
- read16(data);
- read16(data);
-
- objects = new int[pages];
- for (int i = 0; i < pages; i++) {
- objects[i] = objectLeast + readBits(bitsDiffObjects, data);
- }
- for (int i = 0; i < pages; i++) {
- readBits(bitsDiffPageLength, data);
- }
- for (int i = 0; i < pages; i++) {
- readBits(32, data);
- }
- }
-
- private void readSharedObjectsTable(InputStream str) throws IOException {
- readBits(32, str);
- readBits(32, str);
- readBits(32, str);
- int sharedGroups = readBits(32, str);
- readBits(16, str);
- readBits(32, str);
- int bitsDiffGroupLength = readBits(16, str);
- for (int i = 0; i < sharedGroups; i++) {
- readBits(bitsDiffGroupLength, str);
- }
- }
-
- private int readBits(int bits, InputStream data) throws IOException {
- if (bits == 32) {
- return read32(data);
- }
- if (bits == 16) {
- return read16(data);
- }
- throw new IOException("Wrong bits");
- }
-
- private int read32(InputStream data) throws IOException {
- int ch1 = data.read();
- int ch2 = data.read();
- int ch3 = data.read();
- int ch4 = data.read();
- return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4));
- }
-
- private int read16(InputStream data) throws IOException {
- int ch1 = data.read();
- int ch2 = data.read();
- return (ch1 << 8) + (ch2);
- }
-
- private void readStart(InputStream inputStream) throws IOException {
- StringBuilder sb = new StringBuilder();
- while (inputStream.available() > 0) {
- int data = inputStream.read();
- if (data == '\n') {
- if (sb.toString().equals("stream")) {
- return;
- }
- sb.setLength(0);
- } else {
- sb.append((char)data);
- }
- }
- }
-
- public static Map<String, StringBuilder> readObjs(InputStream inputStream) throws IOException {
- Map<String, StringBuilder> objs = new LinkedHashMap<String, StringBuilder>();
- StringBuilder sb = new StringBuilder();
- String key = null;
- while (inputStream.available() > 0) {
- int data = inputStream.read();
- if (data == '\n') {
- if (sb.toString().endsWith(" 0 obj")) {
- key = sb.toString().trim();
- objs.put(key, new StringBuilder());
- } else if (key != null) {
- objs.get(key).append(sb).append("\n");
- }
- sb.setLength(0);
- } else {
- sb.append((char)data);
- }
- }
- return objs;
- }
- }
|