Merging pdf with pdfsharp : exception en the pdfDocument.close() - c#

I would like to create a function with PDFSharp in order to merge some pdf's.
Here is my code
public class PDF_Merge
{
static string [] strTabPdfFiles;
public static string SetPdfToMerge(string strPdfFilesInput)
{
strTabPdfFiles = strPdfFilesInput.Split(';');
return "O";
}
public static string MergeToPdf(string strPdfFilesOutput)
{
try
{
PdfDocument objDocumentFinal = new PdfDocument(strPdfFilesOutput);
foreach (string strDoc in strTabPdfFiles)
{
PdfDocument objDocument = PdfReader.Open(strDoc, PdfDocumentOpenMode.Import);
foreach (PdfPage page in objDocument.Pages)
{
objDocumentFinal.AddPage(page);
}
objDocument.Close();----------> Exception : File cannot be modified
}
objDocumentFinal.Close();
objDocumentFinal.Save(strPdfFilesOutput);
}
catch (Exception ex)
{
return ex.Message;
}
return "O";
}
}
My problem is that on the objDocument.Close() call, i have an exception : "The document cannot be modified".
Anyone could help me about that ?
Great thanks for this lib,
Best regards,
Nixeus

PdfDocument.Close should only be called for documents created with a filename or a stream. Close will then automatically save the contents to the PDF file. You must not call Save in this case.
With the sample code in the question, Close must not be called for objDocument because it was not modified and cannot be saved.
It's OK to call Close for objDocumentFinal to save the changes. You should not call Save for objDocumentFinal because this will only save the changes again.
A PDF file opened with PdfDocumentOpenMode.Import is for import only and cannot be modified.
Try PdfDocumentOpenMode.Modify instead.
Look at the Concatenate Documents sample:
http://www.pdfsharp.net/wiki/ConcatenateDocuments-sample.ashx

I know I am late to the party, but I encountered this issue today.
The close method is trying to save the document, and thus the requirement for .Modify. In this case you don't need objDocument.Close() at all. You can optionally (and probably should?) call objDocument.Dispose().

Related

PdfSharp, Updating Metadata in C# Error

I am using the PdfSharp reference library to attempt to add functionality to my program that adds metadata tags. I am able to successfully add metadata tags to a document, but I am having an issue with updating the tags on existing custom properties. Whenever I attempt to use my method to update the custom properties, I receive the following exception:
"'System.Collections.Generic.KeyValuePair' does not contain a definition for 'Name'."
Could you guys tell me if I am coding the if statement in the foreach loop below to correctly loop through all of the custom elements in the PDF document to see if it exists and needs to be updated? Thanks.
public void AddMetaDataPDF(string property, string propertyValue, string
path)
{
PdfDocument document = PdfReader.Open(path);
bool propertyFound = false;
try {
dynamic properties = document.Info.Elements;
foreach(dynamic p in properties)
{
//Check to see if the property exists. If it does, update
value.
if(string.Equals(p.Name, property,
StringComparison.InvariantCultureIgnoreCase))
{
document.Info.Elements.SetValue("/" + property, new
PdfString(propertyValue));
}
}
// the property doesn't exist so add it
if(!propertyFound)
{
document.Info.Elements.Add(new KeyValuePair<String, PdfItem>
("/"+ property, new PdfString(propertyValue)));
}
}
catch (Exception ex)
{
MessageBox.Show(path + "\n" + ex.Message);
document.Close();
}
finally
{
if(document != null)
{
document.Save(path);
document.Close();
}
}
}
I didn't try your code but a common issue when working with this library is that you need to add a slash before the name of the property for it to be found. The code below will make the trick.
PdfDocument document = PdfReader.Open(path);
var properties = document.Info.Elements;
if (properties.ContainsKey("/" + propertyName))
{
properties.SetValue("/" + propertyName, new PdfString(propertyValue));
}
else
{
properties.Add(new KeyValuePair<String, PdfItem>("/" + propertyName, new PdfString(propertyValue)));
}
document.Save(path);
document.Close();
Also the PDF file shouldn't be write protected. Otherwise you need to use a tool for unlocking the file before calling PdfSharp.

How to generate new PDF using PDFLib 9 in C#?

I am trying to create a new, blank PDF document using PDFLib 9 in my .Net project.
I've looked at some of the tutorials and documentation but could not get it working.
Here is the code I have in a unit test:
public void Test()
{
try
{
var outfile = "newPDF.pdf";
const string docOption = "searchpath={C:\\Users\\me\\Desktop\\Test_Pdfs}";
var p = new PDFlib();
p.set_option(docOption);
p.set_option("errorpolicy=return");
var x = p.begin_document(outfile, "");
if (x != -1)
{
p.begin_page_ext(595.0, 842.0, "topdown");
p.end_page_ext("");
p.end_document("");
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
throw;
}
}
I don't get any errors in the catch, and the test does not fail.
However, when I enable CLR exceptions I get a number of CommunicationAbortedException's and InvalidOperationExceptions that basically talk about how some connection was closed.
This all happens after the last bracket. Also, the PDF is simply not created.
Any insight is really appreciated!
looks like something wrong with searchpath.
I commented out your docOption and PDF is created. this should give you some clue.

Pass the file name of a saved file from one class to another

I'll do my best to explain.
My program takes screen shots which the user can save to their desktop or pass to a media server.
However, to pass to the server I first must have the file location of the image they are saving and so they must first save the file using the save file dialog and I store the location of that in a string which triggers a bool to say that the image has been save. The code looks like this to pass the file to server:
// sfd is the safe file dialog
UploadToServer.HttpUploadFile(Settings.Default.ServerAddress , sfd.FileName.ToString(), "file", "image/jpeg", nvc);
I tried to store the sfd in the following way so I could pass this call to another class:
public String SaveImageLocation
{
get { return sfd.FileName.ToString(); }
set { sfd.FileName.ToString() = value; }
}
But I get the following error:
Error 1 The left-hand side of an assignment must be a variable, property or indexer
What I'm trying to achieve is to take the file upload code and move it to another class. can someone help me with this error?
This is a method/function (call).
ToString()
You cannot assign a method/function (call) to a value..
.ToString() = value;
Try
public String SaveImageLocation
{
get { return sfd.FileName.ToString(); }
set { sfd.FileName = value; }
}
Please note you have not indicated what type FileName is, so it still may not work.

Add an attachment to Bugzilla using XML-RPC in VBA

I am currently developing an Excel macro which allows creating Bugs in a Bugzilla instance.
After some trial and error this now turns out to work fine.
I wanted to enhance the client so that it's also possible to add screenshots to the newly created bug.
The environment I'm using is a little bit tricky:
I have to use MS Excel for my task.
As Excel does not understand XML-RPC, I downloaded an interface DLL (CookComputing.XmlRpcV2.dll from xml-rpc.net) which makes the XML-RPC interface accessible from .NET.
Then I created an additional DLL which can be called from Excel macros (using COM interop).
As already mentioned, this is working fine for tasks like browsing or adding new bugs.
But when adding an attachment to the bug, the image must be converted into a base64 data type. Although this seems to work fine and although the creation of the screenshot seems to succeed, the image seems to be corrupted and cannot be displayed.
Here's what I do to add the image:
The Bugzilla add_attachment method accepts a struct as input:
http://www.bugzilla.org/docs/4.0/en/html/api/Bugzilla/WebService/Bug.html#add_attachment.
This type was defined in C# and is visible also in VBA.
This is the struct definition:
[ClassInterface(ClassInterfaceType.AutoDual)]
public class TAttachmentInputData
{
public string[] ids;
public string data; // base64-encoded data
public string file_name;
public string summary;
public string content_type;
public string comment;
public bool is_patch;
public bool is_private;
public void addId(int id)
{
ids = new string[1];
ids[0] = id.ToString();
}
public void addData(string strData)
{
try
{
byte[] encData_byte = new byte[strData.Length];
encData_byte = System.Text.Encoding.ASCII.GetBytes(strData);
string encodedData = Convert.ToBase64String(encData_byte);
data = new Byte[System.Text.Encoding.ASCII.GetBytes(encodedData).Length];
data = System.Text.Encoding.ASCII.GetBytes(encodedData);
}
catch (Exception e)
{
throw new Exception("Error in base64Encode" + e.Message);
}
}
This is the part in my macro where I would like to add the attachment:
Dim attachmentsStruct As New TAttachmentInputData
fname = attachmentFileName
attachmentsStruct.file_name = GetFilenameFromPath(fname)
attachmentsStruct.is_patch = False
attachmentsStruct.is_private = False
'multiple other definitions
Open fname For Binary As #1
attachmentsStruct.addData (Input(LOF(1), #1))
Close #1
attachmentsStruct.file_name = GetFilenameFromPath(fname)
Call BugzillaClass.add_attachment(attachmentsStruct)
Where BugzillaClass it the interface exposed from my DLL to Excel VBA.
The method add_attachment refers to the XML-RPC method add_attachment.
I assume that my problem is the conversion from the binary file into base64.
This is done using the addData method in my C# DLL.
Is the conversion done correctly there?
Any idea why the images are corrupted?
I think the issue is that you are reading in binary data in the macro, but the addData method is expecting a string. Try declaring the parameter in addData as byte[].

Unregistering datasource and deleting associated CSV file

I'm automating a mailmerge process which uses a CSV file. Part of this process requires creating a database (OpenOffice odb file) and then registering this as a datasource. When I come to delete the database I get an exception stating 'Cannot delete yourFile:It is being used by another person or program'. The problem is that I cannot get the OpenOffice process to release this resource (without killing it). My current code is:
public string DeleteDatasource(string datasourceName)
{
string result = string.Empty;
object databaseContext = _MultiServiceFactory.createInstance("com.sun.star.sdb.DatabaseContext");;
try
{
XDatabaseRegistrations databaseRegistrations = (XDatabaseRegistrations)databaseContext;
if(databaseRegistrations.hasRegisteredDatabase(datasourceName))
{
/* //attempt one
XNameAccess nameAccess = (XNameAccess)OODatabaseContext;
object datasource = nameAccess.getByName(datasourceName);
XNamingService namingservice = (XNamingService)OODatabaseContext;
namingservice.revokeObject(datasourceName);
*/
//attempt 2
string databaseLocation = databaseRegistrations.getDatabaseLocation(datasourceName);
databaseRegistrations.revokeDatabaseLocation(datasourceName);
if (!String.IsNullOrEmpty(databaseLocation))
try
{
//As File Path converts the uno file string into a standard form i.e. "file:///c:/temp/DatabaseFile.odb" to "c:\\temp\\DatabaseFile.odb"
File.Delete(databaseLocation.AsFilepath());
}
catch (System.Exception ex)
{
//some error handling
}
}
return result;
}
catch (System.Exception ex)
{
//More error handling
}
}
Any ideas how I can unregister this datasource such that I can then delete the odb.
Thanks
Managed to get around this issue and just in case anyone else is interested here's how.
The key was to get a reference to the actual datasource and to then dispose of this.
The basic steps are:
Check if a datasource exists with the specified name
Get datasource object
Get the datasource filename
Dispose of the database document associated with the datasource
Dispose the actual datasource
Delete the database file :)
The source code for this looks something like
XNameAccess nameAccess = (XNameAccess)_MultiServiceFactory.createInstance("com.sun.star.sdb.DatabaseContext");
object datasource = nameAccess.getByName(datasourceName);
XDocumentDataSource obj = (XDocumentDataSource)((Any)datasource).Value;
//get the location of the associated odb file before we dispose the document object
//and deregister the datasource
string databaseLocation = databaseRegistrations.getDatabaseLocation(datasourceName);
databaseRegistrations.revokeDatabaseLocation(datasourceName);
((XComponent)obj.DatabaseDocument).dispose();
((XComponent)obj).dispose();
//put in a try block as we want to continue even if this fails
//AsFilepath converts the OpenOffice file path to standard for that can be used with the standard IO file access classes
File.Delete(databaseLocation.AsFilepath());
If there are any improvements please let me know...
Click View,Click Data Sources,
Right Click Registered Databases you wanted to remove,
Click Registered Databases,
Click Delete for the highlighted registered database you want to remove.

Categories