Featured Post

SQL Query in SharePoint

The "FullTextSqlQuery" object's constructor requires an object that has context but don't be fooled. This context will no...

Tuesday, August 16, 2011

Refreshing a SP.UI.ModalDialog's parent page

Basic javascript post around refreshing a modal dialog's parent page. For some reason I didn't find much help online even though such a common function. The dialog options have a property called "diaglogReturnValueCallback" where you can create a delegate callback to another function - remember that this function must exist on the same page. Then inside the Callback function I check whether the dialog result is "Ok" and then I call location.reload(true); Here's the code

//set the callback delegate
options.dialogReturnValueCallback = Function.createDelegate(null, CloseCallback);
                   

// the callback function
function CloseCallback(result, target)
{
  if (result == SP.UI.DialogResult.OK)
  {
    location.reload(true);
  }
}

Monday, May 30, 2011

Why does my image become smaller when inserting into Word?

I recently rewrote a report generation system which used to create word documents in Word (running on the server) to a new system which generates these reports in OpenXML. The report output from the new system had to completely match the output from the old system. One of the discrepencies we found was that some images that were being inserted were larger than those in the old system.

With a little investigation I found out that when inserting images into Word, it scales them down to 96 DPI (If larger). One specific image was 300 DPI so when inserting it using OpenXML is was MUCH larger than in the Word Generator output. I've been working with word for 7 years and I've never noticed or knew that this happened!!! Maybe I'm the only one but I thought this was rather interesting - hence this post.
So if you need your OpenXML code to insert your images the same way Word does here is some code to change the dpi of an image if its greater than 96:

Wednesday, April 13, 2011

using Application.ActiveDocument safely

In Word 2007 I would always check whether there were any document in my current application before I call Application.ActiveDocument. This is because if you call this method and there are no documents it would throw an exception.

Now developing in Word 2010, it only gets more complicated. There is now a ActiveProtectedViewWindow as well and this document cannot be retrieved in the applications document list.

So I created a helper method to get the current active document. Here's the code

Monday, March 7, 2011

Issues with AltChunk

I managed to find the underlying problem to a rather annoying bug using AltChunk. I've generated thousands of reports using OpenXml but this one word document would always break xml markup of the document when inserting it using AltChunk.

After stripping the document to only contain the parts that broke it I managed to find out that the "DocumentSettingsPart" contained some elements called SmartTagType. I've never seen these before and not sure what they are used for but the moment I removed them from the document my AltChunk insertion started to work so I now remove them from all my documents before I insert using AltChunk.

I wonder if this is a known bug - will ask on the forum.

Here's some code:

// Get a list of smart tags in the document settings part and remove these
List<SmartTagType> smartTags = mainDocumentPart.DocumentSettingsPart.Settings.Descendants<SmartTagType>();

// Loop backwards otherwise the elements orders change
for (int i = smartTags.Count - 1; i >= 0; i--)
{
  smartTags[i].Remove();
}

Friday, March 4, 2011

Maintain original image size when moving images in open xml

When inserting images into content control boxes using openxml, the image dimensions will not change to those of the image, you will need to manually do this.

Which objects?

There are two places where the image size needs to be set, inside the DocumentFormat.OpenXml.Drawing.Pictures.Picture object and the DocumentFormat.OpenXml.Drawing.Wordprocessing.Inline object. Both of these objects contain an DocumentFormat.OpenXml.Drawing.Wordprocessing.Extent object which contains the Cx and Cy values for the image.

What size?

Now the next problem is knowing what the Cx and Cy values should be set to. Use the System.Drawing.Image object to get the Width and Height properties from your image. However, word image dimensions are not stored in pixels, they are stored in points.

Converting pixels to points can be very complicated when you're working with text but luckily with images there is a constant value we can use to calculate the points from a pixel value, which is 9525.

Code example please?

Wednesday, February 16, 2011

Trouble with OpenXML and MemoryStreams?

I've been struggling for a while with changing my project to use Memory Streams instead of physical files. There were a few things I was doing wrong which you probably wouldn't pick up if you started off using physical files but because I was now refactoring I was missing a few pointers.

A) MainDocumentPart.Document.Save()

When working with the physical file, there is no need to save but when working with a memory stream you need to call this method just before you close your word document.

B) MemoryStream.WriteTo(fileStream)

Because I was working from a document that already existed I would open the document and not see any changes. This was because I was not saving the document back to the file. Very rookie, I know, but it happened and maybe this helps someone out there. More importantly see next point:

C) When to save your memory stream back to the file!!!!

I was writing my memory stream back to the file while the file was still open. This did not throw any exceptions and it still does not make sense to me why this is a problem but it is! Make sure that you always save the memory stream to a file after you have closed the word document but when your memory stream is still open. This caused me hours of pain :( If anybody knows why this happens please let me know.

Here is an example of what your code should look like

Tuesday, January 25, 2011

Moving images in word headers using OpenXML

From what I discovered moving images from one header in a document to another seems to be a huge problem for most people so I decided to try do this myself. I'm not 100% sure what other issues it might cause but I when I run the "Validate" command in the OpenXML Productivity Tools I get no errors and the images I'm moving are displaying correctly so for now I'm giving it the go ahead :)


Background


To move data from one document to another you can use altChunk but this does not copy headers and footers. If this doesn't phase you - you can read more about altChunk on Brian Jones blog: entry: http://blogs.msdn.com/b/brian_jones/archive/2008/12/08/the-easy-way-to-assemble-multiple-word-documents.aspx.


Brian Jones has tons of examples of how to manipulate documents. He also has some nice information about some open source code called "DocumentBuilder" which I stumbled upon but when I run the "Validate" command using the OpenXML Productivity Tools I get an error for each document I tried to merge so I decided this was not a good option for me. If you are interested though check it out here:  http://www.pubsub.com/events/5e5f8d3fd2346a54739b8b6bb0438b82


Another way to move elements from one part of a document to another is to actually use the "FeedData" method and pass in the other element by getting its Stream. This however doesn't work when moving images in headers between documents.

Looking Deeper




Create a blank document and insert any image into it's header. Use the OpenXML Productivity Tool to open the document and expand it's /word/document.xml node. You will see that there are few header xml nodes inside the document xml node. Thats because there are 3 types of headers inside a document or none at all. The three types distuinguish between First, Default and Even.


If you go to expand "w:document", "w:body" you will see "w:sectPr". If you reflect this node you will see the references to your headers. In my document my "Default" header has been referenced using id "rId8". If you reflect your "/word/document.xml node you should see which Header has been assigned "rId8". This helped me to find out which HeaderPart I need to retrieve to find the elements I'm looking for.


Start Coding


A HeaderPart can contain a few things but if I just have a plain header with an image it should contain a "/word/media/image1.png" element as well as a "w:hdr" element. What I did was create a new Header by passing the old headers OuterXML into the constructor and manually copy paste the Images seperately and this worked. Here is some example code:


reportImagePart.FeedData(headerImagePart.GetStream());

private static void ReplaceImages(HeaderPart headerPart, HeaderPart reportHeaderPart) 

{ 
  foreach (IdPartPair partPair in headerPart.Parts)   
  {
    OpenXmlPart openXmlPart = partPair.OpenXmlPart;   
    Type type = openXmlPart.GetType();   
    if (type.Name == "ImagePart")     
    {
      ImagePart headerImagePart = (ImagePart)openXmlPart;     
      string idImage = headerPart.GetIdOfPart(openXmlPart);     
      ImagePart reportImagePart = reportPart.AddNewPart<ImagePart>("image/png", idImage);
      Header headerNew = new Header(headerPart.Header.OuterXml);
    }
  }
}

This could probably be coded better but I'm still in the POC process. If anyone is having any issues with this strategy please let me know!!!