Is there any way of suppressing ‘Do you want to save changes to xxx.pdf before closing’ dialog using ABCpdf - abcpdf

We are reading the adobe form template using ABCpdf , populating form fields with values retrieved from database and amending them into a single PDF document and sending the document back as File stream in the HTTP response to the users in a ASP.net MVC App.
This approach is working fine and PDF documents are getting generated successfully. But when the user choose to open the generated PDF file and try to close it, they are being prompted ‘Do you want to save changes to xxx.pdf before closing’ dialog from Adobe Acrobat. Is there any way of suppressing this message using ABC pdf?.
Following is the code we are using to generate the PDF.
public byte[] GeneratePDF(Employee employee, String TemplatePath)
{
string[] FieldNames;
Doc theDoc;
MemoryStream MSgeneratedPDFFile = new MemoryStream();
//Get the PDF Template and read all the form fields inside the template
theDoc = new Doc();
theDoc.Read(HttpContext.Current.Server.MapPath(TemplatePath));
FieldNames = theDoc.Form.GetFieldNames();
//Navigate through each Form field and populate employee details
foreach (string FieldName in FieldNames)
{
Field theField = theDoc.Form[FieldName];
switch (FieldName)
{
case "Your_First_Name":
theField.Value = employee.FirstName;
break;
default:
theField.Value = theField.Name;
break;
}
//Remove Form Fields and replace them with text
theField.Focus();
theDoc.Color.String = "240 240 255";
theDoc.FillRect();
theDoc.Rect.Height = 12;
theDoc.Color.String = "220 0 0";
theDoc.AddText(theField.Value);
theDoc.Delete(theField.ID);
}
return theDoc.GetData();
}

Today I ran into this problem too, but with a PDF with no form fields. I ran #CharlieNoTomatoes code and confirmed the FieldNames collection was definitely empty.
I stepped through the various stages of my code and found that if I saved the PDF to the file system and opened from there it was fine. Which narrowed it down to the code that took the abcpdf data stream and sent it directly to the user (I normally don't bother actually saving to disk). Found this in the WebSuperGoo docs and it suggested my server might be sending some extra rubbish in the Response causing the file to be corrupted.
Adding Response.End(); did the trick for me. The resulting PDF files no longer displayed the message.
byte[] theData = _thisPdf.Doc.GetData();
var curr = HttpContext.Current;
curr.Response.Clear();
curr.Response.ContentType = "application/pdf";
curr.Response.AddHeader("Content-Disposition", "attachment; filename=blah.pdf");
curr.Response.Charset = "UTF-8";
curr.Response.AddHeader("content-length", theData.Length.ToString());
curr.Response.BinaryWrite(theData);
curr.Response.End();

I ran into this problem, as well. I found a hint about "appearance streams" here:
The PDF contains form fields and the NeedAppearances entry in the interactive form dictionary is set to true. This means that the conforming PDF reader will generate an appearance stream where necessary for form fields in the PDF and as a result the Save button is enabled. If the NeedAppearances entry is set to false then the conforming PDF reader should not generate any new appearance streams. More information about appearance streams in PDF files and how to control them with Debenu Quick PDF Library.
So, I looked for "appearance" things in the websupergoo doc and was able to set some form properties and call a field method to get rid of the "Save changes" message. In the code sample above, it would look like this:
Edit: After exchanging emails with fast-and-helpful WebSuperGoo support about the same message after creating a PDF with AddImageHtml that WASN'T fixed by just setting the form NeedAppearances flag, I added the lines about Catalog and Atom to remove the core document NeedAppearances flag that gets set during AddImageHtml.
public byte[] GeneratePDF(Employee employee, String TemplatePath)
{
string[] FieldNames;
Doc theDoc;
MemoryStream MSgeneratedPDFFile = new MemoryStream();
//Get the PDF Template and read all the form fields inside the template
theDoc = new Doc();
theDoc.Read(HttpContext.Current.Server.MapPath(TemplatePath));
FieldNames = theDoc.Form.GetFieldNames();
//Tell PDF viewer to not create its own appearances
theDoc.Form.NeedAppearances = false;
//Generate appearances when needed
theDoc.Form.GenerateAppearances = true;
//Navigate through each Form field and populate employee details
foreach (string FieldName in FieldNames)
{
Field theField = theDoc.Form[FieldName];
switch (FieldName)
{
case "Your_First_Name":
theField.Value = employee.FirstName;
break;
default:
theField.Value = theField.Name;
break;
}
//Update the appearance for the field
theField.UpdateAppearance();
//Remove Form Fields and replace them with text
theField.Focus();
theDoc.Color.String = "240 240 255";
theDoc.FillRect();
theDoc.Rect.Height = 12;
theDoc.Color.String = "220 0 0";
theDoc.AddText(theField.Value);
theDoc.Delete(theField.ID);
}
Catalog cat = theDoc.ObjectSoup.Catalog;
Atom.RemoveItem(cat.Resolve(Atom.GetItem(cat.Atom, "AcroForm")), "NeedAppearances");
return theDoc.GetData();
}

Related

Unable to view PDF attached with ServiceNow table records

I am able to successfully attach PDF file with ServiceNow table record using GlideSysAttachment API and attachment.write() function in script, however whenever I download and try to open same, I get the error shown in below screenshot.
Code snippet
(function execute() {
try{
var rec = new GlideRecord('incident');
var attachment = new GlideSysAttachment();
var incidentSysID = incident.number;
rec.get(incidentSysID);
var fileName = 'Test_Incident.pdf';
var contentType = 'application/pdf'; // Also tried with contentType as 'text/pdf'
var content = pdf_content;
var agr = attachment.write(rec, fileName, contentType, content);<br>
gs.info('The PDF attachment sys_id is: ' + agr);
}catch(err){
gs.log('Got Error: ' + err);
gs.info(err);
}
})()
I also tried "AttachmentCreator" with ecc_queue within script but same error occurs. Below is code for it.
(function execute()
{var attCreator = new GlideRecord('ecc_queue');
attCreator.agent = "AttachmentCreator";
attCreator.topic = "AttachmentCreator";
attCreator.name = "Test.pdf" + ":" + "text/pdf";
//Also tried, "Test.pdf:application/pdf"
attCreator.source = "incident"+":"+ incident.number;
// Record Table name and sys_id of the particular record
var content = pdf_content; // pdf_content is any string variable
var stringUtil = new GlideStringUtil();
var base64String = stringUtil.base64Encode(content);
var isValid=GlideStringUtil.isBase64(base64String);
var base64String= gs.base64Encode(content);
gs.info("Is valid base64 format in ecc_queue ? "+ isValid);
attCreator.payload = base64String; //base64 content of the file
attCreator.insert();
})()
I am able to attach and view excel and word files with similar scripts without any issues. I have checked system properties for attachments but everything looks fine. I am able to view the PDF file uploaded from UI to particular table records however not the one I attach via REST API or scripts.
I have also tried sending encoded data as bytes, base64 or simple string but nothing seems to work. I don't get any errors and attachment id is returned each time on creation of attachment.
After modifying my code slightly for above functions w.r.t scoped application instead of global; I got some information from logs when I debug:
05:38:38.411 Security restricted: File type is not allowed or does not match the content for file Test.pdf
05:38:38.410 Security restricted: MIME type mismatch for file: Test.pdf. Expected type:application/pdf, Actual type: text/plain
05:38:38.394 App:XYZ App x_272539_xyz_ap: Is valid base64 format in ecc_queue ? true
First a comment: This line in your code is accidentally working -- make sure you understand that a task number is not the object sys_id
var incidentSysID = incident.number; // should be incident.sys_id
Next, it's unclear where the PDF content is coming from. IF your complete code is listed, I would expect the errors given as you have noted that pdf_content is "any string variable."
ServiceNow does have a the capability to create a PDF from an HTML argument.
Generating a PDF from HTML
Here's a helpful blog post for getting a PDF (Platform generated) of an existing record:
Love PDF? PDF loves you too

How can we give custom icons to cases in Dynamics 9.0 for customer service?

Is there any way to change the icons of the cases created in Dynamics according to predefined condition? Example I want different icons for the cases based on their priority.
That icon is a placeholder for uploading image to be record specific. Either default entity image icon can be showed or we can upload any image by clicking that icon in entity record level. It will be stored in entityimage attribute of each record. Read more
What you want is uploading image dynamically based on record field value, may be a webresource icon to that entityimage everytime when update happens from a plugin. Refer this code sample:
string m_statusImageRed = #"C:\\Images\\Incident\\status_red.jpg";
string m_statusImageGrey = #"C:\\Images\\Incident\\status_grey.jpg";
if(entity.Attributes.Contains("statecode"))
{
OptionSetValue stateCodeValue = entity.Attributes["statecode"] as OptionSetValue;
byte[] imageBytes = null;
switch (stateCodeValue.Value.ToString())
{
case "0": // active
if (File.Exists(m_statusImageRed))
{
imageBytes = File.ReadAllBytes(m_statusImageRed);
entity.Attributes["entityimage"] = imageBytes;
}
break;
case "1": // resolved
if (File.Exists(m_statusImageGrey))
{
imageBytes = File.ReadAllBytes(m_statusImageGrey);
entity.Attributes["entityimage"] = imageBytes;
}
break;
}
service.Update(entity);
}
Reference

ABCPdf - Image not a suitable format

In the end, my goal is to send a raw image data from the front-end, then split that image into however many pages, and lastly send that pdf back to the front-end for download.
But every time I use the theDoc.addImageFile(), it tells me that the "Image is not in a suitable format". I'm using this as reference: https://www.websupergoo.com/helppdfnet/source/5-abcpdf/doc/1-methods/addimagefile.htm
To troubleshoot, I thought that the image might not be rendering correctly, so I added a File.WriteAllBytes to view the rendered image and it was exactly what I wanted, but still not adding to the PDF. I also tried sending the actual path of a previously rendered image thinking that the new image might not have been fully created yet, but it also gave me the same error. Lastly, I thought PNGs might be problematic and changed to JPG but it did not work.
Here is the code:
[HttpPost]
public IActionResult PrintToPDF(string imageString)
{
// Converts dataUri to bytes
var base64Data = Regex.Match(imageString, #"data:image/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
/* Ultimately will be removed, but used for debugging image */
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string imgName= "Test.jpg";
string filename = Path.Combine(path, imgName);
System.IO.File.WriteAllBytes(filename, binData);
/***********************************************************/
using (Doc theDoc = new Doc())
{
// Using explicit path
theDoc.AddImageFile(#"C:\Users\User\Documents\Test.jpg", 1);
// Using variable
//theDoc.AddImageFile(filename, 1);
// What I really want
//theDoc.AddImageFile(binData , 1);
theDoc.Page = theDoc.AddPage();
theDoc.AddText("Thanks");
Response.Headers.Clear();
Response.Headers.Add("content-disposition", "attachment; filename=test.pdf");
return new FileStreamResult(theDoc.GetStream(), "application/pdf");
}
}
Try something like this (not tested, but cleaned up from my own code):
public int AddImageFile(Doc doc, byte[] data, int insertBeforePageID)
{
int pageid;
using (var img = new XImage())
{
img.SetData(data);
doc.Page = doc.AddPage(insertBeforePageID);
pageid = doc.Page;
doc.AddImage(img);
img.Clear();
}
return pageid;
}
To add a JPEG from a byte array you need Doc.AddImageData instead of Doc.AddImageFile. Note that AddImageFile / AddImageData do not support PNG - for that you would definitely need to use an XImage. The XImage.SetData documentation has the currently supported image formats.

Mailchimp.net API and content struct for editable content not displaying

I'm trying to send content to a campaign template in MailChimp using MailChimp.net API. My template contains `
<b>mc:edit="question"</b>`
And the MailChimp API wants a JSON string in a struct/associative array. However, I can't seem to get the data to show up in the editable section and I've tried several different ways:
CampaignSegmentOptions segmentOptions = new CampaignSegmentOptions();
segmentOptions.Match = "All";
CampaignCreateContent content = new CampaignCreateContent();
content.HTML = "<p>Testing</p>";
CampaignCreateOptions options = new CampaignCreateOptions();
options.Title = "Testing";
options.ListId = listID;
options.ToName = "Test Name";
options.FromEmail = "user#example.com";
options.FromName = "Testing from Example.com";
options.Subject = "Test Subject";
options.FacebookComments = false;
//Using struct attempt
sections s = new sections();
s.question = "What did the lion need?";
//Using string attempt
//String[] s = new string [] {"question\":\"What did the lion need?"};
//Using dictionary attempt
Dictionary<string,string> dict = new Dictionary<string,string>();
dict.Add("question","What did the lion need?");
content.Sections = dict;
Campaign result = mc.CreateCampaign("regular", options, content);
Any suggestions? Thank you in advance.
Solved. In my case the Dictionary approach was the only one that worked. I found that whenever I edited an existing MailChimp template, MailChimp appeared to rewrete my mc:edit fields after I saved them and added their own code making my mc:edit fields break. However, if I exported one of their templates to my desktop, and then imported it back as a new template, I found that editing the template on their website no longer changed my code after saving. I remember seeing a note in the documentation about exporting and importing, but nothing that implied that was the only way to keep my fields intact.

Generate a pdf file and send after querying database for a pass mark

My project is almost done, and thanks to stackoverflow. Now that I have managed to capture Users details and their certificates, I am looking for a way to generate pdf which I will send to those who passed.
I am not looking for the code at the moment. I have an asp.net mvc 3 application which shows Certificates details for my students. Now I want the certificates to be generated then sent by email, all this automated.
First I would like help on how I can generate a pdf from database values and sending the generated pdf wont be a problem.
Using iTextSharp, this code will create and serve a PDF:
public FileStreamResult DownloadPDF()
{
MemoryStream workStream = new MemoryStream();
using(Document document = new Document())
{
PdfWriter.GetInstance(document, workStream).CloseStream = false;
document.Open();
document.SetPageSize(PageSize.LETTER);
document.SetMargins(12, 12, 8, 7);
document.NewPage();
// Create a new Paragraph object with the text, "Hello, World!"
var welcomeParagraph = new Paragraph("Hello, World!");
// Add the Paragraph object to the document
document.Add(welcomeParagraph);
// This is where your data would go
document.Close();
}
workStream.Position = 0;
FileStreamResult fileResult = new FileStreamResult(workStream, "application/pdf");
fileResult.FileDownloadName = "test.pdf";
return fileResult;
}
For more information see Creating PDF Documents with ASP.NET and iTextSharp
There are a lot of tutorials online, but this should get you started.

Resources