Created Date: 05 Oct, 2021 11:04
Last Modified Date: 06 Feb, 2024 10:27


The basics

Every page in a PDF defines a rectangle that defines a media box (the overall size of the media, such as an 8½" x 11" sheet of paper). Although optional, most PDFs also define a crop box, which defines the viewable area of the page. A crop box cannot not be larger than the media box, or more accurately, may not extend outside the media box. For the majority of PDFs, the media size and the crop box have the same dimensions, and are assumed to be should the crop box be left undefined.

PDF 1.3 introduced three further boxes to support print workflows. They are the trim box, bleed box, and art box. As with the crop box, they cannot extend outside the media box. Their purposes:

  • Trim box – specifies the trimmed size of the final printed product, often a specific page size such as A5 or US Letter
  • Bleed box – extends the edge of the page by a small amount so that images or areas of color can print right to the edge of the trimmed area. It is typically 3mm larger than the trimmed size in all dimensions
  • Art box – For a page that contains artwork as well as other information, the art box defines the area of the page that comprises the artwork. It is intended to speed up placing PDF content on to a layout in a program such as Adobe InDesign

The following diagram shows a practical application of the different page dimensions:

The two most important sets of dimensions are the MediaBox and the CropBox.

Page boxes in Mako

As stated above, the various dimensions are properties of a page. Thus, they can be obtained from an IPage object:

auto mako = IJawsMako::create();
IJawsMako::enableAllFeatures(mako);

// Open the PDF
auto assembly = IPDFInput::create(mako)->open(L"..\\..\\TestFiles\\EdgeTestA5.pdf");

// Get the first page
auto page = assembly->getDocument()->getPage(0);

// Get all the boxes
FBox mediaFBox = page->getMediaBox();
FRect mediaBox = page->getMediaBox().asRect();
FRect cropBox = page->getCropBox();
FRect bleedBox = page->getBleedBox();
FRect trimBox = page->getTrimBox();
FRect artBox = page->getContentBox();
CPP

IPage::getWidth() and IPage::getHeight() also return the dimensions of the media box, in Mako native units (1/96th in). These APIs are slightly quicker than IPage::getMediaBox().

FRect and FBox

FRect and FBox are structs that express dimensions, but they are defined in different ways.

An FRect defines a top left origin (X, Y), a horizontal, left-to-right dimension (dX) and a vertical, top-to-bottom dimension (dY).

From the example above, the width of the crop box (in 1/96th inch) is given by:

double cropWidth = cropBox.dX;
CPP

An FBox, on the other hand, defines values for left (left), bottom (bottom), top (top), right (right). The origin in this case is bottom left, so the top value increases from bottom to top, and the right value increases from left to right.

From the example above, the width of the media (in 1/72nd inch) is given by:

double mediaWidth = mediaFBox.right - mediaFBox.left
CPP

The distinction between these two definitions is relevant because both have their purposes.

Mako APIs

A typical PDF consisting of a single A5 portrait page reports these dimensions, all in millimeters:

FBox  ------------- Dimensions -------------
          Left       Top      Right   Bottom
Media    0.000   210.000   148.000     0.000

FRect ----- Origin -----  --- Dimensions ---
             X         Y     Width    Height
Media    0.000     0.000   148.000   210.000
Crop     0.000     0.000   148.000   210.000
Bleed    0.000     0.000   148.000   210.000
Trim     0.000     0.000   148.000   210.000
Art      0.000     0.000   148.000   210.000

The code to produce the table above can be found at the end of this page.

The following code was then used to modify the media size, specifically to expand it by 25mm in every direction:

#define MM2PDFUNITS(value) ((value) / 25.4 * 72.0)

// Modify size
mediaFBox.left -= MM2PDFUNITS(25);
mediaFBox.top += MM2PDFUNITS(25);
mediaFBox.right += MM2PDFUNITS(25);
mediaFBox.bottom -= MM2PDFUNITS(25);
page->setMediaBox(mediaFBox);
CPP

These images represent the page before and after the change. In the second image we can see a wide margin around the content, which is centered, as all the dimensions were altered by the same amount. Note that to increase the left and bottom margin, a negative value is required.

The media size can be obtained from the page both as an FBox (the default) or an FRect (by appending .asRect()). Both methods return their values in PDF units (1/72nd inch).

However, only an FBox can be used to set the media box values, so it is more convenient to use an FBox to begin with.

Here we compare the box dimensions, before and after:

Numeric results of expanding

Before
FBox  ------------- Dimensions -------------
          Left       Top      Right   Bottom
Media    0.000   210.000   148.000     0.000

FRect ----- Origin -----  --- Dimensions ---
             X         Y      Width   Height
Media    0.000     0.000   148.000   210.000
Crop     0.000     0.000   148.000   210.000
Bleed    0.000     0.000   148.000   210.000
Trim     0.000     0.000   148.000   210.000
Art      0.000     0.000   148.000   210.000
After
FBox  ------------- Dimensions -------------
          Left       Top      Right   Bottom
Media  -25.000   235.000   173.000   -25.000

FRect ----- Origin -----  --- Dimensions ---
             X         Y      Width   Height
Media  -25.000   -25.000   198.000   260.000
Crop    25.000    25.000   148.000   210.000
Bleed   25.000    25.000   148.000   210.000
Trim    25.000    25.000   148.000   210.000
Art     25.000    25.000   148.000   210.000
  • The crop, bleed, trim, and art boxes have a new origin (their top-left corner is now 25mm in and 25mm down on the page) but their size is unaltered.
  • If you want the dimensions of these boxes to match those of the MediaBox, either explicitly set them, or remove them so that they inherit the MediaBox size. See 'Inheritance' below for more information.

Setting the media box

Setting the media box requires passing an FBox, with PDF units, as in the above example.

In that example, the result means the origin of the MediaBox is no longer 0,0. If you wish to reset it, include this code when writing the PDF:

const auto pdfOutput = IPDFOutput::create(mako);
...
pdfOutput->setForceMediaBoxOriginZero(true);
CPP

This will adjust the mediabox so that its origin is 0,0

Scaling the media box

A convenience method to scale the media box is provided. For example, to scale an A5 media box to A4 (or to A4 to A3, etc.) simply apply a scale of 141.42%:

// Scale media box
mediaFBox.scale(1.4142);
page->setMediaBox(mediaFBox);
CPP

Numeric results of scaling

Before

FBox  ------------- Dimensions -------------
          Left       Top      Right   Bottom
Media    0.000   210.000   148.000     0.000

FRect ----- Origin -----  --- Dimensions ---
             X         Y      Width   Height
Media    0.000     0.000   148.000   210.000
Crop     0.000     0.000   148.000   210.000
Bleed    0.000     0.000   148.000   210.000
Trim     0.000     0.000   148.000   210.000
Art      0.000     0.000   148.000   210.000

After

FBox  ------------- Dimensions -------------
          Left       Top      Right   Bottom
Media    0.000   296.985   209.304     0.000

FRect ----- Origin -----  --- Dimensions ---
             X         Y      Width   Height
Media    0.000     0.000   209.304   296.985
Crop     0.000    86.985   148.000   210.000
Bleed    0.000    86.985   148.000   210.000
Trim     0.000    86.985   148.000   210.000
Art      0.000    86.985   148.000   210.000
  • Page content does not scale with the media box, and remains at the same size and in the same position, relative to the bottom-left corner of the page.
  • Scaling the media box with a value below 100% may result in page boxes acquiring negative origin values to compensate for their dimensions exceeding the size of the media box. This is expected and not invalid.
  • Saving to PDF/X-4 will "normalize" the page boxes, adjusting them to the same size or smaller than the MediaBox, as this is a requirement of the PDF/X-4 standard.

Appearance in Acrobat and other PDF viewers

Increasing the media size does not by itself change how the document is presented in Acrobat or other PDF viewer, since the crop box controls the apparent page size. Nor does it scale page content, as noted earlier.

Decreasing the media size may change how the document is presented in a viewer if one or both MediaBox dimensions are less than those of the original crop box, in which case the new dimensions take priority.

Scaling of content

If scaling the page and its content is required, it is necessary to obtain an IDOMFixedPage from an IPage first, and operate on that.

A code sample showing how this is done is available in the Mako SDK. Look in the simpleexamples folder for imposition.cpp. This shows a worked example of copying page content and scaling as needed (in this case for the purposes of creating a booklet imposition).

Removing page boxes

If you need to remove page box definitions from a PDF, simply set the pagebox with an empty FRect(). When Mako comes to write the PDF, if the box is not set, it will not be written. For example, code such as this will remove all the page boxes:

// Remove the page boxes
for (uint32 pageIndex = 0; pageIndex < document->getNumPages(); pageIndex++)
{
    // Get page from the document
    const IPagePtr page = document->getPage(pageIndex);

    // Get fixed page from IPage
    const IDOMFixedPagePtr fixedPage = page->edit();

    // Clear the page boxes
    fixedPage->setCropBox(FRect());
    fixedPage->setBleedBox(FRect());
    fixedPage->setTrimBox(FRect());
    fixedPage->setContentBox(FRect());
}
CPP

Inheritance of MediaBox values

When you remove page boxes in the manner described above, PDF consumers assume their value to be the same as the MediaBox. This can be useful, as leaving the other page boxes unaltered after changing the MediaBox may lead to incorrect results when displaying or printing.

If you prefer, you can explicitly set these boxes, using code such as this:

#define MM2PDFUNITS(value) ((value) / 25.4 * 72.0)

// Resize all page boxes
for (uint32 pageIndex = 0; pageIndex < document->getNumPages(); pageIndex++)
{
    // Get page from the document
    const IPagePtr page = document->getPage(pageIndex);
    FBox mediaFBox = page->getMediaBox();

    // Modify size
    mediaFBox.left -= MM2PDFUNITS(25);
    mediaFBox.top += MM2PDFUNITS(25);
    mediaFBox.right += MM2PDFUNITS(25);
    mediaFBox.bottom -= MM2PDFUNITS(25);

	page->setMediaBox(mediaFBox);

    // Update the other page boxes to match
    page->edit()->setCropBox(FRect(0.0, 0.0, page->getWidth(), page->getHeight()));
    page->edit()->setBleedBox(FRect(0.0, 0.0, page->getWidth(), page->getHeight())); 
    page->edit()->setTrimBox(FRect(0.0, 0.0, page->getWidth(), page->getHeight())); 
    page->edit()->setContentBox(FRect(0.0, 0.0, page->getWidth(), page->getHeight())); 
}
CPP



Code used to display page box dimensions

#define PDFUNITS2MM(value) ((value) / 72.0 * 25.4)
#define XPSUNITS2MM(value) ((value) / 96.0 * 25.4)

void reportPageDimensions(FRect mediaBox, FRect cropBox, FRect bleedBox, FRect trimBox, FRect artBox)
{
    printf("FRect ----- Origin -----  --- Dimensions ---\n");
    printf("             X         Y     Height    Width\n");
    printf("Media %8.3f  %8.3f  %8.3f  %8.3f\n", PDFUNITS2MM(mediaBox.x), PDFUNITS2MM(mediaBox.y),
           PDFUNITS2MM(mediaBox.dX), PDFUNITS2MM(mediaBox.dY));
    printf("Crop  %8.3f  %8.3f  %8.3f  %8.3f\n", XPSUNITS2MM(cropBox.x), XPSUNITS2MM(cropBox.y),
           XPSUNITS2MM(cropBox.dX), XPSUNITS2MM(cropBox.dY));
    printf("Bleed %8.3f  %8.3f  %8.3f  %8.3f\n", XPSUNITS2MM(bleedBox.x), XPSUNITS2MM(bleedBox.y),
           XPSUNITS2MM(bleedBox.dX), XPSUNITS2MM(bleedBox.dY));
    printf("Trim  %8.3f  %8.3f  %8.3f  %8.3f\n", XPSUNITS2MM(trimBox.x), XPSUNITS2MM(trimBox.y),
           XPSUNITS2MM(trimBox.dX), XPSUNITS2MM(trimBox.dY));
    printf("Art   %8.3f  %8.3f  %8.3f  %8.3f\n\n", XPSUNITS2MM(artBox.x), XPSUNITS2MM(artBox.y),
           XPSUNITS2MM(artBox.dX), XPSUNITS2MM(artBox.dY));
}

void reportMediaBoxDimensions(FBox mediaBox)
{
    printf("FBox  ------------- Dimensions -------------\n");
    printf("          Left       Top      Right   Bottom\n");
    printf("Media %8.3f  %8.3f  %8.3f  %8.3f\n\n", PDFUNITS2MM(mediaBox.left), PDFUNITS2MM(mediaBox.top),
           PDFUNITS2MM(mediaBox.right), PDFUNITS2MM(mediaBox.bottom));
}
CPP