Bug 122147

Summary: insert '%%Title: xyz' (PostScript DSC comment) into printjob so that KJobViewer displays job name (instead using generic dummy name)
Product: [Unmaintained] kpdf Reporter: S. Burmeister <sven.burmeister>
Component: generalAssignee: Albert Astals Cid <aacid>
Status: RESOLVED FIXED    
Severity: wishlist    
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: unspecified   
OS: All   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description S. Burmeister 2006-02-17 11:15:11 UTC
Version:           0.1 (using KDE 3.5.1 Level "a" , SUSE 10.0 UNSUPPORTED)
Compiler:          Target: i586-suse-linux
OS:                Linux (i686) release 2.6.13-15.8-default

Currently, when I print a document from kpdf for example, the column "name" only contains "KDE Print System". I did not find any possibility to display the document's name of a printjob.

Without the document's name, it is hardly possible to distinguish between several printjobs.
Comment 1 Kurt Pfeifle 2007-01-11 14:20:36 UTC
Confirmed.

This is a deficiency. However, I don't think it is KDEPrint's/KJobViewer's realm.

AFAIK, KJobViewer is designed to display the CUPS "job title" that it gets handed over by the application. Only if it doesn't get such an info, it will fill in the  "KDE Print System" string as the job title (because CUPS requires one).

I'll move that bug to the kpdf module for now.

But similar deficiencies probably affect other (KDE) applications as well... I just don't have the time right now to check them all. (KWord for example, does The Right Thing (TM) here...)


@ kpdf developers:
------------------

kpdf should insert a "%%Title: whatever-it-should-be" line in the PostScript DSC comments near the top of the printfile. But this line is completely missing.

See how KWord does it:

  * if the "Title:" line is filled in by the user (menu "File --> Document 
    Information --> General") KWord inserts that string as %%Title:

  * if the "Title:" line is empty, KWord simply takes the the document's file
    name and places that into the PostScript jobfile as %%Title:

I think kpdf should do the same. (Maybe even on the level of Poppler -- you know better than me...)

(BTW, the %%Title: line of a PostScript file is also evaluated by allmost all PostScript printers to display the job name on their front panel displays, or to show it in SNMP queries.)

Cheers,
Kurt

(changed $summary, previous one was: "wish: show name of document in printjob")
Comment 2 Kurt Pfeifle 2007-01-11 14:27:48 UTC
slightly off-topic:

Note, that KWord could improve as well: in case a user creates a new document and prints it without having saved it to a file, the %%Title line is missing in their PostScript as well.

To help the user identify such jobs, KWord should probably insert something like

  %%Title: KWord unsaved doc ($current_date)

instead. Otherwise the users sees only the KDEPrint-inserted dummy "KDE Print System".
Comment 3 Albert Astals Cid 2007-01-11 21:05:29 UTC
Now the question is, which should the title be?
filename, complete file path, the name reported by the pdf file?
Comment 4 Pino Toscano 2007-01-11 21:10:03 UTC
What about document title, or file name if the document has no title?
Comment 5 Kurt Pfeifle 2007-01-11 22:19:24 UTC

Heh... David fixed my wishlist bug 139905 for KWord within 12 minutes  :-)

I am aware that for kpdf the PostScript is not generated by Qt, but by poppler/xpdf, so surely you need a completely different solution... but just in case you want to look, his patch is to be found at bug 139905.

I now also found that even documents where the PDF meta data for Title: are filled in correctly, the commandline pdftops from xpdf does not write a %%Title into the output PS file.

To me, that looks like a clear bug in xpdf too. So you've probably inherited that in Poppler as well....
Comment 6 Kurt Pfeifle 2007-01-11 22:24:54 UTC
@ comment 3 (Albert):

My suggestion (and I *believe* that's how Acrobat handles it too, but can't verify right now), in the order of preference:

 * if the PDF has a meta data a 'Title:' field that's not empty: use this.
 * if the metadata 'Title' is empty, use the filename.
 
Don't use the path *at* *all*. It may leak to much (private and security sensitive) info which the user for sure would not like.

Cheers,
and thanks for the quick reaction :-)

Kurt
Comment 7 Pino Toscano 2007-01-12 20:25:05 UTC
SVN commit 622742 by pino:

When generating a Postscript document, output the %%Title for the PS document this way:
- the document title, if it has one, or
- the file name of the document (eg foo.pdf for /home/me/foo.pdf)

BUGS: 122147


 M  +3 -1      core/generator.h  
 M  +11 -5     core/generator_pdf/generator_pdf.cpp  
 M  +1 -1      core/generator_pdf/generator_pdf.h  
 M  +13 -7     xpdf/xpdf/PSOutputDev.cc  
 M  +3 -3      xpdf/xpdf/PSOutputDev.h  


--- branches/KDE/3.5/kdegraphics/kpdf/core/generator.h #622741:622742
@@ -80,9 +80,11 @@
         /** constructor: takes the Document as a parameter **/
         Generator( KPDFDocument * doc ) : m_document( doc ) {};
 
+    protected:
+        KPDFDocument * m_document;
+
     private:
         Generator();
-        KPDFDocument * m_document;
 };
 
 /**
--- branches/KDE/3.5/kdegraphics/kpdf/core/generator_pdf/generator_pdf.cpp #622741:622742
@@ -440,7 +440,13 @@
     KTempFile tf( QString::null, ".ps" );
     globalParams->setPSPaperWidth(paperWidth);
     globalParams->setPSPaperHeight(paperHeight);
-    PSOutputDev *psOut = new PSOutputDev(tf.name().latin1(), pdfdoc->getXRef(), pdfdoc->getCatalog(), 1, pdfdoc->getNumPages(), psModePS, marginRight, marginBottom, paperWidth - marginLeft, paperHeight - marginTop);
+    QString pstitle = getDocumentInfo("Title", true);
+    if ( pstitle.isEmpty() )
+    {
+        pstitle = m_document->currentDocument().fileName( false );
+    }
+    const char* pstitlechar = !pstitle.isEmpty() ? pstitle.local8Bit() : 0;
+    PSOutputDev *psOut = new PSOutputDev(tf.name().latin1(), pstitlechar, pdfdoc->getXRef(), pdfdoc->getCatalog(), 1, pdfdoc->getNumPages(), psModePS, marginRight, marginBottom, paperWidth - marginLeft, paperHeight - marginTop);
 
     if (psOut->isOk())
     {
@@ -686,17 +692,17 @@
     (*fonts)[fontsLen++] = *font->getID();
 }
 
-QString PDFGenerator::getDocumentInfo( const QString & data ) const
+QString PDFGenerator::getDocumentInfo( const QString & data, bool canReturnNull ) const
 // note: MUTEX is LOCKED while calling this
 {
     // [Albert] Code adapted from pdfinfo.cc on xpdf
     Object info;
     if ( !pdfdoc )
-        return i18n( "Unknown" );
+        return canReturnNull ? QString::null : i18n( "Unknown" );
 
     pdfdoc->getDocInfo( &info );
     if ( !info.isDict() )
-        return i18n( "Unknown" );
+        return canReturnNull ? QString::null : i18n( "Unknown" );
 
     QString result;
     Object obj;
@@ -739,7 +745,7 @@
     }
     obj.free();
     info.free();
-    return i18n( "Unknown" );
+    return canReturnNull ? QString::null : i18n( "Unknown" );
 }
 
 QString PDFGenerator::getDocumentDate( const QString & data ) const
--- branches/KDE/3.5/kdegraphics/kpdf/core/generator_pdf/generator_pdf.h #622741:622742
@@ -92,7 +92,7 @@
         void fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination );
 
         // private functions for accessing document informations via PDFDoc
-        QString getDocumentInfo( const QString & data ) const;
+        QString getDocumentInfo( const QString & data, bool canReturnNull = false ) const;
         QString getDocumentDate( const QString & data ) const;
         // private function for creating the document synopsis hieracy
         void addSynopsisChildren( QDomNode * parent, GList * items );
--- branches/KDE/3.5/kdegraphics/kpdf/xpdf/xpdf/PSOutputDev.cc #622741:622742
@@ -887,7 +887,7 @@
   fwrite(data, 1, len, (FILE *)stream);
 }
 
-PSOutputDev::PSOutputDev(const char *fileName, XRef *xrefA, Catalog *catalog,
+PSOutputDev::PSOutputDev(const char *fileName, const char *title, XRef *xrefA, Catalog *catalog,
 			 int firstPage, int lastPage, PSOutMode modeA,
 			 int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
 			 GBool manualCtrlA) {
@@ -938,7 +938,7 @@
     }
   }
 
-  init(outputToFile, f, fileTypeA,
+  init(outputToFile, f, title, fileTypeA,
        xrefA, catalog, firstPage, lastPage, modeA,
        imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
 }
@@ -963,12 +963,12 @@
   haveTextClip = gFalse;
   t3String = NULL;
 
-  init(outputFuncA, outputStreamA, psGeneric,
+  init(outputFuncA, outputStreamA, 0, psGeneric,
        xrefA, catalog, firstPage, lastPage, modeA,
        imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
 }
 
-void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
+void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, const char *title,
 		       PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
 		       int firstPage, int lastPage, PSOutMode modeA,
 		       int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
@@ -1056,10 +1056,10 @@
       writeHeader(firstPage, lastPage,
 		  catalog->getPage(firstPage)->getMediaBox(),
 		  catalog->getPage(firstPage)->getCropBox(),
-		  catalog->getPage(firstPage)->getRotate());
+		  catalog->getPage(firstPage)->getRotate(), title);
     } else {
       box = new PDFRectangle(0, 0, 1, 1);
-      writeHeader(firstPage, lastPage, box, box, 0);
+      writeHeader(firstPage, lastPage, box, box, 0, title);
       delete box;
     }
     if (mode != psModeForm) {
@@ -1147,13 +1147,15 @@
 
 void PSOutputDev::writeHeader(int firstPage, int lastPage,
 			      PDFRectangle *mediaBox, PDFRectangle *cropBox,
-			      int pageRotate) {
+			      int pageRotate, const char *title) {
   double x1, y1, x2, y2;
 
   switch (mode) {
   case psModePS:
     writePS("%!PS-Adobe-3.0\n");
     writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+    if(title)
+      writePSFmt("%%%%Title: %s\n", title);
     writePSFmt("%%%%LanguageLevel: %d\n",
 	       (level == psLevel1 || level == psLevel1Sep) ? 1 :
 	       (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
@@ -1174,6 +1176,8 @@
   case psModeEPS:
     writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
     writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+    if(title)
+      writePSFmt("%%%%Title: %s\n", title);
     writePSFmt("%%%%LanguageLevel: %d\n",
 	       (level == psLevel1 || level == psLevel1Sep) ? 1 :
 	       (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
@@ -1208,6 +1212,8 @@
   case psModeForm:
     writePS("%!PS-Adobe-3.0 Resource-Form\n");
     writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+    if(title)
+      writePSFmt("%%%%Title: %s\n", title);
     writePSFmt("%%%%LanguageLevel: %d\n",
 	       (level == psLevel1 || level == psLevel1Sep) ? 1 :
 	       (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
--- branches/KDE/3.5/kdegraphics/kpdf/xpdf/xpdf/PSOutputDev.h #622741:622742
@@ -53,7 +53,7 @@
 public:
 
   // Open a PostScript output file, and write the prolog.
-  PSOutputDev(const char *fileName, XRef *xrefA, Catalog *catalog,
+  PSOutputDev(const char *fileName, const char *title, XRef *xrefA, Catalog *catalog,
 	      int firstPage, int lastPage, PSOutMode modeA,
 	      int imgLLXA = 0, int imgLLYA = 0,
 	      int imgURXA = 0, int imgURYA = 0,
@@ -102,7 +102,7 @@
   // Write the document-level header.
   void writeHeader(int firstPage, int lastPage,
 		   PDFRectangle *mediaBox, PDFRectangle *cropBox,
-		   int pageRotate);
+		   int pageRotate, const char *title);
 
   // Write the Xpdf procset.
   void writeXpdfProcset();
@@ -222,7 +222,7 @@
 
 private:
 
-  void init(PSOutputFunc outputFuncA, void *outputStreamA,
+  void init(PSOutputFunc outputFuncA, void *outputStreamA, const char *title,
 	    PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
 	    int firstPage, int lastPage, PSOutMode modeA,
 	    int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,