Subscribe to News feed

Use SharePoint Workflows to inject JavaScript into PDFs and print the ‘open date’

Posted at: 2:29 PM on 24 February 2010 by Muhimbi

Calendar Ah, those pesky customers of ours, always looking for some niche functionality that is impossible to include in a generic product. However, using the Workflow Power Pack for SharePoint we can achieve almost anything we can think of…..almost.

Previously I described how to configure PDF Security settings from a SharePoint workflow and how to automatically watermark PDF files from a workflow.  This time I’ll show how to add JavaScript to any PDF file to automatically print the current date (the date the PDF was opened) on every page. In essence this adds a print date without modifying the PDF file every day to include the current date.

A quick introduction for those not familiar with the product: The Muhimbi Workflow Power Pack for SharePoint allows custom C# or VB.NET code to be embedded in SharePoint Designer Workflows without the need to resort to complex Visual Studio based workflows, the development of bespoke Workflow Activities or long development cycles.

The solution presented below executes a workflow whenever a PDF file is added or updated. It iterates over all pages and inserts a form field on each page. Some client side JavaScript is then added to the PDF file that iterates over all newly added fields to insert the current date every time the PDF file is opened.

As the code is well documented it is easy to make further changes and customisations, e.g. change the formatting of the date or position of the label. Note that this has only been tested with a recent version of Adobe Acrobat reader. If you use a different PDF viewer your mileage may vary.

 
Create the workflow as follows:

  1. Download and install the Muhimbi Workflow Power Pack for SharePoint.
     
  2. Download and install the Muhimbi PDF Converter for SharePoint.
    Note that you need version 3.2.0.20 or newer, older versions do not allow JavaScript to be inserted.
     
  3. Download this article’s source code.
     
  4. We need to be able to access functionality in the Muhimbi.SharePoint.DocumentConverter.PDF and System.Drawing assemblies. Add these references to the relevant Web Application using the Workflow Power Pack Central Administration screens as described in the Administration Guide. Make sure to place each reference on a new line.
      
  5. Make sure you have the appropriate privileges to create workflows on a site collection.
     
  6. Create a new workflow using SharePoint Designer.
     
  7. On the Workflow definition screen associate the workflow with the Shared Documents library, tick the boxes next to both ‘Automatically start….’ options and proceed to the next screen.
     
  8. We only want to act on files of type PDF. Although we could have put this validation in the code, in this example we use a workflow condition for it so add a Compare Any Data Source condition and:
     
    a.  Click on the first value followed by the display data binding (fx) button.
    b.  Select Current Item as the Source and select File Type in the Field. Click the OK button to continue.
    d.  Click on the second value and enter pdf.
     
  9. Click the Actions button and insert the Execute Custom Code action.
     
  10. Optionally click parameter 1 and enter a relative or absolute destination path. Leave the parameter empty to save the modified file on top of the existing PDF file. For details about how paths are handled, see this post and search for the words ‘this url’.
     
  11. Insert the C# based code embedded in step #3’s download (also listed below) by clicking this code.
     
    /*********************************************************************************************
                            Muhimbi PDF Converter - JavaScript Watermarking
     
                  Copyright 2010, Muhimbi Ltd - www.muhimbi.com - All rights reserved
     
     The following code shows a simple way of adding JavaScript to existing PDF Files. It adds 
     the current date to each page in the document in order to simulate a 'print date' that is
     always up to date without the need to modify the PDF file. The code is automatically executed 
     when the document is opened in the Adobe Acrobat Viewer.
     
     Error and permission checking as well as other minor features have been omitted for the sake 
     of brevity and clarity.
     
     Ideally PDF Conversion, applying security and watermarking is executed in the same step, see 
     http://www.muhimbi.com/blog/2010/01/configure-pdf-security-from-sharepoint.html
     
     This code requires Muhimbi’s PDF Converter and Workflow Power Pack to be installed.
    *********************************************************************************************/
     
    using System.Drawing;
    using System.IO;
    using Syncfusion.Pdf;
    using Syncfusion.Pdf.Parsing;
    using Syncfusion.Pdf.Graphics;
    using Syncfusion.Pdf.Interactive;
    using Muhimbi.SharePoint.DocumentConverter.PDF;
     
    SPFile spSourceDocument = MyWorkflow.Item.File;
     
    string destinationFileName = spSourceDocument.Name;
    string destinationFolderName = MyWorkflow.Parameter1 as string;
     
    // ** Load the document
    PdfLoadedDocument sourceDocument = new PdfLoadedDocument(spSourceDocument.OpenBinary());
    PdfDocument destinationDocument = new PdfDocument();
     
    // ** Copy all pages from the source document into the destination document 
    // ** so we can add JavaScript actions.
    destinationDocument.ImportPageRange(sourceDocument, 0, sourceDocument.Pages.Count - 1);
    sourceDocument.Dispose();
     
    // ** Iterate over all pages and add a form element
    for (int i = 0; i < destinationDocument.Pages.Count; i++)
    {
        PdfPage destinationPage = destinationDocument.Pages[i];
     
        // ** Create a new field using a unique name
        PdfTextBoxField field = new PdfTextBoxField(destinationPage, "_M_PrintDateField_" + i);
        // ** Center the field
        const int BOX_WIDTH = 200;
        int boxLeft = (int)((destinationPage.Size.Width - BOX_WIDTH) / 2);
        field.Bounds = new RectangleF(boxLeft, 20, BOX_WIDTH, 20);
        // ** Format the field
        PdfFont font = new PdfStandardFont(PdfFontFamily.Helvetica, 12f);
        field.Font = font;
        field.BorderColor = new PdfColor(Color.White);
        field.BackColor = new PdfColor(Color.White);
        field.ReadOnly = true;
        field.TextAlignment = PdfTextAlignment.Center;
     
        destinationDocument.Form.Fields.Add(field);
    }
     
    // ** Create a client side script that iterates over all fields and populates the date
    string jscript = @"
            var pages = " + destinationDocument.Pages.Count + @";
            var today = util.printd('dd-mm-yyyy', new Date());
            for(var i=0; i<pages; i++)
            {
                var field = this.getField('_M_PrintDateField_' + i);
                field.value = 'Today is: ' + today;
            }
            ";
     
    // ** Attach the script to the Document Open event.
    PdfJavaScriptAction jsAction = new PdfJavaScriptAction(jscript);
    destinationDocument.Actions.AfterOpen = jsAction;
     
    // ** Construct the path and file to write the watermarked PDF file to.
    if (string.IsNullOrEmpty(destinationFolderName) == true)
        destinationFolderName = spSourceDocument.ParentFolder.Url;
    SPFolder destinationFolder = Utility.GetSPFolder(destinationFolderName, MyWorkflow.Web);
    string destinationFilePath = string.Format("{0}/{1}", destinationFolder.Url,
                                               destinationFileName);
    SPWeb destinationWeb = destinationFolder.ParentWeb;
    SPFile spDestinationFile = destinationWeb.GetFile(destinationFilePath);
     
    // ** If a document library requires manual checkout and the file is not checked out, then 
    // ** check the file out before uploading.
    if (spDestinationFile.Exists && spDestinationFile.Item.ParentList.ForceCheckout &&
        spDestinationFile.CheckOutStatus == SPFile.SPCheckOutStatus.None)
    {
        spDestinationFile.CheckOut();
    }
     
    // ** Add the file to the site including the meta data
    using (MemoryStream watermarkedFile = new MemoryStream())
    {
        destinationDocument.Save(watermarkedFile);
        spDestinationFile = destinationWeb.Files.Add(destinationFilePath, watermarkedFile,
                                                     spSourceDocument.Item.Properties, true);
    }
     
    // ** Check the file back in if this script was responsible for checking it out.
    if (spDestinationFile.Item.ParentList.ForceCheckout == true)
    {
        spDestinationFile.CheckIn("Auto check-in after PDF watermarking.");
    }
     
  12. Click the Actions button, select Log to History List, click this message and enter File watermarked.
     
  13. Close the Workflow Designer.
     
  14. Update an existing PDF or add a new PDF file to your library to trigger the workflow and apply the JavaScript.

 WaterMarkScript 
Naturally this is just a simple example. Feel free to play around with the code, change which parameters are passed into the workflow, or add different JavaScript. Note that you may want to add a check to the code to check if the JavaScript / fields have previously been added, otherwise duplicate form fields may be added every time the PDF is updated.

Adobe’s JavaScript for Acrobat reference can be found here.

 

.

Labels: , , , ,

SharePoint Workflow Power Pack User Guide – Creating custom methods

Posted at: 2:17 PM on 09 February 2010 by Muhimbi

User-Guide In part 4 of our series of User Guide related blog postings for the Muhimbi Workflow Power Pack for SharePoint we show how to create your own methods in a WPP script in order to keep the code organised and easy to maintain.

A quick introduction In case you are not familiar with the product: The Muhimbi Workflow Power Pack for SharePoint allows custom C# or VB.NET code to be embedded in SharePoint Designer Workflows without the need to resort to complex Visual Studio based workflows, the development of bespoke Workflow Activities or long development cycles.

The following Blog postings are part of this User Guide series:

  1. Language Features: Discusses the script like syntax, the generic workflow action and condition, passing parameters, returning values from a workflow and using the MyWorkflow property.
     
  2. Embedding .net code in a Workflow Condition: Provides a number of examples of how to use the Evaluate Custom Code condition to carry out basic as well as complex conditional tasks.
     
  3. Embedding .net code in a Workflow Action: Contains a number of examples of how to use the Execute Custom Code  to basically carry out any action you can think of in a SharePoint Designer Workflow.
     
  4. Creating Custom Methods (this article): Shows how to create your own methods in your scripts in order to keep the code organised and easy to maintain.


 



Due to its scripting like approach, the Workflow Power Pack does not allow regular .NET methods to be created. However, by cleverly using delegates you can create your own reusable pieces of code.

To facilitate this, the following delegates can be used in addition to the normal delegates available in the .net framework. Note that this only works for C# as VB.net does not allow anonymous methods to be created.
 

delegate void WorkflowMethod(params object[] parameters);

delegate object WorkflowFunction(params object[] parameters);

delegate void WorkflowMethod<ParameterType>(params ParameterType[] parameters);

delegate ReturnType WorkflowFunction<ParameterType, ReturnType>(params ParameterType[] parameters);

 
There is no need to add these delegates to your WPP Code, they are added automatically.

 

Delegate name

Description

WorkflowMethod

Method with a void return type. Accepts any number of Object based parameters that can be accessed from the delegate body using the parameters array.

Parameters may need to be cast to the correct type before they can be used.

WorkflowFunction

Method using a return type of Object. Accepts any number of Object based parameters that can be accessed from the delegate body using the parameters array.

Parameters may need to be cast to the correct type before they can be used.

WorkflowMethod (Using generics)

Generics based version that allows strongly typed parameters to be passed.

WorkflowFunction (Using generics)

Generics based version that allows strongly typed parameters to be passed and returned

 

The example provided below creates a generic Debug method to concatenate information to a string. This string is then returned as the workflow’s ReturnValue, from where it can be written to the Workflow History.
 

string debugString = String.Empty;
 
WorkflowMethod<string> Debug = delegate(string[] parameters)
{
    debugString += parameters[0] + "\r\n";
};
 
WorkflowFunction Calculate = delegate(object[] parameters)
{
    return (int)parameters[0] + (int)parameters[1];
};
 
WorkflowFunction<int, string> Calculate2 = delegate(
                               int[] parameters)
{
    return (parameters[0] + parameters[1]).ToString();
};
 
Debug("Hello");
Debug("World");
Debug(Calculate(1, 2).ToString());
Debug(Calculate2(3, 4));
 
MyWorkflow.ReturnValue = debugString;

 

Labels: , , , ,

Workflow Power Pack 1.1 - Embed C#/VB code in SharePoint Designer Workflows

Posted at: 11:25 AM on by Muhimbi

WPPBox I can’t believe it has only been 6 weeks since we launched the Workflow Power Pack for SharePoint. We are getting great feedback from our customers, who seem to universally love the product. The support call from one frustrated SharePoint Designer workflow developer who was almost in tears stood out particularly.

The version released today adds support for the number one user request, which is the ability to add your own custom methods to the code to allow some degree of usability and reduce the size of scripts.  Read this post for more details about how to use this new functionality.

A quick introduction for those not familiar with the product: The Muhimbi Workflow Power Pack for SharePoint allows custom C# or VB.NET code to be embedded in SharePoint Designer Workflows without the need to resort to complex Visual Studio based workflows, the development of bespoke Workflow Activities or long development cycles.

We have been working very hard to write as many blog posts as possible to provide examples of what can be achieved using the product as well as how to integrate the WPP with our other products such as the PDF Converter and URL Shortener. Have a look at the following posts:

Embed C# code directly into a SharePoint Designer workflow

 
The main changes in version 1.1 are as follows:

743 Add Support for Custom methods using Delegates (See details in User Guide)
763 Trial version causes an error when used after a Pause For Duration activity.

 
For more information check out the following resources:

 
As always, feel free to contact us using Twitter, our Blog, regular email or subscribe to our newsletter.

 

Download your free trial here (1MB).


.

Labels: , , ,

Tuning SharePoint’s workflow engine

Posted at: 11:36 AM on 04 February 2010 by Muhimbi

workflow As most of our products can be used from a SharePoint workflow, it is perhaps useful to know how to tweak SharePoint’s workflow engine for high-load or other specific scenarios.

This article explains in detail what can be tuned and how it can be tuned. If you are in a rush then you can skip over the first 20%.

In summary:

  • Workflow Throttle: Controls how many workflows can be processing at any one time on the entire server farm. This setting does not control how many workflows can be "In Progress" concurrently, but rather how many can be actively using the processor. When this number is exceeded, workflow instances that are started and events that wake up dehydrated workflows are queued for later processing. The default value is 15. This setting is per farm, so the number of front-end Web servers is irrelevant

    stsadm -o setproperty -pn workflow-eventdelivery-throttle -pv "25"
     
     
  • Workflow Batch Size: Workflows, by their very nature, do not execute in a nonstop, linear fashion. Instead, they run for a little while, pause, run some more, and then pause again, continuing in this manner until the process is complete. Although an outside observer or a developer might disagree, workflows are a collection of batches and the workflow engine is simply a glorified batch controller.

    stsadm -o setproperty -pn workitem-eventdelivery-batchsize -pv "125"
     
     
  • Workflow Timeout: The timeout setting specifies the amount of time (in minutes) in which a workflow timer job must complete before it is considered to have stopped responding and is forced to stop processing. Jobs that time out are returned to the queue to be reprocessed later. The default timeout period is five minutes

    stsadm -o setproperty -pn workflow-eventdelivery-timeout -pv "10"
     
     
  • Workflow Timer Interval: The workflow timer interval specifies how often the workflow SPTimer job fires to process pending workflow tasks. This interval also represents the granularity of delay timers within your workflow. If a timer is set to delay for one minute, but the interval timer fires only every five minutes, the workflow delays for five minutes, not one minute

    stsadm -o setproperty -pn job-workflow -pv value -url http://myWssServer
     

For our products you may need to tweak Workflow Timeout for very long running PDF Conversions. Changing the Timer Interval can be useful during development when using Pause Until or Pause For workflow Activities.

.

Labels: , , , ,

Adding a watermark to a PDF file from a SharePoint Workflow

Posted at: 12:18 PM on 26 January 2010 by Muhimbi

We get a great amount of interest from our existing PDF Converter customers for the Workflow Power Pack for SharePoint. I am not really surprised as there is a lot of of synergy between the two.

Last week I described how to configure PDF Security settings from a SharePoint workflow. This time I’ll describe another common request; adding a watermark to a PDF File.

A quick introduction for those not familiar with the product: The Muhimbi Workflow Power Pack for SharePoint allows custom C# or VB.NET code to be embedded in SharePoint Designer Workflows without the need to resort to complex Visual Studio based workflows, the development of bespoke Workflow Activities or long development cycles.

The solution presented below executes a workflow whenever a PDF file is added or updated. As part of the workflow it loads portrait and landscape based watermarks and applies the relevant template to each page of the document. The workflow author can specify if the watermark goes in the foreground or the background, the SharePoint location of the watermarks as well as the level of transparency. As the code is well documented it is easy to make further changes and customisations, e.g. the PDF file that needs to be watermarked may not be the file the workflow is acting on.

 WatermarkedPages

 
Create the workflow as follows:

  1. Download and install the Muhimbi Workflow Power Pack for SharePoint.
     
  2. Download and install the Muhimbi PDF Converter for SharePoint.
    Note that you need version 3.1.2.18 or newer, older versions do not allow watermarking.
     
  3. Download this article’s source code and sample watermarks.
     
  4. We need to be able to access functionality in the Muhimbi.SharePoint.DocumentConverter.PDF and System.Drawing assemblies. Add these references to the relevant Web Application using the Workflow Power Pack Central Administration screens as described in the Administration Guide. Make sure to place each reference on a new line.
      
  5. Make sure you have the appropriate privileges to create workflows on a site collection.
     
  6. Create a new workflow using SharePoint Designer.
     
  7. On the Workflow definition screen associate the workflow with the Shared Documents library, tick the boxes next to both ‘Automatically start….’ options and proceed to the next screen.
     
  8. We only want to act on files of type PDF. Although we could have put this validation in the code, in this example we use a workflow condition for it so add a Compare Any Data Source condition and:
     
    a.  Click on the first value followed by the display data binding (fx) button.
    b.  Select Current Item as the Source and select File Type in the Field. Click the OK button to continue.
    d.  Click on the second value and enter pdf.
     
  9. Click the Actions button and insert the Execute Custom Code action.
     
  10. Optionally click parameter 1 and enter a relative or absolute destination path. Leave the parameter empty to save the watermarked file on top of the existing PDF file. For details about how paths are handled, see this post and search for the words ‘this url’.
     
  11. Insert the C# based code embedded in step #3’s download (also listed below) by clicking this code.
     
    /*********************************************************************************************
                                 Muhimbi PDF Converter - Watermarking
     
                  Copyright 2010, Muhimbi Ltd - www.muhimbi.com - All rights reserved
     
     The following code shows a simple way of adding a watermark to existing PDF Files. 
     Error and permission checking as well as other minor features have been omitted for the sake 
     of brevity and clarity.
     
     Ideally PDF Conversion, applying security and watermarking is executed in the same step, see 
     http://www.muhimbi.com/blog/2010/01/configure-pdf-security-from-sharepoint.html
     
     This code requires Muhimbi’s PDF Converter and Workflow Power Pack to be installed.
    *********************************************************************************************/
     
    using System.Drawing;
    using System.IO;
    using Syncfusion.Pdf;
    using Syncfusion.Pdf.Parsing;
    using Syncfusion.Pdf.Graphics;
    using Muhimbi.SharePoint.DocumentConverter.PDF;
     
    SPFile spSourceDocument = MyWorkflow.Item.File;
     
    string destinationFileName = spSourceDocument.Name;
    string destinationFolderName = MyWorkflow.Parameter1 as string;
    string watermarkDocumentPortraitPath = @"Shared Documents/Watermarks/WatermarkA4Portrait.pdf";
    string watermarkDocumentLandscapePath = @"Shared Documents/Watermarks/WatermarkA4Landscape.pdf";
     
    // ** z-order and transparency of the watermark
    bool watermarkInBackground = true;
    float watermarkTransparancy = 0.25f;
     
    // ** Load the document and watermarks
    PdfLoadedDocument sourceDocument = new PdfLoadedDocument(spSourceDocument.OpenBinary());
    SPFile spWatermarkDocumentPortrait = MyWorkflow.Web.GetFile(watermarkDocumentPortraitPath);
    PdfLoadedDocument watermarkDocumentPortrait = new PdfLoadedDocument(
                                                    spWatermarkDocumentPortrait.OpenBinary());
    SPFile spWatermarkDocumentLandscape = MyWorkflow.Web.GetFile(watermarkDocumentLandscapePath);
    PdfLoadedDocument watermarkDocumentLandscape = new PdfLoadedDocument(
                                                    spWatermarkDocumentLandscape.OpenBinary());
     
    // ** Create the PDF Templates
    PdfTemplate watermarkTemplatePortrait = watermarkDocumentPortrait.Pages[0].CreateTemplate();
    PdfTemplate watermarkTemplateLandscape = watermarkDocumentLandscape.Pages[0].CreateTemplate();
     
    // ** Iterate over all pages and apply watermark
    foreach (PdfPageBase page in sourceDocument.Pages)
    {
        // ** Is the current page portrait or landscape?
        PdfTemplate watermarkTemplate = null;
        if (page.Size.Width > page.Size.Height)
            watermarkTemplate = watermarkTemplateLandscape;
        else
            watermarkTemplate = watermarkTemplatePortrait;
     
        // ** Place watermark behind or in front of text?
        if (watermarkInBackground == true)
        {
            PdfTemplate pageTemplate = page.CreateTemplate();
            page.Layers.Clear();
            PdfGraphics g = page.Graphics;
            g.SetTransparency(watermarkTransparancy);
            g.DrawPdfTemplate(watermarkTemplate, PointF.Empty, page.Size);
            g.SetTransparency(1f);
            g.DrawPdfTemplate(pageTemplate, PointF.Empty, page.Size);
        }
        else
        {
            PdfGraphics g = page.Graphics;
            g.SetTransparency(watermarkTransparancy);
            g.DrawPdfTemplate(watermarkTemplate, PointF.Empty, page.Size);
        }
    }
     
    // ** Construct the path and file to write the watermarked PDF file to.
    if (string.IsNullOrEmpty(destinationFolderName) == true)
        destinationFolderName = spSourceDocument.ParentFolder.Url;
    SPFolder destinationFolder = Utility.GetSPFolder(destinationFolderName, MyWorkflow.Web);
    string destinationFilePath = string.Format("{0}/{1}", destinationFolder.Url,
                                               destinationFileName);
    SPWeb destinationWeb = destinationFolder.ParentWeb;
    SPFile spDestinationFile = destinationWeb.GetFile(destinationFilePath);
     
    // ** If a document library requires manual checkout and the file is not checked out, then 
    // ** check the file out before uploading.
    if (spDestinationFile.Exists && spDestinationFile.Item.ParentList.ForceCheckout &&
        spDestinationFile.CheckOutStatus == SPFile.SPCheckOutStatus.None)
    {
        spDestinationFile.CheckOut();
    }
     
    // ** Add the file to the site including the meta data
    using (MemoryStream watermarkedFile = new MemoryStream())
    {
        sourceDocument.Save(watermarkedFile);
        spDestinationFile = destinationWeb.Files.Add(destinationFilePath, watermarkedFile,
                                                     spSourceDocument.Item.Properties, true);
    }
     
    // ** Check the file back in if this script was responsible for checking it out.
    if (spDestinationFile.Item.ParentList.ForceCheckout == true)
    {
        spDestinationFile.CheckIn("Auto check-in after PDF watermarking.");
    }
     
  12. Click the Actions button, select Log to History List, click this message and enter File watermarked.
     
  13. Close the Workflow Designer.
     
  14. In the Shared Documents library create a sub folder named Watermarks and copy the 2 watermark files that are part of step #3’s download into it. If the watermarks are named differently or stored in a different location then update the paths in the script accordingly. Note that the sample watermarks are exactly A4 sized but they work fine on differently sized documents.
     
  15. Update an existing PDF or add a new PDF file to your library to trigger the workflow and apply the watermarks.
     

WaterMarkScript 

Naturally this is just a simple example. Feel free to play around with the code, change which parameters are passed into the workflow, modify where watermarked files are written to or add dynamic text as a watermark. Leave a comment below if you are trying to do anything specific.

.

Labels: , , , ,

How we license our products – Make sure your organisation is compliant

Posted at: 12:03 PM on 22 January 2010 by Muhimbi

LicenseAny organisation that deals with computer software, free or otherwise, must be aware of the License Agreement that comes with a software product. How many computers can the software be used on, by how many users and how long is the license valid are only some of the questions that need to be answered.

We have invested quite some time in making our Software License Agreement readable for people without a legal background. However, it is difficult to cover all grounds using plain English.

This post attempts to explain the key elements of our Software Agreement in plain English. Note that this is only a summary and does not replace the actual License Agreement.

The following topics are discussed in this post:

     

Summary of available licenses

We use a graded licensing system to match your budget and exact needs. The following license types are available:
 

License-Matrix

 

  • Free evaluation version: If you install the software without a license then you are using the evaluation version. The software is fully functional without any time limits, but an evaluation message will be displayed on most screens and in any generated document. You are not permitted to use any evaluation software in your production environment. Support is provided using any of the means in the Support area on our site.
     
  • Web Application License: This license is sold at a considerable discount to allow small organisations with just a single SharePoint server and Web Application to get started with our software. If you have a single SharePoint server then you can use this license on a single Web Application on as many Site Collections as you like.
     
  • Web Farm License: If you have more than one server in your SharePoint farm or want to use our software on multiple Web Applications then you may want to consider this license. If you want to use our software on multiple farms or if your farm is spread over multiple geographical locations then you need either a Site or OEM license as described below.
     
  • Site License: If you have multiple separate SharePoint Farms, for example when you are a hosting company, then this license may be the best option as it allows the software to be used on an unlimited number of separate SharePoint farms at a single location.
     
  • OEM License: If your SharePoint Farm or Farms spreads multiple physical locations, e.g. across a data centre, Disaster recovery site and or local branch offices OR if you want to bundle our Software as part of your own solution then the OEM Subscription is most likely the best option. Please read the details in the Software License Agreement if you want to bundle our software with your own solution. Note that you are not allowed to use our Products to develop derived works that offer similar functionality as the Product or expose the features of the Product for use by an unlicensed third party unless agreed with Muhimbi.
     
  • OEM License + Source Code: If you need all the benefits of the OEM License and / or you need access to the source code to make modifications specific to your organisation, then this license type is the best option. Note that we do not provide support for our software once changes have been made to the source code. Please read the details in the Software License Agreement if you want to bundle our software with your own solution. Note that you are not allowed to use our Products to develop derived works that offer similar functionality as the Product or expose the features of the Product for use by an unlicensed third party unless agreed with Muhimbi.

 

Renewing Licenses / Support licenses

Independent of the type of license purchased, you automatically receive a 1 year support license, which entitles you to free updates and access to our support desk using any of the means listed on the Contact Us page.

After the support license has expired your software will continue to work, but you can no longer download new versions released after the expiry of the license. You can renew your support license for 30% of the current retail price, which is not necessarily the price you originally bought the product for, although they may be the same.

 

What servers / environments do you need a license for

Some vendors charge extra license fees for Development or Test environments, which - quite frankly - we find a questionable practice. Having said that, some organisations run the same software in multiple environments. The most common environments are summarised below with an explanation about any extra licenses needed.

  • Development: This environment is commonly used by Software or SharePoint developers to create or update solutions using tools such as Visual Studio and SharePoint Designer. Providing our software is used for development purposes only and not used for any production use then you don’t need a separate license for this environment. Examples of Production use in a Development environment is running our PDF Converter on the Development Team’s SharePoint Server if this server is located in the Development subnet and used for production use, e.g. storing documents for the development projects.
     
  • Systems Test: Once development on a software project has finished, the solution is commonly installed and tested in a clean test environment that resembles the Production environment. Providing this environment is not used for Production use, it rarely is, you do not need an extra license.
     
  • User Acceptance Test: Once the development team has finished development, the end-users usually test the solution as well to see if it matches the requirements and functions as expected. Some organisations use the Systems Test environment for this, but other organisations have a separate UAT environment. Providing this environment is not used for Production use, it rarely is, you do not need an extra license.
     
  • Support: Some organisations run an identical copy of their Production environment in a so called Support environment. Quite often this environment runs very recent data based on backups taken the day before. Support staff can assist users and troubleshoot problems on a relatively up to date copy of the system without impacting the data in the Production system. From a licensing perspective this is a grey area as this environment is sometimes used for Production use. For example, if a Production user requests assistance with the conversion of a PDF file and this conversion is then carried out by a member of the support team in the Support environment and the resulting file is transferred to the user then this is considered Production use and you need a license for this environment.
     
  • Staging: Depending on the kind of solutions in place, an organisation or team may need a staging environment. Staging environments are commonly used, but not limited to, content management based solutions to prepare content for an Intranet or public web site. Providing this environment runs on a farm separate from the Production farm you need a license for this environment:
     
  • Production: Production environments always need a license.
     
  • Disaster Recovery: Many of the larger organisation mirror their production environment in an off-site Disaster Recovery Centre. From a licensing perspective we consider Disaster Recovery Centres to be Production environments, even if disaster never strikes and the environment is never used.
    In summary, if you need a license for more than one environment, get a Site License if all servers are based in one physical location. Purchase an OEM License if your servers are spread over multiple locations.

 

Licensing requirements for non SharePoint based deployments

Our products mainly focus on use from a SharePoint environment. However, some products can also be used from non SharePoint environments as well. For example, our PDF Conversion Service can run as a standalone service and be accessed from any application that supports Web Services.

The licenses are largely the same, with the exception of the Web Application License, which is only available for SharePoint based environments.

  • Web Farm License: Get this license if you want to access our software from a single solution on an unlimited number of servers located at a single location, using an unlimited number of developers and end-users.
     
  • Site License: If you intend to access our software from multiple solutions located on servers at the same site, then get this license.
     
  • OEM License: If you want to access our software from servers spread across more than one physical location then get this license.
     
  • OEM License + Source Code: If you need all the benefits of the OEM License and / or you need access to the source code to make modifications specific to your organisation, then this license type is the best option. Note that we do not provide support for our software once changes have been made to the source code. Please read the details in the Software License Agreement if you want to bundle our software with your own solution. Note that you are not allowed to use our Products to develop derived works that offer similar functionality as the Product or expose the features of the Product for use by an unlicensed third party unless agreed with Muhimbi.
     

I realise this post is almost longer than the License Agreement is is trying to explain, but I hope it clarifies our licensing position. If you have any further questions then please check out the following sources or contact us at licensing@muhimbi.com.

.

Labels: , , , , ,

Configure PDF Security from a SharePoint Workflow

Posted at: 4:35 PM on 15 January 2010 by Muhimbi

combination_lock Our PDF Converter for SharePoint is getting great reviews, but naturally we cannot please everyone, or at least not yet. One of the requests we get from time to time is to add support for the ability to specify PDF Security settings (Open Password, Owner Password, Block Print, Block Copy etc).

The thing is, our underlying engine and Web Service interface already support this functionality. However, the user interface and workflow action have not yet been updated. In this article we describe how to access this ‘hidden’ functionality from a workflow using the Workflow Power Pack.

A quick introduction for those not familiar with the product: The Muhimbi Workflow Power Pack for SharePoint allows custom C# or VB.NET code to be embedded in SharePoint Designer Workflows without the need to resort to complex Visual Studio based workflows, the development of bespoke Workflow Activities or long development cycles.

The solution presented below automatically converts any updated or newly created files to PDF format and applies the DisablePrint and DisableContentCopy security flags to the file. As the code is well documented it is easy to make further changes and customisations.

image

 
Create the workflow as follows:

  1. Download and install the Muhimbi Workflow Power Pack for SharePoint.
     
  2. Download and install the Muhimbi PDF Converter for SharePoint.
     
  3. We need to be able to access functionality in the Muhimbi.SharePoint.DocumentConverter.PDF, System.ServiceModel and System.Runtime.Serialization assemblies. Add these references to the relevant Web Application using the Workflow Power Pack Central Administration screens as described in the Administration Guide. Make sure to place each reference on a new line.
      
  4. Make sure you have the appropriate privileges to create workflows on a site collection.
     
  5. Create a new workflow using SharePoint Designer.
     
  6. On the Workflow definition screen associate the workflow with the library of your choice, tick the boxes next to both ‘Automatically start….’ options and proceed to the next screen.
     
  7. To prevent the code from acting on files that are already in PDF format, add a Compare Any Data Source condition and:
     
    a.  Click on the first value followed by the display data binding (fx) button.
    b.  Select Current Item as the Source and select File Type in the Field. Click the OK button to continue.
    c.  Click equals and change it to not equals.
    d.  Click on the second value and enter pdf.
     
  8. Click the Actions button and insert the Execute Custom Code action.
     
  9. Click parameter 1 and optionally enter a relative or absolute destination path (For details see this post and search for the words ‘this url’). Leave the parameter empty to write the PDF file to the same directory as the source file.
     
  10. Download the source code or insert the C# based code listed below by clicking this code.
     
    /********************************************************************************************
                                      Muhimbi PDF Converter
     
                  Copyright 2010, Muhimbi Ltd - www.muhimbi.com - All rights reserved
     
     The following code is a simplification of the code that is normally executed by the Muhimbi 
     PDF Converter Workflow Action. Error and permission checking as well as other minor features
     have been omitted for the sake of brevity and clarity.
     
     This code allows more control over the PDF Conversion process compared to what is possible 
     with the Out-Of-The-Box action, for example: PDF Security Options, Use of PDF/A, Quality, 
     Enable Macros and the ability to specify a password to open a source file.
     
     This code requires Muhimbi’s PDF Converter and Workflow Power Pack to be installed.
     
     For details about the Web Services interface see:
     
     http://www.muhimbi.com/blog/2009/12/converting-office-files-to-pdf-format.html
     
    ********************************************************************************************/
     
    using Muhimbi.SharePoint.DocumentConverter.PDF;
    using Muhimbi.SharePoint.DocumentConverter.PDF.WebServiceClient;
    using System.Collections;
     
    // ** Set all variables required for the conversion of the file.
    SPFile sourceFile = MyWorkflow.Item.File;
    // ** Specify an empty string or null to use the same directory as the source file. 
    // ** Alternatively specify an absolute or relative (to the web) path, e.g. 
    // ** subsite1/Shared Documents/PDF  or /sites/HumanResources/subsite1/Shared Documents/PDF
    string          destinationFolderName   = MyWorkflow.Parameter1 as string;
    string          destinationFileName     = Utility.ExtractFileName(sourceFile.Name) + ".pdf";
    string          openPassword            = "";
    string          ownerPassword           = "A Nice And Strong Password!";
    SecurityOptions securityOptions         = SecurityOptions.DisablePrint | 
                                              SecurityOptions.DisableContentCopy;
    bool            copyMetadata            = true;
     
    // ** Get a reference to the PDF Converter web service.
    DocumentConverterServiceClient client   = WebServiceConverterHelper.OpenService();
     
    //** Set the various open options
    OpenOptions openOptions                 = new OpenOptions();
    openOptions.Password                    = "";
    openOptions.OriginalFileName            = sourceFile.Name;
    openOptions.FileExtension               = Utility.ExtractFileExtension(sourceFile.Name);
    openOptions.AllowMacros                 = MacroSecurityOption.None;
    openOptions.RefreshContent              = true;
     
    //** Specify the various security settings
    ConversionSettings conversionSettings   = new ConversionSettings();
    conversionSettings.Fidelity             = ConversionFidelities.Full;
    conversionSettings.Format               = OutputFormat.PDF;
    conversionSettings.Quality              = ConversionQuality.OptimizeForPrint;
    conversionSettings.Range                = ConversionRange.VisibleDocuments;
    conversionSettings.StartPage            = 0;
    conversionSettings.EndPage              = 0;
    conversionSettings.GenerateBookmarks    = BookmarkGenerationOption.Automatic;
    conversionSettings.PDFProfile           = PDFProfile.PDF_1_5;
    // ** Specify either an Open or Owner Password in order to activate the security Options
    conversionSettings.OpenPassword         = openPassword;
    conversionSettings.OwnerPassword        = ownerPassword;
    conversionSettings.SecurityOptions      = securityOptions;
     
    // ** Read the content of the source file
    byte[] sourceFileArray = sourceFile.OpenBinary();
    // ** Carry out the actual conversion to PDF
    byte[] convertedFile = client.Convert(sourceFileArray, openOptions, conversionSettings);
     
    // ** Construct the path and file to write the PDF file to.
    if (string.IsNullOrEmpty(destinationFolderName) == true)
        destinationFolderName = sourceFile.ParentFolder.Url;
    SPFolder destinationFolder = Utility.GetSPFolder(destinationFolderName, MyWorkflow.Web);
    string destinationFilePath = string.Format("{0}/{1}", destinationFolder.Url, 
                                               destinationFileName);
    SPWeb destinationWeb = destinationFolder.ParentWeb;
    SPFile spDestinationFile = destinationWeb.GetFile(destinationFilePath);
     
    // ** If a document library requires manual checkout and the file is not checked out, then 
    // ** check the file out before uploading.
    if (spDestinationFile.Exists && spDestinationFile.Item.ParentList.ForceCheckout && 
        spDestinationFile.CheckOutStatus == SPFile.SPCheckOutStatus.None)
    {
        spDestinationFile.CheckOut();
    }
     
    // ** Copy metadata, if requested.
    if (copyMetadata == true && 
        sourceFile.Name.EndsWith("x", StringComparison.InvariantCultureIgnoreCase) == false)
    {
        // ** Pre office 2007 formats (without the trailing x) are treated differently 
        // ** from the office 2007 formats when it comes to copying meta data.
        Hashtable metadata = sourceFile.Item.Properties;
        // ** Add the file to the site including the meta data
        spDestinationFile = destinationWeb.Files.Add(destinationFilePath, convertedFile, 
                                                     metadata, true);
    }
    else if (copyMetadata == true)
    {
        // ** Add the file to the site.
        spDestinationFile = destinationWeb.Files.Add(destinationFilePath, 
                                                     convertedFile, null, true);
        // ** Copy the Actual meta data to the newly created file.
        foreach (SPField field in sourceFile.Item.Fields)
        {
            if (field.ReadOnlyField == false && 
    spDestinationFile.Item.Fields.ContainsField(field.InternalName) == true)
            {
                spDestinationFile.Item[field.InternalName] = sourceFile.Item[field.InternalName];
            }
        }
        // ** Update the meta data
        spDestinationFile.Item.Update();
    }
    else
    {
        // ** Actively strip all meta data
        Hashtable metadata = new Hashtable(sourceFile.Item.Properties.Count);
        foreach (Object key in sourceFile.Item.Properties.Keys)
        {
            metadata.Add(key, string.Empty);
        }
        // ** Add the file to the site with all meta data stripped
        spDestinationFile = destinationWeb.Files.Add(destinationFilePath, convertedFile, 
                                                     metadata, true);
    }
     
    // ** Check the file back in if this script was responsible for checking it out.
    if (spDestinationFile.Item.ParentList.ForceCheckout == true)
    {
        spDestinationFile.CheckIn("Auto check-in after PDF Conversion");
    }
     
  11. Click the Actions button, select Log to History List, click this message and enter File converted to PDF.
     
  12. Close the Workflow Designer and update or add an item to your library to trigger the workflow.
     
SetPDFSecurity

 
Naturally this is just a simple example. Feel free to play around with the code, change which parameters are passed into the workflow or modify where converted PDF files are written to.

.

Labels: , , , ,

Send rich emails with attachments from a SharePoint Designer Workflow

Posted at: 1:49 PM on 29 December 2009 by Muhimbi

emailOne of the most common (sub) tasks executed from a SharePoint workflow is the submission of an email. SharePoint 2007 ships with an Email Workflow Action out of the box, which is unfortunately very limited in its abilities. For example, it is not possible to include attachments, specify the From Address, set the Priority or specify the SMTP server to use.

In this blog post I’ll describe how to send an email from a workflow that automatically includes all files / attachments for the current item from a SharePoint Designer workflow using the Workflow Power Pack.

A quick introduction for those not familiar with the product: The Muhimbi Workflow Power Pack for SharePoint allows custom C# or VB.NET code to be embedded in SharePoint Designer Workflows without the need to resort to complex Visual Studio based workflows, the development of bespoke Workflow Activities or long development cycles.

The solution presented below uses the standard Build Dynamic String Action to create the body of the email. This body is then passed as Parameter 1 to the Execute Custom Code Action. Parameter 2 is used to specify the To Address. This code is a great starting point for further customisation. For more details see the standard .net MailMessage and SmtpClient classes.

Create the workflow as follows:

  1. Download and install the Muhimbi Workflow Power Pack for SharePoint.
     
  2. Make sure you have the appropriate privileges to create workflows on a site collection.
     
  3. Create a new workflow using SharePoint Designer.
     
  4. On the Workflow definition screen associate the workflow with the list or library of your choice, tick the boxes next to both ‘Automatically start… ’ items and proceed to the next screen.
     
  5. Click the Actions button and insert the Build Dynamic String action.
     
  6. Click dynamic string and enter an HTML based email.
     
  7. Click variable1 and create a new string based variable named mailMessage.
     
  8. Click the Actions button and insert the Execute Custom Code action.
     
  9. Click parameter 1, open the Workflow Lookup dialog and select Source: Workflow Data, Field: mailMessage.
     
  10. Click parameter 2 end enter the address to send the email to. Naturally this could be a lookup value as well.
     
  11. Insert the following C# based code by clicking this code.
     
    using System.Net.Mail;
    using System.IO;
     
    string smtpServer = MyWorkflow.Site.WebApplication.OutboundMailServiceInstance.Server.Address;
    SPListItem item = MyWorkflow.Item;
     
    // ** Get the standard sender address for the Web App. 
    // ** Feel free to replace with an address of your choice.
    string from = MyWorkflow.Site.WebApplication.OutboundMailSenderAddress;
    string to = (string) MyWorkflow.Parameter2;
    string subject = "New SharePoint Files";
    string body = (string) MyWorkflow.Parameter1;
    // ** Process any 'workflow variables' that may exist in the body.
    body =  Helper.ProcessStringField(body, MyWorkflow.ActivityExecutionContext.Activity, null);
     
    MailMessage message = new MailMessage(from, to, subject, body);
    message.IsBodyHtml = true;
    message.Priority = MailPriority.Normal;
     
    // ** Add optional CCs and BCCs
    //message.Bcc.Add("someone@somewhere.com");
    //message.CC.Add("someone@somewhere.com");
     
    // ** Do we need to attach a single file or a list of files attached to a list item?
    if (item.File != null)
    {
        // ** Attach the file itself
        Stream attachmentStream = new MemoryStream(item.File.OpenBinary());
        Attachment attachment = new Attachment(attachmentStream, item.File.Name);
        message.Attachments.Add(attachment);
    }
    else
    {
        // ** Attach all files that are part of the list item
        foreach (string fileName in item.Attachments)
        {
            SPFile file = item.ParentList.ParentWeb.GetFile(item.Attachments.UrlPrefix + fileName);
            Stream attachmentStream = new MemoryStream(file.OpenBinary());
            Attachment attachment = new Attachment(attachmentStream, file.Name);
            message.Attachments.Add(attachment);
        }
    }
     
    // ** Send the email
    SmtpClient client = new SmtpClient(smtpServer);
    client.Send(message);
     
  12. Close the Workflow Designer and add an item to your list or library to trigger the workflow.
        emailAttachments

 
The code in this example is a great starting point for making further customisations. You may want to change which parameters are passed in or load the attachments from a different item or even using an HTTP Request. The solution presented in this post also works very well when combined with one of our other postings: Automatically convert files to PDF using an e-mail enabled SharePoint Document Library

.

Labels: , , , , ,