ITextSharp - Adding a Watermark; Leaving the PDF editable - FormFlattening = false - itext

We have a large amount of PDF files that we are creating a web site to allow users to download them and when they do we want to:
Put a watermark on it with their name.
We want the form fields to be left open so they can enter their information.
We want to be able to print and save the document
When I put the Watermark on the document and then open it I get a message from Adobe:
"The document has been changed since it was created and use of extended features is no longer available. Please contact the author..."
According the book "iText-in-Action", this is a security issue (Chapter 8). There seems to be 2 ways to open them:
Remove usage rights : This breaks # 3 above.
Open it in append mode : It does not matter if modify it and save it with "FormFlattening = false" or true, if I put a water mark on the form the fields are no longer editable.
The error message from Adobe does describe the problem, I have modified the content of the document with the watermark, and the form fields become blocked because of this.
I have tried opening the document putting the watermark on it and saving it to a new file, and then closing it. Then reopening it and the trying to unblock the form fields, but it does not work.
Does anyone know if this is possible?
I have read something about templates; I don't know if this is a solution because of the work to convert the documents to templates? Does anyone know if this would help?
Below is a sample of my code for using an Image as a watermark, although I have tried adding text as well:
PdfReader reader = new PdfReader(sourceFile.FullName);
//reader.RemoveUsageRights();
var fileStream = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite);
PdfStamper pdfStamper = new PdfStamper(reader, fileStream, '\0', true);
Image image = Image.GetInstance(imagePath);
image.SetAbsolutePosition(250, 300);
for (int i = 1; i <= reader.NumberOfPages; i++) // Must start at 1 because 0 is not an actual page.
{
PdfContentByte pdfPageContents = pdfStamper.GetUnderContent(i);
pdfPageContents.AddImage(image);
}
pdfStamper.FormFlattening = false; // enable this if you want the PDF flattened.
//bool have = pdfStamper.PartialFormFlattening("test");
pdfStamper.Close(); // Always close the stamper or you'll have a 0 byte stream.

A document that is Reader-enabled is digitally signed using a private key owned by Adobe. If Adobe Reader can validate that signature using Adobe's public key, the extra functionality (e.g. allowing you to save a form that has been filled out) is enabled.
Adding a watermark isn't part of the actions you're allowed to do with a digitally signed document. There is absolutely no way you can achieve what you want without invalidating the digital signature that triggers the reader enabling.
In short: you're trying to do something that is impossible. You can only achieve this by using Adobe software because you need Adobe's private key to 'restore' the reader enabling after breaking it.

Good advice.
Every time I reboot my computer Adobe complains about needing to be updated. Last thing I want is to be stuck with a hack, that may not work in the future.
One of my attempts was to create a watermark on a different layer of the PDF in the hopes that it would not see it as changing the text layer of the PDF, but this did not work. My boss had a thought of grabing the text from the original PDF and coping it to a new document and then putting the watermark on it. even though I created a new PDF it still sees it as modifying it, and the fields are still not editable.
Still stuck

Related

Word addin, set filename

If one starts a blank file on Word you can usually see in the top bar a name such as "Document1", "Document2" and so on.
Yet, if you attempt to open a file using the Word JS API like this:
Word.run((context) => {
context.application.createDocument(documentB64).open()
return context.sync()
})
The top bar comes out like this:
No filename is set.
To set a filename/handle(?), I tried using the code given here Office JS - Add customProperty to new document but that didn't help.
My addin is usually used in conjunction with another (VSTO) add-on and that add-on can't work properly with the documents opened by my addin and I believe the lack of a filename (/handle?) explains it to some extent.
Is there something I can do about this?
Thank you
Currently you can't do this because the newly created document is just a temporary file and not saved. can you try to call the following code to make sure the newly created file is saved?
const documentCreated = context.application.createDocument(externalDoc);
documentCreated.save();
documentCreated.open();

Novacode LineChart type

I have a code that implements a Novacode.LineChart. And the LineChart type which is shown by default is this one:
But I dont want this type of chart, I want it without points, like this:
This is the code where I create the chart:
LineChart c = new LineChart();
c.AddLegend(ChartLegendPosition.Bottom, false);
c.Grouping = Grouping.Stacked;
Anyone knows how can I hide thoose points and show only the lines? Thanks to everyone!!
Your question is shown up while I was searching for the exact same feature. It's probably a bit late but I hope it would be useful for other people in need of this feature.
My so called answer is not more than a few lines of dirty and unmanageable hack so unless you are not in dire need, I do not recommend to follow this way.
I also do not know if is it an approved approach here but I prefer to write the solution step by step so it may help you to grasp the concept and use better methods.
After I have realized that I was unable to use DocX to create a line chart without markers, using currently provided API, I wanted to know what were the differences between actual and desired output. So I saved a copy of .docx file with line chart after I manually edited the chart to expected result.
Before and after the edit
As you may already know, a .docx is a container format and essentially comprised of a few different folders and files. You can open it up with a .zip archive extractor. I used 7-Zip for this task and found chart file at location of /word/charts/chart1.xml but this may differ depending on the file, but you can easily figure it out.
Compared both of chart1.xml files and the difference was, the file without the markers had and extra XML tag with an additional attribute;
<c:marker>
<c:symbol val="none" />
</c:marker>
I had to somehow add this segment of code to chart. I added these up to example code provided by DocX. You can follow up from: DocX/ChartSample.cs at master
This is where the fun begins. Easy part first.
using System.Xml;
using System.Xml.Linq;
using Xceed.Words.NET;
// Create a line chart.
var line_chart = new LineChart();
// Create the data.
var PlaceholderData = ChartData.GenerateRandomDataForLinechart();
// Create and add series
var Series_1 = new Series("Your random chart with placeholder data");
Series_1.Bind(PlaceholderData, "X-Axis", "Y-Axis");
line_chart.AddSeries(Series_1);
// Create a new XmlDocument object and clone the actual chart XML
XmlDocument XMLWithNewTags = new XmlDocument();
XMLWithNewTags.LoadXml(line_chart.Xml.ToString());
I've used XPath Visualizer Tool to determine the XPath query, which is important to know because you can't just add the marker tag to somewhere and expect it to work. Why do I tell this? Because I appended marker tag on a random line and expected it to work. Naive.
// Set a namespace manager with the proper XPath location and alias
XmlNamespaceManager NSMngr = new XmlNamespaceManager(XMLWithNewTags.NameTable);
string XPathQuery = "/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser";
string xmlns = "http://schemas.openxmlformats.org/drawingml/2006/chart";
NSMngr.AddNamespace("c", xmlns);
XmlNode NewNode = XMLWithNewTags.SelectSingleNode(XPathQuery, NSMngr);
Now create necessary tags on newly created XML Document object with specified namespace
XmlElement Symbol = XMLWithNewTags.CreateElement("c", "symbol", xmlns);
Symbol.SetAttribute("val", "none");
XmlElement Marker = XMLWithNewTags.CreateElement("c", "marker", xmlns);
Marker.AppendChild(Symbol);
NewNode.AppendChild(Marker);
And we should copy the contents of latest changes to actual XML object. But oops, understandably it is defined as private so it is a read-only object. This is where I thought like "Okay, I've fiddled enough with this. I better find another library" but then decided to go on because reasons.
Downloaded DocX repo, changed this line to
get; set;
recompiled, copied Xceed.Words.NET.dll to both projectfolder/packages and projectfolder/projectname/bin/Debug folder and finally last a few lines were
// Copy the contents of latest changes to actual XML object
line_chart.Xml = XDocument.Parse(XMLWithNewTags.InnerXml);
// Insert chart into document
document.InsertChart(line_chart);
// Save this document to disk.
document.Save();
Is it worth it? I'm not sure but I have learned a few things while working on it. There're probably lots of bad programming practises in this answer so please tell me if you see one. Sorry for meh English.

Add Eventhandler to Object of type Word.Application

With the following code I open a a new word document. To save the word document programmatically I want to add an event listener to the object, which occurs when word will be closed. Is this possible?
Set objWord = createobject("Word.Application")
objWord.visible = True
Set objDoc = objWord.documents.add()
Call objDoc.content.select()
Set selection = objWord.selection()
Call selection.collapse()
objDoc.Close
Set objDoc = Nothing
objWord.Quit
Set objWord = Nothing
EDIT:
I try to explain better what I want to do. My Lotusscript Agent should open a word document for the user. The user types in some text and then closes the word document. Instead of showing the save dialog of word I want to save the document programmatically to embedd the file as attachment to an notes document. Until now I have not found a solution to get an handle of the event when word is closing.
I think this link on one of the ldd wikis probably has what you need. If you are a little clearer on what you need, you may get better answers though.
I think you are wanting to be notified when word closes so you can force a save or something correct? You can already force the save using similar lotusscript to how you are closing it, you don't need to wait until they close it themselves.

itextsharp PDF to text dump

I am looking for a way to actually get the contents of the file itself, in its text format, dumped. E.g.: i don't want a dictionary object, i don't want some sort of extractionstrategy option, i just want the same text document that itextsharp uses to parse... the WHOLE thing as a string or stringbuilder...
I have not yet found a way to do this using any tools what so ever... my problem is that i am trying to read a dynamic PDF into a C# application... and we all know that those darn dynamic PDFs can't be parsed by iTextSharp (AcroForm and AcroFields always comes up empty), so i figured that if i can get the actual text dump of the entire file, i can see what it looks like and parse it myself for this specific task (e.g.: make a class for each document i know i can received, and make a map there based on what i see).
If anyone can help me do that, or even better, find a way, in C#, to extract the XML Source for the PDF (kinda like clicking the XML Source tab in LiveCycle) instead, it would be greatly appreciated.
Thanks!
Matt
If you are looking for the actual operators and commands of each page in the raw text format, try the following code:
var reader = new PdfReader("test.pdf");
int intPageNum = reader.NumberOfPages;
for (int i = 1; i <= intPageNum; i++)
{
byte[] contentBytes = reader.GetPageContent(i);
File.WriteAllBytes("page-" + i + ".txt", contentBytes);
}
reader.Close();
I am looking for a way to actually get the contents of the file
itself, in its text format, dumped. E.g.: i don't want a dictionary
object, i don't want some sort of extractionstrategy option, i just
want the same text document that itextsharp uses to parse... the WHOLE
thing as a string or stringbuilder...
Unfortunately the data that itextsharp uses to parse are not yet text; the operators in that data are given in some textual format but the actual glyphs may be given in a completely arbitrary ad-hoc encoding. That been said, often some standard encoding is used as it is the most simple solution for the components in use. You cannot in general count on that, though. The answer by VahidN shows you how to access the starting points for that content; not seldomly, though, that page content data he extracts only contain references to resources which are contained in different objects.
my problem is that i am trying to read a dynamic PDF into a C#
application... and we all know that those darn dynamic PDFs can't be
parsed by iTextSharp (AcroForm and AcroFields always comes up empty),
This sounds as if you actually have a completely different task at hand. Dynamic forms and their contents are not part of the page content but instead stored in a separate XML Forms Architecture stream.
iText in Action, 2nd edition, in chapter 8 gives you some information on how to access the XFA stream data, for a first glimps look at the sample XfaMovie.cs.
You might also want to look at the iText XML Worker project for easier manipulation of XFA streams.
if you just want to dump the text, try this:
PdfReader reader = new PdfReader(pdfFileName);
String text = "";
nPages = reader.NumberOfPages;
for (int i = 0; i < nPages; i++)
{
text += PdfTextExtractor.GetTextFromPage(reader, i + 1);
}

Modus Operandi - Upload and Resize Multiple images using Zend Framework and HTML5

The good news:
I don't care if it uses ajax or not.
I don't care if the user must install a specific browser to make it work.
I don't care if there isn't any specifc progress bar.
The bad news:
I don't want to use flash.
The user must upload a file from any width or height - however no bigger then 8MB.
The file must be stored on a specific folder (or database column).
A thumbnail must be generated on a specific folder (or database column).
Those images must be associated with a specific record.
This is a "modus operandi" question, I realise that there is to much code involved here.
So:
We first create our form element to support multiple upload, like this:
$element = new Zend_Form_Element_File('multifile');
$element->setAttrib('multiple', true);
$element->setIsArray(true);
We then, need to add some validations and allowed extensions;
Then we need to process the upload;
Once the upload is done, we need to resize those multiple files according to our needs.
We need to store those resized files somewhere else.
Once all this is done, we are ready to display the files associated with a specific database record?
Is this the way to go? Should I have more steps? Am I missing something. I've never done this before, but I'm taking it like a challenge.
First, you create a form. Not much complication here:
$this->addElement('File','Filedata');
$this->Filedata
->setLabel('Select images')
->setDestination('somepath') //define & create it somewhere earlier ;)
->addValidator('Size', false, 1024000)
->addValidator('Extension', false, 'jpg,png,gif')
->setMultiFile(5)
->addValidator('Count', false, array('min'=>0,'max' => 5))
;
In the controller, you receive the images. They will have temporary random names, which you can keep later if you wish (I usually do).
$fileinfo = $form->Filedata->getFileInfo();
$path = 'somepath'; //make sure it exists
for($i=0;$i<5;$i++) {
if($fileinfo['Filedata_'.$i.'_']['tmp_name']) {
$img = new Imagick($fileinfo['Filedata_'.$i.'_']['tmp_name']);
// image processing goes here
file_put_contents('somepath',$img);
}
}
And that's it ;)