From 43c5da3bb493419843b1bb68b3cbd8cd71765e4f Mon Sep 17 00:00:00 2001 From: Marek Kasik Date: Thu, 3 Oct 2013 15:17:39 +0200 Subject: [PATCH] Add PDFBuilder class PDFBuilder is a new class which can be used for building of PDF by addition of pages by method addPage(). Resulting PDF is saved by function saveAs(). https://bugs.freedesktop.org/show_bug.cgi?id=69965 --- CMakeLists.txt | 2 + poppler/Makefile.am | 2 + poppler/PDFBuilder.cc | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++ poppler/PDFBuilder.h | 60 ++++++++++++++ 4 files changed, 283 insertions(+) create mode 100644 poppler/PDFBuilder.cc create mode 100644 poppler/PDFBuilder.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fadd0e..fe5086e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,6 +316,7 @@ set(poppler_SRCS poppler/PDFDoc.cc poppler/PDFDocEncoding.cc poppler/PDFDocFactory.cc + poppler/PDFBuilder.cc poppler/PopplerCache.cc poppler/ProfileData.cc poppler/PreScanOutputDev.cc @@ -474,6 +475,7 @@ if(ENABLE_XPDF_HEADERS) poppler/PDFDocBuilder.h poppler/PDFDocEncoding.h poppler/PDFDocFactory.h + poppler/PDFBuilder.h poppler/PopplerCache.h poppler/ProfileData.h poppler/PreScanOutputDev.h diff --git a/poppler/Makefile.am b/poppler/Makefile.am index aa7c924..b859dfd 100644 --- a/poppler/Makefile.am +++ b/poppler/Makefile.am @@ -207,6 +207,7 @@ poppler_include_HEADERS = \ PDFDocBuilder.h \ PDFDocEncoding.h \ PDFDocFactory.h \ + PDFBuilder.h \ PopplerCache.h \ ProfileData.h \ PreScanOutputDev.h \ @@ -286,6 +287,7 @@ libpoppler_la_SOURCES = \ PDFDoc.cc \ PDFDocEncoding.cc \ PDFDocFactory.cc \ + PDFBuilder.cc \ PopplerCache.cc \ ProfileData.cc \ PreScanOutputDev.cc \ diff --git a/poppler/PDFBuilder.cc b/poppler/PDFBuilder.cc new file mode 100644 index 0000000..d4cd836 --- /dev/null +++ b/poppler/PDFBuilder.cc @@ -0,0 +1,219 @@ +//======================================================================== +// +// PDFBuilder.cc +// +// Copyright 2013 Red Hat, Inc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2013 Marek Kasik +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include + +#include "poppler-config.h" +#include "GlobalParams.h" +#include "PDFBuilder.h" +#include "PDFDoc.h" +#include "Page.h" +#include "Stream.h" +#include "ErrorCodes.h" + +//------------------------------------------------------------------------ +// PDFBuilder +//------------------------------------------------------------------------ + +void PDFBuilder::init() { + pages = NULL; +} + +PDFBuilder::PDFBuilder() { + init(); +} + +PDFBuilder::~PDFBuilder() { + if (pages != NULL) { + delete pages; + } +} + +void +PDFBuilder::addPage(Page *page) { + if (pages == NULL) { + pages = new GooList(); + } + + pages->append(page); +} + +int +PDFBuilder::saveAs(GooString *name) { + std::vector offsets; + const char *key; + OutStream *outStr; + Goffset uxrefOffset; + PDFDoc *doc; + Object value; + Object obj; + Guint numOffset = 0; + XRef *yRef, *countRef; + Dict *trailerDict; + Dict *pageDict; + Page *page; + FILE *f; + Ref refPage; + Ref ref; + int majorVersion = 0; + int minorVersion = 0; + int objectsCount = 0; + int i, j, rootNum; + std::map > docs; + std::map >::iterator doc_iter; + std::list::iterator page_iter; + + if (pages == NULL) { + return gFalse; + } + + if (!globalParams) { + globalParams = new GlobalParams(); + } + + for (i = 0; i < pages->getLength(); i++) { + page = (Page *) pages->get(i); + doc = page->getDoc(); + if (doc->isOk() && !doc->isEncrypted()) { + if (doc->getPDFMajorVersion() > majorVersion) { + majorVersion = doc->getPDFMajorVersion(); + minorVersion = doc->getPDFMinorVersion(); + } else if (doc->getPDFMajorVersion() == majorVersion) { + if (doc->getPDFMinorVersion() > minorVersion) { + minorVersion = doc->getPDFMinorVersion(); + } + } + } else if (doc->isOk()) { + error(errUnimplemented, -1, "Could not merge encrypted files"); + return -1; + } else { + error(errSyntaxError, -1, "Could not merge damaged documents"); + return -1; + } + } + + if (!(f = fopen(name->getCString(), "wb"))) { + error(errIO, -1, "Couldn't open file '{0:t}'", name); + return errOpenFile; + } + + outStr = new FileOutStream(f, 0); + countRef = new XRef(); + yRef = new XRef(); + + yRef->add(0, 65535, 0, gFalse); + outStr->printf("%%PDF-%d.%d\n", majorVersion, minorVersion); + outStr->printf("%%\xE2\xE3\xCF\xD3\n"); + + for (i = 0; i < pages->getLength(); i++) { + page = (Page *) pages->get(i); + docs[page->getDoc()].push_back (i); + } + + for (doc_iter = docs.begin(); doc_iter != docs.end(); ++doc_iter) { + doc = doc_iter->first; + for (page_iter = doc_iter->second.begin(); page_iter != doc_iter->second.end(); ++page_iter) { + page = (Page *) pages->get(*page_iter); + + refPage = page->getRef(); + doc->getXRef()->fetch(refPage.num, refPage.gen, &obj); + pageDict = obj.getDict(); + + offsets.push_back(numOffset); + doc->markPageObjects(pageDict, yRef, countRef, numOffset); + obj.free(); + } + doc_iter->second.clear(); + + objectsCount += doc->writePageObjects(outStr, yRef, numOffset, gTrue); + numOffset = yRef->getNumObjects() + 1; + } + + rootNum = yRef->getNumObjects() + 1; + yRef->add(rootNum, 0, outStr->getPos(), gTrue); + outStr->printf("%d 0 obj\n", rootNum); + outStr->printf("<< /Type /Catalog /Pages %d 0 R", rootNum + 1); + outStr->printf(">>\nendobj\n"); + objectsCount++; + + yRef->add(rootNum + 1, 0, outStr->getPos(), gTrue); + outStr->printf("%d 0 obj\n", rootNum + 1); + outStr->printf("<< /Type /Pages /Kids ["); + for (j = 0; j < (int) pages->getLength(); j++) + outStr->printf(" %d 0 R", rootNum + j + 2); + outStr->printf(" ] /Count %zd >>\nendobj\n",(size_t) pages->getLength()); + objectsCount++; + + for (i = 0; i < pages->getLength(); i++) { + page = (Page *) pages->get(i); + + yRef->add(rootNum + i + 2, 0, outStr->getPos(), gTrue); + outStr->printf("%d 0 obj\n", rootNum + i + 2); + outStr->printf("<< "); + + refPage = page->getRef(); + doc->getXRef()->fetch(refPage.num, refPage.gen, &obj); + pageDict = obj.getDict(); + for (j = 0; j < pageDict->getLength(); j++) { + if (j > 0) + outStr->printf(" "); + key = pageDict->getKey(j); + pageDict->getValNF(j, &value); + if (strcmp(key, "Parent") == 0) { + outStr->printf("/Parent %d 0 R", rootNum + 1); + } else { + outStr->printf("/%s ", key); + PDFDoc::writeObject(&value, outStr, yRef, offsets[i], NULL, cryptRC4, 0, 0, 0); + } + value.free(); + } + obj.free(); + outStr->printf(" >>\nendobj\n"); + objectsCount++; + } + + ref.num = rootNum; + ref.gen = 0; + uxrefOffset = outStr->getPos(); + trailerDict = PDFDoc::createTrailerDict(objectsCount, gFalse, 0, &ref, yRef, + name->getCString(), outStr->getPos()); + + PDFDoc::writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */, + uxrefOffset, outStr, yRef); + + delete trailerDict; + delete yRef; + delete countRef; + + outStr->close(); + delete outStr; + fclose(f); + + return errNone; +} diff --git a/poppler/PDFBuilder.h b/poppler/PDFBuilder.h new file mode 100644 index 0000000..d219763 --- /dev/null +++ b/poppler/PDFBuilder.h @@ -0,0 +1,60 @@ +//======================================================================== +// +// PDFBuilder.h +// +// Copyright 2013 Red Hat, Inc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2013 Marek Kasik +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#ifndef PDFBUILDER_H +#define PDFBUILDER_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "poppler-config.h" +#include "goo/GooList.h" +#include "Page.h" + +class GooList; +class GooFile; + +//------------------------------------------------------------------------ +// PDFBuilder +//------------------------------------------------------------------------ + +class PDFBuilder { +public: + + PDFBuilder(); + + ~PDFBuilder(); + + // Add a page. + void addPage(Page *page); + + // Save all pages to given filename. + int saveAs(GooString *name); + +private: + void init(); + + GooList *pages; +}; + +#endif -- 1.8.3.1