Zend Framework

Cannot reliably draw on loaded documents containing rotated pages

Details

  • Type: Bug Bug
  • Status: Postponed Postponed
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: 0.1.3
  • Fix Version/s: None
  • Component/s: Zend_Pdf
  • Labels:
    None
  • Fix Version Priority:
    Should Have

Description

If an existing PDF document is loaded which contains a page that is rotated, drawing pretty much doesn't work as the end-user would expect. The original report:

drawText renders text rotated 90 degrees counter-clockwise when using a 5.5(w) x 8.5(h) in. document. You can see an example of this at http://dfinc.net/pdf/nstv.pdf .

The problem Aaron is experiencing is that the page he's trying to draw to has been rotated 270 degrees and cropped in the page dictionary:

10 0 obj<</Contents[17 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R]
/Type/Page/Parent 4 0 R/Rotate 270/MediaBox[0 0 612 792]
/CropBox[0.0 396.0 612.0 792.0]/Resources 11 0 R>>
endobj

Zend_Pdf currently does not handle page rotation, so doesn't do anything special with the rotation entry in the page's dictionary.

The issue is that even though the page is "rotated", it is only rotated at display time; the page's coordinate system is unchanged. This is why the $line_1 y coordinate in the example below must be at just over 9 inches to appear on the page.

The illustration zf33illustration.png attached to this issue shows the actual drawing coordinate system for this page:

As a workaround, the user can rotate the drawing coordinate system with page->rotate($x, $y, $degrees) and then adjust the $x and $y coordinates appropriately, but this is a pain.

I'm not sure what we should actually do here. It would be convenient for the end-user if we 'automagically' rotated and translated the coordinate system if a rotated page is loaded, but there may be cases where such behavior is not desired.

  1. 6890.pdf
    20/Jun/06 11:03 AM
    15 kB
    Aaron Edmonds
  2. nstv.pdf
    19/Jun/06 11:00 PM
    16 kB
    Aaron Edmonds
  3. reduction1.pdf
    20/Jun/06 10:34 AM
    0.8 kB
    Willie Alberty
  1. zf33illustration.png
    35 kB
    20/Jun/06 12:11 PM

Issue Links

Activity

Hide
Aaron Edmonds added a comment -

This is the example of the issue. All that was used to generate this is the $page->drawText method.

Show
Aaron Edmonds added a comment - This is the example of the issue. All that was used to generate this is the $page->drawText method.
Hide
Willie Alberty added a comment -

This isn't a problem with drawing the text. The following example works as expected (result attached as reduction1.pdf):

$pdf = new Zend_Pdf();

// 5.5x8.5in document. the extra colon needed in the page definition appears to be a bug...
$pdf->pages[] = ($page = $pdf->newPage('396:612:'));

$page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES), 18);
$page->drawText('This is a test', 72, 300);

$pdf->save('/path/to/reduction1.pdf');

The problem is not that the PDF document uses a custom size, it's that the page that is being drawn to is rotated:

10 0 obj 
<</Contents [17 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 27 0 R ] /Type /Page /Parent 4 0 R /Rotate 270 /MediaBox [0 0 612 792 ] 
/CropBox [0 396 612 792 ] /Resources 11 0 R >>
endobj

The text appears to be drawing on the page in its original (non-rotated) orientation. Looking to see what needs to be fixed...

In the interim, can you post the actual code you're using to generate this document (as with the sample above)?

Show
Willie Alberty added a comment - This isn't a problem with drawing the text. The following example works as expected (result attached as reduction1.pdf):
$pdf = new Zend_Pdf();

// 5.5x8.5in document. the extra colon needed in the page definition appears to be a bug...
$pdf->pages[] = ($page = $pdf->newPage('396:612:'));

$page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES), 18);
$page->drawText('This is a test', 72, 300);

$pdf->save('/path/to/reduction1.pdf');
The problem is not that the PDF document uses a custom size, it's that the page that is being drawn to is rotated:
10 0 obj 
<</Contents [17 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 27 0 R ] /Type /Page /Parent 4 0 R /Rotate 270 /MediaBox [0 0 612 792 ] 
/CropBox [0 396 612 792 ] /Resources 11 0 R >>
endobj
The text appears to be drawing on the page in its original (non-rotated) orientation. Looking to see what needs to be fixed... In the interim, can you post the actual code you're using to generate this document (as with the sample above)?
Hide
Aaron Edmonds added a comment -

Here is the code that is used to generate the pdf. This is extracted from a method in a controller for a MCV app. The view just sets the content type and echoes $data.

$data = $this->Sale->read();
		
		$pdf = Zend_Pdf::load(ROOT.DS.'pdfs'.DS.'6890.pdf');
		
		$page = $pdf->pages[0];
		$page->setFont(new Zend_Pdf_Font_Standard(Zend_Pdf_Const::FONT_HELVETICA), 12);
		$margin_left = 50;
		
		// Line #1
		$line_1 = 650;
		// Plate Number
		$page->drawText($data['Inventory']['license_number'], $margin_left + 5, $line_1);
		
		$this->set('data', $pdf->render());
Show
Aaron Edmonds added a comment - Here is the code that is used to generate the pdf. This is extracted from a method in a controller for a MCV app. The view just sets the content type and echoes $data.
$data = $this->Sale->read();
		
		$pdf = Zend_Pdf::load(ROOT.DS.'pdfs'.DS.'6890.pdf');
		
		$page = $pdf->pages[0];
		$page->setFont(new Zend_Pdf_Font_Standard(Zend_Pdf_Const::FONT_HELVETICA), 12);
		$margin_left = 50;
		
		// Line #1
		$line_1 = 650;
		// Plate Number
		$page->drawText($data['Inventory']['license_number'], $margin_left + 5, $line_1);
		
		$this->set('data', $pdf->render());
Hide
Aaron Edmonds added a comment -

Actually I forgot a line of code. The pdf that is imported is two pages so I use

unset($pdf->page[1]);
to take off the extra page. Not sure if that helps but I thought I'd put it in there.

Show
Aaron Edmonds added a comment - Actually I forgot a line of code. The pdf that is imported is two pages so I use
unset($pdf->page[1]);
to take off the extra page. Not sure if that helps but I thought I'd put it in there.
Hide
Aaron Edmonds added a comment -

This is the source template that is used in my code.

Show
Aaron Edmonds added a comment - This is the source template that is used in my code.
Hide
Willie Alberty added a comment -

Thanks for the code. I'm trying to reproduce your issue here, but Zend_Pdf is throwing an exception when trying to read the nstv.pdf file. (That's another bug.) Can you attach the original 6890.pdf file?

Show
Willie Alberty added a comment - Thanks for the code. I'm trying to reproduce your issue here, but Zend_Pdf is throwing an exception when trying to read the nstv.pdf file. (That's another bug.) Can you attach the original 6890.pdf file?
Hide
Willie Alberty added a comment -

LOL - you beat me to the punch. Taking a look now...

Show
Willie Alberty added a comment - LOL - you beat me to the punch. Taking a look now...
Hide
Willie Alberty added a comment -

Attached illustration showing the actual drawing coordinate system

Show
Willie Alberty added a comment - Attached illustration showing the actual drawing coordinate system
Hide
Willie Alberty added a comment -

Changed title of issue and revised description to reflect root of problem. We'll need to hash out a solution here--it's not going to be a trivial change.

Show
Willie Alberty added a comment - Changed title of issue and revised description to reflect root of problem. We'll need to hash out a solution here--it's not going to be a trivial change.
Hide
Aaron Edmonds added a comment -

Can you give an example of how you could use $page->rotate($x, $y, $degrees) to fix the text?

Show
Aaron Edmonds added a comment - Can you give an example of how you could use $page->rotate($x, $y, $degrees) to fix the text?
Hide
Willie Alberty added a comment -

You need to do two things:

First, you need to rotate the coordinate system. $x and $y specify the rotation point. Positive numbers for $degrees rotate counter-clockwise; negative numbers rotate clockwise. I find it easiest to rotate about the origin (imagine rotating the a sheet of paper with the lower-left corner pinned). So you'd need something like this: $page->rotate(0, 0, deg2rad(-90));

Then, you need to adjust the $x and $y coordinates for your drawing commands. Right now, you'll have to do this manually. (In addition to $page->rotate(), we really need $page->translate() so it becomes automatic. See ZF-64.) If you rotated about the origin, you probably only need an offset for your $x coordinates: $xOffset = -792

Note that the rotation origin and the specific offsets you use will be entirely dependent on the page you're working with. For your specific example, the page was rotated 270 degrees clockwise and the bottom half was cropped. Other documents will be different. Trial-and-error and a little bit of sleuthing inside the PDF file itself will help you find the right values to use.

Here's a full example using your document:

$pdf = Zend_Pdf::load('/path/to/6890.pdf');

$page = $pdf->pages[0];
$page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES), 18);

// Rotate the coordinate system 90 degrees clockwise
$page->rotate(0, 0, deg2rad(-90));

// Calculate the x and y offsets to "shift the origin."
$xOffset = -792;
$yOffset = 0;

// Make the text blue (so you can see it; I find it easier to adjust positioning this way).
$page->setFillColor(new Zend_Pdf_Color_HTML('blue'));

$page->drawText('This is a test', (24 + $xOffset), (418 + $yOffset));

$pdf->save('/path/to/result.pdf');
Show
Willie Alberty added a comment - You need to do two things: First, you need to rotate the coordinate system. $x and $y specify the rotation point. Positive numbers for $degrees rotate counter-clockwise; negative numbers rotate clockwise. I find it easiest to rotate about the origin (imagine rotating the a sheet of paper with the lower-left corner pinned). So you'd need something like this: $page->rotate(0, 0, deg2rad(-90)); Then, you need to adjust the $x and $y coordinates for your drawing commands. Right now, you'll have to do this manually. (In addition to $page->rotate(), we really need $page->translate() so it becomes automatic. See ZF-64.) If you rotated about the origin, you probably only need an offset for your $x coordinates: $xOffset = -792 Note that the rotation origin and the specific offsets you use will be entirely dependent on the page you're working with. For your specific example, the page was rotated 270 degrees clockwise and the bottom half was cropped. Other documents will be different. Trial-and-error and a little bit of sleuthing inside the PDF file itself will help you find the right values to use. Here's a full example using your document:
$pdf = Zend_Pdf::load('/path/to/6890.pdf');

$page = $pdf->pages[0];
$page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES), 18);

// Rotate the coordinate system 90 degrees clockwise
$page->rotate(0, 0, deg2rad(-90));

// Calculate the x and y offsets to "shift the origin."
$xOffset = -792;
$yOffset = 0;

// Make the text blue (so you can see it; I find it easier to adjust positioning this way).
$page->setFillColor(new Zend_Pdf_Color_HTML('blue'));

$page->drawText('This is a test', (24 + $xOffset), (418 + $yOffset));

$pdf->save('/path/to/result.pdf');
Hide
Jayson Minard added a comment -

Positioned out a few releases, if timing isn't right please set fix version to something more appropriate.

Show
Jayson Minard added a comment - Positioned out a few releases, if timing isn't right please set fix version to something more appropriate.
Hide
Bill Karwin added a comment -

Changing fix version to 0.6.0.

Show
Bill Karwin added a comment - Changing fix version to 0.6.0.
Hide
Alexander Veremyev added a comment -

Zend_Pdf needs clear API for rotating.

There are two different rotating types:
a) page presentation rotating (/Rotate PDF page property is intended for this and must be multiple of 90)
b) drawing coordinate system rotation (also needs translate() implementation)

That's a question, should we automatically translate drawing coordinate system if page presentation is rotated???

It needs to be discussed.

Show
Alexander Veremyev added a comment - Zend_Pdf needs clear API for rotating. There are two different rotating types: a) page presentation rotating (/Rotate PDF page property is intended for this and must be multiple of 90) b) drawing coordinate system rotation (also needs translate() implementation) That's a question, should we automatically translate drawing coordinate system if page presentation is rotated??? It needs to be discussed.
Hide
Alexander Veremyev added a comment -

Postponed to post-1.0 period

Show
Alexander Veremyev added a comment - Postponed to post-1.0 period
Hide
Wil Sinclair added a comment -

This doesn't appear to have been fixed in 1.5.0. Please update if this is not correct.

Show
Wil Sinclair added a comment - This doesn't appear to have been fixed in 1.5.0. Please update if this is not correct.
Hide
Alexander Veremyev added a comment -

It's clear now how to implement this feature, but it breaks backward compatibility at drawing behavior level. Automatic rotation and shifting coordinate system affects drawing behavior.

So it may come only with ZF 1.8 or 2.0 and must be described in the release notes.

Show
Alexander Veremyev added a comment - It's clear now how to implement this feature, but it breaks backward compatibility at drawing behavior level. Automatic rotation and shifting coordinate system affects drawing behavior. So it may come only with ZF 1.8 or 2.0 and must be described in the release notes.

People

Vote (1)
Watch (4)

Dates

  • Due:
    Created:
    Updated:

Time Tracking

Estimated:
4h
Original Estimate - 4 hours
Remaining:
4h
Remaining Estimate - 4 hours
Logged:
Not Specified
Time Spent - Not Specified