Automating Commercial Printing Prepress Tasks in Publisher 2003, Part 2

 

Andrew May
Microsoft Corporation

February 2004

Applies to:
    Microsoft® Office Publisher 2003

Summary: Use the Publisher 2003 object model to automate, customize, and extend prepress operations involved publication page setup, embedded and linked pictures, and design considerations. This is part two of a three part series. (34 printed pages)

Contents

Introduction
Automating Page Setup
Managing Graphics
Automating Publication Design Checks
Fixing Picture and Design Problems
Putting It All Together
Object Model Hierarchies
Conclusion

Introduction

This is the second of three articles meant to supplement the Publisher 2003 Prepress Reference Guide, and discuss how to use the Publisher 2003 object model to accomplish prepress tasks. This article discusses page setup, managing graphics, and performing design checks.

For detailed information about the Publisher 2003 commercial printing functionality, including technical issues, troubleshooting, and workarounds, see the Publisher 2003 Prepress Reference, available for download from Publisher Prepress on Office Online.

For information about setting a publication's color mode, printing separations, and other advanced printing options, see the first article in this series, Automating Commercial Printing Prepress Tasks in Publisher 2003, Part 1.

Automating Page Setup

You can use the Document.PageSetup object and its members to automate a wide range of preflight operations, including:

  • Set page size and imposition options
  • Make sure the page will correctly print on the selected paper size
  • Print multiple pages per paper sheet

Set Page Size

Use the PageHeight and PageWidth properties of the PageSetup object to set the dimensions of the publication page. For most publications, you define these settings when you create the publication, and there is no need to change them later. Both of these properties, and most properties in the object model that pertain to page or shape measurements, take a Variant data type that represents the page dimension in points. However, when writing code that sets these dimensions, you can specify measurements in other units, and use global (that is, Application) methods included in the object model to convert them to points. For example, the following sample sets the page height and width of the active publication, using inches as the measurement unit, and using the InchesToPoints method to convert the measurements to points.

With ActiveDocument.PageSetup
    .PageWidth = InchesToPoints(8.5)
    .PageHeight = InchesToPoints(5.5)
End With

Table 1. Methods to convert measurements to and from points

Unit Convert to Points Convert From Points 1 Inch =
centimeters CentimetersToPoints PointsToCentimeters 2.54 cm
emus EmusToPoints PointsToEmus 914,4000 emus
inches InchesToPoints PointsToInches 1 inch
lines LinesToPoints PointsToLines 6 lines
millimeters MillimetersToPoints PointsToMillimeters 25.4 mm
picas PicasToPoints PointsToPicas 6 picas
pixels PixelsToPoints PointsToPixels 96 pixels
twips TwipsToPoints PointsToTwips 1,440 twips

In addition, most of the Publisher object properties specifying dimensions can also take a string, which Publisher then converts to points. This string must be a number followed by the measurement unit abbreviation. Again, this is true of shape dimensions as well as page sizes. For example, the following code sets the height and width of a shape using a string specifying measurements in inches.

With ActiveDocument.Pages(1).Shapes(1)
    .Height = "2 in"
    .Width = "2 in"
End With

Setting the Page Size by Selecting a Publication Layout

Another factor that affects the publication page size is the layout type chosen. Publisher offers a number of pre-defined publication layout formats, such as banners, business cards, or envelopes. When you select a layout type, Publisher automatically re-sizes the publication. The default size of each layout type is based on the size of the paper being printed to; if you increase or decrease the paper size, or change the paper orientation, the default publication page size for a layout type changes as well.

**Caution   **Again, in most instances, Publisher selects the layout type when you first create the publication, not when you change it. Use care when changing the layout type or paper size of a publication after you submit it for printing, because changing either of these may change the publication page size, leading to unpredictable print results.

To change the layout type of a publication, set the PublicationLayout property to the constant representing the layout type you want. The value of the PageHeight and PageWidth properties update to reflect the default dimensions of the layout type selected.

The following example creates a publication, with the same publication layout type, page height, and page width as the active publication.

Dim objNewDoc As Document

Set objNewDoc = NewDocument
With objNewDoc.PageSetup
    .PublicationLayout = ActiveDocument.PageSetup.PublicationLayout
    .PageHeight = ActiveDocument.PageSetup.PageHeight
    .PageWidth = ActiveDocument.PageSetup.PageWidth
End With

Verify That the Selected Paper Size Is Large Enough To Print the Publication

In addition to setting the dimensions of a publication, the PageHeight and PageWidth properties are useful in making sure the paper used for the publication is large enough to contain the entire publication page, including any printer's marks that you select.

You cannot set the paper size using the Publisher object model. However, the AdvancedPrintOptions.PrintableRect object contains properties that represent the dimensions of the paper's printable area. By comparing those dimensions with the publication page dimension, and taking into account any extra space needed to display printer's marks, you can determine if the paper size you chose appropriate.

The following example compares the height and width of the active publication to the height and width of the printable area of the paper used for the publication, and displays an alert if either dimension is too large to print. If any printer's marks are also printed, Publisher adds an inch to the height and width of the publication page before making the comparison (printer's marks typically extend a half-inch on each side). If you set up the publication to print multiple times on each paper sheet, Publisher displays a message to that affect and does not make the comparison. The multiple layout option is discussed in detail later in this article.

Sub CompareTotalPageSizeToPrintArea()
Dim intTotalPageHeight As Integer
Dim intTotalPageWidth As Integer
Dim intStartPrintMode As Integer

With ActiveDocument
    If .PageSetup.MultiplePagesPerSheet = False Then
        'Call function to determine if printers marks are on
        If PrintersMarksSet(.AdvancedPrintOptions) = True Then
            'Add one inch for printers marks
            intTotalPageHeight = .PageSetup.PageHeight _
                    + InchesToPoints(1)
            intTotalPageWidth = .PageSetup.PageWidth _
                    + InchesToPoints(1)
        Else
            intTotalPageHeight = .PageSetup.PageHeight
            intTotalPageWidth = .PageSetup.PageWidth
        End If
        
        'Compare page height to paper print area height
        If intTotalPageHeight > _
            .AdvancedPrintOptions.PrintableRect.Height Then
            MsgBox "The publication page is too tall " & _
                "for the sheet it's being printed to." & _
                vbLf & "Increase the size paper you're printing to." & _
                vbLf & "Make sure to account for any " & _
                "printer's marks being printed.", , _
                "Page Height Exceeds Paper Size"
        Else
            MsgBox "The publication page height fits " & _
                "on the selected sheet.", , _
                "Page Height Fits Paper Size"
        End If
        
        'Compare page width to paper print area width
        If intTotalPageWidth > _
            .AdvancedPrintOptions.PrintableRect.Width Then
            MsgBox "The publication page is too wide " & _
                "for the sheet it's being printed to." & _
                vbLf & "Increase the size paper you're printing to." & _
                vbLf & "Make sure to account for any " & _
                "printer 's marks being printed.", , _
                "Page Width Exceeds Paper Size"
        Else
            MsgBox "The publication page width fits " & _
                "on the selected sheet.", , _
                "Page Width Fits Paper Size"
        End If
    Else
    MsgBox "This publication is set to automatically print " & _
            "multiple copies of the page per sheet", , _
            "Comparison Invalid"
    End If
End With

End Sub

Note that the sample uses the helper function below to determine if you specified printer's marks for the publication. In the function, the code changes the print mode of the publication to separations before checking to see if you specified any of the printer's marks. This is because the PrintColorBars, PrintDensityBars, and PrintRegistrationMarks properties are only accessible when the PrintMode property is set to separations. However, these options are available in the Publisher user interface for the composite CYMK and composite grayscale print modes. Therefore, the function changes the print mode to separations, determines if you specified any printer's marks, and then sets the print mode back to its original value.

Public Function PrintersMarksSet _
    (AdvancedPrintOptions As AdvancedPrintOptions) As Boolean
Dim intStartPrintMode As Integer
    With AdvancedPrintOptions
        'Store original publication print mode
        intStartPrintMode = .PrintMode
        'Set print mode to separations
        .PrintMode = pbPrintModeSeparations
        'Check for printers marks
        If .AllowBleeds Or .PrintCropMarks _
            Or .PrintColorBars Or .PrintDensityBars _
            Or .PrintJobInformation _
            Or .PrintRegistrationMarks = True Then
            PrintersMarksSet = True
        End If
        'Restore original print mode
        .PrintMode = intStartPrintMode
    End With
End Function

Choosing Automatic Imposition Options

Publisher includes several basic imposition layouts in its collection of layout types. You select these options by setting the PublicationLayout property to the appropriate constant.

Table 2. Imposition Options

Imposition option Constant Description
Booklet pbLayoutBook Prints the publication as printer's spreads, as for a saddle-stitched booklet.
Tent card pbLayoutTentCard Prints two pages head-to-head on the same plate or piece of film.
Side-fold card pbLayoutGreetingCardL Prints pages four-up, with some pages inverted, as for a side-fold greeting card.
Top-fold card pbLayoutGreetingCardT Prints pages four-up, with some pages inverted, as for a top-fold greeting card.

Note   Again, use caution when applying an imposition layout type to a publication that was not originally created based on that layout type. Changing the layout type of a publication can change other publication layout properties, such as page dimensions, leading to unpredictable print results.

Manual Imposition Using Publisher

You can also manipulate the Publisher object model to perform customized imposition procedures. For more information, see the third article in this series Automating Commercial Printing Prepress Tasks in Publisher 2003, Part 3.

Printing Multiple Copies per Paper Sheet

Publisher provides you the option of printing each publication page multiple times per sheet. Publisher automatically sets the page to print multiple times if it fits more than once on the paper to which you are printing. Layouts are based on paper size, so the pages always fit within the paper's printable area. You can use the MultiplePagesPerSheet property to select or deselect this option.

When printing multiple copies of a page per sheet, Publisher automatically lays out as many copies as fit on the page. The appropriate space for printer's marks is also included between copies, if necessary. If you change the dimensions or orientation of the publication, or those of the paper to which you are printing, Publisher updates the layout to consider these changes.

While Publisher creates the layout automatically, it also gives you the flexibility to customize the spacing between copies, and thereby determine the number of copies printed on each sheet. The TopMargin, LeftMargin, HorizontalGap, and VerticalGap properties let you control the placement and spacing of the copies on the page. Publisher automatically updates the placement and number of copies printed per page based on the spacing you specify.

The following sample sets each publication page to print multiple times per sheet, and specifies the horizontal and vertical spacing between each copy on the sheet. Note that the top and left margins specified refer to distance from the top and left edge of the paper sheet (as opposed to top and left edge of the sheet's printable area.) Once again, all dimensions are expressed in inches and converted to points.

With ActiveDocument.PageSetup
    .MultiplePagesPerSheet = True
    .VerticalGap = InchesToPoints(0.75)
    .HorizontalGap = InchesToPoints(0.75)
    .TopMargin = InchesToPoints(0.75)
    .LeftMargin = InchesToPoints(0.75)
End With

When you explicitly define the placement and spacing of the copies, as opposed to allowing Publisher to lay them out automatically, you should make sure you have left adequate room between the pages for any printer's marks you specified to print. The following sample employs the helper function shown earlier to determine if you specified printer's marks for the active publication. If they are, it checks to make sure the horizontal and vertical spacing is wide enough for the printer's marks to print, and displays a dialog box with the results.

Sub CheckSpaceBetweenPages()
Dim strMessage As String
Dim sngSpaceForMarks As Single

sngSpaceForMarks = InchesToPoints(0.5)

With ActiveDocument.PageSetup
    If (PrintersMarksSet(ActiveDocument.AdvancedPrintOptions) = True) _
        And (.HorizontalGap < sngSpaceForMarks) Then
        strMessage = "The horizontal spacing between pages " & _
            "is too small to show printer's marks." & vbLf
    Else
       strMessage = "Horizontal spacing between pages is fine." & vbLf
    End If
    If (PrintersMarksSet(ActiveDocument.AdvancedPrintOptions) = True) _
        And (.VerticalGap < sngSpaceForMarks) Then
        strMessage = strMessage & "The vertical spacing between pages " & _
            "is too small to show printer's marks."
    Else
       strMessage = strMessage & "Vertical spacing between pages is fine."
    End If
    MsgBox prompt:=strMessage, Title:="Spacing Between Pages"
End With
End Sub

The next sample determines how many copies of each publication page to print on each page, if Publisher automatically controls the placement and spacing. Once again, it takes into account any specified printer's marks when determining the number of copies that can fit on the page. This information is provided in the Publisher user interface, but there are no analogous properties for it in the PageSetup object.

Sub PrintPagesPerSheet2()
Dim intWidthCount As Integer
Dim intHeightCount As Integer
Dim sngPaperWidth As Single
Dim sngPaperHeight As Single
Dim sngTotalWidth As Single
Dim sngTotalHeight As Single
Dim intTotalCopies As Integer

With ActiveDocument
    If .PageSetup.MultiplePagesPerSheet = True Then
        sngPaperWidth = .AdvancedPrintOptions.PrintableRect.Width
        sngPaperHeight = .AdvancedPrintOptions.PrintableRect.Height
    
        'Call function to determine if printer's marks are on
        'Add a half-inch to page dimensions if they are
        If PrintersMarksSet(.AdvancedPrintOptions) = True Then
            sngTotalWidth = .PageSetup.PageWidth + (InchesToPoints(0.5))
            sngTotalHeight = .PageSetup.PageHeight + (InchesToPoints(0.5))
        End If
        
        'Determine how many pages fit horizontally
        Debug.Print sngPaperWidth / sngTotalWidth
        intWidthCount = Int(sngPaperWidth / sngTotalWidth)
        'Determine how many pages fit vertically
        Debug.Print sngPaperHeight / sngTotalHeight
        intHeightCount = Int(sngPaperHeight / sngTotalHeight)
        
        'determine total number of copies per paper sheet
        intTotalCopies = intHeightCount * intWidthCount
        MsgBox intTotalCopies & " copies of your page will " & _
            "print on the selected paper size." _
            & vbLf & intWidthCount & " column(s) of " & intHeightCount & _
            " copies each.", _
            vbOKOnly, "Multiple Layouts Printed"
     End If
End With
End Sub

The TopMargin, LeftMargin, HorizontalGap, and VerticalGap properties correspond to the options found on the Small Publications Print Options dialog box. To do this in the UI, on the File menu, click Page Setup, and then click Change Copies Per Sheet.

Managing Graphics

Microsoft Office Publisher 2003 provides a greatly expanded object model with more support for identifying, analyzing, and manipulating the pictures in a publication. In the Publisher user interface, you can perform most of these tasks using the Graphics Manager. While there is no way to invoke the Graphics Manager directly through the object model, you can perform the same tasks programmatically as well.

Most of these tasks involve using the Shape and PictureFormat objects and their respective members. Publisher represents each picture in a publication by a Shape object whose Type property is either pbPicture or pbLinkedPicture. You can only access PictureFormat object for Shape objects of these two types; access is not permitted for Shape objects of other types.

Using these objects and their members, you can write code that performs the following Graphics Manager tasks:

  • Identify embedded and linked pictures in the publication.
  • Generate a list of all pictures that were modified or whose links are broken.
  • Update linked pictures whose originals were modified.
  • Convert linked pictures to embedded pictures.
  • Save embedded pictures as linked pictures.
  • Replace one picture with another picture.
  • Replace an empty picture frame with a picture.
  • Gather detailed information about a specific picture.

The real power of the Publisher object model, however, isn't that it just lets you duplicate the tasks the Graphics Manager performs in the user interface. The advantage is that the object model enables you to automate, customize, and extend those tasks. For example, you can automate the creation of a report that lists each picture in a publication and lists only the picture properties you're interested in. Or you can write a procedure that takes a specific action based on its analysis of the pictures in a publication; for example, later in the article, there's one code sample that automatically re-sizes any pictures in a publication that are not scaled proportionally, and another that updates any linked pictures that were modified since being inserted into the publication.

While this section focuses on automating Graphics Manager tasks, chances are you may find the most useful aspect of the object model is adapting those tasks for what works the best for your prepress process.

View Picture Details

You can use the various properties of the PictureFormat object to return the specific picture information in which you are interested. If the picture is a linked picture, these properties include information about the linked file, such as file size, resolution, and color information.

Not all PictureFormat properties are accessible for all picture types. None of the various properties that return properties of linked files are accessible for an embedded picture. In addition, if a linked file is missing, certain properties that Publisher reads from the original file are not accessible either. Finally, certain properties are not accessible for empty picture frames, which by definition contain neither an embedded or linked picture.

Table 3. Selected PictureFormat properties and their accessibility, based on picture type

PictureFormat property Embedded Picture

(.Islinked = False)

Linked Picture

(.Islinked = True)

Linked But Missing Picture

(.LinkedFileStatus = pbLinkedFileStatusMissing)

Empty Frame

(.IsEmpty = True)

EffectiveResolution X X
HorizontalScale X X
ImageFormat X X
IsGreyScale X X
LinkedFileStatus X X X
OriginalColorsInPalette X X X
OriginalFilesSize X X X
OriginalHasAlphaChannel X X X
OriginalHeight X X X
OriginalIsTrueColor X X X
OriginalResolution X X X
OriginalWidth X X X
VerticalScale X X

The following example creates a text file that lists selected properties of each picture in the specified publication.

**Note   **For this and many of the examples in this article to execute properly, your Microsoft Visual Basic® project must contain a reference to the Microsoft Scripting Runtime object library. This library enables you to manipulate files (such as the text file this example creates and writes to) outside the Publisher object model. To add a reference to the library, in the Visual Basic Editor, select your project in the Project Explorer window. On the Tools menu, click References. Under Available References, check the Microsoft Scripting Runtime box and then click OK.

Function ReportPictureDetails(pubDocument As Document)
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream
Dim strTextFilePath As String
Dim pgloop As Page
Dim shploop As Shape

'NOTE: using the FileSystemObject requires
'a reference to the MS Scripting Runtime library

'name file and place in same file path as
'publication being checked
strTextFilePath = pubDocument.FullName & "_picture_details.txt"
'create text file
Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.CreateTextFile(strTextFilePath)


With pubDocument
    For Each pgloop In .Pages
        For Each shploop In pgloop.Shapes
            'Determine if shape is picture
            If shploop.Type = pbPicture Or _
                shploop.Type = pbLinkedPicture Then
                With shploop.PictureFormat
                    'Write picture details to file
                    objTextStream.WriteLine "Shape Name: " & shploop.Name
                    objTextStream.WriteLine "Page: " & pgloop.PageNumber
                    If .IsEmpty = msoFalse Then
                        'Write properties for embedded pictures
                        If .IsLinked = msoFalse Then
                            objTextStream.WriteLine "File name: " & .Filename
                            objTextStream.WriteLine "Effective Resolution: " & _
                                                    .EffectiveResolution & " dpi"
                            objTextStream.WriteLine "Scaling: " & _
                                .VerticalScale & _
                                "% high by " & .HorizontalScale & _
                                "% wide"
                            objTextStream.WriteLine "File size: " & .FileSize
                            objTextStream.WriteLine "Color model: " & _
                                .ColorModel
                        'Write properties for linked pictures
                        ElseIf (.IsLinked = msoTrue) And _
                            Not .LinkedFileStatus = pbLinkedFileMissing Then
                            objTextStream.WriteLine "File name: " & .Filename
                            objTextStream.WriteLine "Effective Resolution: " & _
                                                    .EffectiveResolution & " dpi"
                            objTextStream.WriteLine "Original Resolution: " & _
                                                    .OriginalResolution & " dpi"
                            objTextStream.WriteLine "Scaling: " & _
                                .VerticalScale & _
                                "% high by " & .HorizontalScale & _
                                "% wide"
                            objTextStream.WriteLine "File size: " & .FileSize
                            objTextStream.WriteLine "Original File siz: " & _
                                .OriginalFileSize
                            objTextStream.WriteLine "Color model: " & _
                                .ColorModel
                        'Write note for missing linked pictures
                        Else
                                objTextStream.WriteLine "This linked " & _
                                    "picture is missing. " & _
                                "No picture information is available."
                        End If
                    'Write note for empty picture frames
                    Else
                        objTextStream.WriteLine "This is an empty picture " & _
                            "frame. No picture information is available."
                    End If
                End With
                objTextStream.WriteBlankLines (2)
            End If
        Next
    Next
End With

'Close text stream to file
objTextStream.Close
End Function

Identifying Types of Pictures

Each shape that represents a picture (that is, shapes whose Shape.Type is pbPictures or pbLinkedPictures) has a PictureFormat object, which in turn contains an IsLinked property. This property is always True for linked pictures and False for embedded pictures or empty picture frames. For linked pictures, you can access the PictureFormat.LinkedFileStatus property, which returns whether the linked picture is missing, was modified since you inserted into the publication, or remains unchanged at its specified location.

Once you determine the status of a linked picture, you can use the Replace method to replace or update the picture, if necessary. When updating a picture that was modified, replacing the picture with itself, as in the example below, effectively updates the picture.

The following example examines each picture in the specified publication, and writes five lists to the specified text file:

  • Embedded pictures
  • Linked pictures
  • Linked pictures whose file is missing
  • Linked pictures whose file is modified
  • Empty picture frames

In addition, the procedure updates any pictures that were modified since their insertion in the publication.

Function ListPictureTypes(pubDocument As Document, strFilePath As String) As Document
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream

Dim pgloop As Page
Dim shploop As Shape
'dim arrays to hold lists of pictures
Dim strEmbeddedPics() As String
Dim strLinkedPics() As String
Dim strModifiedPics() As String
Dim strMissingPics() As String
Dim strEmptyPicFrames() As String

'dim integers to keep count of pictures
Dim intPicsEmbedded As Integer
Dim intPicsLinked As Integer
Dim intPicsModified As Integer
Dim intPicsMissing As Integer
Dim intPicFramesEmpty As Integer
Dim intCount As Integer

'initialize integers to 0 to start
intPicsEmbedded = 0
intPicsLinked = 0
intPicsModified = 0
intPicsMissing = 0
intPicFramesEmpty = 0
intCount = 0

With pubDocument
    For Each pgloop In .Pages
        For Each shploop In pgloop.Shapes
        
            'Determine which shapes are linked or embedded pictures
            If shploop.Type = pbPicture Or shploop.Type = pbLinkedPicture Then
                If shploop.PictureFormat.IsLinked = msoFalse Then
                    'Create a list of embedded pictures
                    If shploop.PictureFormat.IsEmpty = msoFalse Then
                        ReDim Preserve strEmbeddedPics(intPicsEmbedded)
                        strEmbeddedPics(intPicsEmbedded) = _
                            shploop.Name & " on page " & pgloop.PageIndex
                        intPicsEmbedded = intPicsEmbedded + 1
                    'Create a list of empty picture frames
                    ElseIf shploop.PictureFormat.IsEmpty = msoTrue Then
                        ReDim Preserve strEmptyPicFrames(intPicFramesEmpty)
                        strEmptyPicFrames(intPicFramesEmpty) = _
                            shploop.Name & " on page " & pgloop.PageIndex
                        intPicFramesEmpty = intPicFramesEmpty + 1
                    End If

                'Create a list of linked pictures
                ElseIf shploop.PictureFormat.IsLinked = msoTrue Then
                    ReDim Preserve strLinkedPics(intPicsLinked)
                    strLinkedPics(intPicsLinked) = _
                        shploop.Name & " on page " & pgloop.PageIndex
                    intPicsLinked = intPicsLinked + 1
                    'Create a list of missing linked pictures
                    If shploop.PictureFormat.LinkedFileStatus = _
                        pbLinkedFileMissing Then
                        ReDim Preserve strMissingPics(intPicsMissing)
                        strMissingPics(intPicsMissing) = _
                            shploop.Name & " on page " & pgloop.PageIndex
                        intPicsMissing = intPicsMissing + 1
                    'Create a list of modified pictures
                    'Re-insert pictures that were modified
                    ElseIf shploop.PictureFormat.LinkedFileStatus = _
                        pbLinkedFileModified Then
                        ReDim Preserve strModifiedPics(intPicsModified)
                        strModifiedPics(intPicsModified) = _
                            shploop.Name & " on page " & pgloop.PageIndex
                        intPicsModified = intPicsModified + 1
                        shploop.PictureFormat.Replace _
                            pathname:=shploop.PictureFormat.Filename
                        PubChanged = True
                    End If
                End If
            End If
        Next
    Next
End With

Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.OpenTextFile _
    (Filename:=strFilePath, IOMode:=ForAppending)

With objTextStream
    'List any embedded pictures
    If intPicsEmbedded > 0 Then
        .WriteLine "There are " & intPicsEmbedded & _
            " embedded pictures in this publication: "
        For intCount = 1 To intPicsEmbedded
            .WriteLine strEmbeddedPics(intCount - 1)
        Next
    Else
        .WriteLine "There are no embedded pictures " & _
            "in the publication."
    End If

    'List any linked pictures
    If intPicsLinked > 0 Then
        .WriteLine "There are " & intPicsLinked & _
            " linked pictures in this publication: "
        For intCount = 1 To intPicsLinked
            .WriteLine strLinkedPics(intCount - 1)
        Next
    Else
        .WriteLine "There are no linked pictures " & _
            "in this publication."
    End If
        
    'List any modified linked pictures
    'that were updated
    If intPicsModified > 0 Then
        .WriteLine "The following " & intPicsModified & _
            " pictures were updated: "
        For intCount = 1 To intPicsModified
            .WriteLine strModifiedPics(intCount - 1)
        Next
    Else
        .WriteLine "There were no modified pictures " & _
            "to update in this publication."
    End If
    
    'List any missing linked pictures
    If intPicsMissing > 0 Then
        .WriteLine "The following " & intPicsMissing & _
            " pictures are missing: "
        For intCount = 1 To intPicsMissing
            .WriteLine strMissingPics(intCount - 1)
        Next
    Else
        .WriteLine "There are no missing pictures " & _
            "in this publication."
    End If
        
    'List any empty picture frames
    If intPicFramesEmpty > 0 Then
        .WriteLine "The following " & intPicFramesEmpty & _
                " picture frames are empty: "
        For intCount = 1 To intPicFramesEmpty
            .WriteLine strEmptyPicFrames(intCount - 1)
        Next
    Else
        .WriteLine "There are no empty picture frames " & _
            "in this publication."
    End If
    
    'Close text stream to the text file
    .WriteBlankLines (2)
    .Close
End With

'Return publication
Set ListPictureTypes = pubDocument

End Function

Creating a Linked Picture from an Embedded Picture

You can easily create a linked picture from an embedded picture. Using linked pictures instead of embedded pictures not only decreases the file size of a publication but also provides a separate image file that can be edited if necessary, and then updated quickly in Publisher.

The following example creates a linked picture from an embedded one. Currently in the Publisher object model, the SaveAsPicture method applies only to the Page object, not individual shapes on a page. The function below creates a publication of the exact same dimensions as the shape passed it. It then pastes the shape onto the publication's single page, and saves the page as a .jpg file. It passes the full file path of the saved JPG file back to the calling procedure.

Note   The resulting linked picture may not be the same format or resolution as the original picture embedded in the publication. This is because Publisher converted the picture twice: once when it embedded the picture, and again when it saved the picture as a separate file. Also, you cannot save an embedded EPS picture as an EPS file.

Function CreatePictureAsFile(shpEmbeddedPicture As Shape, _
strFileName As String) As String
Dim pubDocument As Document

'Create the new publication
Set pubDocument = NewDocument
    'Set the page dimensions to equal
    'the picture dimensions
    With pubDocument.PageSetup
        .PageHeight = shpEmbeddedPicture.Height
        .PageWidth = shpEmbeddedPicture.Width
    End With

'Paste the picture into the new publication
shpEmbeddedPicture.Copy
pubDocument.Pages(1).Shapes.Paste

'Position the picture correctly
With pubDocument.Pages(1)
    With .Shapes(1)
        .Top = 0
        .Left = 0
    End With
    'Passes file path of picture back to calling procedure
    CreatePictureAsFile = strFileName & "_" & _
            shpEmbeddedPicture.Name & ".jpg"
    'Saves a picture at the specified file path
    .SaveAsPicture Filename:=CreatePictureAsFile

End With

'Closes Publisher instance without
'saving publication created
pubDocument.Application.Quit

End Function

Below is an example of a procedure that may call this function. It specifies the shape from which to create a linked picture, and the location to which to save the resulting picture file. It takes the file path returned from the function and uses it to replace the embedded picture with the newly-created linked picture.

Sub ReplaceEmbeddedPictureWithLinked()
Dim pubShape As Shape
Dim PubFileName As String
Dim PicFileName As String

'Select the embedded picture to create a linked picture from
Set pubShape = ActiveDocument.Pages(3).Shapes("Picture 5")
'Specify the file path to save picture
PubFileName = ActiveDocument.FullName
'Call function
PicFileName = CreatePictureAsFile(pubShape, PubFileName)
'Debug.Print PicFileName
'Replace embedded picture with linked picture
pubShape.PictureFormat.Replace pathname:=PicFileName, _
    insertas:=pbPictureInsertAsLinked

End Sub

Change an Inserted Picture to an Embedded Picture

Similarly, you can use the Replace method to change an inserted picture into an embedded one. In this case, you replace the linked picture with itself, but this time specify the InsertAs parameter as pbPictureInsertAsEmbedded:

Dim shpLinkedPicture As Shape
...
Set shpLinkedPicture = ActiveDocument.Pages(1).Shapes("Picture 1")
...
With shpLinkedPicture.PictureFormat
    .Replace pathname:=.Filename, insertas:=pbPictureInsertAsEmbedded
End With

Identifying Pictures That Are Not Scaled Proportionally

The following example identifies any pictures that are not scaled proportionally in the specified publication, and writes that information out to a text file. It uses the HorizontalScale and VerticalScale properties of the PictureFormat object to identify pictures that are disproportionate.

Note that the code does not return scaling information for missing pictures. As mentioned earlier, in the case of linked pictures whose original file is missing, Publisher cannot calculate scaling information, and returns an error when the HorizontalScale or VerticalScale properties are accessed.

Sub PictureNotScaledProp(pubDocument As Document, strFilePath As String)
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream

Dim pgloop As Page
Dim shploop As Shape
Dim strMessage As String

Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.OpenTextFile _
    (Filename:=strFilePath, IOMode:=ForAppending)

For Each pgloop In pubDocument.Pages
    For Each shploop In pgloop.Shapes
        If shploop.Type = pbLinkedPicture Or shploop.Type = pbPicture Then
            With shploop.PictureFormat
                If .IsEmpty = msoFalse Then
                    If .IsLinked = msoTrue Then
                        If .LinkedFileStatus = pbLinkedFileMissing Then
                            objTextStream.WriteLine shploop.Name & _
                            " on page " & pgloop.PageIndex & _
                            " is missing, so no scaling " & _
                            "information is available."
                        Else
                            If Not .HorizontalScale = .VerticalScale Then
                                objTextStream.WriteLine shploop.Name & _
                                " on page " & pgloop.PageIndex & _
                                " is not scaled proportionally."
                            End If
                        End If
                    Else
                        If Not .HorizontalScale = .VerticalScale Then
                            objTextStream.WriteLine shploop.Name & _
                            " on page " & pgloop.PageIndex & _
                            " is not scaled proportionally."
                        End If
                    End If
                End If
            End With
        End If
    Next
Next

objTextStream.WriteBlankLines (1)
objTextStream.Close

End Sub

Automating Publication Design Checks

The Publisher user interface includes the Design Checker task pane, which performs checks for potential problems in a publication. For commercial printing, there is a specific set of checks that look for just the kind of problems that may affect how a publication prints for commercial output.

The Design Checker cannot be called directly using the object model; however, much like with the Graphics Manager, you can write procedures that perform design checks programmatically. And again, you can take these design checks even further by customizing and extending them so they work best with your prepress work process.

The Design Checker offers the following commercial printing checks:

  • Publication contains more than two spot colors.
  • There are unused spot colors in the publication.
  • Publication is in RGB color mode.
  • Object is not visible.
  • Object has no line or fill, or text box is empty.
  • Object has transparency.
  • Page has space below top margin.
  • Picture is low resolution.
  • Picture is missing.
  • Picture was modified since it was inserted.
  • Picture is not scaled proportionally.
  • Story has text in the overflow area.
  • Story is on the scratch area.

As you can see, the Design Checker performs some of the same picture file checks on a publication-wide level that the Graphics Manager performs for the individual pictures. We already showed several code samples that check for picture problems, such as missing pictures or empty picture frames, in the Managing Graphics section of this article.

Publication Color Mode and Spot Colors

You can use the Document.ColorMode property to get or set the color mode of a publication to desktop (or RGB), single spot color, spot color, process color (or CMYK), or spot and process. For the spot and spot and process color modes, each spot color ink in a publication is represented by a Plate object contained in the Plates collection. For more information about color modes, Plate objects and how they relate to Printable Plate objects (which represent the inks that actually print for the publication), see the first article in this series, Automating Commercial Printing Prepress Tasks in Publisher 2003, Part 1.

Determine If the Publication Color Mode Is RGB (Desktop)

The following example determines if the publication's color mode is set to RGB, and if it is, writes a warning to that affect out to the specified text file.

Sub CheckColorMode(pubDocument As Document, strFilePath As String)
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream

Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.OpenTextFile _
    (Filename:=strFilePath, IOMode:=ForAppending)

If pubDocument.ColorMode = pbColorModeDesktop Then
    objTextStream.WriteLine "Publication color mode is RGB."
End If

objTextStream.WriteBlankLines (1)
objTextStream.Close

End Sub

Determine If There Are More Than Two Spot Colors in a Publication

The following example determines the publication's color mode, and if the color mode is spot or spot and process, determines the number of spot colors present in the publication. If more than two spot colors are present, the code writes a notice to this effect to the specified text file.

Note that for the spot and process color mode, the first four Plate objects in the Plates collection always represent the C, M, Y, and K inks.

Sub NumberOfSpotColors(pubDocument As Document, strFilePath As String)
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream

'Set objFileSystem = CreateObject("Scripting.FileSystemObject")
Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.OpenTextFile _
    (Filename:=strFilePath, IOMode:=ForAppending)

With pubDocument
    If .ColorMode = pbColorModeSpot Then
        'Each plate is a spot color ink
        If .Plates.Count > 2 Then
            objTextStream.WriteLine "There are more than two " & _
                "spot colors defined for this publication."
        End If
    ElseIf .ColorMode = pbColorModeSpotAndProcess Then
        'In process and spot mode
        'CMYK plates are the first four plates
        If .Plates.Count > 6 Then
            objTextStream.WriteLine "There are more than two " & _
                "spot colors defined for this publication."
        End If
    Else
        objTextStream.WriteLine "There are two " & _
            "or fewer spot colors in this publication."
    End If
End With
    
objTextStream.WriteBlankLines (1)
objTextStream.Close
    
End Sub

Determine If There Are Unused Spot Colors in a Publication

The following procedure determines if any unused spot color inks were defined for the publication. It does this by querying the InUse property of each Plate object that represents a spot color ink.

Sub CheckForUnusedSpotColors(pubDocument As Document, _
strFilePath As String)
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream
Dim plLoop As Plate
Dim intCount As Integer

Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.OpenTextFile _
    (Filename:=strFilePath, IOMode:=ForAppending)

'for spot color, check to see if any plates.inuse = false
'for spot and process, check plates
'from 5 to .count for .inuse = false
With pubDocument
    If .ColorMode = pbColorModeSpot Then
        For Each plLoop In .Plates
            If plLoop.InUse = False Then
                objTextStream.WriteLine plLoop.Name & _
                    " (" & _
                    plLoop.InkName & _
                    ") represents a spot color " & _
                        "not used in the publication."
            End If
        Next
    ElseIf .ColorMode = pbColorModeSpotAndProcess Then
        With .Plates
            If .Count > 4 Then
                For intCount = 5 To .Count
                    If Plates.Item(intCount).InUse = False Then
                            objTextStream.WriteLine _
                                Plates(intCount).Name & _
                                " (" & _
                                Plates(intCount).InkName & _
                                ") represents a spot color " & _
                                "not used in the publication."
                    End If
                Next
            End If
         End With
    ElseIf .ColorMode = pbColorModeBW Or _
        .ColorMode = pbColorModeDesktop Or _
        .ColorMode = pbColorModeProcess Then
        objTextStream.WriteLine _
            "This publication is not set up for spot colors."
    End If
End With
objTextStream.WriteBlankLines (1)
objTextStream.Close

End Sub

Working With Stories and Text Boxes

Each story in a publication consists of one or more text boxes that appear in the publication. Longer stories may extend through several text boxes. If the last text box for a story is not large enough to contain the remaining text in a story, the text is stored in an overflow area that does not appear in the publication, and so does not print.

Each text box in a publication is represented by a Shape object whose Type is pbTextFrame, and contains a TextFrame child object. You can use the HasText property of the TextFrame to determine if the text box contains text or is empty, and the Overflowing property to determine if there is additional text stored in the overflow area.

Determine If a Text Box Is Empty or Overflowing With Text

The following example determines whether each shape in the publication has text, and if so, if that text is overflowing. Also, it identifies each text box in the publication, and determines whether the text box is empty.

Sub TextBoxEmptyOrShapeTextOverflowing _
    (pubDocument As Document, strFilePath As String)
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream

Dim pgloop As Page
Dim shploop As Shape
Dim strMessage As String

'open text stream to existing file
Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.OpenTextFile _
    (Filename:=strFilePath, IOMode:=ForAppending)

For Each pgloop In pubDocument.Pages
    For Each shploop In pgloop.Shapes
        'Determine if any shape has oveflowing text
        If shploop.HasTextFrame = msoTrue Then
            If shploop.TextFrame.HasText = msoTrue Then
                If shploop.TextFrame.Overflowing = msoTrue Then
                    objTextStream.Write shploop.Name & _
                        " on page " & pgloop.PageNumber & _
                        " has text in the overflow area."
                End If
            End If
        End If
                
        'Determine if any textboxes are empty
        If shploop.Type = pbTextFrame Then
            If shploop.TextFrame.HasText = msoFalse Then
                objTextStream.WriteLine shploop.Name & _
                    " on page " & pgloop.PageNumber & _
                    " is an empty text box."
            
            End If
        End If
    Next
Next

'Close text stream to text file
objTextStream.WriteBlankLines (1)
objTextStream.Close

End Sub

Automating Other Custom Design Checks

When using the object model to create customized prepress procedures, you certainly aren't limited to the graphics and design checks offered through the Publisher user interface. You can check, and, in many cases, specify, any of the publication, page, and shape properties exposed through the object model. Below we discuss several other design checks you may want to incorporate programmatically into your preflight process.

Identify BorderArt

BorderArt is picture borders that you can apply to text boxes, picture frames, or rectangles. While a popular customer feature, BorderArt may appear pixilated when commercial printed due to limitations of the Windows graphics engine. Because of this, you may want to identify any BorderArt that appears in a publication, to give the customer the option to leave it as is, change it to a line border, or remove it altogether.

Each Shape object to which you apply BorderArt has a BorderArt object which contains the properties of the border. You can use the Exists property of the BorderArt object to determine if BorderArt was applied to a shape, and the Delete method to remove the border.

Identify WordArt In Previous Publisher Versions

WordArt is text to which special text effects were applied. The way in which the new version of Publisher renders WordArt has changed from earlier versions. When you open a publication saved in an earlier version of Publisher in Publisher 2003, Publisher converts any WordArt in the publication to the new method of rendering. In some cases, the WordArt appearance or dimensions may change slightly. Because of this, if you open a publication saved as an earlier version of Publisher, you may want to identify WordArt shapes to double-check their size and appearance.

WordArt is represented by a Shape object whose Type property is pbTextEffect.

The example below determines if the Publisher file was saved in an earlier version of Publisher. If it was, the code generates a list of any WordArt present in the publication.

If pubDocument.SaveFormat = pbFilePublisher2000 _
    Or pbFilePublisher98 Then
    For Each pgloop In pubDocument.Pages
        For Each shploop In pgloop.Shapes
            If shploop.Type = pbTextEffect Then
                objTextStream.Write shploop.Name & _
                        " on page " & pgloop.PageNumber & _
                        " is a WordArt shape."
            End If
        Next
    Next
End If

There is a Publisher add-in that prevents WordArt in older Publisher files from updating to the new method of rendering when opened in Microsoft Publisher 2002, Service Pack 2 (SP2) or Microsoft Office Publisher 2003. For more information, see Publisher 2000 Add-In: WordArt Compatibility.

Fixing Picture and Design Problems

Not only can you use the object model to identify and analyze preflight issues with publications, you can also automatically fix these problems as well. Most issues with pictures and publication design elements affect the appearance of the publication, and therefore require human judgment and decision-making. For example, if you delete empty text boxes or picture frames from a publication automatically, this may affect the text flow or pagination of the publication. However, you can programmatically automate your preferred substitutions, and get a head start on resolving these issues.

Also, take care whenever you make changes to a customer's file. In most cases, it's best to create a copy of the publication to change and leave the original file unaltered. This also provides you with comprehensive before and after versions to present to clients for approval.

For example, the following function determines whether the picture passed to it is scaled proportionally. If it is not, the code resizes the picture to the current vertical or horizontal scale, depending on which is smaller. Then, the function passes the resized, proportionally-scaled picture object back to the calling procedure. The calling procedure could then use the Document.SaveAs method to save a copy of the current publication. Note that the LockAspectRatio property of the Shape object must be set to False before rescaling the picture. This property is then reset to its original value once the operation is complete.

Function ResizeDistortedPictures(shpPicture As Shape) As Shape
Dim intLockAspect As Integer

intLockAspect = shpPicture.LockAspectRatio
shpPicture.LockAspectRatio = msoFalse

With shpPicture.PictureFormat
    If Not .HorizontalScale = .VerticalScale Then
        If .HorizontalScale > .VerticalScale Then
            shpPicture.Width = shpPicture.Width * _
                (.VerticalScale / .HorizontalScale)
        Else
            shpPicture.Height = shpPicture.Height * _
                (.HorizontalScale / .VerticalScale)
        End If
    End If
End With

shpPicture.LockAspectRatio = intLockAspect
Set ResizeDistortedPictures = shpPicture

End Function

Putting It All Together

Now let's combine some of the previous examples together into a real-world project we can use to automate prepress checks on Publisher files. We complete several of the preflight checks we discussed and create a project that runs the checks on each Publisher file in a specified folder. The results of the checks are written out to a separate text file for each Publisher file analyzed. In addition, we want to get ahead on fixing the issues found. One of the automated preflight checks makes changes to the Publisher file if it contains linked pictures to update. In this case, Publisher saves the updated file as a copy, leaving the original Publisher file unaltered.

First, to navigate folders and manipulate files outside the Publisher object model, we need to employ the Microsoft Scripting Runtime object library. To use this library, we must add a reference to the library into our Visual Basic for Application project. In the Visual Basic Editor, select the project in the Project Explorer window, and from the Tools menu click References. Under Available References, check the box for Microsoft Scripting Runtime and then click OK.

With a reference to the Microsoft Scripting Runtime object library, we can write the top-level procedure of our project. This procedure uses the built-in Visual Basic method InputBox, which creates a dialog box and prompts the user to enter the desired folder path, and then returns their input as a string. The procedure then loops through the files in the specified folder. For each file with a .pub file extension, the procedure passes a string representing the file location to the RunCustomDesignChecks procedure, which in turn actually calls the prepress checks we want to perform.

Figure 1. Dialog box generated by the InputBox method

Note that a limitation of the InputBox method is that you cannot validate user input until after the method runs and returns the string. Therefore, if the user adds a non-existent folder location, or no text at all, Publisher generates an error.

Sub RunChecksOnAllPubsInFolder()
Dim objFileSystem As FileSystemObject
Dim strFolderPath As String
Dim objLoop As File
'NOTE: using the FileSystemObject requires
'a reference to the MS Scripting Runtime library

'Display dialog box to get folder path
'of publications from user
strFolderPath = InputBox _
    (Prompt:="Enter the folder location in the text box below" & _
        vbLf & "and click OK.", _
    Title:="Folder Location")

'create the file system object
Set objFileSystem = New Scripting.FileSystemObject

For Each objLoop In objFileSystem.GetFolder(strFolderPath).Files
    If UCase(objFileSystem.GetExtensionName(objLoop.Path)) = "PUB" Then
        RunCustomDesignChecks (objLoop.Path)
    End If
    
Next
MsgBox Prompt:="All Publisher files were checked.", _
    Title:="Custom Preflight Checks"
End Sub

Next, we can write a procedure to accomplish three things:

  • Create the text file that each of the preflight check procedure write to.
  • Call the preflight checks to be run on each Publisher file.
  • Save any changed Publisher files as copies, thereby leaving the original files unchanged.

Publisher passes the path to the file as a string from the calling procedure; in this case, RunChecksOnAllPubsInFolder. With this string, the procedure uses the FileSystemObject (from the Microsoft Scripting Runtime library) to create a text file in the same folder as the Publisher file, and writes a few comments to the text file. It also uses the string to find and open the specified Publisher file. It then passes the Document object representing the open Publisher file, along with the string representing the path to the associated text file, to several of the procedures from earlier in this article. Each procedure runs on the Document object passed it, and writes the results out to the associated text file.

In this example, the only code making changes to the Publisher file is the ListPictureTypes function. Besides listing picture types present in the publication, this function also updates any modified linked pictures in the publication, and returns a Document object that represents the possibly-edited version of the original Publisher file. The ListPictureTypes function also sets a module-level Boolean variable, PubChanged, to True if any modified pictures are updated. The RunCustomDesignChecks procedure then uses the value of that variable to determine whether to save the returned Document object as a copy of the original file. If the procedure included more than one function that may make changes to the original Publisher file, you want to set the pubDocument variable equal to the Document object returned by each function, and wait until all those functions had run before saving the file copy. This ensures that all the changes made to the original Publisher document by the various functions are retained in the file copy.

Sub RunCustomDesignChecks(strFilePath As String)
Dim objFileSystem As FileSystemObject
Dim objTextStream As TextStream
Dim pubDocument As Document
Dim strTextFilePath As String
'NOTE: using the FileSystemObject requires
'a reference to the MS Scripting Runtime library

Set pubDocument = Application.Open(strFilePath)
'name file and place in same file path as
'publication being checked
strFilePath = strFilePath & "_prepress.txt"

'create text file
Set objFileSystem = New Scripting.FileSystemObject
Set objTextStream = objFileSystem.CreateTextFile(strFilePath)
'set up text file
With objTextStream
    .WriteLine "Prepress checks for: " & pubDocument.FullName
    .WriteBlankLines (2)
    .Close
End With

'Make sure PubChanged is False to start
PubChanged = False
'run prepress procedures
CheckColorMode pubDocument, strFilePath
NumberOfSpotColors pubDocument, strFilePath
CheckForUnusedSpotColors pubDocument, strFilePath
Set pubDocument = ListPictureTypes(pubDocument, strFilePath)
'Save a copy of the publication
'if changes were made to it
If PubChanged = True Then
    pubDocument.SaveAs Filename:=pubDocument.FullName & "_edited.pub"
End If
PictureNotScaledProp pubDocument, strFilePath
TextBoxEmptyOrOverflowing pubDocument, strFilePath
IdentifyWordArt pubDocument, strFilePath

'Close Pub application instance
'without saving any changes to original publication
pubDocument.Application.Quit

End Sub

Object Model Hierarchies

Below are diagrams of the sections of the Publisher object model that involve page setup and picture format functionality.

Click here to see larger image

Figure2. Page Setup Object Model Hierarchy (Click picture to see larger image)

Click here to see larger image

Figure 3. Part 1 of the PictureFormat Object Model Hierarchy (Click picture to see larger image)

Click here to see larger image

Figure 4. Part 2 of the PictureFormat Object Model Hierarchy (Click picture to see larger image)

Conclusion

Using the example above as a starting point, you can create any number of projects to perform specialized prepress operations. Perhaps you want one set of operations for spot color publications, and another for process publications, and a third for spot and process color publications. Or perhaps certain clients have certain needs for their publications. By automating and customizing prepress operations with the Publisher object model, you can guarantee that Publisher performs all the appropriate procedures on each file, and performs in exactly the same way, thereby speeding up your prepress operations and ensuring uniform results.

For more in this series, see the following articles: