Hi,

Thanks Albert for committing my previous patches.

On Saturday 01 October 2011, Albert Astals Cid wrote:
> A Dijous, 29 de setembre de 2011, vàreu escriure:
> > I also want to be able to save a single page from a PDF file in a new PDF
> > file. I guess the cleanest way to do this will be to add a function
> > "savePageAs(const QString &exportFilePath, int page)" to
> > Poppler::Document. Is that OK?
> 
> No, please add a void setPageList(const QList<int> &pageList); like we have
> in PSConverter.
> 
> Also it would be great if instead of sending the patches to me directly you
> uses the poppler mailing list at
> http://lists.freedesktop.org/mailman/listinfo/poppler

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.

Best regards,
Glad

-- 
 Truth is stranger than fiction, but it is because fiction is obliged
 to stick to possibilities. Truth isn't.
      -- Mark Twain
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 01d2759..0b958e5 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -689,6 +689,98 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
   return errNone;
 }
 
+int PDFDoc::savePagesAs(OutStream *outStr, std::vector<int> pagesList)
+{
+  int objectsCount = 0;
+  Guint numOffset = 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;
+    }
+  }
+
+  yRef = new XRef();
+  countRef = new XRef();
+  yRef->add(0, 65535, 0, gFalse);
+  PDFDoc::writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion());
+
+  for (int i = 0; i < (int) pagesList.size(); ++i) {
+    PDFRectangle *cropBox = NULL;
+    if (getCatalog()->getPage(pagesList[i])->isCropped())
+      cropBox = getCatalog()->getPage(pagesList[i])->getCropBox();
+    replacePageDict(pagesList[i],
+      getCatalog()->getPage(pagesList[i])->getRotate(),
+      getCatalog()->getPage(pagesList[i])->getMediaBox(), cropBox, NULL);
+    Ref *refPage = getCatalog()->getPageRef(pagesList[i]);
+    Object page;
+    getXRef()->fetch(refPage->num, refPage->gen, &page);
+    pages.push_back(page);
+    offsets.push_back(numOffset);
+    Dict *pageDict = page.getDict();
+    markPageObjects(pageDict, yRef, countRef, numOffset);
+    objectsCount += 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 (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, 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, getFileName()->getCString(), outStr->getPos());
+
+  delete yRef;
+  delete countRef;
+  for (int j = 0; j < (int) pages.size (); ++j)
+    pages[j].free();
+  return errNone;
+}
+
 int PDFDoc::saveAs(GooString *name, PDFWriteMode mode) {
   FILE *f;
   OutStream *outStr;
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 92cee78..e5619de 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -222,6 +222,8 @@ public:
 
   // 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)
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to