Add picture in header to a .docx using novacode DocX - c#

Header header_default = doc.Headers.first;
Paragraph p1 = header_default.InsertParagraph();
I've tried to add a picture in my header in a word file. I tried it with:
p1.AppendPicture(picture);
And also with a table:
Table t1 = header_default.InsertTable(10,2);
t1.Pictures.Add(picture);
Well the big problem is that the code never run to this place it's always crashing by inserting a paragraph to the header:
Paragraph p1 = header_default.InsertParagraph();
or
Table t1 = header_default.InsertTable(10,2);
Error: System.NullReferenceException
I'm new in .net and docx library hope someone can help me with the prblem

This is how I do it, notice I use Doc.Headers.odd rather than first
Doc.AddHeaders();
var headerDefault = Doc.Headers.odd;
var headlineFormat = GetTopHeadlineFormat();
var logo = System.Drawing.Image.FromFile(AppSettings.MulalleyLogoSmall);
using (var ms = new MemoryStream())
{
logo.Save(ms, logo.RawFormat);
ms.Seek(0, SeekOrigin.Begin);
var img = Doc.AddImage(ms);
var pic1 = img.CreatePicture();
var p = headerDefault.InsertParagraph();
p.InsertPicture(pic1);
p.InsertParagraphBeforeSelf(Doc.InsertParagraph());
}

Related

Copying hyperlinks from a cell to another with NPOI

I am trying to copy certain data from a sheet to another, but some cells are simple strings and some are hyperlinks.
If I use StringCellValue on the strings one it's ok, but I haven't found a method to copy the hyperlinks from the original sheet into the new one that I am constructing.
For the construction of the new sheet and for data copying I am using NPOI.
//UPDATE
I have added the code to insert the hyperlinks but when I run the program it shows the following exception: Object reference not set to an instance of an object.
Here is my code:
using (FileStream fs = new FileStream(#"C:\Users\File.xlsx", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
Console.WriteLine("Time to wait....");
templateWorkbook = new XSSFWorkbook(fs);
}
row.GetCell(6).SetCellValue(sheettoget.GetRow(1).GetCell(13).StringCellValue);
var sourceLink = sheettoget.GetRow(1).GetCell(13).Hyperlink;
if(sourceLink != null)
{
Console.WriteLine("Inserting first Juice session...");
var targetLink = new XSSFHyperlink(sourceLink.Type);
targetLink.Address = sourceLink.Address;
}
row.GetCell(6).Hyperlink = targetLink;
row.GetCell(6).CellStyle = sheettoget.GetRow(1).GetCell(13).CellStyle;
You can copy a hyperlink like this, where sourceCell is the cell you are copying from, and targetCell is the cell you are copying to:
targetCell.SetCellValue(sourceCell.StringCellValue);
var sourceLink = sourceCell.Hyperlink;
if (sourceLink != null)
{
var targetLink = new XSSFHyperlink(sourceLink.Type);
targetLink.Address = sourceLink.Address;
targetCell.Hyperlink = targetLink;
// also copy the cell style to ensure the copied link still looks like a link
targetCell.CellStyle = sourceCell.CellStyle;
}

Addin Link [URL] to an Image in Excel cell using open xml

I'm trying to use AddExternalRelationship method, but it doesn't work,
simply I want to add Link to File [my file in this case is an image on a server] using openXML
using (var newDoc = SpreadsheetDocument.Open(xlsDestFilePath, true)) {
var run = new DocumentFormat.OpenXml.Spreadsheet.Run();
var picture = new DocumentFormat.OpenXml.Spreadsheet.Picture();
var shape = new DocumentFormat.OpenXml.Vml.Shape() {
Id = "_x0000_i1025",
Style = "width:453.5pt;height:270.8pt"
};
run.Append(picture);
newDoc.AddHyperlinkRelationship(
new Uri("URL GOES HERE", System.UriKind.Absolute), true);
}
Use AddHyperlinkRelationship
It is clearly stated in the msdn documentation to not use AddExternalRelationship
Refer:
https://msdn.microsoft.com/en-us/library/office/cc562653.aspx
public HyperlinkRelationship AddHyperlinkRelationship(
Uri hyperlinkUri,
bool isExternal,
string id
)

How to edit bookmarks in a Word template using DocumentFormat.OpenXml and save it as a new PDF file?

I'm really having trouble in editing bookmarks in a Word template using Document.Format.OpenXML and then saving it to a new PDF file.
I cannot use Microsoft.Word.Interop as it gives a COM error on the server.
My code is this:
public static void CreateWordDoc(string templatePath, string destinationPath, Dictionary<string, dynamic> dictionary)
{
byte[] byteArray = File.ReadAllBytes(templatePath);
using (MemoryStream stream = new MemoryStream())
{
stream.Write(byteArray, 0, (int)byteArray.Length);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true))
{
var bookmarks = (from bm in wordDoc.MainDocumentPart.Document.Body.Descendants<BookmarkStart>()
select bm).ToList();
foreach (BookmarkStart mark in bookmarks)
{
if (mark.Name != "Table" && mark.Name != "_GoBack")
{
UpdateBookmark(dictionary, mark);//Not doing anything
}
else if (mark.Name != "Table")
{
// CreateTable(dictionary, wordDoc, mark);
}
}
File.WriteAllBytes("D:\\RohitDocs\\newfile_rohitsingh.docx", stream.ToArray());
wordDoc.Close();
}
// Save the file with the new name
}
}
private static void UpdateBookmark(Dictionary<string, dynamic> dictionary, BookmarkStart mark)
{
string name = mark.Name;
string value = dictionary[name];
Run run = new Run(new Text(value));
RunProperties props = new RunProperties();
props.AppendChild(new FontSize() { Val = "20" });
run.RunProperties = props;
var paragraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph(run);
mark.Parent.InsertAfterSelf(paragraph);
paragraph.PreviousSibling().Remove();
mark.Remove();
}
I was trying to replace bookmarks with my text but the UpdateBookmark method doesn't work. I'm writing stream and saving it because I thought if bookmarks are replaced then I can save it to another file.
I think you want to make sure that when you reference mark.Parent that you are getting the correct instance that you are expecting.
Once you get a reference to the correct Paragraph element where your content should go, use the following code to add/swap the run.
// assuming you have a reference to a paragraph called "p"
p.AppendChild<Run>(new Run(new Text(content)) { RunProperties = props });
// and here is some code to remove a run
p.RemoveChild<Run>(run);
To answers the second part of your question, when I did a similar project a few years ago we used iTextSharp to create PDFs from Docx. It worked very well and the API was easy to grok. We even added password encryption and embedded watermarks to the PDFs.

Change object's color inside existiong PDF with iTextSharp

Major part of my job is automation of engineering process, so I have to create simple program, that compares 2 different version of 1 drawn element, by overlapping drawings, in order to review differences. Drawings represent single sheet PDF files.
I'm using .Net Framework and C# 4.5;
iTextSharp library for editing PDF files;
Initially, I'm getting 2 files, read them and create the third one, that contains the result;
var file1 = "file1.pdf";
var file2 = "file2.pdf";
var result = "result.pdf";
using (Stream f1Stream = new FileStream(file1, FileMode.Open))
using (Stream f2Stream = new FileStream(file2, FileMode.Open))
using (Stream resultStream = new FileStream(result, FileMode.Create, FileAccess.ReadWrite))
using (PdfReader f2Reader = new PdfReader(f2Stream))
using (PdfReader f1Reader = new PdfReader(f1Stream))
{
PdfStamper pdfStamper = new PdfStamper(f1Reader, resultStream);
PdfContentByte pdfContentByte = pdfStamper.GetOverContent(1);
var page = pdfStamper.GetImportedPage(f2Reader, 1);
pdfContentByte.AddTemplate(page,2,2);
pdfStamper.Close();
}
The code above makes just that, but a few sequential questions are arising
I want to change the color of elements in the result file i.e. elements that come from the 1st drawing in green and the others from 2nd one - in red color. Maybe I have to change the color of entities in initial 2 PDFs and then to merge;
Initial files have layers, and because they are two sequential revision of the same construction element and differences between them are very few, they have identical layers. And I want to have " layerFoo " and " layerFoo# " in the result PDF. Maybe I have to rename all the layers in one the the 2 initial PDFs and then to merge them.
Аll suggestions are welcomed including usage of another library :)
--> Edit1
Big thanks to Chris Haas! You are absolutely right for token type and string value! iTextRUPS is great helping tool for understanding the structure of PDF files.
Following code is taken from the post that you pointed me out.
The following statement:
stream.SetData(System.Text.Encoding.ASCII.GetBytes(String.Join("\n", newBuf.ToArray())));
updates the stream of the file and then with
using (var fs = new FileStream(file2, FileMode.Create, FileAccess.Write, FileShare.None))
{
var stamper = new PdfStamper(reader, fs);
reader.SetPageContent(1,reader.GetPageContent(1));
stamper.Close();
}
the new file is created with updated stream.
I made 1 simple test file with only 2 lines, change their color and save back to a new file.
No problem!
After that, I tried the same simple operation with real file, that represents real drawing of construction element, the result file was less than half of the original and was broken.
What comes to mind is the updated stream is saved to the new file but the other information inside other containers is not saved, it's just the stream.
Because I stuck with that, I continue to the next step of investigation -> layers
I wrote this code in order to get available layers in a PDF file. I will try to insert more records into layers dictionary to see what will happen.
var resourcesReference = page.Get(PdfName.RESOURCES) as PdfIndirectReference;
var resources = PdfReader.GetPdfObject(resourcesReference) as PdfDictionary;
var propertiesObjhectReferences = resources.Get(PdfName.PROPERTIES);
var properties = PdfReader.GetPdfObject(propertiesObjhectReferences) as PdfDictionary;
foreach (var property in properties.Keys)
{
var layerReference = properties.Get(property);
var layerObject = PdfReader.GetPdfObject(layerReference) as PdfDictionary;
foreach (var key in layerObject.Keys)
{
if (key.ToString()!=PdfName.TYPE.ToString())
{
var layerName = layerObject.GetAsString(key).ToUnicodeString();
}
}
}
If I come back to my main goal from the top of the post, I tends to insert the stream and layers from first file into second in order to obtain result file, that contains objects from the previous 2, painted in different colors + layers from both.
Feel free to suggest me another, more simpler and beautiful solution! I will be happy if you revise my code and correct it! Thank You very much!
EDIT 2
I will simplify the work because the lack of time, just change the color of entities inside one PDF and put it on the background on the other.
const string Pdf = "file1.pdf";
var reader = new PdfReader(Pdf);
var page = reader.GetPageN(1);
var objectReference = page.Get(PdfName.CONTENTS) as PdfIndirectReference;
var stream = (PRStream)PdfReader.GetPdfObject(objectReference);
var streamBytes = PdfReader.GetStreamBytes(stream);
var tokenizer = new PRTokeniser(new RandomAccessFileOrArray(streamBytes));
var newBuf = new List<string>();
while (tokenizer.NextToken())
{
var token = tokenizer.StringValue;
newBuf.Add(token);
if (tokenizer.TokenType == PRTokeniser.TokType.OTHER
&& newBuf[newBuf.Count - 1].Equals("S", StringComparison.CurrentCultureIgnoreCase))
{
newBuf.Insert(newBuf.Count - 1, "0");
newBuf.Insert(newBuf.Count - 1, "1");
newBuf.Insert(newBuf.Count - 1, "1");
newBuf.Insert(newBuf.Count - 1, "RG");
}
}
var resultStream = String.Join("\n", newBuf.ToArray());
stream.SetData(System.Text.Encoding.ASCII.GetBytes(resultStream));
var file2 = Pdf.Insert(Pdf.Length - 4, "Result");
using (var fs = new FileStream(file2, FileMode.Create, FileAccess.Write, FileShare.None))
{
var stamper = new PdfStamper(reader, fs);
reader.SetPageContent(1, reader.GetPageContent(1));
stamper.Close();
}
Result PDF is broken and iTextRUPS throws exception when try to get the stream data from the page.

iTextSharp - Change order of Optional content groups

I have a PDF file with a hierarchy of layers (aka OCG). Using the following code snippet
var ocProps = reader.Catalog.GetAsDict(PdfName.OCPROPERTIES);
var occd = ocProps.GetAsDict(PdfName.D);
var order = occd.GetAsArray(PdfName.ORDER);
I can query the current order from the source file. But I have no idea how to modify this data in order to copy it into a new file with the following snippet.
var reader = new PdfReader(input);
var document = new Document(reader.GetPageSizeWithRotation(1));
var pdfCopyProvider = new PdfCopy(document,
new System.IO.FileStream(output, System.IO.FileMode.Create));
document.Open();
// TBD do OCG modification ...
var importedPage = pdfCopyProvider.GetImportedPage(reader, 1);
pdfCopyProvider.AddPage(importedPage);
document.Close();
Nonetheless, the ocg information is copied to the new pdf file by default. I saw a comment from Bruno Lowagie several weeks ago concerning merging of ocgs https://stackoverflow.com/questions/21573892/itextsharp-merge-impose-pdfs-while-maintaining-layers-optional-content-groups but I'm not sure whether this includes simple copying also.
Any hint on this is welcome. Merging of ocgs might be a topic in future so hints on that topic are welcome, too
Regards,
Holger
Added: I'm using most recent version 5.5.0.0
Added:
In addition to Bruno's answer, I publish the C# version of the manipulatePdf method
public void ManipulatePdf(string source, string destination)
{
var reader = new PdfReader(source);
var ocProps = reader.Catalog.GetAsDict(PdfName.OCPROPERTIES);
var occd = ocProps.GetAsDict(PdfName.D);
var order = occd.GetAsArray(PdfName.ORDER);
var nestedLayers = (PdfObject)order[0];
var nestedLayerArray = (PdfObject)order[1];
var groupedLayers = (PdfObject)order[2];
var radiogroup = (PdfObject)order[3];
order[0] = radiogroup;
order[1] = nestedLayers;
order[2] = nestedLayerArray;
order[3] = groupedLayers;
var stamper = new PdfStamper(reader, new System.IO.FileStream(destination, System.IO.FileMode.Create));
stamper.Close();
reader.Close();
}
You're already very close to the solution. See the ChangeOCGOrder to find out how to change ocg.pdf into ocg_reordered.pdf. (The code is in Java, but you shouldn't have any trouble porting it to... VB.NET?)
You already had something like this:
PdfDictionary catalog = reader.getCatalog();
PdfDictionary ocProps = catalog.getAsDict(PdfName.OCPROPERTIES);
PdfDictionary occd = ocProps.getAsDict(PdfName.D);
PdfArray order = occd.getAsArray(PdfName.ORDER);
This is good: you're looking at the right place!
Now you need something like this:
PdfObject nestedLayers = order.getPdfObject(0);
PdfObject nestedLayerArray = order.getPdfObject(1);
PdfObject groupedLayers = order.getPdfObject(2);
PdfObject radiogroup = order.getPdfObject(3);
order.set(0, radiogroup);
order.set(1, nestedLayers);
order.set(2, nestedLayerArray);
order.set(3, groupedLayers);
In my example, the ORDER array contains 4 elements. I get these four elements, and I change the order of the entries in the original array.
Note that I could also have done something like:
order.addFirst(order.remove(3));
That would have the same effect as the 8 lines of code above, but the 8 lines help you understand the mechanism.

Categories

Resources