Ready An Existing PDF Page Size (ex. 8.5 x 11, 11 x 17) VB.Net - vb.net

Like the title says i'd like to read an existing pdf page size with VB.Net. I've been working with Itext.Sharp, and the Acrobat.dll. Is this possible??

There are a number of different "Boxes" a given page can have:
Media Box (required): The initial page size when printing viewing.
Crop Box (optional): Supersedes the media box. Defaults to match the media box. Must be a subset or match the media box.
There's also art/trim/bleed boxes, but they don't matter as much and are much less common.
So, the page size:
PdfReader reader = new PdfReader(myPath);
// gets the MEDIA BOX
Rectangle pageRect = reader.getPageSize(1); // 1 -> first page
// gets the crop box if present, or the media box if not.
Rectangle cropRect = reader.getCropBox(1);
// and finally
Rectangle artBox = reader.getBoxSize( 1, "art");
// could be "art", "bleed", "crop", "media", or "trim"
I'd go with getCropBox().
I also recommend checking out the JavaDoc for things like this. At the very least you would have come up with getPageSize() on your own. No, it's not C#. Yes, it's very useful.
http://api.itextpdf.com/
Also note that these Rectangles need not be based on 0,0 (which would be the lower left corner on an unrotated page).
Further, you should check the page's rotation, getPageRotation(int), and swap height and width if the rotation is 90 or 270. There is getPageSizeWithRotation(int), but it only works with the media box, so I'd do it yourself if I were you. It's only a few extra lines of code:
// rotation has to be 0, 90, 180, or 270. "360" isn't kosher IIRC.
if (reader.getPageRotation(pageNum) % 180 != 0) {
float tmp = width;
width = height;
height = tmp;
}

Related

Is there a way to set the dimensions of a paragraph in itext7?

Trying to set the height along with setting the rotation on a Paragraph object results in the following error:
ERROR c.i.layout.renderer.BlockRenderer - Rotation was not correctly processed for ParagraphRenderer
Also, the height is sent to infinity resulting in an apparently empty page which I'm not sure if it's the expected behavior or not.
If I don't set the height, the text shows up rotated (which is what I want). But my task is to place the text at certain coordinates with certain dimensions and rotation. The placement is fine, but not being able to set the height results in assigning the rotation points to the wrong values and in turn displacing the final position of the text.
Paragraph paragraph = new Paragraph(text);
paragraph.setHeight(height);
paragraph.setMargins(0, 0, 0, 0);
paragraph.setProperty(ROTATION_POINT_X, x);
paragraph.setProperty(ROTATION_POINT_Y, y);
paragraph.setProperty(ROTATION_ANGLE, asFloat(toRadians(rotation))));
document.add(paragraph);
Setting the margins to 0 doesn't seem to have any influence either. The text looks to keep some sort of margin anyway.
So is there a way to control what the dimensions of the object displayed are? I could also settle for a way to make the rotation pivot from the center of the object.
You should set both width and height at the same time for rotated objects.
Here is an example code:
Paragraph paragraph = new Paragraph("Hello world");
paragraph.setWidth(200);
paragraph.setHeight(20);
paragraph.setBackgroundColor(ColorConstants.RED);
paragraph.setMargins(0, 0, 0, 100);
paragraph.setProperty(ROTATION_POINT_X, paragraph.getWidth().getValue() / 2);
paragraph.setProperty(ROTATION_POINT_Y, paragraph.getHeight().getValue() / 2);
paragraph.setRotationAngle(Math.PI / 180 * 45);
document.add(paragraph);
Visual result:

iText - PDFAppearence issue

We're using iText to put a text inside a signature placeholder in a PDF. We use a code snippet similar to this to define the Signature Appearence
PdfStamper stp = PdfStamper.createSignature(inputReader, os, '\0', tempFile2, true);
sap = stp.getSignatureAppearance();
sap.setVisibleSignature(placeholder);
sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
Calendar cal = Calendar.getInstance();
sap.setSignDate(cal);
sap.setLayer2Text(text+"\n"+cal.getTime().toString());
sap.setReason(text+"\n"+cal.getTime().toString()); `
Everything works fine, but the signature text does not fill all the signature placeholder area as expected by us, but the area filled seems to have an height that is approximately the 70% of the available space.
As a result, sometimes especially if the length of the signature text is quite big, the signature text does not fit in the placeholder and the text is striped away.
Example of filled Signature:
I looked into the PdfSignatureAppearence class and I found this code snippet in the getApperance() method that is responsible of this behaviour and is invoked when
sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
is being called
else {
dataRect = new Rectangle(
MARGIN,
MARGIN,
rect.getWidth() - MARGIN,
rect.getHeight() * (1 - TOP_SECTION) - MARGIN);
}
I don't get the reason for that, because I expect that the text could use all the available placeholder height, with the proper margin.
Is there any way to bypass this behaviour?
We are using iText 5.4.2, but also newer version contains same code snippet so I expect that the behaviour will be same.
As #JJ. already commented,
TOP_SECTION is connected with acro6layers rendering and the code [determining the datarect in pure DESCRIPTION mode] does not take into account the value of the acro6layer flag.
Unless one wants to fix this in the iText 5 code itself, the easiest way to make one's description use the whole signature space is to construct the layer 2 appearance oneself.
To do so one merely has to retrieve a PdfTemplate from PdfSignatureAppearance.getLayer(2) and fill it as desired after one has called PdfSignatureAppearance.setVisibleSignature. The PdfSignatureAppearance remembers that you already have retrieved the layer 2 and doesn't change it anymore.
For the case at hand we essentially copy the PdfSignatureAppearance.getAppearance code for generating layer 2 in pure DESCRIPTION mode, merely correcting the code determining the datarect:
PdfSignatureAppearance appearance = ...;
[...]
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
PdfTemplate layer2 = appearance.getLayer(2);
String text = "We're using iText to put a text inside a signature placeholder in a PDF. "
+ "We use a code snippet similar to this to define the Signature Appearence.\n"
+ "Everything works fine, but the signature text does not fill all the signature "
+ "placeholder area as expected by us, but the area filled seems to have an height "
+ "that is approximately the 70% of the available space.\n"
+ "As a result, sometimes especially if the length of the signature text is quite "
+ "big, the signature text does not fit in the placeholder and the text is striped "
+ "away.";
Font font = new Font();
float size = font.getSize();
final float MARGIN = 2;
Rectangle dataRect = new Rectangle(
MARGIN,
MARGIN,
appearance.getRect().getWidth() - MARGIN,
appearance.getRect().getHeight() - MARGIN);
if (size <= 0) {
Rectangle sr = new Rectangle(dataRect.getWidth(), dataRect.getHeight());
size = ColumnText.fitText(font, text, sr, 12, appearance.getRunDirection());
}
ColumnText ct = new ColumnText(layer2);
ct.setRunDirection(appearance.getRunDirection());
ct.setSimpleColumn(new Phrase(text, font), dataRect.getLeft(), dataRect.getBottom(), dataRect.getRight(), dataRect.getTop(), size, Element.ALIGN_LEFT);
ct.go();
(CreateSignature.java test signWithCustomLayer2)
(As description text I used some paragraphs from the question body.)
The result:
By adapting the MARGIN value in the code above, one can even use more are. As that can result in the text touching the border, though, that might not be really beautiful.
As an aside:
if the length of the signature text is quite big, the signature text does not fit in the placeholder and the text is striped away.
If you initialize the size variable above with a non-positive value, the code in the if (size <= 0) block will calculate a font size which allows all of the text to fit into the signature rectangle. This does happen in the code above as new Font() returns a font with a size of UNDEFINED which is a constant -1.

How do I get phantomJS to generate pdf that is just a single page that contains my page?

I am trying to create a pdf from a webpage using phantomJS. I want the pdf to just be a single page long that is the same height as my webpage. If I don't set paperSize or viewportSize at all then it creates a page that is almost the right height, it is just a little short by about 100px. If I detect page height and use that to set viewportSize I have the exact same problem, it's short by about 100px. Is there a way to get phantomJS to just create a pdf based on the webpage's size? I want it to be exact because the page is a dark colour and it looks really bad to have a big white block at the end of the page (which is what is there if I add a constant to viewport height to make it fit everything in one page).
My code to find height(Note: the height is the same whether I use body or the classname below to find it):
var size = page.evaluate(function() {
var height = $('.export-athlete-detail-report').outerHeight(true);
return {width: 700, height:height};
});
page.paperSize = size;
page.render(reportFile);

How is iBooks rendering the index view so quickly when viewing a PDF? Or: how do draw UIImages on UIScrollView directly without UIImageView?

I have a 140 pages test PDF (the full Adobe PDF specification, http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000.pdf) and open it in iBooks. Then switch to index (thumbnail) view. If I scroll to the end fast enough I can see that I can scroll faster than iBooks renders the pages but it catches up pretty quickly on iPad 2.
I learn two things from this:
First iBooks is showing 140 empty squares in the right size and then populates the preview.
iBooks really renders all of the previews and keeps them in memory (if I scroll around I cannot spot any re-rendering)
I also tested with another Adobe Spec that has 700+ pages: exactly same behavior! Fascinating!
The question is how are they doing it? I wrote some code that gets each page of the PDF as an image, adds it to a UIImageView and adds that to the scrollview.
I use the same technique and layout as iBooks does. It renders just as quick as iBooks but memory consumption is insane and especially when scrolling the app gets totally stuck after a while. Can anybody point me in the right direction? I already removed the PDF rendering for testing and it is really fast, so I can pin it down to the thumbnail generation.
EDIT:
If from the code below the PDF generation is removed and an empty UIImageView is returned instead, the performance is still extremely weak. So my assumption is that the UIImageView is causing the problem. How can I draw the PDF thumbs onto my UIScrollView without the requirement of 140 UIImageViews?
For those firm in Monotouch, here's the code I'm using to render the thumbs, maybe it shows an obvious weakness:
/// <summary>
/// Gets the low res page preview of a PDF page. Does a quick image render of the page.
/// </summary>
/// <param name="iPage">the number of the page to render</param>
/// <param name="oTergetRect">the target rect to fit the PDF page into</param>
/// <returns>
/// The low res page image view.
/// </returns>
public static UIImageView GetLowResPagePreview (CGPDFPage oPdfPage, RectangleF oTargetRect)
{
RectangleF oOriginalPdfPageRect = oPdfPage.GetBoxRect (CGPDFBox.Media);
RectangleF oPdfPageRect = PdfViewerHelpers.RotateRectangle( oPdfPage.GetBoxRect (CGPDFBox.Media), oPdfPage.RotationAngle);
// If preview is requested for the PDF index view, render a smaller version.
if (!oTargetRect.IsEmpty)
{
// Resize the PDF page so that it fits the target rectangle.
oPdfPageRect = new RectangleF (new PointF (0, 0), GetFittingBox (oTargetRect.Size, oPdfPageRect.Size));
}
// Create a low res image representation of the PDF page to display before the TiledPDFView
// renders its content.
int iWidth = Convert.ToInt32 ( oPdfPageRect.Size.Width );
int iHeight = Convert.ToInt32 ( oPdfPageRect.Size.Height );
CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB();
CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedLast);
// First fill the background with white.
oContext.SetFillColor (1.0f, 1.0f, 1.0f, 1.0f);
oContext.FillRect (oOriginalPdfPageRect);
// Scale the context so that the PDF page is rendered
// at the correct size for the zoom level.
oContext.ConcatCTM ( oPdfPage.GetDrawingTransform ( CGPDFBox.Media, oPdfPageRect, 0, true ) );
oContext.DrawPDFPage (oPdfPage);
CGImage oImage = oContext.ToImage();
UIImage oBackgroundImage = UIImage.FromImage( oImage );
oContext.Dispose();
oImage.Dispose ();
oColorSpace.Dispose ();
UIImageView oBackgroundImageView = new UIImageView (oBackgroundImage);
oBackgroundImageView.Frame = new RectangleF (new PointF (0, 0), oPdfPageRect.Size);
oBackgroundImageView.ContentMode = UIViewContentMode.ScaleToFill;
oBackgroundImageView.UserInteractionEnabled = false;
oBackgroundImageView.AutoresizingMask = UIViewAutoresizing.None;
return oBackgroundImageView;
}
internal static RectangleF RotateRectangle ( RectangleF oRect, int iRotationAngle )
{
if ( iRotationAngle == 90 || iRotationAngle == 270 )
{
return new RectangleF (oRect.X, oRect.Y, oRect.Height, oRect.Width);
}
return oRect;
}
You shouldn't be using 140 UIImageViews !!! use only just enough to fill the area and then recycle the ones that are no longer displayed.
How did Apple implement UITableView ?? Do you think they keep all tableview cells in memory??
Look at the PhotoScroller sample code and the corresponding WWDC 2010 video. I think it is named "Desigining apps with scrollViews"
WWDC 2011 video of similar name is continuation of the same trick of view reuse.
Hope this helps.
Have you checked the size of each UIImageView? Perhaps each of your thumbnails is actually the size of a full page.
Perhaps iBooks doesn't put each thumbnail in a UIImageView? Maybe the app is using something from CoreAnimation or even OpenGL ES?

iTextSharp Overlay Image

Hi guys I have an instance where I have a logo image as part of some artwork..
If a user uploads a new logo I have a form field which is larger than the default logo.
I then use that form field to position the new image.
The problem is I need to set the background colour of that form field to white so that it covers the old logo in the event that the new image is smaller than the old logo..
what I have done is:
foreach (var imageField in imageReplacements)
{
fields.SetFieldProperty(imageField.Key, "bgcolor", iTextSharp.text.Color.WHITE, null);
fields.RegenerateField(imageField.Key);
PdfContentByte overContent = stamper.GetOverContent(imageField.Value.PageNumber);
float[] logoArea = fields.GetFieldPositions(imageField.Key);
if (logoArea != null)
{
iTextSharp.text.Rectangle logoRect = new iTextSharp.text.Rectangle(logoArea[1], logoArea[2], logoArea[3], logoArea[4]);
var logo = iTextSharp.text.Image.GetInstance(imageField.Value.Location);
if (logo.Width >= logoRect.Width || logo.Height >= logoRect.Height)
{
logo.ScaleToFit(logoRect.Width, logoRect.Height);
}
logo.Alignment = iTextSharp.text.Image.ALIGN_LEFT;
logo.SetAbsolutePosition(logoRect.Left, logoArea[2] + (logoRect.Height - logo.ScaledHeight) / 2);
// left: logoArea[3] - logo.ScaledWidth + (logoRect.Width - logo.ScaledWidth) / 2
overContent.AddImage(logo);
}
}
The problem with this is that the background colour of the field is set to white and the image then doesn't appear.. i remove the SetFieldProperty and RegenerateField commands and the image replacement works fine..
is there a way to set a stacking order on layers?
Annotations (such as form fields) are always on top of page contents. Annotation Z order is just the order of the annotations array on a given page.
Page content Z order is just the order everything appears in the content stream. New drawing operators go on top of proceeding operators.
If you want to cover your old image, draw a white box over it and then draw the new logo over top that. No need to worry about annotations.
Actually, all you really need to do is not set the background color of the imageField. You're already scaling the new logo to match the size of the old one.
However, if you really must draw that white box, it's fairly simple:
overContent.setColorFill(iTextSharp.text.Color.WHITE);
overContent.rectangle( logoRect );
overcontent.fill();