ITextSharp open pdf at page index with zoom - visual-studio

I've some pdf with a lot of sheets.
I made a serach in those files and I've a list with the page numers where the string is found.
Now I have to open those files to the exact page, perhaps with a zoom and a rectangle that shows the result.
Any idea?
P.S. The code I use for reading and open the pdf files is:
Dim reader As New PdfReader(FileToOpen)
Dim stamper As New PdfStamper(reader, New System.IO.FileStream("j:\Zoom.pdf", FileMode.Open, FileAccess.ReadWrite))
Dim pdfDest As New PdfDestination(PdfDestination.FITH)
Dim OA As PdfAction = PdfAction.GotoLocalPage(2, pdfDest, stamper.Writer)
stamper.Writer.SetOpenAction(OA)
stamper.Close()
reader.Close()

I almost closed this question as a duplicate of How to set initial view properties? because I found the question in the official iText documentation with a link to Stack Overflow: How to set initial view properties?
Of as a duplicate of How to set zoom level to pdf using iTextSharp? (see How to set the zoom level of a PDF using iTextSharp?)
However, I see that the answer on the official iText web site is better than the answer on Stack Overflow, because it combines everything you need to know.
In short: you need an open action:
//Create a destination that fit's width (fit horizontal)
var D = new PdfDestination(PdfDestination.FITH);
//Create an open action that points to a specific page using this destination
var OA = PdfAction.GotoLocalPage(1, D, stamper.Writer);
//Set the open action on the writer
stamper.Writer.SetOpenAction(OA);
Obviously, you can choose to create another destination when you define D.
If you are by any chance using iText 7, then you should read chapter 7 of the iText 7: Building Blocks tutorial to learn about the open action, and chapter 6 where all the possible destinations (XYZ, FitH, FitB,...) are explained.
Please read the documentation before posting a question.

Related

Adobe Reader cannot read fonts from my project?

I am generating the PDF using iTextPdf version 5 and am using Calibri font inside that PDF. I have loaded that font from the src/resource/fonts folder as I am working with Boot. All is working fine as I can view that PDF in my project and download also except that when I am trying to open the PDF using Adobe Reader, than the page is showing something like that-
I have opened that PDF using Google Chrome, WPS office and other PDF Reader and that PDF is working perfectly fine but I can't seem to understand what is wrong when I am trying to view the PDF using Adobe. I have also attached the screenshot of PDF in WPS office below -
Here is the code that I have loaded the font in my PDF -
static URL calibriFont = UserProfileController.class.getResource("/static/fonts/Calibri Regular.ttf");
static Font namefont = FontFactory.getFont(calibriFont.toString(), 20, Font.BOLD, new BaseColor(139, 0, 0));
FontFactory.register(calibriFont.toString());
Here is the PDF File link shared below -
Sample PDF
In short
Additional data was added to the PDF after initial generation, introducing a cross reference error. Take the first 1019493 bytes of the file to get the original working file.
My first guess would be another program postprocessing the PDF incorrectly but as it turned out the iText objects were closed incorrectly resulting in that error.
In detail
The final version of the PDF you shared is not generated by iText, at least not by correct iText usage.
The file has a size of 1021972 bytes. The initial 1019493 bytes constitute a valid PDF.
The extra 2479 bytes extend the PDF providing some updated old object, some new objects, and a full cross reference table. And in this cross reference table the offset entry for the first new object 33 is incorrect, it should be 0001019493 (the first byte added after the original contents, i.e. the start of the first new object) but it is 0001018667 (the start of the cross reference table of the original PDF).
Thus, a PDF processor will incorrectly find the original cross references when looking for the new object 33.
As the object 33 happens to contain the FontDescriptor of the font Calibri in the updated object 1, an attempt to parse this font fails. This font is referenced from all document pages.
As a results, Adobe Reader stops drawing each page as soon as it comes across an instruction using that font.
Some other PDF viewers repair that error under the hood and, therefore, show you what you want to see.
The actual cause
In a comment you write
The error was coming due to PdfWriter instance object was closed before document.
Indeed, you are not expected to close the PdfWriter at all, and in particular not before the Document.
When requesting a PdfWriter using PdfWriter.getInstance for a Document, a PdfDocument instance is created and registered as listener of the Document; then a PdfWriter is created and registered as listener of the PdfDocument.
To finalize the PDF generation you are expected to close the Document. This will call its listeners' respective close methods, i.e. PdfDocument.close, which will finish some last objects, write them, and then call its own listener's close method, i.e. PdfWriter.close, which will write the cross references.
In your code you first explicitly called PdfWriter.close (which wrote the first cross reference table) and then Document.close (which caused PdfDocument to write some objects and then trigger PdfWriter.close again to write the second cross references). This incorrect sequence also resulted in an incorrect cross reference offset.
I have found the solution of my problem as what I was doing that, I have closed PdfWriter instance before the document. When I closed that instance after the document, it was working fine.

itext7 PdfButtonFormField setImage method does not work on a signed pdf

I am using itext7 java library as shown below to add PdfButtonFormField to an existing pdf :
String src = "sample.pdf";
String dest = "acro_sample_empty_fields.pdf";
PdfDocument pdf = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
PdfButtonFormField button = PdfFormField.createPushButton(pdf, new Rectangle(Integer.parseInt(control.xCord), Integer.parseInt(control.yCord),Integer.parseInt(control.width), Integer.parseInt(control.height)), control.name, control.value);
form.addField(button, page);
String resource = "sample.png";
button.setImage(resource);
After this i use the following code to fill the form like below :
String src = "1540982441_313554925_acro_sample_empty_fields_signedFinal.pdf";
String dest = "acro_sample_filled_fields.pdf";
PdfReader reader = new PdfReader(src);
File output = new File(dest);
OutputStream outputStream = new FileOutputStream(output);
PdfDocument document = new PdfDocument(reader,
new PdfWriter(outputStream),
new StampingProperties().useAppendMode());
PdfAcroForm form = PdfAcroForm.getAcroForm(document, true);
Map<String, PdfFormField> fields = form.getFormFields();
String resource = "sample_test.png";
((PdfButtonFormField)fields.get(control.name)).setImage(resource);
Everything works fine for a normal pdf. But if i digitally sign the created pdf and then try to fill it. then the image is not set properly.
For a normal pdf the image on the push button is changed as expected. But on the digitally signed pdf the image is not set.
I have tried looking for this on google but no luck yet. Any help will be appreciated. Thanks in advance.
I tested the code in this answer with the signed but unfilled PDF you shared. As you didn't share a sample image, though, I used one of my own.
A more precise observation
You say
Everything works fine for a normal pdf. But if i digitally sign the created pdf and then try to fill it. then the image is not set properly. For a normal pdf the image on the push button is changed as expected. But on the digitally signed pdf the image is not set.
This is not entirely true, the image is set but not all PDF viewers show it.
In detail: If you set the image in the signed PDF using your code, Adobe Reader indeed shows merely a grey box
but other PDF viewers, e.g. Foxit or Chrome's built-in viewer, do show the replacement image
Thus, the image is set for the digitally signed PDF, too. The actual problem is that Adobe Reader does not display it!
The cause
After some analysis and having followed some red herrings, the cause of the problem appears to be that if Adobe Reader displays a PDF with a changed AcroForm button appearance and
the PDF is not signed, then Adobe Reader simply uses the updated appearance stream; but if
the PDF is signed, then Adobe Reader tries to ignore the updated appearance stream and construct a new appearance from appearance characteristics information.
(Other PDF viewers, though, appear to always use the updated appearance stream.)
iText does create an appearance characteristics dictionary for the button (so Adobe Reader assumes it can ignore the updated appearance and can construct an new one based on this dictionary) but unfortunately does not add some button specific information to it, neither when constructing the button nor when changing the button. This in particular concerns the following two entries:
I
stream
(Optional; push-button fields only; shall be an indirect reference) A form XObject defining the widget annotation’s normal icon, which shall be displayed when it is not interacting with the user.
TP
integer
(Optional; push-button fields only) A code indicating where to position the text of the widget annotation’s caption relative to its icon:
0 No icon; caption only
1 No caption; icon only
2 Caption below the icon
3 Caption above the icon
4 Caption to the right of the icon
5 Caption to the left of the icon
6 Caption overlaid directly on the icon
Default value: 0.
(ISO 32000-2, Table 192 — Entries in an appearance characteristics dictionary)
As iText does not supply the TP value, the Default value kicks in and Adobe Reader creates a button appearance with "No icon; caption only". As no caption is defined, the result is a grey box.
A work-around
The most simple work-around is to remove the whole appearance characteristics dictionary during image update, i.e. replace
((PdfButtonFormField)fields.get(control.name)).setImage(resource);
by
PdfButtonFormField button = (PdfButtonFormField)fields.get(control.name);
button.setImage(resource);
if (button.getPdfObject().containsKey(PdfName.MK)) {
button.setModified();
button.getPdfObject().remove(PdfName.MK);
}
(SetButtonImage helper method setLikeGautamAnandImproved)
Now Adobe Reader does not find any appearance characteristics and, therefore, cannot ignore the updated appearance stream.
A fix
Alternatively we can add the missing appearance characteristics entries, e.g. like this:
PdfButtonFormField button = (PdfButtonFormField)fields.get(control.name);
button.setImage(resource);
PdfWidgetAnnotation widget = button.getWidgets().get(0);
PdfDictionary characteristics = widget.getAppearanceCharacteristics();
if (characteristics != null) {
characteristics.setModified();
characteristics.put(PdfName.I, widget.getNormalAppearanceObject());
characteristics.put(PdfName.TP, new PdfNumber(1));
}
(SetButtonImage helper method setLikeGautamAnandImproved2)
The result looks slightly different, though:
As you see, there is a small frame around the image. Most likely you can make it vanish by setting other characteristics accordingly.

Best way to show many mini versions of painted InkCanvas in UWP

I have a problem to depict many mini-versions of my InkCanvas. In my app it is possible to write or draw on a InkCanvas. Now I want to depict all created InkCanvas in a GridView.
But with mini versions in this GridView i can not create enough mini versions.
I tested it with 36 mini versions and after I show one and navigate back, the App crashs everytime by rendering the same mini InkCanvas with the error: Insufficient Memory. So I searched an found this post:
Insufficient memory to continue the execution of the program when trying to initialize array of InkCanvas in UWP
I checked the Memory workload:
var AppUsageLevel = MemoryManager.AppMemoryUsageLevel;
var AppMemoryLimit = MemoryManager.AppMemoryUsageLimit;
and the memory has enough free space. (is this a bug?)
So I tried to render a image from my grid with a InkCanvas but the strokes were not rendered and all pictures were empty. ( can I save Memory this way?)
So now my question is:
Can someone tell me how to solve this problem? And what is the best way?
Thank you very much in advance!
Agredo
If you want to preview your drawings, better way is to render them to bitmap and show this bitmaps in grid instead of multiple complex controls InkCanvas is.
Here is some code to render inks to bitmap from another SO Answer:
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int)inkCanvas.ActualWidth, (int)inkCanvas.ActualHeight, 96);
using (var ds = renderTarget.CreateDrawingSession())
{
ds.Clear(Colors.White);
ds.DrawInk(inkCanvas.InkPresenter.StrokeContainer.GetStrokes());
}
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Jpeg, 1f);
You also need to add Win2D.uwp nuget package to your project.

Formatting Image in Excel using win32com.client

I am creating an excel spreadsheet using pythons win32com module excel client. I wanted to add a logo to my excel spreadsheet report. So far I have managed to add the picture:
# Set a variable to an empty excel instance
excel = win32com.client.Dispatch("Excel.Application")
# Initialize a workbook within excel
book = excel.Workbooks.Add()
# Create sheet in book
sheet = book.Worksheets(1)
sheet.Pictures().Insert(r"G:\logos\Logo.jpg")
I've been pouring through the web and I cannot seem to find a way to access the position properties of the picture to move to it a particular place, nor can I find out how to access the sizing properties. Is there a help doc out there that has some examples that I cannot seem to find?
Try
cell = sheet.Cells(1,1)
pic = sheet.Pictures().Insert(r"G:\logos\Logo.jpg")
pic.Left = cell.Left + 20
pic.Top = cell.Top + 30
which will position your picture at 20 pixels right and 30 down from top left corner of given cell.
Regarding help, my reference is search for "excel interop " such as "excel interop range" or "excel interop picture" which leads to Picture object docs.

Dynamically change an image in a Crystal Report at runtime

I'm using the Crystal Reports included with VisualStudio 2005. I would like to change the image that is displayed on the report at runtime ideally by building a path to the image file and then have that image displayed on the report.
Has anyone been able to accomplish this with this version of Crystal Reports?
At work we do this by pushing the image(s) into the report as fields of a datatable. It's not pretty, but it gets the job done. Of course, this solution requires that you push data into the reports via a DataSet. I've always felt this was a hack at best. I really wish that image parameters were a possibility with CR.
Edit: It's worth noting, if you are binding your crystal report to plain old objects you want to expose a byte[] property for the report to treat that as an image.
I finally reached a solution using the byte[] tip posted here by Josh.
This solution applies if you are using a plain old C# Object to populate your Crystal Reports (see http://www.aspfree.com/c/a/C-Sharp/Crystal-Reports-for-Visual-Studio-2005-in-CSharp/ for info on this approach).
In your C# class, insert the following code:
private static byte[] m_Bitmap = null;
public byte[] Bitmap
{
get
{
FileStream fs = new FileStream(bitmapPath, FileMode.Open);
BinaryReader br = new BinaryReader(fs);
int length = (int)br.BaseStream.Length;
m_Bitmap = new byte[length];
m_Bitmap = br.ReadBytes(length);
br.Close();
fs.Close();
return m_Bitmap;
}
}
Now, update your C# Object Mapping in CR using the "Verify Database" option. You should then see the Bitmap property as a CR field. Just drag it onto the form. It will be of type IBlobFieldObject. When you run, you should see your image.
[I have since found a solution using a byte array via a C# Object property - see separate Answer. Leaving this answer here for reference...]
Here's what I have seen suggested (but I tried and failed in both C#-2005 and C#-2008).
Choose a directory and place a BMP there (e.g., "C:\Temp\image.bmp").
From the CR-Designer a) Right-click->Insert->OLE Object... b) Select "Create from File" c) Check the "Link" checkbox d) Browse and pick the bmp defined in step 1 e) Click OK f) Place the image on the form.
Overwrite/update the image at runtime in your C# code. In theory, since you inserted a Link to an image file, it will be updated when the form is refreshed.
I had no luck with this approach. The image appears when I first design the form (step 2). But at runtime, the image does not update for me. From this point forward, things get really odd. It seems that CR caches some sort of image that just won't go away. I can delete the OLE object link in CR-Designer, but if I recreate it, I always get a black box the same size as the original image (even if I change the size of image.bmp).
You can also use a conditional formula to set an image's location. See Crystal Reports: Dynamic Images.
Try using a combination of using a parameter containing the path of the image and the tutorial on this page: http://www.idautomation.com/crystal/streaming_crystal.html
Then in step #8, use the parameter instead of a hard-coded path.
Another option that I've found useful is inserting the pictures you would like to use. Position the graphic accordingly, then right-click the graphic and go to Format Graphic > Common. Check the Suppress box, then click the formula button, shown as x-2. Once in the formula window, simply add the code for determining whether the graphic should be suppressed or not.
In my case, I was building one invoice template for multiple entities. In the formula window, I simply wrote COMPANY <> 1100 which meant that every time the invoice was run for a company other than 1100, the 1100 graphic would be suppressed.
Hopefully this makes life easier...
The current version of Crystal Reports (for Visual Studio 2012+) that I use with Visual Studio 2015 supports this function. Follow the following steps:
Insert a picture into your report. This will serve as your
placeholder.'
Right click your picture and choose Format Object
Select the Picture tab and the press the formula button
A formula window will open. Enter a formula that will find your pictures as links.
if({#isDonor}="1")
then "http://www.ny.org/images/aaf/picture1.jpg"
else "http://www.ny.org/images/aaf/picture2.jpg"
And you're done!
Just like Josh said.. You will have to push the image with a dataset. Or, put the image into a database table once and pull it in many times with a subreport.

Resources