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

Reply via email to