How to scale a page less then 1 percent? - itext

I want to scale a full pdf-page and insert into an new document. This works fine. But i have problems with the scale-factor when the factor is less than 1%. for example with a factor of 0,5%, no scale is happening. With a factor from 0,7%, the document (rectagle) has the correct size, but the scaled page is bigger then the calculated new size. Is there a way to scale a page continuously? It looks like, that in such cases with very small scale factors, the scaling works only in stages. Or maybe is there a problem with the internal matrix-calculation?
float scale = 1.005f; //100,5%
var newWidth = originWidth*scale;
var newHeight = originHeight*scale;
PdfReader reader = new PdfReader(inputfile);
var newMediaBox = new Rectangle(newWidth, newHeight);
Document doc = new Document(newMediaBox);
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(outputfile,FileMode.Create));
doc.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1); //page #1
cb.AddTemplate(page, scale, 0, 0, scale, 0, 0);
doc.Close();
The other way: Can i calculate or read out the new size after the scaling?
Thanks.

iTextSharp by default will use two decimal places rounded when adding the template. You can change this by setting the HIGH_PRECISION static variable of the ByteBuffer class to true which will give you six decimal places. I do not know if this will affect your overall application performance but I'm fairly confident that it won't.
iTextSharp.text.pdf.ByteBuffer.HIGH_PRECISION = true;

Related

Is it possible to define a 3d model/prefab size in unity?

Is there a way I can define a 3d model size in unity? Like height = 1, width = 3, depth = 3?
I want the model to take a defined space in unity's scene, no matter how big or small I make the fbx in Blender. So I can't use scale as changing the model size in Blender will break this scaling.
I need it to be a square 3 wide, 3 long and 1 high, not depending on the model's size that is exported from Blender. Is it possible?
The same question but from another angle - how to set model size in unity? There is only the scale setting, but no size setting. This looks weird.
So far I have found a workaround like getting object's rendered bounds and adjusting scaling quotient in a script, but this doesn't seem right to me.
You can use the Mesh.bounds to get the 3D model size without applied scaling.
Then you recalculate the scale according to your needs e.g.
// The desired scales
// x = width
// y = height
// z = depth
var targetScale = new Vector3(3, 1, 3);
var meshFilter = GetComponent<MeshFilter>();
var mesh = meshFilter.mesh;
// This would be equal to the 3D bounds if scale was 1,1,1
var meshBounds = mesh.bounds.size;
// This would make the model have world scale 1,1,1
var invertMeshBounds = new Vector3(1/meshBounds.x, 1/meshBounds.y, 1/meshBounds.z);
// Use this if you want exactly the scale 3,1,3 but maybe stretching the fbx
var finalScale = Vector3.Scale(invertMeshBounds, targetScale);
As I understand you want to keep the correct relative scales of the 3D model but make it fit into the defined targetScale so I would use the smallest of the 3 values as scaling factor
var minFactor = Mathf.Min(finalScale.x, finalScale.y);
minFactor = Mathf.Min(minFactor, finalScale.z);
transform.localScale = Vector3.one * minFactor;

Scale image to fill multiple pages with iText

I am trying to scale an image with iText (on a new PDF document) in order to make it fill the width of the page without streching, so that it could take several pages.
I've found a lot of solutions but they were pretty complicated and I don't really like coding like that. The best solution I've found till now (from another question on SO) is using PdfTable but it always uses a single page, scaling the image.
// Load image from external storage
Image image = Image.getInstance(path + "/img.png");
// Calculate ratio
float width = PageSize.A4.getWidth();
float heightRatio = image.getHeight() * width / image.getWidth();
Document document = new Document();
document.open();
PdfPTable table = new PdfPTable(1);
table.setWidthPercentage(100);
PdfPCell c = new PdfPCell(image, true);
c.setBorder(PdfPCell.NO_BORDER);
c.setPadding(0);
// Set image dimensions
c.getImage().scaleToFit(width, heightRatio);
table.addCell(c);
document.add(table);
// Write PDF file
document.close();
Any suggestions?
Ok I finally decided to go the way I didn't want to go, since it seems to be the only way: adding the same image to every page and setting the proper vertical offset to each one. The offset gets calculated as the number of pages left to draw + the gap the remains blank. For each step I decrement the number of pages until there's nothing left to draw.
// Open new PDF file
Document document = new Document();
PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(getSharedDirPath() + File.separator + "file.pdf"));
document.open();
PdfContentByte content = pdfWriter.getDirectContent();
// Load image from external folder
Image image = Image.getInstance(path + "/img.png");
image.scaleAbsolute(PageSize.A4);
image.setAbsolutePosition(0, 0);
float width = PageSize.A4.getWidth();
float heightRatio = image.getHeight() * width / image.getWidth();
int nPages = (int) (heightRatio / PageSize.A4.getHeight());
float difference = heightRatio % PageSize.A4.getHeight();
while (nPages >= 0) {
document.newPage();
content.addImage(image, width, 0, 0, heightRatio, 0, -((--nPages * PageSize.A4.getHeight()) + difference));
}
// Write PDF file
document.close();
Honestly I don't like this solution, I thought it was possible to auto-adjust dimensions as I do in a text editor, but after all it was not very difficult.....it just took me three days to figure out how the whole PDF thing worked.

How to create a multi page TOC using itext?

I need to create TOC in a PDF. It can be of 1 page or multi pages depending on the number of pages in PDF. I have learnt that PdfStamper, PdfAction, PdfAnnotaion can be used to achieve this.
I am currently merging more than one document and creating both bookmarks and TOC for all the documents in JAVA. I have got rid of bookmarks but got stuck on multi-pages TOC.
Also, please explain this line of your code - link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);... What I have understood is you are passing the dimensions of a rectangle on the page on which it will be going after clicking the link (, 36, ct.getYLine(), 559, y, ).. And thus I am facing an issue of not going to correct position of the page on clicking the link, in the case if page size is different from US Letter Portrait.
Here is the snippet -
int tocPages = 1;
Document tocDocument = new Document();
String tocFilename ="toc-filename";
Phrase tocPhrase =
new Phrase("Table of Contents", new Font(Font.FontFamily.HELVETICA, 20, Font.BOLD, BaseColor.BLACK));
PdfWriter writer = PdfWriter.getInstance(tocDocument, new FileOutputStream(tocFilename));
tocDocument.open();
tocDocument.add(new Paragraph(tocPhrase));
PdfReader reader = new PdfReader(tocFilename);
page = copy.getImportedPage(reader, tocPages);
stamp = copy.createPageStamp(page);
float y = 770;
ColumnText ct = new ColumnText(stamp.getOverContent());
ct.setSimpleColumn(36, 36, 559, y);
for (Map.Entry<Integer, String> entry : toc.entrySet()) {
if (y <= 20) {
copy.addPage(page);
copy.newPage(); //(tried with writer.newPage() and tocDocument.newPage(), not working )
page = copy.getImportedPage(reader, ++tocPages);
}
p = new Paragraph(entry.getValue());
p.add(new Chunk(new DottedLineSeparator()));
p.add(String.valueOf(entry.getKey() + 1));
ct.addElement(p);
ct.go();
action = PdfAction.gotoLocalPage("p" + entry.getKey(), false);
link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);
stamp.addAnnotation(link);
y = ct.getYLine();
}
ct.go();
stamp.alterContents();
copy.addPage(page);
tocDocument.close();
reader.close();
com.itextpdf.text.exceptions.InvalidPdfException: PDF header signature not found.
at com.itextpdf.text.pdf.PRTokeniser.getHeaderOffset(PRTokeniser.java:227)
at com.itextpdf.text.pdf.PdfReader.getOffsetTokeniser(PdfReader.java:442)
at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:176)
at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:219)
at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:207)
at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:197)
Excetion at line - PdfReader reader = new PdfReader(tocFilename);
You have adapted your question so that it became a question about this snippet from my answer to Create Index File(TOC) for merged pdf using itext library in java
Paragraph p;
PdfAction action;
PdfAnnotation link;
float y = 770;
ColumnText ct = new ColumnText(stamp.getOverContent());
ct.setSimpleColumn(36, 36, 559, y);
for (Map.Entry<Integer, String> entry : toc.entrySet()) {
p = new Paragraph(entry.getValue());
p.add(new Chunk(new DottedLineSeparator()));
p.add(String.valueOf(entry.getKey()));
ct.addElement(p);
ct.go();
action = PdfAction.gotoLocalPage("p" + entry.getKey(), false);
link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);
stamp.addAnnotation(link);
y = ct.getYLine();
}
ct.go();
Your question was reduced to: please explain this line of your code:
link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);
I have pasted the complete snippet, because this line can not be explained out of context,
In the snippet, we create a link annotation using the PdfAnnotation class. A link annotation is a area somewhere on a page, that triggers an action when clicked.
Which action is triggered in this case? That's what the action object is about, in this case, it jumps to a local page that is defined by a named destination. This is very similar to HTML where you have <a name="dest" /> and Jump to a specific destination on the current page.
When creating a PdfAnotation, you always need a PdfWriter instance. In this case, we are merging documents using a PdfCopy instance named copy. As PdfCopy extends PdfWriter, we can pass the copy instance as a parameter.
Finally, we define the clickable area. This is always a rectangle that is defined using two coordinates: the coordinate of the lower-left corner and the coordinate of the upper-right corner.
In the above snippet, we add paragraphs using ColumnText. ColumnText allows you to get information about the current y position after adding content. For instance, when we do this:
ct.addElement(p);
ct.go();
We can do this to get the current Y-coordinate:
float y = ct.getYLine();
In our code snippet, we keep track of the previous y value (the Y position before we add p) and we use the current value of ct.getYLine() to get the current y position.
This way, I can define the coordinate of the lower-left corner like this:
float llx = 36;
float lly = ct.getYLine();
And the coordinate of the upper-right corner like this:
float urx = 559;
float ury = y;
These are the values that you can see when we construct the link annotation.
I have hardcode the x values. They are based on the fact that I am creating a document with pages of size A4 and margins of half an inch. An A-4 page is 595 user units wide. To the left, I have a margin of 36 user units; to the right I also have a margin of 36 user units, which I have to subtract from the width of the page: 595 - 36 = 559.
If you have a page of which the format is LETTER, you need to adapt these values. However: it's better to calculate them based on the actual value of the MediaBox / CropBox of the existing page. This way, your code keeps working when you're accidentally confronted with documents that have a different page size.
You can read more about the MediaBox and the CropBox in my answer to this question: How to get dimensions of each page of a pdf file

Add Gradient Shading using Stamper

I have code that uses iTextSharp to add a variety of colored rectangles to an existing PDF document using the PdfStamper object with code like the following:
Dim reader As New PdfReader(byte_contets_of_PDF_file)
Dim stamper As New PdfStamper(reader, someOutputBuffer)
Dim under As PdfContentByte = stamper.GetUnderContent(pageNumber)
under.SetColorFill(BaseColors.RED)
under.Rectangle(x, y, rectWidth, rectHeight)
under.Fill()
This works swimmingly for drawing monochromatic rectangles on an existing PDF document, but I was hoping I could place rectangles that use a color gradient.
My research has turned up examples using the PdfShading and PdfShadingPattern objects, but those require a PdfWriter. To my understanding, the PdfWriter is used for creating new PDFs and not for updating existing PDFs.
Is it possible to add rectangles to an existing PDF document that have a gradient?
Thanks
I assume you have read the answer to this question: How to add a shading pattern to a custom shape
I assume that your problem is that you don't know which parameter to use instead of writer.
If that is the case, use 'stamper.GetOverContent(p)' instead of writer.DirectContent and use stamper.Writer instead of writer:
int p = 1; // or whatever page number applies
PdfContentByte canvas = stamper.GetOverContent(p);
float x = 36;
float y = 740;
float side = 70;
PdfShading axial = PdfShading.SimpleAxial(writer, x, y,
x + side, y, BaseColor.PINK, BaseColor.BLUE);
PdfShadingPattern shading = new PdfShadingPattern(axial);
canvas.SetShadingFill(shading);
canvas.MoveTo(x,y);
canvas.LineTo(x + side, y);
canvas.LineTo(x + (side / 2), (float)(y + (side * Math.sin(Math.PI / 3))));
canvas.ClosePathFillStroke();

How to calculate the correct image size in out pdf using itextsharp?

I' am trying to add an image to a pdf using itextsharp, regardless of the image size it always appears to be mapped to a different greater size inside the pdf ?
The image I add is 624x500 pixel (DPI:72):
alt text http://www.freeimagehosting.net/uploads/727711dc70.png
And here is a screen of the output pdf:
alt text http://www.freeimagehosting.net/uploads/313d49044d.png
And here is how I created the document:
Document document = new Document();
System.IO.MemoryStream stream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, stream);
document.Open();
System.Drawing.Image pngImage = System.Drawing.Image.FromFile("test.png");
Image pdfImage = Image.GetInstance(pngImage, System.Drawing.Imaging.ImageFormat.Png);
document.Add(pdfImage);
document.Close();
byte[] buffer = stream.GetBuffer();
FileStream fs = new FileStream("test.pdf", FileMode.Create);
fs.Write(buffer, 0, buffer.Length);
fs.Close();
Any idea on how to calculate the correct size ?
I alreay tried ScaleAbsolute and the image still renders with incorrect dimensions.
I forget to mention that I' am using itextsharp 5.0.2.
It turned out that PDF DPI = 110, which means 110 pixels per inch, and since itextsharp uses points as measurment unit then :
n pixels = n/110 inches.
n inches = n * 72 points.
Having a helper method to convert pixels to points is all I needed:
public static float PixelsToPoints(float value,int dpi)
{
return value / dpi * 72;
}
By using the above formula and passing a dpi value of 110 it worked perfectly:
Note: Since you can create pdf documents in any size you want, this may lead to incorrect scaling when printing out your documents. To overcome this issue all you need to do is to have the correct aspect ratio between width and height [approximately 1:1.4142] (see : Paper Size - The international standard: ISO 216 ).
Multiply the image's height and width by 72 and divide them by the dpi(ppi): points = pixels * 72 / dpi.