On Thursday 06 October 2011, Albert Astals Cid wrote:
> A Dimarts, 4 d'octubre de 2011, Glad Deschrijver vàreu escriure:
> > Following your request, I implemented setPageList(...) in PDFConverter.
> > In order to have a similar behavior as in PSConverter (i.e. saving the
> > selected pages to one file, and not to a file per page), I also added a
> > function savePagesAs(OutStream *outStr, std::vector<int> pagesList); to
> > PDFDoc. Since I have no PDF-hacking experience, I copied the code from
> > pdfunite.cc and adapted it to the new situation. So I hope that the code
> > is decent. At least it works perfectly on my PDF files.
>
> I see there is quite a bit of code "copied" from the pdfunite sources, do
> you think you can make it a bit more generic so we only have one source
> and both functions use that same code?
I tried (see attachment). I noticed that there was also quite some code
shared with PDFDoc::savePageAs() so I put the shared code in two function
PDFDoc::fetchPage() and PDFDoc::writePagesAndTrailer().
Best regards,
Glad
--
The only way to abolish war is to make peace heroic.
-- John Dewey, American philosopher and educator (1859-1952)
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 01d2759..109dc1b 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -574,28 +574,77 @@ Hints *PDFDoc::getHints()
return hints;
}
-int PDFDoc::savePageAs(GooString *name, int pageNo)
+Object PDFDoc::fetchPage(PDFDoc *doc, int pageNo, XRef *yRef, XRef *countRef, int numOffset)
+{
+ PDFRectangle *cropBox = NULL;
+ if (doc->getCatalog()->getPage(pageNo)->isCropped())
+ cropBox = doc->getCatalog()->getPage(pageNo)->getCropBox();
+ doc->replacePageDict(pageNo,
+ doc->getCatalog()->getPage(pageNo)->getRotate(),
+ doc->getCatalog()->getPage(pageNo)->getMediaBox(), cropBox, NULL);
+ Ref *refPage = doc->getCatalog()->getPageRef(pageNo);
+ Object page;
+ doc->getXRef()->fetch(refPage->num, refPage->gen, &page);
+ Dict *pageDict = page.getDict();
+ doc->markPageObjects(pageDict, yRef, countRef, numOffset);
+ return page;
+}
+
+void PDFDoc::writePagesAndTrailer(OutStream *outStr, const char *fileName, std::vector<Object> pages, std::vector<Guint> offsets, XRef *xRef, XRef *yRef, int rootNum, int objectsCount)
+{
+ yRef->add(rootNum + 1, 0, outStr->getPos(), gTrue);
+ outStr->printf("%d 0 obj\n", rootNum + 1);
+ outStr->printf("<< /Type /Pages /Kids [");
+ for (int j = 0; j < (int) pages.size(); ++j)
+ outStr->printf(" %d 0 R", rootNum + j + 2);
+ outStr->printf(" ] /Count %d >>\nendobj\n", pages.size());
+ objectsCount++;
+
+ for (int i = 0; i < (int) pages.size(); ++i) {
+ yRef->add(rootNum + i + 2, 0, outStr->getPos(), gTrue);
+ outStr->printf("%d 0 obj\n", rootNum + i + 2);
+ outStr->printf("<< ");
+ Dict *pageDict = pages[i].getDict();
+ for (int j = 0; j < pageDict->getLength(); ++j) {
+ if (j > 0)
+ outStr->printf(" ");
+ const char *key = pageDict->getKey(j);
+ Object value;
+ 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, NULL, outStr, xRef, offsets[i]);
+ }
+ value.free();
+ }
+ outStr->printf(" >>\nendobj\n");
+ objectsCount++;
+ }
+ Guint uxrefOffset = outStr->getPos();
+ yRef->writeToFile(outStr, gFalse /* do not write unnecessary entries */);
+
+ Ref ref;
+ ref.num = rootNum;
+ ref.gen = 0;
+ PDFDoc::writeTrailer(uxrefOffset, objectsCount, outStr, (GBool) gFalse, 0,
+ &ref, xRef, fileName, outStr->getPos());
+}
+
+int PDFDoc::savePageAs(GooString *name, int pageNo)
{
FILE *f;
OutStream *outStr;
+ std::vector<Object> pages;
+ std::vector<Guint> offsets;
XRef *yRef, *countRef;
int rootNum = getXRef()->getSize() + 1;
if (pageNo < 1 || pageNo > getNumPages()) {
error(-1, "Illegal pageNo: %d(%d)", pageNo, getNumPages() );
- return errOpenFile;
- }
- PDFRectangle *cropBox = NULL;
- if (getCatalog()->getPage(pageNo)->isCropped()) {
- cropBox = getCatalog()->getPage(pageNo)->getCropBox();
+ return errBadPageNum;
}
- replacePageDict(pageNo,
- getCatalog()->getPage(pageNo)->getRotate(),
- getCatalog()->getPage(pageNo)->getMediaBox(),
- cropBox, NULL);
- Ref *refPage = getCatalog()->getPageRef(pageNo);
- Object page;
- getXRef()->fetch(refPage->num, refPage->gen, &page);
if (!(f = fopen(name->getCString(), "wb"))) {
error(-1, "Couldn't open file '%s'", name->getCString());
@@ -620,13 +669,14 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
optContentProps.free();
}
- Dict *pageDict = page.getDict();
- markPageObjects(pageDict, yRef, countRef, 0);
+ Object page = fetchPage(this, pageNo, yRef, countRef, 0);
+ pages.push_back(page);
+ offsets.push_back(0);
Guint objectsCount = writePageObjects(outStr, yRef, 0);
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("<< /Type /Catalog /Pages %d 0 R", rootNum + 1);
if (ocgs != NULL) {
Object catDict, optContentProps;
getXRef()->getCatalog(&catDict);
@@ -648,43 +698,57 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
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 [ %d 0 R ] /Count 1 >>\n", rootNum + 2);
- outStr->printf("endobj\n");
- objectsCount++;
+ writePagesAndTrailer(outStr, name->getCString(), pages, offsets, getXRef(), yRef, rootNum, objectsCount);
- yRef->add(rootNum + 2,0,outStr->getPos(),gTrue);
- outStr->printf("%d 0 obj\n", rootNum + 2);
- outStr->printf("<< ");
- for (int n = 0; n < pageDict->getLength(); n++) {
- if (n > 0) outStr->printf(" ");
- const char *key = pageDict->getKey(n);
- Object value; pageDict->getValNF(n, &value);
- if (strcmp(key, "Parent") == 0) {
- outStr->printf("/Parent %d 0 R", rootNum + 1);
- } else {
- outStr->printf("/%s ", key);
- writeObject(&value, NULL, outStr, getXRef(), 0);
+ outStr->close();
+ fclose(f);
+ delete yRef;
+ delete countRef;
+ page.free();
+
+ return errNone;
+}
+
+int PDFDoc::savePagesAs(OutStream *outStr, std::vector<int> pagesList)
+{
+ int objectsCount = 0;
+ std::vector<Object> pages;
+ std::vector<Guint> offsets;
+ XRef *yRef, *countRef;
+ int rootNum;
+
+ for (int i = 0; i < (int) pagesList.size(); ++i) {
+ if (pagesList[i] < 1 || pagesList[i] > getNumPages()) {
+ error(-1, "Illegal pageNo: %d(%d)", pagesList[i], getNumPages());
+ return errBadPageNum;
}
- value.free();
}
- outStr->printf(" >>\nendobj\n");
- objectsCount++;
- page.free();
- Guint uxrefOffset = outStr->getPos();
- yRef->writeToFile(outStr, gFalse /* do not write unnecessary entries */);
+ yRef = new XRef();
+ countRef = new XRef();
+ yRef->add(0, 65535, 0, gFalse);
+ PDFDoc::writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion());
- Ref ref;
- ref.num = rootNum;
- ref.gen = 0;
- writeTrailer(uxrefOffset, objectsCount, outStr, gFalse, 0, &ref, getXRef(), name->getCString(), outStr->getPos());
+ for (int i = 0; i < (int) pagesList.size(); ++i) {
+ Object page = fetchPage(this, pagesList[i], yRef, countRef, 0);
+ pages.push_back(page);
+ offsets.push_back(0);
+ }
+ objectsCount += writePageObjects(outStr, yRef, 0);
+
+ 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++;
+
+ writePagesAndTrailer(outStr, getFileName()->getCString(), pages, offsets, yRef, yRef, rootNum, objectsCount);
- outStr->close();
- fclose(f);
delete yRef;
delete countRef;
+ for (int j = 0; j < (int) pages.size (); ++j)
+ pages[j].free();
return errNone;
}
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 92cee78..d84f239 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -220,8 +220,15 @@ public:
//Return the PDF ID in the trailer dictionary (if any).
GBool getID(GooString *permanent_id, GooString *update_id);
+ // Fetch a page to be saved in another document and mark its objects
+ static Object fetchPage(PDFDoc *doc, int pageNo, XRef *yRef, XRef *countRef, int numOffset);
+ // Write selected pages and the trailer in the given output stream
+ static void writePagesAndTrailer(OutStream *outStr, const char *fileName, std::vector<Object> pages, std::vector<Guint> offsets, XRef *xRef, XRef *yRef, int rootNum, int objectsCount);
+
// Save one page with another name.
int savePageAs(GooString *name, int pageNo);
+ // Save multiple pages in the given output stream.
+ int savePagesAs(OutStream *outStr, std::vector<int> pagesList);
// Save this file with another name.
int saveAs(GooString *name, PDFWriteMode mode=writeStandard);
// Save this file in the given output stream.
diff --git a/qt4/src/poppler-pdf-converter.cc b/qt4/src/poppler-pdf-converter.cc
index 9699b75..887365b 100644
--- a/qt4/src/poppler-pdf-converter.cc
+++ b/qt4/src/poppler-pdf-converter.cc
@@ -34,6 +34,7 @@ class PDFConverterPrivate : public BaseConverterPrivate
public:
PDFConverterPrivate();
+ QList<int> pageList;
PDFConverter::PDFOptions opts;
};
@@ -66,6 +67,12 @@ PDFConverter::PDFOptions PDFConverter::pdfOptions() const
return d->opts;
}
+void PDFConverter::setPageList(const QList<int> &pageList)
+{
+ Q_D(PDFConverter);
+ d->pageList = pageList;
+}
+
bool PDFConverter::convert()
{
Q_D(PDFConverter);
@@ -90,7 +97,14 @@ bool PDFConverter::convert()
int errorCode = errNone;
QIODeviceOutStream stream(dev);
- if (d->opts & WithChanges)
+ if (!d->pageList.isEmpty())
+ {
+ std::vector<int> pageList;
+ for (int i = 0; i < d->pageList.size(); ++i)
+ pageList.push_back(d->pageList.at(i));
+ errorCode = d->document->doc->savePagesAs(&stream, pageList);
+ }
+ else if (d->opts & WithChanges)
{
errorCode = d->document->doc->saveAs(&stream);
}
diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h
index 637b69f..82bc826 100644
--- a/qt4/src/poppler-qt4.h
+++ b/qt4/src/poppler-qt4.h
@@ -1566,6 +1566,12 @@ height = dummy.height();
bool convert();
+ /**
+ Sets the list of pages to print. If the list of pages
+ is empty, all pages are printed.
+ */
+ void setPageList(const QList<int> &pageList);
+
private:
Q_DECLARE_PRIVATE(PDFConverter)
Q_DISABLE_COPY(PDFConverter)
diff --git a/utils/pdfunite.cc b/utils/pdfunite.cc
index 3b3d2bb..a1dd9f0 100644
--- a/utils/pdfunite.cc
+++ b/utils/pdfunite.cc
@@ -30,12 +30,7 @@ static const ArgDesc argDesc[] = {
{NULL}
};
-///////////////////////////////////////////////////////////////////////////
-int main (int argc, char *argv[])
-///////////////////////////////////////////////////////////////////////////
-// Merge PDF files given by arguments 1 to argc-2 and write the result
-// to the file specified by argument argc-1.
-///////////////////////////////////////////////////////////////////////////
+int unite(char *fileName, std::vector<PDFDoc *> docs, int majorVersion, int minorVersion)
{
int objectsCount = 0;
Guint numOffset = 0;
@@ -44,8 +39,57 @@ int main (int argc, char *argv[])
XRef *yRef, *countRef;
FILE *f;
OutStream *outStr;
- int i;
- int j, rootNum;
+ int rootNum;
+
+ if (!(f = fopen(fileName, "wb"))) {
+ error(-1, "Could not open file '%s'", fileName);
+ return -1;
+ }
+ outStr = new FileOutStream(f, 0);
+
+ yRef = new XRef();
+ countRef = new XRef();
+ yRef->add(0, 65535, 0, gFalse);
+ PDFDoc::writeHeader(outStr, majorVersion, minorVersion);
+
+ for (int i = 0; i < (int) docs.size(); ++i) {
+ for (int j = 1; j <= docs[i]->getNumPages(); ++j) {
+ Object page = PDFDoc::fetchPage(docs[i], j, yRef, countRef, numOffset);
+ pages.push_back(page);
+ offsets.push_back(numOffset);
+ }
+ objectsCount += docs[i]->writePageObjects(outStr, yRef, numOffset);
+ numOffset = yRef->getNumObjects() + 1;
+ }
+ for (int i = 0; i < (int) docs.size(); ++i)
+ delete docs[i];
+
+ 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++;
+
+ PDFDoc::writePagesAndTrailer(outStr, fileName, pages, offsets, yRef, yRef, rootNum, objectsCount);
+
+ delete yRef;
+ delete countRef;
+ for (int j = 0; j < (int) pages.size(); ++j)
+ pages[j].free();
+
+ outStr->close();
+ fclose(f);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+int main (int argc, char *argv[])
+///////////////////////////////////////////////////////////////////////////
+// Merge PDF files given by arguments 1 to argc-2 and write the result
+// to the file specified by argument argc-1.
+///////////////////////////////////////////////////////////////////////////
+{
std::vector<PDFDoc *>docs;
int majorVersion = 0;
int minorVersion = 0;
@@ -65,9 +109,8 @@ int main (int argc, char *argv[])
exitCode = 0;
return exitCode;
}
- exitCode = 0;
- for (i = 1; i < argc - 1; i++) {
+ for (int i = 1; i < argc - 1; ++i) {
GooString *gfileName = new GooString(argv[i]);
PDFDoc *doc = new PDFDoc(gfileName, NULL, NULL, NULL);
if (doc->isOk() && !doc->isEncrypted()) {
@@ -89,88 +132,5 @@ int main (int argc, char *argv[])
}
}
- if (!(f = fopen(fileName, "wb"))) {
- error(-1, "Could not open file '%s'", fileName);
- return -1;
- }
- outStr = new FileOutStream(f, 0);
-
- yRef = new XRef();
- countRef = new XRef();
- yRef->add(0, 65535, 0, gFalse);
- PDFDoc::writeHeader(outStr, majorVersion, minorVersion);
-
- for (i = 0; i < (int) docs.size(); i++) {
- for (j = 1; j <= docs[i]->getNumPages(); j++) {
- PDFRectangle *cropBox = NULL;
- if (docs[i]->getCatalog()->getPage(j)->isCropped())
- cropBox = docs[i]->getCatalog()->getPage(j)->getCropBox();
- docs[i]->replacePageDict(j,
- docs[i]->getCatalog()->getPage(j)->getRotate(),
- docs[i]->getCatalog()->getPage(j)->getMediaBox(), cropBox, NULL);
- Ref *refPage = docs[i]->getCatalog()->getPageRef(j);
- Object page;
- docs[i]->getXRef()->fetch(refPage->num, refPage->gen, &page);
- pages.push_back(page);
- offsets.push_back(numOffset);
- Dict *pageDict = page.getDict();
- docs[i]->markPageObjects(pageDict, yRef, countRef, numOffset);
- }
- objectsCount += docs[i]->writePageObjects(outStr, yRef, numOffset);
- 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.size(); j++)
- outStr->printf(" %d 0 R", rootNum + j + 2);
- outStr->printf(" ] /Count %d >>\nendobj\n", pages.size());
- objectsCount++;
-
- for (i = 0; i < (int) pages.size(); i++) {
- yRef->add(rootNum + i + 2, 0, outStr->getPos(), gTrue);
- outStr->printf("%d 0 obj\n", rootNum + i + 2);
- outStr->printf("<< ");
- Dict *pageDict = pages[i].getDict();
- for (j = 0; j < pageDict->getLength(); j++) {
- if (j > 0)
- outStr->printf(" ");
- const char *key = pageDict->getKey(j);
- Object value;
- 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, NULL, outStr, yRef, offsets[i]);
- }
- value.free();
- }
- outStr->printf(" >>\nendobj\n");
- objectsCount++;
- }
- Guint uxrefOffset = outStr->getPos();
- yRef->writeToFile(outStr, gFalse /* do not write unnecessary entries */ );
-
- Ref ref;
- ref.num = rootNum;
- ref.gen = 0;
- PDFDoc::writeTrailer(uxrefOffset, objectsCount, outStr, (GBool) gFalse, 0,
- &ref, yRef, fileName, outStr->getPos());
-
- outStr->close();
- fclose(f);
- delete yRef;
- delete countRef;
- for (j = 0; j < (int) pages.size (); j++) pages[j].free();
- for (i = 0; i < (int) docs.size (); i++) delete docs[i];
- return exitCode;
+ return unite(fileName, docs, majorVersion, minorVersion);
}
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler