2

I need to generate a pdf document that has the Print Options of Page Scaling set to "None" or "Actual Size"

This setting in the document would mean that the default when you open the document in Adobe Reader or other PDF reader will be " Do not Shrink this page to fit in the printer margins"

In Adobe Reader 10 the setting I would like to control is under the Print dialog and "Page Sizing & Handling" the option for "Size Options" I would like the document to default to "Actual Size" instead of "Shrink oversized pages".

I have talked to my sources and tested with creating/saving a PDF document with Adobe Standard edition and you can set the View properties of the document to have a default for this exact property and Adobe Reader will honor that instead of using the Adobe Reader default which is shink.

I am using PDF Creator 1.5.0 to "Print" the pfd document which seems to allow postscript to be applied to the document. However I could use a alternate PDF printer if it suited my purpose and had this option. I do not see any GUI option in PDF Creator settings for controlling it.

I am pretty sure I could use ghostscript to apply a property but I need to know how to do it.

Update: I have been looking at the Adobe pdf specification and the document properties I am looking for seem to be in the PDF 1.6 specification.

12.2 Viewer Preferences The ViewerPreferences entry in a document’s catalogue (see 7.7.2, “Document Catalog”) designates a viewer preferences dictionary (PDF 1.2) controlling the way the document shall be presented on the screen or in print. If no such dictionary is specified, conforming readers should behave in accordance with their own current user preference settings. Table 150 shows the contents of the viewer preferences dictionary.

PrintScaling - (Optional; PDF 1.6) The page scaling option that shall be selected when a print dialog is displayed for this document. Valid values are None, which indicates no page scaling, and AppDefault, which indicates the conforming reader’s default print scaling. If this entry has an unrecognized value, AppDefault shall be used. Default value: AppDefault. If the print dialog is suppressed and its parameters are provided from some other source, this entry nevertheless shall be honored.

This is EXACTLY what I want to control through some 3rd party PDF printer software or ghostscript. I am not a PDF expert and I don't know how to do it.

Update: I developed a solution using Pdf Creator and edited the solution into the accepted answer. I also looked at the following that has potential for applications when using an API to generate the pdf.
Solid Documents pdf

itextpdf - Also available in a C# version

10
  • I know a lot about PDF and Ghostscript (at least I like to think so)... but I do not understand your problem, sorry. Oct 12, 2012 at 21:36
  • Sorry my first time trying to comment and my browser is freaking out I keep hitting enter. and now I can't edit. Simple question I want the ghostscript parameter opposite to -dPDFFitPage. It can be done with Adobe Standard... but through the GUI I don't know the property to set.
    – Collin
    Oct 12, 2012 at 21:45
  • Open a PDF in Adobe Reader -> Print -> look under the Title "Page Sizing & Handling" look at "Size Options" and usually the default will be " Shink oversized Pages" (other PDF viewers have a similar setting but for simplicity I am sticking to adobe's exact words) want to embed the option of "Actual Size" into the document. I know this is possible because Adobe Standard (Full creator) lets you set this, and It is honored when you open the PDF in Adobe Reader.
    – Collin
    Oct 12, 2012 at 21:47
  • As the author of a question, you can always edit it. Try to be clear and logical. Start with telling what software+version you currently use, and what you want to achieve. And you should do so before it gets downvoted or even deleted... You currently start with "I need to generate a PDF..." without telling what software you use. Then you continue to talk about "Print Options of Page Scaling"... which is something completely different from "generate a PDF" -- printing a PDF is a function of a PDF viewer, not a PDF generator. Oct 12, 2012 at 21:53
  • 1
    Note also that PDFFitPage doesn't do what you seem to think it does. It scales an incoming PDF file so that it fits to a different media size. There is nothing in Ghostscript's pdfwrite device which alters the default printing behaviour of a PDF viewer. In fact I'm not aware of any way to do this. If you have a PDF file for which this is possible, then I suggest that you make it publicly available, so that we can look at it.
    – KenS
    Oct 13, 2012 at 7:32

2 Answers 2

2

This should be possible by specifying /PrintScaling /None in the ViewerPreferences dict (see section 12.2 in ISO 32000-1:2008.

Update: Try this:

[ {Catalog} << /ViewerPreferences << /PrintScaling /None >> >> /PUT
pdfmark

See http://www.digipedia.pl/usenet/thread/1191/1835/

Update: From Poster
The final solution was to add the above postscript line into the postscript generated by PDF Creator using the "Actions" feature of PDF Creator. (Action Before Saving)

http://www.pdfforge.org/content/actions

I also used this link as inspiration for the action and looked at the preinstalled vbs scripts to figure out what needed to be done to add information to the convert to pdf postscript file.

PDFCreator Document View settings - It seems that a script similar to this used to be included in PdfCreator.

Anyway this is my final script that can be added to Pdf Creator to add the PrintScaling default property.

' SetPrintScalingNone.vbs script
' Author: Collin Kulbacki
' Version: 1.0.0.0
' Date: Oct 18, 2012
' Comment: This script Sets the ViewerPrefferences Print Scalling to none.

Option Explicit

Const AppTitle = "PDFCreator - SetPrintScallingNone"
Const ForReading = 1, ForAppending = 8

Dim objArgs, objNetwork, section, ini, fso, f
Dim fname, key, psFile, strTitle,  printScalingFile

Set objArgs = WScript.Arguments

If objArgs.Count = 0 Then
 MsgBox "This script needs a parameter!", vbExclamation, AppTitle
 WScript.Quit
End If

fname = objArgs(0)


Set ini = New IniFile
ini.Load fName, true

Set fso = CreateObject("Scripting.FileSystemObject")
printScalingFile = fso.GetParentFolderName(fName) & "\" & GenerateGUID & ".ps"
Set f = fso.OpenTextFile(printScalingFile, ForAppending, True)
f.writeline "[ {Catalog} << /ViewerPreferences << /PrintScaling /None >> >> /PUT pdfmark"

f.Close

Set objNetwork = CreateObject("WScript.Network")

set section = ini.AddSection(GenerateGUID)
section.AddKey("SessionId").Value = " "
section.AddKey("WinStation").Value = " "
section.AddKey("UserName").Value = objNetwork.UserName
section.AddKey("ClientComputer").Value = objNetwork.ComputerName
section.AddKey("SpoolFileName").Value = printScalingFile
section.AddKey("PrinterName").Value = " "
section.AddKey("JobId").Value = " "
section.AddKey("DocumentTitle").Value = "PrintScaling"

ini.Save fName, true



WScript.Quit



Private Function GenerateGUID()
 GenerateGUID = Replace(Mid(CreateObject("Scriptlet.TypeLib").GUID, 2, 36), "-", "")
End Function



' http://www.codeproject.com/Articles/21896/INI-Reader-Writer-Class-for-C-VB-NET-and-VBScript
' IniFile class used to read a nd write ini files by loading the file into memory
Class IniFile
    'List of IniSection objects keeps track of all the sections in the INI file
    Private m_pSections, OpenAsUnicode
    'Public constructor
    Public Sub Class_Initialize()
        Set m_pSections = CreateObject("Scripting.Dictionary")
        m_pSections.CompareMode = vbTextCompare
    End Sub

    'Returns an array of the IniSections in the IniFile
    Public Property Get Sections
         Sections = m_pSections.Items
    End Property

    'Load IniFile object with existing INI Data
    Public Sub Load( ByVal sFileName , ByVal bAppend )
        Dim intAsc1Chr, intAsc2Chr
        If Not bAppend Then RemoveAllSections() ' Clear the object...

        Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject") 
        Dim tempsection : Set tempsection = Nothing
        'Dim oReader : Set oReader = objFSO.OpenTextFile( sFileName, , , format )
        Dim oReader, Stream
        Set Stream = objFSO.OpenTextFile(sFileName, 1, False)
        intAsc1Chr = Asc(Stream.Read(1))
        intAsc2Chr = Asc(Stream.Read(1))
        Stream.Close

        ' (255, 254 == FF, FE -> UniCode) Or (91, 0 == [ '\0' -> Widechar inf file from pdfcmon.dll)
        If (intAsc1Chr = 255 And intAsc2Chr = 254) Or (intAsc1Chr = 91 And intAsc2Chr = 0) Then 
            OpenAsUnicode = True
        Else
            OpenAsUnicode = False
        End If

        Set oReader = objFSO.OpenTextFile( sFileName, 1, 0, OpenAsUnicode )
        Dim regexsection : set regexsection = new regexp 
        Dim regexkey : Set regexkey = new regexp
        Dim regexcomment : Set regexcomment = new regexp

        regexcomment.Pattern = "^([\s]*#.*)"
        regexcomment.Global = False
        regexcomment.IgnoreCase = True
        regexcomment.MultiLine = False

        ' Left for history
        'regexsection.Pattern = "\[[\s]*([^\[\s].*[^\s\]])[\s]*\]"
        'regexsection.Pattern = "^[\s]*\[[\s]*([^\[\s].*[^\s\]])[\s]*\][\s]*$"
        regexsection.Pattern = "^\s*\[\s*(.*[^\s])\s*\]\s*$"
        regexsection.Global = False
        regexsection.IgnoreCase = True
        regexsection.MultiLine = False

        regexkey.Pattern = "^\s*([^=\s]*)[^=]*=(.*)" 
        regexkey.Global = False
        regexkey.IgnoreCase = True
        regexkey.MultiLine = False

        While Not oReader.AtEndOfStream
            Dim line : line = oReader.ReadLine()
            If line <> "" Then
                Dim m
                If regexcomment.Test(line) Then
                    Set m = regexcomment.Execute(line)
                    'WScript.Echo("Skipping Comment " & m.Item(0).subMatches.Item(0) )
                ElseIf regexsection.Test(line) Then
                    Set m = regexsection.Execute(line)
                    'WScript.Echo("Adding section [" & m.Item(0).subMatches.Item(0) &"]" )
                    Set tempsection = AddSection( m.Item(0).subMatches.Item(0) )
                ElseIf regexkey.Test(line) And Not tempsection Is Nothing Then
                    Set m = regexkey.Execute(line)
                    'WScript.Echo("Adding Key ["& m.Item(0).subMatches.Item(0) &"]=["& m.Item(0).subMatches.Item(1) &"]" )
                    tempsection.AddKey( m.Item(0).subMatches.Item(0) ).Value = m.Item(0).subMatches.Item(1)
                ElseIf Not tempsection Is Nothing Then
                    'WScript.Echo("Adding Key ["& line &"]" )
                    tempsection.AddKey( line )
                'Else
                 '   WScript.Echo("Skipping unknown type of data: " & line)
                End If
            End If
        Wend
        oReader.Close()
    End Sub

    'Allows you to do a save the IniFile resident in memory to file
    Public Sub Save(ByVal sFileName, ByVal AsUnicode)
        Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
        Dim oWriter : Set oWriter = objFSO.CreateTextFile( sFileName , True, AsUnicode )

        Dim s 'IniSection
        Dim k 'IniKey
        For Each s In Sections
            'WScript.Echo("Writing Section: " & s.Name)
            oWriter.WriteLine("[" & s.Name & "]")
            For Each k In s.Keys
                If k.Value <> vbNullString Then
                    'WScript.Echo("Writing Key: "&k.Name&"="&k.Value)
                    oWriter.WriteLine(k.Name & "="& k.Value )
                Else
                    'WScript.Echo("Writing Key: "&k.Name)
                    oWriter.WriteLine(k.Name)
                End if
            Next
        Next
        oWriter.Close()
    End Sub

    'Returns the IniSection object associated with a section name
    Public Function GetSection(ByVal sSection )
        Set GetSection = Nothing
        sSection = Trim(sSection) 'Trim spaces
        If Len( sSection ) <> 0 Then
            If m_pSections.Exists( sSection ) Then
                Set GetSection = m_pSections.Item(sSection)
            End If
        End If
    End Function

    ' Adds a section to the IniFile object, returns a IniSection object
    Public Function AddSection(ByVal sSection )
        Set AddSection = Nothing
        If StrComp(TypeName(sSection),"IniSection",1) = 0 Then 
            If Not sSection Is Nothing Then
                ' Only purpose is to be used by child to re-insert
                If Not sSection Is Nothing Then
                    If Not m_pSections.Exists( sSection.Name ) Then
                        Set m_pSections.Item( sSection.Name ) = sSection
                        Set AddSection = sSection
                    End If
                End If
            End If 
        ElseIf StrComp(TypeName(sSection),"String",1) = 0 Then
            sSection = Trim(sSection)
            If Len( sSection ) <> 0 Then 
                If m_pSections.Exists( sSection ) Then
                    Set AddSection = m_pSections.Item(sSection)
                Else
                    Dim s : Set s = New IniSection
                    Call s.Init( Me , sSection )
                    Set m_pSections.Item(sSection) = s
                    Set AddSection = s
                End If
            End If      
        End If
    End Function

    ' Removes all existing sections (clears the object) 
    Public Sub RemoveAllSections()
        Call m_pSections.RemoveAll()
    End Sub

    ' Remove a section by name or section object
    Public Function RemoveSection(ByVal Obj)
        RemoveSection = False
        If StrComp(TypeName(Obj),"IniSection",1) = 0 Then 
            If Not Obj Is Nothing Then
                m_pSections.Remove(Obj.Name)
                RemoveSection = True
            End If 
        ElseIf StrComp(TypeName(Obj),"String",1) = 0 Then
            RemoveSection = RemoveSection( GetSection(Obj) )
        End If 
    End Function

    ' Remove a key by section namd and key name
    Public Function RemoveKey(ByVal sSection , ByVal sKey)
        RemoveKey = False
        Dim s : Set s = GetSection(sSection)
        If Not s Is Nothing Then
            RemoveKey = s.RemoveKey( sKey )
        End If
    End Function

    ' Returns a KeyValue in a certain section
    Public Function GetKeyValue(ByVal sSection , ByVal sKey )
        GetKeyValue = vbNullString
        Dim s : Set s = GetSection(sSection)
        If Not s Is Nothing Then
            Dim k : Set k = s.GetKey(sKey)
            If Not k Is Nothing Then
                GetKeyValue = k.Value
            End If
        End If
    End Function

    ' Sets a KeyValuePair in a certain section
    Public Function SetKeyValue(ByVal sSection , ByVal sKey , ByVal sValue )
        SetKeyValue = False
        Dim s : Set s = AddSection(sSection)
        If Not s Is Nothing Then
            Dim k : Set k = s.AddKey(sKey)
            If Not s Is Nothing Then
                k.Value = sValue
                SetKeyValue = True
            End If
        End If
    End Function

    ' Renames an existing section returns true on success, false if the section didn't exist or there was another section with the same sNewSection
    Public Function RenameSection(ByVal sSection , ByVal sNewSection)
        ' Note string trims are done in lower calls.
        RenameSection = False
        Dim s : Set s = GetSection(sSection)
        If Not s Is Nothing Then
            RenameSection = s.SetName(sNewSection)
        End If
    End Function

    ' Renames an existing key returns true on success, false if the key didn't exist or there was another section with the same sNewKey
    Public Function RenameKey(ByVal sSection , ByVal sKey, ByVal sNewKey)
        ' Note string trims are done in lower calls.
        RenameKey = False
        Dim s : Set s = GetSection(sSection)
        If Not s Is Nothing Then
            Dim k : Set k = s.GetKey(sKey)
            If Not k Is Nothing Then
                RenameKey = k.SetName(sNewKey)
            End If
        End If
    End Function

End Class


'IniSection Class 
Class IniSection
   ' IniFile IniFile object instance
   Private m_pIniFile
   ' Name of the section
   Private m_sSection
   ' List of IniKeys in the section
   Private m_keys

   'Friend constuctor so objects are internally managed
   Public Sub Class_Initialize
       Set m_pIniFile = Nothing
       m_sSection = ""
       Set m_keys = CreateObject("Scripting.Dictionary")
       m_keys.CompareMode = vbTextCompare
   End Sub

    ' Function only works once...
    Public Sub Init( ByVal oIniFile , ByVal sSection )
        If m_pIniFile is Nothing Then 
            Set m_pIniFile = oIniFile
            m_sSection = sSection
        End If  
    End Sub

    'Returns an array of the IniKeys in the IniFile
    Public Property Get Keys
         Keys = m_keys.Items
    End Property

   'Returns the section name
   Public Property Get Name
           name = m_sSection
   End Property

   'Set the section name
   'Returns true on success, False if key already exists in the section
   Public Function SetName(ByVal sSection)
       SetName = False  ' Default
       sSection = Trim(sSection)
       If Len( sSection ) <> 0 Then
           Dim s : Set s = m_pIniFile.GetSection(sSection)
           If Not s Is Me And Not s Is Nothing Then Exit Function
           Call m_pIniFile.RemoveSection(Me)
           m_sSection = sSection
           Call m_pIniFile.AddSection(Me)           
           SetName = True
       End If
   End Function

   'Returns the section name
   Public Function GetName()
           GetName = m_sSection
   End Function

   'Adds a key to the IniSection object
   'Returns Nothing on failure
    Public Function AddKey(ByVal sKey)
        Set AddKey = Nothing
        ' Is this a string or object of IniKey
        If StrComp(TypeName(sKey),"IniKey",1) = 0 Then 
            ' Only purpose is to be used by child to re-insert
            If Not sKey Is Nothing Then
                If Not m_keys.Exists( sKey.Name ) Then
                    Set m_keys.Item(sKey.Name) = sKey
                    Set AddKey = sKey
                End If
            End If
        ElseIf StrComp(TypeName(sKey),"String",1) = 0 Then
            ' String was passed...
            sKey = Trim(sKey)
            If Len(sKey) <> 0 Then
                If m_keys.Exists( sKey ) Then
                    Set AddKey = m_keys.Item(sKey)
                Else
                    Dim k : Set k = New IniKey
                    Call k.Init( Me , sKey )
                    Set m_keys.Item(sKey) = k
                    Set AddKey = k
                End If
            End If
        End If        
   End Function

   'Returns a IniKey
   'Returns Nothing on failure 
    Public Function GetKey(ByVal sKey)
        Set GetKey = Nothing
        sKey = Trim(sKey)
        If Len(sKey) <> 0 Then
            If m_keys.Exists( sKey ) Then
                Set GetKey = m_keys.Item(sKey)
            End If 
        End If
    End Function

   'Removes all the keys in the section
   Public Sub RemoveAllKeys()
       Call m_keys.RemoveAll()
   End Sub

   'Removes a single key by IniKey object by string or object
   Public Function RemoveKey(ByVal Obj)
        RemoveKey = False
        If StrComp(TypeName(Obj),"IniKey",1) = 0 Then 
            If Not Obj Is Nothing Then
                m_keys.Remove(Obj.Name)
                RemoveKey = True
            End If
        ElseIf StrComp(TypeName(Obj),"String",1) = 0 Then
            RemoveKey = RemoveKey( GetKey(Obj) )
        End If        
   End Function

End Class  ' End of IniSection

'IniKey Class
Class IniKey
    ' Name of the Key
    Private m_sKey
    ' Value associated
    Private m_sValue
    ' Pointer to the parent CIniSection
    Private m_pSection

    'Friend constuctor so objects are internally managed
    Public Sub Class_Initialize
        m_sKey = ""
        m_sValue = ""
        Set m_pSection = Nothing
    End Sub

    'Returns the key's parent IniSection
    Public Sub Init( ByVal oIniSection , ByVal sKey )
           If m_pSection Is Nothing Then
                Set m_pSection = oIniSection
                m_sKey = sKey
           End If 
    End Sub

    'Returns the name of the Key
    Public Property Get Name
            name = m_sKey
    End Property

'     'Gets\Sets the value associated with the Key
     Public Property Let Value( strKeyValue )
             m_sValue = strKeyValue
     End Property

    'Gets\Sets the value associated with the Key
    Public Property Get Value()
            value = m_sValue
    End Property

    'Sets the key name
    'Returns true on success, fails if the section name sKeyName already exists
    Public Function SetName(ByVal sKey )
        SetName = False
        sKey = Trim(sKey)
        If Len(sKey) <> 0 Then
            Dim s : Set s = m_pSection.GetKey(sKey)
            If Not s Is Me And Not s Is Nothing Then Exit Function
            Call m_pSection.RemoveKey(Me)
            ' Set our new name
            m_sKey = sKey
            ' Put our own object back
            Call m_pSection.AddKey(Me)
            SetName = True
        End If
    End Function

    ' Returns the current key name
    Public Function GetName()
            GetName = m_sKey
    End Function

End Class

I can't take credit for the ini file class used to parse the output from PdfCreator that was provided via the existing vbs scrips in PdfCreator.

0
1

Checking version 9 of the pdfmark reference, I cannot see any pdfmark which affect Viewer Preferences. SO there is no way for you to achieve this using Ghostscript without modifying the pdfwrite device.

Ghostscript's pdfwrite device doesn't emit a ViewerPreferences dictionary in the Catalog object at all, so you would need to add one.

4
  • Thank you for the information maybe ghostscript is the wrong technology to be asking about. My knowledge of it is extremely minimal. From my understanding I thought that ghostscript uses ps2pdf and it seemed like ps2pdf could add/edit the catalog. But like I said I am a pdf/ghostscript rookie and cannot figure out what the syntax is. Even after reading this. ghostscript.com/doc/current/Ps2pdf.htm#Orientation
    – Collin
    Oct 16, 2012 at 14:12
  • @Collin: I believe this can be made to work; see the update to my answer. Oct 16, 2012 at 20:07
  • ps2pdf (in at least one incarnation by that name) is just a script that calls Ghostscript. If Ghostscript is involved then anything else will be using it, not the other way around. Ghostscript is the underlying technology.
    – KenS
    Oct 17, 2012 at 7:06
  • Martin, your answer is exactly the correct way to do this with pdfmark, I believe, with one small problem. As I said, Ghostscript doesn't emit ViewerPreferences in the Catalog dictionary and since it builds the Catalog as required (at the end of the process) you can't add anything to the Catalog dictionary in the course of the job. The only way to do this with Ghostscript, as far as I can see, is to get out your favourite editor and C compiler and start coding. The Catalog is written in gdevpdf.c, pdf_close() at around line 2421.
    – KenS
    Oct 17, 2012 at 7:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .